diff --git a/objdiff-core/src/arch/mips.rs b/objdiff-core/src/arch/mips.rs index 7abce86..00146ef 100644 --- a/objdiff-core/src/arch/mips.rs +++ b/objdiff-core/src/arch/mips.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use anyhow::{bail, Result}; -use object::{elf, Endian, Endianness, File, Object, Relocation, RelocationFlags}; +use object::{elf, Endian, Endianness, File, Object, Relocation, RelocationFlags, SectionIndex}; use rabbitizer::{config, Abi, InstrCategory, Instruction, OperandType}; use crate::{ @@ -38,6 +38,9 @@ impl ObjArch for ObjArchMips { let code = §ion.data [symbol.section_address as usize..(symbol.section_address + symbol.size) as usize]; + let line_info = + obj.line_info.as_ref().and_then(|map| map.get(&SectionIndex(section.orig_index))); + let start_address = symbol.address; let end_address = symbol.address + symbol.size; let ins_count = code.len() / 4; @@ -110,10 +113,8 @@ impl ObjArch for ObjArchMips { } } } - let line = obj - .line_info - .as_ref() - .and_then(|map| map.range(..=cur_addr as u64).last().map(|(_, &b)| b)); + let line = + line_info.and_then(|map| map.range(..=cur_addr as u64).last().map(|(_, &b)| b)); insts.push(ObjIns { address: cur_addr as u64, size: 4, diff --git a/objdiff-core/src/arch/ppc.rs b/objdiff-core/src/arch/ppc.rs index 39b463b..3c82f6c 100644 --- a/objdiff-core/src/arch/ppc.rs +++ b/objdiff-core/src/arch/ppc.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use anyhow::{bail, Result}; -use object::{elf, File, Relocation, RelocationFlags}; +use object::{elf, File, Relocation, RelocationFlags, SectionIndex}; use ppc750cl::{Argument, InsIter, GPR}; use crate::{ @@ -39,6 +39,9 @@ impl ObjArch for ObjArchPpc { let code = §ion.data [symbol.section_address as usize..(symbol.section_address + symbol.size) as usize]; + let line_info = + obj.line_info.as_ref().and_then(|map| map.get(&SectionIndex(section.orig_index))); + let ins_count = code.len() / 4; let mut ops = Vec::::with_capacity(ins_count); let mut insts = Vec::::with_capacity(ins_count); @@ -131,10 +134,8 @@ impl ObjArch for ObjArchPpc { } ops.push(ins.op as u16); - let line = obj - .line_info - .as_ref() - .and_then(|map| map.range(..=cur_addr as u64).last().map(|(_, &b)| b)); + let line = + line_info.and_then(|map| map.range(..=cur_addr as u64).last().map(|(_, &b)| b)); insts.push(ObjIns { address: cur_addr as u64, size: 4, diff --git a/objdiff-core/src/arch/x86.rs b/objdiff-core/src/arch/x86.rs index 90501aa..f6a11d8 100644 --- a/objdiff-core/src/arch/x86.rs +++ b/objdiff-core/src/arch/x86.rs @@ -6,7 +6,7 @@ use iced_x86::{ GasFormatter, Instruction, IntelFormatter, MasmFormatter, NasmFormatter, NumberKind, OpKind, PrefixKind, Register, }; -use object::{pe, Endian, Endianness, File, Object, Relocation, RelocationFlags}; +use object::{pe, Endian, Endianness, File, Object, Relocation, RelocationFlags, SectionIndex}; use crate::{ arch::{ObjArch, ProcessCodeResult}, @@ -36,6 +36,9 @@ impl ObjArch for ObjArchX86 { let code = §ion.data [symbol.section_address as usize..(symbol.section_address + symbol.size) as usize]; + let line_info = + obj.line_info.as_ref().and_then(|map| map.get(&SectionIndex(section.orig_index))); + let mut result = ProcessCodeResult { ops: Vec::new(), insts: Vec::new() }; let mut decoder = Decoder::with_ip(self.bits, code, symbol.address, DecoderOptions::NONE); let mut formatter: Box = match config.x86_formatter { @@ -80,7 +83,7 @@ impl ObjArch for ObjArchX86 { args: vec![], reloc: reloc.cloned(), branch_dest: None, - line: obj.line_info.as_ref().and_then(|m| m.get(&address).cloned()), + line: line_info.and_then(|m| m.get(&address).cloned()), orig: None, }; // Run the formatter, which will populate output.ins diff --git a/objdiff-core/src/obj/mod.rs b/objdiff-core/src/obj/mod.rs index cfa1d20..0260d24 100644 --- a/objdiff-core/src/obj/mod.rs +++ b/objdiff-core/src/obj/mod.rs @@ -1,11 +1,16 @@ pub mod read; pub mod split_meta; -use std::{borrow::Cow, collections::BTreeMap, fmt, path::PathBuf}; +use std::{ + borrow::Cow, + collections::{BTreeMap, HashMap}, + fmt, + path::PathBuf, +}; use filetime::FileTime; use flagset::{flags, FlagSet}; -use object::RelocationFlags; +use object::{RelocationFlags, SectionIndex}; use split_meta::SplitMeta; use crate::{arch::ObjArch, util::ReallySigned}; @@ -127,7 +132,7 @@ pub struct ObjInfo { /// Common BSS symbols pub common: Vec, /// Line number info (.line or .debug_line section) - pub line_info: Option>, + pub line_info: Option>>, /// Split object metadata (.note.split section) pub split_meta: Option, } diff --git a/objdiff-core/src/obj/read.rs b/objdiff-core/src/obj/read.rs index c65956f..3463d9d 100644 --- a/objdiff-core/src/obj/read.rs +++ b/objdiff-core/src/obj/read.rs @@ -1,4 +1,9 @@ -use std::{collections::BTreeMap, fs, io::Cursor, path::Path}; +use std::{ + collections::{BTreeMap, HashMap}, + fs, + io::Cursor, + path::Path, +}; use anyhow::{anyhow, bail, ensure, Context, Result}; use byteorder::{BigEndian, ReadBytesExt}; @@ -268,13 +273,20 @@ fn relocations_by_section( Ok(relocations) } -fn line_info(obj_file: &File<'_>) -> Result>> { +fn line_info(obj_file: &File<'_>) -> Result>>> { + let mut map = HashMap::new(); + // 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); } + let text_section = obj_file + .sections() + .find(|s| s.kind() == SectionKind::Text) + .context("No text section found for line info")?; + let mut lines = BTreeMap::new(); + let data = section.uncompressed_data()?; let mut reader = Cursor::new(data.as_ref()); @@ -287,13 +299,20 @@ fn line_info(obj_file: &File<'_>) -> Result>> { log::warn!("Unhandled statement pos {}", statement_pos); } let address_delta = reader.read_u32::()? as u64; - map.insert(base_address + address_delta, line_number); + lines.insert(base_address + address_delta, line_number); } + + map.insert(text_section.index(), lines); } // DWARF 2+ #[cfg(feature = "dwarf")] { + let mut text_sections = obj_file.sections().filter(|s| s.kind() == SectionKind::Text); + let first_section = text_sections.next().context("No text section found for line info")?; + map.insert(first_section.index(), BTreeMap::new()); + let mut lines = map.get_mut(&first_section.index()).unwrap(); + let dwarf_cow = gimli::DwarfSections::load(|id| { Ok::<_, gimli::Error>( obj_file @@ -308,13 +327,23 @@ fn line_info(obj_file: &File<'_>) -> Result>> { }; let dwarf = dwarf_cow.borrow(|section| gimli::EndianSlice::new(section, endian)); let mut iter = dwarf.units(); - while let Some(header) = iter.next()? { + 'outer: 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()); + lines.insert(row.address(), line.get()); + } + if row.end_sequence() { + // The next row is the start of a new sequence, which means we must + // advance to the next .text section. + if let Some(next_section) = text_sections.next() { + map.insert(next_section.index(), BTreeMap::new()); + lines = map.get_mut(&next_section.index()).unwrap(); + } else { + break 'outer; + } } } }