|
1 |
| -use std::{collections::HashSet, fs, io::Cursor, path::Path}; |
| 1 | +use std::{collections::HashSet, fs, io::Cursor, mem::size_of, path::Path}; |
2 | 2 |
|
3 | 3 | use anyhow::{anyhow, bail, ensure, Context, Result};
|
4 | 4 | use cwextab::decode_extab;
|
5 | 5 | use filetime::FileTime;
|
6 | 6 | use flagset::Flags;
|
7 | 7 | use object::{
|
| 8 | + endian::LittleEndian as LE, |
| 9 | + pe::{ImageAuxSymbolFunctionBeginEnd, ImageLinenumber}, |
| 10 | + read::coff::{CoffFile, CoffHeader, ImageSymbol}, |
8 | 11 | Architecture, BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget,
|
9 |
| - SectionIndex, SectionKind, Symbol, SymbolKind, SymbolScope, SymbolSection, |
| 12 | + SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope, SymbolSection, |
10 | 13 | };
|
11 | 14 |
|
12 | 15 | use crate::{
|
@@ -401,7 +404,7 @@ fn relocations_by_section(
|
401 | 404 | Ok(relocations)
|
402 | 405 | }
|
403 | 406 |
|
404 |
| -fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection]) -> Result<()> { |
| 407 | +fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection], obj_data: &[u8]) -> Result<()> { |
405 | 408 | // DWARF 1.1
|
406 | 409 | if let Some(section) = obj_file.section_by_name(".line") {
|
407 | 410 | let data = section.uncompressed_data()?;
|
@@ -490,6 +493,121 @@ fn line_info(obj_file: &File<'_>, sections: &mut [ObjSection]) -> Result<()> {
|
490 | 493 | }
|
491 | 494 | }
|
492 | 495 |
|
| 496 | + // COFF |
| 497 | + if let File::Coff(coff) = obj_file { |
| 498 | + line_info_coff(coff, sections, obj_data)?; |
| 499 | + } |
| 500 | + |
| 501 | + Ok(()) |
| 502 | +} |
| 503 | + |
| 504 | +fn line_info_coff(coff: &CoffFile, sections: &mut [ObjSection], obj_data: &[u8]) -> Result<()> { |
| 505 | + let symbol_table = coff.coff_header().symbols(obj_data)?; |
| 506 | + |
| 507 | + // Enumerate over all sections. |
| 508 | + for sect in coff.sections() { |
| 509 | + let ptr_linenums = sect.coff_section().pointer_to_linenumbers.get(LE) as usize; |
| 510 | + let num_linenums = sect.coff_section().number_of_linenumbers.get(LE) as usize; |
| 511 | + |
| 512 | + // If we have no line number, skip this section. |
| 513 | + if num_linenums == 0 { |
| 514 | + continue; |
| 515 | + } |
| 516 | + |
| 517 | + // Find this section in our out_section. If it's not in out_section, |
| 518 | + // skip it. |
| 519 | + let Some(out_section) = sections.iter_mut().find(|s| s.orig_index == sect.index().0) else { |
| 520 | + continue; |
| 521 | + }; |
| 522 | + |
| 523 | + // Turn the line numbers into an ImageLinenumber slice. |
| 524 | + let Some(linenums) = |
| 525 | + &obj_data.get(ptr_linenums..ptr_linenums + num_linenums * size_of::<ImageLinenumber>()) |
| 526 | + else { |
| 527 | + continue; |
| 528 | + }; |
| 529 | + let Ok(linenums) = object::pod::slice_from_all_bytes::<ImageLinenumber>(linenums) else { |
| 530 | + continue; |
| 531 | + }; |
| 532 | + |
| 533 | + // In COFF, the line numbers are stored relative to the start of the |
| 534 | + // function. Because of this, we need to know the line number where the |
| 535 | + // function starts, so we can sum the two and get the line number |
| 536 | + // relative to the start of the file. |
| 537 | + // |
| 538 | + // This variable stores the line number where the function currently |
| 539 | + // being processed starts. It is set to None when we failed to find the |
| 540 | + // line number of the start of the function. |
| 541 | + let mut cur_fun_start_linenumber = None; |
| 542 | + for linenum in linenums { |
| 543 | + let line_number = linenum.linenumber.get(LE); |
| 544 | + if line_number == 0 { |
| 545 | + // Starting a new function. We need to find the line where that |
| 546 | + // function is located in the file. To do this, we need to find |
| 547 | + // the `.bf` symbol "associated" with this function. The .bf |
| 548 | + // symbol will have a Function Begin/End Auxillary Record, which |
| 549 | + // contains the line number of the start of the function. |
| 550 | + |
| 551 | + // First, set cur_fun_start_linenumber to None. If we fail to |
| 552 | + // find the start of the function, this will make sure the |
| 553 | + // subsequent line numbers will be ignored until the next start |
| 554 | + // of function. |
| 555 | + cur_fun_start_linenumber = None; |
| 556 | + |
| 557 | + // Get the symbol associated with this function. We'll need it |
| 558 | + // for logging purposes, but also to acquire its Function |
| 559 | + // Auxillary Record, which tells us where to find our .bf symbol. |
| 560 | + let symtable_entry = linenum.symbol_table_index_or_virtual_address.get(LE); |
| 561 | + let Ok(symbol) = symbol_table.symbol(SymbolIndex(symtable_entry as usize)) else { |
| 562 | + continue; |
| 563 | + }; |
| 564 | + let Ok(aux_fun) = symbol_table.aux_function(SymbolIndex(symtable_entry as usize)) |
| 565 | + else { |
| 566 | + continue; |
| 567 | + }; |
| 568 | + |
| 569 | + // Get the .bf symbol associated with this symbol. To do so, we |
| 570 | + // look at the Function Auxillary Record's tag_index, which is |
| 571 | + // an index in the symbol table pointing to our .bf symbol. |
| 572 | + if aux_fun.tag_index.get(LE) == 0 { |
| 573 | + continue; |
| 574 | + } |
| 575 | + let Ok(bf_symbol) = |
| 576 | + symbol_table.symbol(SymbolIndex(aux_fun.tag_index.get(LE) as usize)) |
| 577 | + else { |
| 578 | + continue; |
| 579 | + }; |
| 580 | + // Do some sanity checks that we are, indeed, looking at a .bf |
| 581 | + // symbol. |
| 582 | + if bf_symbol.name(symbol_table.strings()) != Ok(b".bf") { |
| 583 | + continue; |
| 584 | + } |
| 585 | + // Get the Function Begin/End Auxillary Record associated with |
| 586 | + // our .bf symbol, where we'll fine the linenumber of the start |
| 587 | + // of our function. |
| 588 | + let Ok(bf_aux) = symbol_table.get::<ImageAuxSymbolFunctionBeginEnd>( |
| 589 | + SymbolIndex(aux_fun.tag_index.get(LE) as usize), |
| 590 | + 1, |
| 591 | + ) else { |
| 592 | + continue; |
| 593 | + }; |
| 594 | + // Set cur_fun_start_linenumber so the following linenumber |
| 595 | + // records will know at what line the current function start. |
| 596 | + cur_fun_start_linenumber = Some(bf_aux.linenumber.get(LE) as u32); |
| 597 | + // Let's also synthesize a line number record from the start of |
| 598 | + // the function, as the linenumber records don't always cover it. |
| 599 | + out_section.line_info.insert( |
| 600 | + sect.address() + symbol.value() as u64, |
| 601 | + bf_aux.linenumber.get(LE) as u32, |
| 602 | + ); |
| 603 | + } else if let Some(cur_linenumber) = cur_fun_start_linenumber { |
| 604 | + let vaddr = linenum.symbol_table_index_or_virtual_address.get(LE); |
| 605 | + out_section |
| 606 | + .line_info |
| 607 | + .insert(sect.address() + vaddr as u64, cur_linenumber + line_number as u32); |
| 608 | + } |
| 609 | + } |
| 610 | + } |
493 | 611 | Ok(())
|
494 | 612 | }
|
495 | 613 |
|
@@ -620,7 +738,7 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<ObjInfo> {
|
620 | 738 | if config.combine_data_sections {
|
621 | 739 | combine_data_sections(&mut sections)?;
|
622 | 740 | }
|
623 |
| - line_info(&obj_file, &mut sections)?; |
| 741 | + line_info(&obj_file, &mut sections, data)?; |
624 | 742 | let common = common_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?;
|
625 | 743 | let extab = exception_tables(&mut sections, &obj_file)?;
|
626 | 744 | Ok(ObjInfo { arch, path: None, timestamp: None, sections, common, extab, split_meta })
|
|
0 commit comments