Coff line number (#100)

* Update object to 0.36

* Add COFF line number support
This commit is contained in:
Robin Lambertz 2024-09-05 02:36:09 +02:00 committed by GitHub
parent 68606dfdcb
commit a32d99923c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 126 additions and 8 deletions

6
Cargo.lock generated
View File

@ -2875,7 +2875,7 @@ dependencies = [
"memmap2", "memmap2",
"msvc-demangler", "msvc-demangler",
"num-traits", "num-traits",
"object 0.35.0", "object 0.36.4",
"pbjson", "pbjson",
"pbjson-build", "pbjson-build",
"ppc750cl", "ppc750cl",
@ -2950,9 +2950,9 @@ dependencies = [
[[package]] [[package]]
name = "object" name = "object"
version = "0.35.0" version = "0.36.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]

View File

@ -34,7 +34,7 @@ flagset = "0.4.5"
log = "0.4.21" log = "0.4.21"
memmap2 = "0.9.4" memmap2 = "0.9.4"
num-traits = "0.2.18" num-traits = "0.2.18"
object = { version = "0.35.0", features = ["read_core", "std", "elf", "pe"], default-features = false } object = { version = "0.36.0", features = ["read_core", "std", "elf", "pe"], default-features = false }
pbjson = { version = "0.7.0", optional = true } pbjson = { version = "0.7.0", optional = true }
prost = { version = "0.13.1", optional = true } prost = { version = "0.13.1", optional = true }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View File

@ -1,12 +1,15 @@
use std::{collections::HashSet, fs, io::Cursor, path::Path}; use std::{collections::HashSet, fs, io::Cursor, mem::size_of, path::Path};
use anyhow::{anyhow, bail, ensure, Context, Result}; use anyhow::{anyhow, bail, ensure, Context, Result};
use cwextab::decode_extab; use cwextab::decode_extab;
use filetime::FileTime; use filetime::FileTime;
use flagset::Flags; use flagset::Flags;
use object::{ use object::{
endian::LittleEndian as LE,
pe::{ImageAuxSymbolFunctionBeginEnd, ImageLinenumber},
read::coff::{CoffFile, CoffHeader, ImageSymbol},
Architecture, BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, Architecture, BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget,
SectionIndex, SectionKind, Symbol, SymbolKind, SymbolScope, SymbolSection, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope, SymbolSection,
}; };
use crate::{ use crate::{
@ -401,7 +404,7 @@ fn relocations_by_section(
Ok(relocations) Ok(relocations)
} }
fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection]) -> Result<()> { fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection], obj_data: &[u8]) -> Result<()> {
// DWARF 1.1 // DWARF 1.1
if let Some(section) = obj_file.section_by_name(".line") { if let Some(section) = obj_file.section_by_name(".line") {
let data = section.uncompressed_data()?; let data = section.uncompressed_data()?;
@ -490,6 +493,121 @@ fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection]) -> Result<()> {
} }
} }
// COFF
if let File::Coff(coff) = obj_file {
line_info_coff(coff, sections, obj_data)?;
}
Ok(())
}
fn line_info_coff(coff: &CoffFile, sections: &mut [ObjSection], obj_data: &[u8]) -> Result<()> {
let symbol_table = coff.coff_header().symbols(obj_data)?;
// Enumerate over all sections.
for sect in coff.sections() {
let ptr_linenums = sect.coff_section().pointer_to_linenumbers.get(LE) as usize;
let num_linenums = sect.coff_section().number_of_linenumbers.get(LE) as usize;
// If we have no line number, skip this section.
if num_linenums == 0 {
continue;
}
// Find this section in our out_section. If it's not in out_section,
// skip it.
let Some(out_section) = sections.iter_mut().find(|s| s.orig_index == sect.index().0) else {
continue;
};
// Turn the line numbers into an ImageLinenumber slice.
let Some(linenums) =
&obj_data.get(ptr_linenums..ptr_linenums + num_linenums * size_of::<ImageLinenumber>())
else {
continue;
};
let Ok(linenums) = object::pod::slice_from_all_bytes::<ImageLinenumber>(linenums) else {
continue;
};
// In COFF, the line numbers are stored relative to the start of the
// function. Because of this, we need to know the line number where the
// function starts, so we can sum the two and get the line number
// relative to the start of the file.
//
// This variable stores the line number where the function currently
// being processed starts. It is set to None when we failed to find the
// line number of the start of the function.
let mut cur_fun_start_linenumber = None;
for linenum in linenums {
let line_number = linenum.linenumber.get(LE);
if line_number == 0 {
// Starting a new function. We need to find the line where that
// function is located in the file. To do this, we need to find
// the `.bf` symbol "associated" with this function. The .bf
// symbol will have a Function Begin/End Auxillary Record, which
// contains the line number of the start of the function.
// First, set cur_fun_start_linenumber to None. If we fail to
// find the start of the function, this will make sure the
// subsequent line numbers will be ignored until the next start
// of function.
cur_fun_start_linenumber = None;
// Get the symbol associated with this function. We'll need it
// for logging purposes, but also to acquire its Function
// Auxillary Record, which tells us where to find our .bf symbol.
let symtable_entry = linenum.symbol_table_index_or_virtual_address.get(LE);
let Ok(symbol) = symbol_table.symbol(SymbolIndex(symtable_entry as usize)) else {
continue;
};
let Ok(aux_fun) = symbol_table.aux_function(SymbolIndex(symtable_entry as usize))
else {
continue;
};
// Get the .bf symbol associated with this symbol. To do so, we
// look at the Function Auxillary Record's tag_index, which is
// an index in the symbol table pointing to our .bf symbol.
if aux_fun.tag_index.get(LE) == 0 {
continue;
}
let Ok(bf_symbol) =
symbol_table.symbol(SymbolIndex(aux_fun.tag_index.get(LE) as usize))
else {
continue;
};
// Do some sanity checks that we are, indeed, looking at a .bf
// symbol.
if bf_symbol.name(symbol_table.strings()) != Ok(b".bf") {
continue;
}
// Get the Function Begin/End Auxillary Record associated with
// our .bf symbol, where we'll fine the linenumber of the start
// of our function.
let Ok(bf_aux) = symbol_table.get::<ImageAuxSymbolFunctionBeginEnd>(
SymbolIndex(aux_fun.tag_index.get(LE) as usize),
1,
) else {
continue;
};
// Set cur_fun_start_linenumber so the following linenumber
// records will know at what line the current function start.
cur_fun_start_linenumber = Some(bf_aux.linenumber.get(LE) as u32);
// Let's also synthesize a line number record from the start of
// the function, as the linenumber records don't always cover it.
out_section.line_info.insert(
sect.address() + symbol.value() as u64,
bf_aux.linenumber.get(LE) as u32,
);
} else if let Some(cur_linenumber) = cur_fun_start_linenumber {
let vaddr = linenum.symbol_table_index_or_virtual_address.get(LE);
out_section
.line_info
.insert(sect.address() + vaddr as u64, cur_linenumber + line_number as u32);
}
}
}
Ok(()) Ok(())
} }
@ -620,7 +738,7 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<ObjInfo> {
if config.combine_data_sections { if config.combine_data_sections {
combine_data_sections(&mut sections)?; combine_data_sections(&mut sections)?;
} }
line_info(&obj_file, &mut sections)?; line_info(&obj_file, &mut sections, data)?;
let common = common_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?; let common = common_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?;
let extab = exception_tables(&mut sections, &obj_file)?; let extab = exception_tables(&mut sections, &obj_file)?;
Ok(ObjInfo { arch, path: None, timestamp: None, sections, common, extab, split_meta }) Ok(ObjInfo { arch, path: None, timestamp: None, sections, common, extab, split_meta })