Skip to content

Commit

Permalink
Handle relocations
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc committed Dec 28, 2018
1 parent 155dfb9 commit 2589d8f
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 28 deletions.
13 changes: 10 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ license = "Apache-2.0/MIT"

[dependencies]
fnv = "1.0"
gimli = { git = "https://github.com/gimli-rs/gimli", rev = "3d15ab86ad6432e3e8dd8bf5c989c4fa63ef4dbd" }
gimli = { git = "https://github.com/gimli-rs/gimli", rev = "d23b4f5fc4f4d60c33ea6d375d9f61543ea5a136" }
log = "0.4"
memmap = "0.7"
moria = { git = "https://github.com/gimli-rs/moria", rev = "83e27832cd70f33ce835726d6b91f064ae0cb50f" }
Expand Down
250 changes: 226 additions & 24 deletions parser/src/file/dwarf.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use std::borrow::Cow;
use std::cell::Cell;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};
use std::mem;
use std::rc::Rc;
use std::u32;

use gimli;
use object;
use gimli::Reader as GimliReader;
use object::{self, ObjectSection};

use file::{DebugInfo, FileHash, StringCache};
use function::{
Expand All @@ -25,7 +26,189 @@ use unit::Unit;
use variable::{LocalVariable, Variable, VariableOffset};
use {Address, Result, Size};

type Reader<'input, Endian> = gimli::EndianSlice<'input, Endian>;
type RelocationMap = HashMap<usize, object::Relocation>;

fn add_relocations<'input, 'file, Object>(
relocations: &mut RelocationMap,
file: &Object,
section: &Object::Section,
) where
Object: object::Object<'input, 'file>,
{
for (offset64, mut relocation) in section.relocations() {
let offset = offset64 as usize;
if offset as u64 != offset64 {
continue;
}
let offset = offset as usize;
match relocation.kind() {
object::RelocationKind::Direct32 | object::RelocationKind::Direct64 => {
if let Some(symbol) = file.symbol_by_index(relocation.symbol()) {
let addend = symbol.address().wrapping_add(relocation.addend() as u64);
relocation.set_addend(addend as i64);
if relocations.insert(offset, relocation).is_some() {
println!(
"Multiple relocations for section {} at offset 0x{:08x}",
section.name().unwrap(),
offset
);
}
} else {
println!(
"Relocation with invalid symbol for section {} at offset 0x{:08x}",
section.name().unwrap(),
offset
);
}
}
_ => {
println!(
"Unsupported relocation for section {} at offset 0x{:08x}",
section.name().unwrap(),
offset
);
}
}
}
}

#[derive(Debug, Clone, Copy)]
struct Relocate<'a, R: gimli::Reader<Offset = usize>> {
relocations: &'a RelocationMap,
section: R,
reader: R,
}

impl<'a, R: gimli::Reader<Offset = usize>> Relocate<'a, R> {
fn relocate(&self, offset: usize, value: u64) -> u64 {
if let Some(relocation) = self.relocations.get(&offset) {
match relocation.kind() {
object::RelocationKind::Direct32 | object::RelocationKind::Direct64 => {
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, Endian> Relocate<'a, gimli::EndianSlice<'a, Endian>>
where
Endian: gimli::Endianity,
{
fn to_string_lossy(&self) -> Cow<'a, str> {
self.reader.to_string_lossy()
}

fn slice(&self) -> &'a [u8] {
self.reader.slice()
}
}

impl<'a, R: gimli::Reader<Offset = usize>> gimli::Reader for Relocate<'a, R> {
type Endian = R::Endian;
type Offset = R::Offset;

fn read_address(&mut self, address_size: u8) -> gimli::Result<u64> {
let offset = self.reader.offset_from(&self.section);
let value = self.reader.read_address(address_size)?;
Ok(self.relocate(offset, value))
}

fn read_length(&mut self, format: gimli::Format) -> gimli::Result<usize> {
let offset = self.reader.offset_from(&self.section);
let value = self.reader.read_length(format)?;
<usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64))
}

fn read_offset(&mut self, format: gimli::Format) -> gimli::Result<usize> {
let offset = self.reader.offset_from(&self.section);
let value = self.reader.read_offset(format)?;
<usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64))
}

fn read_sized_offset(&mut self, size: u8) -> gimli::Result<usize> {
let offset = self.reader.offset_from(&self.section);
let value = self.reader.read_sized_offset(size)?;
<usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64))
}

#[inline]
fn split(&mut self, len: Self::Offset) -> gimli::Result<Self> {
let mut other = self.clone();
other.reader.truncate(len)?;
self.reader.skip(len)?;
Ok(other)
}

// All remaining methods simply delegate to `self.reader`.

#[inline]
fn endian(&self) -> Self::Endian {
self.reader.endian()
}

