Skip to content

Commit

Permalink
examples: use object::RelocationMap
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc committed Apr 10, 2024
1 parent 0012ab2 commit 1aa8a0a
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 101 deletions.
101 changes: 17 additions & 84 deletions crates/examples/src/bin/dwarfdump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use fallible_iterator::FallibleIterator;
use gimli::{Section, UnitHeader, UnitOffset, UnitSectionOffset, UnitType, UnwindSection};
use object::{Object, ObjectSection, ObjectSymbol};
use object::{Object, ObjectSection};
use regex::bytes::Regex;
use std::borrow::Cow;
use std::cmp::min;
Expand Down Expand Up @@ -154,89 +154,31 @@ impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where
{
}

fn add_relocations(
relocations: &mut RelocationMap,
file: &object::File,
section: &object::Section,
) {
for (offset64, mut relocation) in section.relocations() {
let offset = offset64 as usize;
if offset as u64 != offset64 {
continue;
}
// There are other things we could match but currently don't
#[allow(clippy::single_match)]
match relocation.kind() {
object::RelocationKind::Absolute => {
match relocation.target() {
object::RelocationTarget::Symbol(symbol_idx) => {
match file.symbol_by_index(symbol_idx) {
Ok(symbol) => {
let addend =
symbol.address().wrapping_add(relocation.addend() as u64);
relocation.set_addend(addend as i64);
}
Err(_) => {
eprintln!(
"Relocation with invalid symbol for section {} at offset 0x{:08x}",
section.name().unwrap(),
offset
);
}
}
}
_ => {}
}
if relocations.0.insert(offset, relocation).is_some() {
eprintln!(
"Multiple relocations for section {} at offset 0x{:08x}",
section.name().unwrap(),
offset
);
}
}
_ => {
#[derive(Debug, Default)]
struct RelocationMap(object::read::RelocationMap);

impl RelocationMap {
fn add(&mut self, file: &object::File, section: &object::Section) {
for (offset, relocation) in section.relocations() {
if let Err(e) = self.0.add(file, offset, relocation) {
eprintln!(
"Unsupported relocation for section {} at offset 0x{:08x}",
"Relocation error for section {} at offset 0x{:08x}: {}",
section.name().unwrap(),
offset
offset,
e
);
}
}
}
}

#[derive(Debug, Default)]
struct RelocationMap(HashMap<usize, object::Relocation>);

impl RelocationMap {
fn relocate(&self, offset: usize, value: u64) -> u64 {
if let Some(relocation) = self.0.get(&offset) {
// There are other things we could match but currently don't
#[allow(clippy::single_match)]
match relocation.kind() {
object::RelocationKind::Absolute => {
if relocation.has_implicit_addend() {
// Use the explicit addend too, because it may have the symbol value.
return value.wrapping_add(relocation.addend() as u64);
} else {
return relocation.addend() as u64;
}
}
_ => {}
}
};
value
}
}

impl<'a> gimli::read::Relocate for &'a RelocationMap {
fn relocate_address(&self, offset: usize, value: u64) -> gimli::Result<u64> {
Ok(self.relocate(offset, value))
Ok(self.0.relocate(offset as u64, value))
}

fn relocate_offset(&self, offset: usize, value: usize) -> gimli::Result<usize> {
<usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64))
<usize as gimli::ReaderOffset>::from_u64(self.0.relocate(offset as u64, value as u64))
}
}

Expand Down Expand Up @@ -453,16 +395,6 @@ fn main() {
}
}

fn empty_file_section<Endian: gimli::Endianity>(
endian: Endian,
arena_relocations: &Arena<RelocationMap>,
) -> Relocate<'_, gimli::EndianSlice<'_, Endian>> {
let section = gimli::EndianSlice::new(&[], endian);
let relocations = RelocationMap::default();
let relocations = arena_relocations.alloc(relocations);
Relocate::new(relocations, section)
}

fn load_file_section<'input, 'arena, Endian: gimli::Endianity>(
id: gimli::SectionId,
file: &object::File<'input>,
Expand All @@ -484,7 +416,7 @@ fn load_file_section<'input, 'arena, Endian: gimli::Endianity>(
Some(ref section) => {
// DWO sections never have relocations, so don't bother.
if !is_dwo {
add_relocations(&mut relocations, file, section);
relocations.add(file, section);
}
section.uncompressed_data()?
}
Expand All @@ -494,7 +426,7 @@ fn load_file_section<'input, 'arena, Endian: gimli::Endianity>(
let data_ref = arena_data.alloc(data);
let section = gimli::EndianSlice::new(data_ref, endian);
let relocations = arena_relocations.alloc(relocations);
Ok(Relocate::new(relocations, section))
Ok(Relocate::new(section, relocations))
}

fn dump_file<Endian>(file: &object::File, endian: Endian, flags: &Flags) -> Result<()>
Expand Down Expand Up @@ -554,7 +486,8 @@ where

let w = &mut BufWriter::new(io::stdout());
if flags.dwp {
let empty = empty_file_section(endian, &arena_relocations);
let empty_relocations = arena_relocations.alloc(RelocationMap::default());
let empty = Relocate::new(gimli::EndianSlice::new(&[], endian), empty_relocations);
let dwp = gimli::DwarfPackage::load(&mut load_section, empty)?;
dump_dwp(w, &dwp, dwo_parent.unwrap(), dwo_parent_units, flags)?;
w.flush()?;
Expand Down
78 changes: 61 additions & 17 deletions crates/examples/src/bin/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,38 @@
//! Most of the complexity is due to loading the sections from the object
//! file and DWP file, which is not something that is provided by gimli itself.
use gimli::Reader as _;
use object::{Object, ObjectSection};
use std::{borrow, env, error, fs};

// This is a simple wrapper around `object::read::RelocationMap` that implements
// `gimli::read::Relocate` for use with `gimli::RelocateReader`.
// You only need this if you are parsing relocatable object files.
#[derive(Debug, Default)]
struct RelocationMap(object::read::RelocationMap);

impl<'a> gimli::read::Relocate for &'a RelocationMap {
fn relocate_address(&self, offset: usize, value: u64) -> gimli::Result<u64> {
Ok(self.0.relocate(offset as u64, value))
}

fn relocate_offset(&self, offset: usize, value: usize) -> gimli::Result<usize> {
<usize as gimli::ReaderOffset>::from_u64(self.0.relocate(offset as u64, value as u64))
}
}

// The section data that will be stored in `DwarfSections` and `DwarfPackageSections`.
#[derive(Default)]
struct Section<'data> {
data: borrow::Cow<'data, [u8]>,
relocations: RelocationMap,
}

// The reader type that will be stored in `Dwarf` and `DwarfPackage`.
// If you don't need relocations, you can use `gimli::EndianSlice` directly.
type Reader<'data> =
gimli::RelocateReader<gimli::EndianSlice<'data, gimli::RunTimeEndian>, &'data RelocationMap>;

fn main() {
let mut args = env::args();
if args.len() != 2 && args.len() != 3 {
Expand Down Expand Up @@ -46,19 +75,28 @@ fn dump_file(
dwp_object: Option<&object::File>,
endian: gimli::RunTimeEndian,
) -> Result<(), Box<dyn error::Error>> {
// Load a section and return as `Cow<[u8]>`.
fn load_section<'a>(
object: &'a object::File,
// Load a `Section` that may own its data.
fn load_section<'data>(
object: &object::File<'data>,
name: &str,
) -> Result<borrow::Cow<'a, [u8]>, Box<dyn error::Error>> {
) -> Result<Section<'data>, Box<dyn error::Error>> {
Ok(match object.section_by_name(name) {
Some(section) => section.uncompressed_data()?,
None => borrow::Cow::Borrowed(&[]),
Some(section) => Section {
data: section.uncompressed_data()?,
relocations: section.relocation_map().map(RelocationMap)?,
},
None => Default::default(),
})
}

// Borrow a `Cow<[u8]>` to create an `EndianSlice`.
let borrow_section = |section| gimli::EndianSlice::new(borrow::Cow::as_ref(section), endian);
// Borrow a `Section` to create a `Reader`.
fn borrow_section<'data>(
section: &'data Section<'data>,
endian: gimli::RunTimeEndian,
) -> Reader<'data> {
let slice = gimli::EndianSlice::new(borrow::Cow::as_ref(&section.data), endian);
gimli::RelocateReader::new(slice, &section.relocations)
}

// Load all of the sections.
let dwarf_sections = gimli::DwarfSections::load(|id| load_section(object, id.name()))?;
Expand All @@ -68,13 +106,17 @@ fn dump_file(
})
.transpose()?;

