diff --git a/Cargo.lock b/Cargo.lock index 55db834..71c21ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1483,6 +1483,12 @@ dependencies = [ "libc", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + [[package]] name = "fastrand" version = "1.9.0" @@ -1820,6 +1826,10 @@ name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] [[package]] name = "gio-sys" @@ -2867,6 +2877,7 @@ dependencies = [ "flagset", "float-ord", "font-kit", + "gimli", "globset", "log", "memmap2", @@ -3900,6 +3911,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 7b2ac68..e7cf41c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ filetime = "0.2.23" flagset = "0.4.4" float-ord = "0.3.2" font-kit = "0.12.0" +gimli = { version = "0.28.1", default-features = false, features = ["read-all"] } globset = { version = "0.4.14", features = ["serde1"] } log = "0.4.20" memmap2 = "0.9.3" diff --git a/src/diff/code.rs b/src/diff/code.rs index fdccc18..78f32a1 100644 --- a/src/diff/code.rs +++ b/src/diff/code.rs @@ -23,7 +23,7 @@ pub fn no_diff_code( data: &[u8], symbol: &mut ObjSymbol, relocs: &[ObjReloc], - line_info: &Option>, + line_info: &Option>, ) -> Result<()> { let code = &data[symbol.section_address as usize..(symbol.section_address + symbol.size) as usize]; @@ -57,8 +57,8 @@ pub fn diff_code( right_symbol: &mut ObjSymbol, left_relocs: &[ObjReloc], right_relocs: &[ObjReloc], - left_line_info: &Option>, - right_line_info: &Option>, + left_line_info: &Option>, + right_line_info: &Option>, ) -> Result<()> { let left_code = &left_data[left_symbol.section_address as usize ..(left_symbol.section_address + left_symbol.size) as usize]; diff --git a/src/obj/elf.rs b/src/obj/elf.rs index 6bd27f2..6cecce2 100644 --- a/src/obj/elf.rs +++ b/src/obj/elf.rs @@ -1,4 +1,4 @@ -use std::{collections::BTreeMap, fs, io::Cursor, path::Path}; +use std::{borrow::Cow, collections::BTreeMap, fs, io::Cursor, path::Path}; use anyhow::{anyhow, bail, Context, Result}; use byteorder::{BigEndian, ReadBytesExt}; @@ -6,8 +6,8 @@ use cwdemangle::demangle; use filetime::FileTime; use flagset::Flags; use object::{ - elf, Architecture, File, Object, ObjectSection, ObjectSymbol, RelocationKind, RelocationTarget, - SectionIndex, SectionKind, Symbol, SymbolKind, SymbolScope, SymbolSection, + elf, Architecture, Endianness, File, Object, ObjectSection, ObjectSymbol, RelocationKind, + RelocationTarget, SectionIndex, SectionKind, Symbol, SymbolKind, SymbolScope, SymbolSection, }; use crate::obj::{ @@ -278,7 +278,9 @@ fn relocations_by_section( Ok(relocations) } -fn line_info(obj_file: &File<'_>) -> Result>> { +fn line_info(obj_file: &File<'_>) -> Result>> { + // DWARF 1.1 + let mut map = BTreeMap::new(); if let Some(section) = obj_file.section_by_name(".line") { if section.size() == 0 { return Ok(None); @@ -286,22 +288,49 @@ fn line_info(obj_file: &File<'_>) -> Result>> { let data = section.uncompressed_data()?; let mut reader = Cursor::new(data.as_ref()); - let mut map = BTreeMap::new(); let size = reader.read_u32::()?; - let base_address = reader.read_u32::()?; + let base_address = reader.read_u32::()? as u64; while reader.position() < size as u64 { - let line_number = reader.read_u32::()?; + let line_number = reader.read_u32::()? as u64; let statement_pos = reader.read_u16::()?; if statement_pos != 0xFFFF { log::warn!("Unhandled statement pos {}", statement_pos); } - let address_delta = reader.read_u32::()?; + let address_delta = reader.read_u32::()? as u64; map.insert(base_address + address_delta, line_number); } - // log::debug!("Line info: {map:#X?}"); - return Ok(Some(map)); } - Ok(None) + + // DWARF 2+ + let dwarf_cow = gimli::Dwarf::load(|id| { + Ok::<_, gimli::Error>( + obj_file + .section_by_name(id.name()) + .and_then(|section| section.uncompressed_data().ok()) + .unwrap_or(Cow::Borrowed(&[][..])), + ) + })?; + let endian = match obj_file.endianness() { + Endianness::Little => gimli::RunTimeEndian::Little, + Endianness::Big => gimli::RunTimeEndian::Big, + }; + let dwarf = dwarf_cow.borrow(|section| gimli::EndianSlice::new(section, endian)); + let mut iter = dwarf.units(); + while let Some(header) = iter.next()? { + let unit = dwarf.unit(header)?; + if let Some(program) = unit.line_program.clone() { + let mut rows = program.rows(); + while let Some((_header, row)) = rows.next_row()? { + if let Some(line) = row.line() { + map.insert(row.address(), line.get()); + } + } + } + } + if map.is_empty() { + return Ok(None); + } + Ok(Some(map)) } pub fn read(obj_path: &Path) -> Result { diff --git a/src/obj/mips.rs b/src/obj/mips.rs index 3d6a7aa..bd07ffe 100644 --- a/src/obj/mips.rs +++ b/src/obj/mips.rs @@ -19,7 +19,7 @@ pub fn process_code( start_address: u64, end_address: u64, relocs: &[ObjReloc], - line_info: &Option>, + line_info: &Option>, ) -> Result { configure_rabbitizer(); @@ -83,8 +83,9 @@ pub fn process_code( } } } - let line = - line_info.as_ref().and_then(|map| map.range(..=cur_addr).last().map(|(_, &b)| b)); + let line = line_info + .as_ref() + .and_then(|map| map.range(..=cur_addr as u64).last().map(|(_, &b)| b)); insts.push(ObjIns { address: cur_addr, code, diff --git a/src/obj/mod.rs b/src/obj/mod.rs index a923373..947b749 100644 --- a/src/obj/mod.rs +++ b/src/obj/mod.rs @@ -113,7 +113,7 @@ pub struct ObjIns { pub reloc: Option, pub branch_dest: Option, /// Line info - pub line: Option, + pub line: Option, /// Original (unsimplified) instruction pub orig: Option, } @@ -172,7 +172,7 @@ pub struct ObjInfo { pub timestamp: FileTime, pub sections: Vec, pub common: Vec, - pub line_info: Option>, + pub line_info: Option>, } #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum ObjRelocKind { diff --git a/src/obj/ppc.rs b/src/obj/ppc.rs index 8856d74..e11db76 100644 --- a/src/obj/ppc.rs +++ b/src/obj/ppc.rs @@ -24,7 +24,7 @@ pub fn process_code( data: &[u8], address: u64, relocs: &[ObjReloc], - line_info: &Option>, + line_info: &Option>, ) -> Result { let ins_count = data.len() / 4; let mut ops = Vec::::with_capacity(ins_count); @@ -82,7 +82,7 @@ pub fn process_code( ops.push(simplified.ins.op as u8); let line = line_info .as_ref() - .and_then(|map| map.range(..=simplified.ins.addr).last().map(|(_, &b)| b)); + .and_then(|map| map.range(..=simplified.ins.addr as u64).last().map(|(_, &b)| b)); insts.push(ObjIns { address: simplified.ins.addr, code: simplified.ins.code,