Add DWARF 2+ line info support

Resolves #37
This commit is contained in:
Luke Street 2024-01-21 23:38:52 -07:00
parent 405a2a82db
commit eef9598e76
7 changed files with 69 additions and 21 deletions

17
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -23,7 +23,7 @@ pub fn no_diff_code(
data: &[u8],
symbol: &mut ObjSymbol,
relocs: &[ObjReloc],
line_info: &Option<BTreeMap<u32, u32>>,
line_info: &Option<BTreeMap<u64, u64>>,
) -> 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<BTreeMap<u32, u32>>,
right_line_info: &Option<BTreeMap<u32, u32>>,
left_line_info: &Option<BTreeMap<u64, u64>>,
right_line_info: &Option<BTreeMap<u64, u64>>,
) -> Result<()> {
let left_code = &left_data[left_symbol.section_address as usize
..(left_symbol.section_address + left_symbol.size) as usize];

View File

@ -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<Option<BTreeMap<u32, u32>>> {
fn line_info(obj_file: &File<'_>) -> Result<Option<BTreeMap<u64, u64>>> {
// 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<Option<BTreeMap<u32, u32>>> {
let data = section.uncompressed_data()?;
let mut reader = Cursor::new(data.as_ref());
let mut map = BTreeMap::new();
let size = reader.read_u32::<BigEndian>()?;
let base_address = reader.read_u32::<BigEndian>()?;
let base_address = reader.read_u32::<BigEndian>()? as u64;
while reader.position() < size as u64 {
let line_number = reader.read_u32::<BigEndian>()?;
let line_number = reader.read_u32::<BigEndian>()? as u64;
let statement_pos = reader.read_u16::<BigEndian>()?;
if statement_pos != 0xFFFF {
log::warn!("Unhandled statement pos {}", statement_pos);
}
let address_delta = reader.read_u32::<BigEndian>()?;
let address_delta = reader.read_u32::<BigEndian>()? 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<ObjInfo> {

View File

@ -19,7 +19,7 @@ pub fn process_code(
start_address: u64,
end_address: u64,
relocs: &[ObjReloc],
line_info: &Option<BTreeMap<u32, u32>>,
line_info: &Option<BTreeMap<u64, u64>>,
) -> Result<ProcessCodeResult> {
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,

View File

@ -113,7 +113,7 @@ pub struct ObjIns {
pub reloc: Option<ObjReloc>,
pub branch_dest: Option<u32>,
/// Line info
pub line: Option<u32>,
pub line: Option<u64>,
/// Original (unsimplified) instruction
pub orig: Option<String>,
}
@ -172,7 +172,7 @@ pub struct ObjInfo {
pub timestamp: FileTime,
pub sections: Vec<ObjSection>,
pub common: Vec<ObjSymbol>,
pub line_info: Option<BTreeMap<u32, u32>>,
pub line_info: Option<BTreeMap<u64, u64>>,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ObjRelocKind {

View File

@ -24,7 +24,7 @@ pub fn process_code(
data: &[u8],
address: u64,
relocs: &[ObjReloc],
line_info: &Option<BTreeMap<u32, u32>>,
line_info: &Option<BTreeMap<u64, u64>>,
) -> Result<ProcessCodeResult> {
let ins_count = data.len() / 4;
let mut ops = Vec::<u8>::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,