#[inline]
fn len(&self) -> Self::Offset {
self.reader.len()
}

#[inline]
fn empty(&mut self) {
self.reader.empty()
}

#[inline]
fn truncate(&mut self, len: Self::Offset) -> gimli::Result<()> {
self.reader.truncate(len)
}

#[inline]
fn offset_from(&self, base: &Self) -> Self::Offset {
self.reader.offset_from(&base.reader)
}

#[inline]
fn find(&self, byte: u8) -> gimli::Result<Self::Offset> {
self.reader.find(byte)
}

#[inline]
fn skip(&mut self, len: Self::Offset) -> gimli::Result<()> {
self.reader.skip(len)
}

#[inline]
fn to_slice(&self) -> gimli::Result<Cow<[u8]>> {
self.reader.to_slice()
}

#[inline]
fn to_string(&self) -> gimli::Result<Cow<str>> {
self.reader.to_string()
}

#[inline]
fn to_string_lossy(&self) -> gimli::Result<Cow<str>> {
self.reader.to_string_lossy()
}

#[inline]
fn read_u8_array<A>(&mut self) -> gimli::Result<A>
where
A: Sized + Default + AsMut<[u8]>,
{
self.reader.read_u8_array()
}
}

type Reader<'input, Endian> = Relocate<'input, gimli::EndianSlice<'input, Endian>>;

pub(crate) struct DwarfDebugInfo<'input, Endian>
where
Expand Down Expand Up @@ -169,28 +352,47 @@ where
Object: object::Object<'input, 'file>,
Cb: FnOnce(Vec<Unit>, DebugInfo<Endian>) -> Result<()>,
{
let get_section = |name| {
object
.section_data_by_name(name)
.unwrap_or(Cow::Borrowed(&[]))
};
let debug_abbrev = get_section(".debug_abbrev");
let debug_abbrev = gimli::DebugAbbrev::new(&debug_abbrev, endian);
let debug_info = get_section(".debug_info");
let debug_info = gimli::DebugInfo::new(&debug_info, endian);
let debug_line = get_section(".debug_line");
let debug_line = gimli::DebugLine::new(&debug_line, endian);
let debug_str = get_section(".debug_str");
let debug_str = gimli::DebugStr::new(&debug_str, endian);
let debug_ranges = get_section(".debug_ranges");
let debug_ranges = gimli::DebugRanges::new(&debug_ranges, endian);
let debug_rnglists = get_section(".debug_rnglists");
let debug_rnglists = gimli::DebugRngLists::new(&debug_rnglists, endian);
macro_rules! get_section {
($name:expr) => {{
let mut relocations = RelocationMap::default();
let data = match object.section_by_name($name) {
Some(ref section) => {
add_relocations(&mut relocations, object, section);
section.uncompressed_data()
}
None => Cow::Borrowed(&[][..]),
};
(data, relocations)
}};
}
macro_rules! get_reader {
($data:expr) => {{
let reader = gimli::EndianSlice::new(&$data.0, endian);
let section = reader.clone();
Relocate {
relocations: &$data.1,
section,
reader,
}
}};
}
let debug_abbrev = get_section!(".debug_abbrev");
let debug_abbrev = gimli::DebugAbbrev::from(get_reader!(debug_abbrev));
let debug_info = get_section!(".debug_info");
let debug_info = gimli::DebugInfo::from(get_reader!(debug_info));
let debug_line = get_section!(".debug_line");
let debug_line = gimli::DebugLine::from(get_reader!(debug_line));
let debug_str = get_section!(".debug_str");
let debug_str = gimli::DebugStr::from(get_reader!(debug_str));
let debug_ranges = get_section!(".debug_ranges");
let debug_ranges = gimli::DebugRanges::from(get_reader!(debug_ranges));
let debug_rnglists = get_section!(".debug_rnglists");
let debug_rnglists = gimli::DebugRngLists::from(get_reader!(debug_rnglists));
let range_lists = gimli::RangeLists::new(debug_ranges, debug_rnglists)?;
let debug_loc = get_section(".debug_loc");
let debug_loc = gimli::DebugLoc::new(&debug_loc, endian);
let debug_loclists = get_section(".debug_loclists");
let debug_loclists = gimli::DebugLocLists::new(&debug_loclists, endian);
let debug_loc = get_section!(".debug_loc");
let debug_loc = gimli::DebugLoc::from(get_reader!(debug_loc));
let debug_loclists = get_section!(".debug_loclists");
let debug_loclists = gimli::DebugLocLists::from(get_reader!(debug_loclists));
let location_lists = gimli::LocationLists::new(debug_loc, debug_loclists)?;

let mut dwarf = DwarfDebugInfo {
Expand Down

0 comments on commit 2589d8f

Please sign in to comment.