Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ exclude = ["/.github", "/.vscode", "/tests", "/fixtures", "/big-fixtures"]

[dependencies]
gimli = "0.27.0"
object = { version = ">=0.30", optional = true }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, what are the best practices around features? I find this behavior of "optional dependencies automatically turn into off-by-default feature names" a bit weird, it's hard to see at a glance what the list of available features is. Is this a common way of doing things?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a consumer perspective (I've not authored many crates with this requirement), I see this pattern occasionally. The convenient part is that it Just Works:tm: as a sibling to the optional crate. E.g., if I have a project where I'm using object already and then I add framehop to do some stuff (such a situation is likely to be quite common), the framehop support for the object crate will be automatically enabled without me doing anything else.

If you feel that it should be behind a separate, explicit flag, I can get behind that. But FWIW I think that cargo/docs.rs could use improvement when it comes to feature documentation as it is. I would have preferred a world where features in Cargo.toml had to have descriptions of their purpose. But IMO an optional dependency of this nature is a little different from explicit features, as it's meant to add some convenience features when the other dependency is present.

thiserror = "1.0.30"
macho-unwind-info = "0.3.0"
fallible-iterator = "0.2.0"
Expand Down
2 changes: 1 addition & 1 deletion src/arcdata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ impl<D: Deref<Target = [u8]>> Deref for ArcData<D> {
type Target = [u8];

fn deref(&self) -> &Self::Target {
&*self.0
&self.0
}
}

Expand Down
62 changes: 33 additions & 29 deletions src/dwarf.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use std::{marker::PhantomData, ops::Range};
use std::marker::PhantomData;

use gimli::{
BaseAddresses, CfaRule, CieOrFde, DebugFrame, EhFrame, EhFrameHdr, Encoding, EndianSlice,
Evaluation, EvaluationResult, EvaluationStorage, Expression, LittleEndian, Location,
ParsedEhFrameHdr, Reader, ReaderOffset, Register, RegisterRule, UnwindContext,
UnwindContextStorage, UnwindOffset, UnwindSection, UnwindTableRow, Value,
CfaRule, CieOrFde, DebugFrame, EhFrame, EhFrameHdr, Encoding, EndianSlice, Evaluation,
EvaluationResult, EvaluationStorage, Expression, LittleEndian, Location, ParsedEhFrameHdr,
Reader, ReaderOffset, Register, RegisterRule, UnwindContext, UnwindContextStorage,
UnwindOffset, UnwindSection, UnwindTableRow, Value,
};

use crate::{arch::Arch, unwind_result::UnwindResult, ModuleSvmaInfo};
pub(crate) use gimli::BaseAddresses;

use crate::{arch::Arch, unwind_result::UnwindResult, ModuleSectionInfo};

#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
pub enum DwarfUnwinderError {
Expand Down Expand Up @@ -90,9 +92,9 @@ impl<'a, R: Reader, A: DwarfUnwinding, S: UnwindContextStorage<R> + EvaluationSt
unwind_section_type: UnwindSectionType,
eh_frame_hdr_data: Option<&'a [u8]>,
unwind_context: &'a mut UnwindContext<R, S>,
svma_info: &ModuleSvmaInfo,
bases: BaseAddresses,
base_svma: u64,
) -> Self {
let bases = base_addresses_for_sections(svma_info);
let eh_frame_hdr = match eh_frame_hdr_data {
Some(eh_frame_hdr_data) => {
let hdr = EhFrameHdr::new(eh_frame_hdr_data, unwind_section_data.endian());
Expand All @@ -109,7 +111,7 @@ impl<'a, R: Reader, A: DwarfUnwinding, S: UnwindContextStorage<R> + EvaluationSt
eh_frame_hdr,
unwind_context,
bases,
base_svma: svma_info.base_svma,
base_svma,
_arch: PhantomData,
}
}
Expand Down Expand Up @@ -180,19 +182,21 @@ impl<'a, R: Reader, A: DwarfUnwinding, S: UnwindContextStorage<R> + EvaluationSt
}
}

fn base_addresses_for_sections(svma_info: &ModuleSvmaInfo) -> BaseAddresses {
fn start_addr(range: &Option<Range<u64>>) -> u64 {
if let Some(range) = range {
range.start
} else {
0
}
}
pub(crate) fn base_addresses_for_sections<D>(
section_info: &mut impl ModuleSectionInfo<D>,
) -> BaseAddresses {
let mut start_addr = |names: &[&[u8]]| -> u64 {
names
.iter()
.find_map(|name| section_info.section_svma_range(name))
.map(|r| r.start)
.unwrap_or_default()
};
BaseAddresses::default()
.set_eh_frame(start_addr(&svma_info.eh_frame))
.set_eh_frame_hdr(start_addr(&svma_info.eh_frame_hdr))
.set_text(start_addr(&svma_info.text))
.set_got(start_addr(&svma_info.got))
.set_eh_frame(start_addr(&[b"__eh_frame", b".eh_frame"]))
.set_eh_frame_hdr(start_addr(&[b"__eh_frame_hdr", b".eh_frame_hdr"]))
.set_text(start_addr(&[b"__text", b".text"]))
.set_got(start_addr(&[b"__got", b".got"]))
}

#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -279,26 +283,26 @@ impl DwarfCfiIndex {
})
}

