Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow access to the parsed dwarf #159

Merged
merged 2 commits into from
May 5, 2020
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ travis-ci = { repository = "gimli-rs/addr2line" }
[dependencies]
gimli = { version = "0.20", default-features = false, features = ["read"] }
fallible-iterator = { version = "0.2", default-features = false }
object = { version = "0.17", default-features = false, features = ["read"], optional = true }
object = { version = "0.18", default-features = false, features = ["read"], optional = true }
smallvec = { version = "1", default-features = false }
lazycell = "1"
rustc-demangle = { version = "0.1", optional = true }
Expand Down
9 changes: 6 additions & 3 deletions benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ fn with_file<F: FnOnce(&object::File)>(target: &path::Path, f: F) {

fn dwarf_load<'a>(object: &object::File<'a>) -> gimli::Dwarf<Cow<'a, [u8]>> {
let load_section = |id: gimli::SectionId| -> Result<Cow<'a, [u8]>, gimli::Error> {
Ok(object
.section_data_by_name(id.name())
.unwrap_or(Cow::Borrowed(&[][..])))
use object::ObjectSection;
let data = object
.section_by_name(id.name())
.and_then(|section| section.data().ok())
.unwrap_or(&[][..]);
Ok(Cow::Borrowed(data))
};
let load_section_sup = |_| Ok(Cow::Borrowed(&[][..]));
gimli::Dwarf::load(&load_section, &load_section_sup).unwrap()
Expand Down
34 changes: 29 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,12 @@ impl Context<gimli::EndianRcSlice<gimli::RunTimeEndian>> {
S: gimli::Section<gimli::EndianRcSlice<Endian>>,
Endian: gimli::Endianity,
{
use object::ObjectSection;

let data = file
.section_data_by_name(S::section_name())
.unwrap_or(Cow::Borrowed(&[]));
.section_by_name(S::section_name())
.and_then(|section| section.data().ok())
.unwrap_or(&[]);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm going to have to rethink the object API here. For compressed sections, we should support either decompressing or returning an error (based on whether the compression feature is enabled).

S::from(gimli::EndianRcSlice::new(Rc::from(&*data), endian))
}

Expand Down Expand Up @@ -266,7 +269,12 @@ impl<R: gimli::Reader> Context<R> {
})
}

fn find_unit(&self, probe: u64) -> Option<usize> {
/// The dwarf sections associated with this `Context`.
pub fn dwarf(&self) -> &gimli::Dwarf<R> {
&self.sections
}

fn find_unit_id(&self, probe: u64) -> Option<usize> {
let idx = self.unit_ranges.binary_search_by(|r| {
if probe < r.0.begin {
Ordering::Greater
Expand All @@ -285,9 +293,14 @@ impl<R: gimli::Reader> Context<R> {
Some(unit_id)
}

/// Find the DWARF unit corresponding to the given virtual memory address.
pub fn find_dwarf_unit(&self, probe: u64) -> Option<&gimli::Unit<R>> {
self.find_unit_id(probe).map(|unit_id| &self.units[unit_id].dw_unit)
}

/// Find the source file and line corresponding to the given virtual memory address.
pub fn find_location(&self, probe: u64) -> Result<Option<Location<'_>>, Error> {
match self.find_unit(probe) {
match self.find_unit_id(probe) {
Some(unit_id) => self.units[unit_id].find_location(probe, &self.sections),
None => Ok(None),
}
Expand All @@ -303,7 +316,7 @@ impl<R: gimli::Reader> Context<R> {
/// to the innermost inline function. Subsequent frames contain the caller and call
/// location, until an non-inline caller is reached.
pub fn find_frames(&self, probe: u64) -> Result<FrameIter<R>, Error> {
let (unit_id, loc, funcs) = match self.find_unit(probe) {
let (unit_id, loc, funcs) = match self.find_unit_id(probe) {
Some(unit_id) => {
let unit = &self.units[unit_id];
let loc = unit.find_location(probe, &self.sections)?;
Expand Down Expand Up @@ -665,6 +678,7 @@ struct Functions<R: gimli::Reader> {
}

struct Function<R: gimli::Reader> {
dw_die_offset: gimli::UnitOffset<R::Offset>,
name: Option<R>,
call_file: u64,
call_line: u32,
Expand All @@ -687,10 +701,12 @@ impl<R: gimli::Reader> Functions<R> {
let mut inlined = Vec::new();
let mut entries = unit.entries_raw(None)?;
while !entries.is_empty() {
let dw_die_offset = entries.next_offset();
let depth = entries.next_depth();
if let Some(abbrev) = entries.read_abbreviation()? {
if abbrev.tag() == gimli::DW_TAG_subprogram {
Function::parse(
dw_die_offset,
&mut entries,
abbrev,
depth,
Expand Down Expand Up @@ -725,6 +741,7 @@ impl<R: gimli::Reader> Functions<R> {

impl<R: gimli::Reader> Function<R> {
fn parse(
dw_die_offset: gimli::UnitOffset<R::Offset>,
entries: &mut gimli::EntriesRaw<R>,
abbrev: &gimli::Abbreviation,
depth: isize,
Expand Down Expand Up @@ -800,6 +817,7 @@ impl<R: gimli::Reader> Function<R> {

let mut local_inlined = Vec::new();
loop {
let dw_die_offset = entries.next_offset();
let next_depth = entries.next_depth();
if next_depth <= depth {
break;
Expand All @@ -809,6 +827,7 @@ impl<R: gimli::Reader> Function<R> {
|| abbrev.tag() == gimli::DW_TAG_inlined_subroutine
{
Function::parse(
dw_die_offset,
entries,
abbrev,
next_depth,
Expand All @@ -832,6 +851,7 @@ impl<R: gimli::Reader> Function<R> {

let function_index = functions.len();
functions.push(Function {
dw_die_offset,
name,
call_file,
call_line,
Expand Down Expand Up @@ -896,6 +916,7 @@ where
(loc, Some(func)) => (loc, func),
(Some(loc), None) => {
return Ok(Some(Frame {
dw_die_offset: None,
function: None,
location: Some(loc),
}))
Expand Down Expand Up @@ -928,6 +949,7 @@ where
}

Ok(Some(Frame {
dw_die_offset: Some(func.dw_die_offset),
function: func.name.clone().map(|name| FunctionName {
name,
language: unit.lang,
Expand All @@ -952,6 +974,8 @@ where

/// A function frame.
pub struct Frame<'ctx, R: gimli::Reader> {
/// The DWARF unit offset corresponding to the DIE of the function.
pub dw_die_offset: Option<gimli::UnitOffset<R::Offset>>,
/// The name of the function.
pub function: Option<FunctionName<R>>,
/// The source location corresponding to this frame.
Expand Down
10 changes: 7 additions & 3 deletions tests/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ fn with_file<F: FnOnce(&object::File)>(target: &path::Path, f: F) {

fn dwarf_load<'a>(object: &object::File<'a>) -> gimli::Dwarf<Cow<'a, [u8]>> {
let load_section = |id: gimli::SectionId| -> Result<Cow<'a, [u8]>, gimli::Error> {
Ok(object
.section_data_by_name(id.name())
.unwrap_or(Cow::Borrowed(&[][..])))
use object::ObjectSection;

let data = object
.section_by_name(id.name())
.and_then(|section| section.data().ok())
.unwrap_or(&[][..]);
Ok(Cow::Borrowed(data))
};
let load_section_sup = |_| Ok(Cow::Borrowed(&[][..]));
gimli::Dwarf::load(&load_section, &load_section_sup).unwrap()
Expand Down