// Create `EndianSlice`s for all of the sections and do preliminary parsing.
let empty_relocations = RelocationMap::default();
let empty_section =
gimli::RelocateReader::new(gimli::EndianSlice::new(&[], endian), &empty_relocations);

// Create `Reader`s for all of the sections and do preliminary parsing.
// Alternatively, we could have used `Dwarf::load` with an owned type such as `EndianRcSlice`.
let dwarf = dwarf_sections.borrow(borrow_section);
let dwarf = dwarf_sections.borrow(|section| borrow_section(section, endian));
let dwp = dwp_sections
.as_ref()
.map(|dwp_sections| {
dwp_sections.borrow(borrow_section, gimli::EndianSlice::new(&[], endian))
dwp_sections.borrow(|section| borrow_section(section, endian), empty_section)
})
.transpose()?;

Expand All @@ -86,7 +128,7 @@ fn dump_file(
header.offset().as_debug_info_offset().unwrap().0
);
let unit = dwarf.unit(header)?;
dump_unit(&unit)?;
dump_unit(&dwarf, &unit)?;

// Check for a DWO unit.
let Some(dwp) = &dwp else { continue };
Expand All @@ -99,15 +141,13 @@ fn dump_file(
continue;
};
let unit = dwo.unit(header)?;
dump_unit(&unit)?;
dump_unit(&dwo, &unit)?;
}

Ok(())
}

fn dump_unit(
unit: &gimli::Unit<gimli::EndianSlice<gimli::RunTimeEndian>>,
) -> Result<(), gimli::Error> {
fn dump_unit(dwarf: &gimli::Dwarf<Reader>, unit: &gimli::Unit<Reader>) -> Result<(), gimli::Error> {
// Iterate over the Debugging Information Entries (DIEs) in the unit.
let mut depth = 0;
let mut entries = unit.entries();
Expand All @@ -118,7 +158,11 @@ fn dump_unit(
// Iterate over the attributes in the DIE.
let mut attrs = entry.attrs();
while let Some(attr) = attrs.next()? {
println!(" {}: {:?}", attr.name(), attr.value());
print!(" {}: {:?}", attr.name(), attr.value());
if let Ok(s) = dwarf.attr_string(unit, attr.value()) {
print!(" '{}'", s.to_string_lossy()?);
}
println!();
}
}
Ok(())
Expand Down

0 comments on commit 1aa8a0a

Please # to comment.