pub fn try_new_eh_frame(
pub fn try_new_eh_frame<D>(
eh_frame_data: &[u8],
svma_info: &ModuleSvmaInfo,
section_info: &mut impl ModuleSectionInfo<D>,
) -> Result<Self, DwarfCfiIndexError> {
let bases = base_addresses_for_sections(svma_info);
let bases = base_addresses_for_sections(section_info);
let mut eh_frame = EhFrame::from(EndianSlice::new(eh_frame_data, LittleEndian));
eh_frame.set_address_size(8);

Self::try_new(eh_frame, bases, svma_info.base_svma)
Self::try_new(eh_frame, bases, section_info.base_svma())
}

pub fn try_new_debug_frame(
pub fn try_new_debug_frame<D>(
debug_frame_data: &[u8],
svma_info: &ModuleSvmaInfo,
section_info: &mut impl ModuleSectionInfo<D>,
) -> Result<Self, DwarfCfiIndexError> {
let bases = base_addresses_for_sections(svma_info);
let bases = base_addresses_for_sections(section_info);
let mut debug_frame = DebugFrame::from(EndianSlice::new(debug_frame_data, LittleEndian));
debug_frame.set_address_size(8);

Self::try_new(debug_frame, bases, svma_info.base_svma)
Self::try_new(debug_frame, bases, section_info.base_svma())
}

pub fn fde_offset_for_relative_address(&self, rel_lookup_address: u32) -> Option<u32> {
Expand Down
34 changes: 16 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@
//!
//! ## Example
//!
//! ```rust
//! # fn test_root_doc_comment() {
//! ```
//! use std::ops::Range;
//! use framehop::aarch64::{CacheAarch64, UnwindRegsAarch64, UnwinderAarch64};
//! use framehop::{FrameAddress, Module, ModuleSvmaInfo, ModuleUnwindData, TextByteData};
//! use framehop::{ExplicitModuleSectionInfo, FrameAddress, Module, ModuleSectionInfo};
//!
//! let mut cache = CacheAarch64::<_>::new();
//! let mut unwinder = UnwinderAarch64::new();
Expand All @@ -59,21 +59,20 @@
//! "mybinary".to_string(),
//! 0x1003fc000..0x100634000,
//! 0x1003fc000,
//! ModuleSvmaInfo {
//! ExplicitModuleSectionInfo {
//! base_svma: 0x100000000,
//! text: Some(0x100000b64..0x1001d2d18),
//! text_env: None,
//! stubs: Some(0x1001d2d18..0x1001d309c),
//! stub_helper: Some(0x1001d309c..0x1001d3438),
//! eh_frame: Some(0x100237f80..0x100237ffc),
//! eh_frame_hdr: None,
//! got: Some(0x100238000..0x100238010),
//! text_svma: Some(0x100000b64..0x1001d2d18),
//! text: Some(vec![/* __text */]),
//! stubs_svma: Some(0x1001d2d18..0x1001d309c),
//! stub_helper_svma: Some(0x1001d309c..0x1001d3438),
//! got_svma: Some(0x100238000..0x100238010),
//! unwind_info: Some(vec![/* __unwind_info */]),
//! eh_frame_svma: Some(0x100237f80..0x100237ffc),
//! eh_frame: Some(vec![/* __eh_frame */]),
//! text_segment_file_range: Some(0x1003fc000..0x100634000),
//! text_segment: Some(vec![/* __TEXT */]),
//! ..Default::default()
//! },
//! ModuleUnwindData::CompactUnwindInfoAndEhFrame(vec![/* __unwind_info */], None),
//! Some(TextByteData::new(
//! vec![/* __TEXT */],
//! 0x1003fc000..0x100634000,
//! )),
//! );
//! unwinder.add_module(module);
//!
Expand Down Expand Up @@ -109,7 +108,6 @@
//! FrameAddress::from_return_address(0x1003fc000 + 0x12ca28).unwrap()
//! ]
//! );
//! # }
//! ```

mod add_signed;
Expand Down Expand Up @@ -137,7 +135,7 @@ pub use code_address::FrameAddress;
pub use error::Error;
pub use rule_cache::CacheStats;
pub use unwinder::{
Module, ModuleSvmaInfo, ModuleUnwindData, TextByteData, UnwindIterator, Unwinder,
ExplicitModuleSectionInfo, Module, ModuleSectionInfo, UnwindIterator, Unwinder,
};

/// The unwinder cache for the native CPU architecture.
Expand Down
Loading