Skip to content

Commit

Permalink
Issue gimli-rs#40 -- Support DWARF-in-PE
Browse files Browse the repository at this point in the history
DWARF sections names in PE files are stored indirectly through a symbol table.
Names of the form "/n" where "n" is a number indicate the section name is
stored in index "n" of a hidden symbol table.  The hidden symbol table immediately
follows the COFF symbol table and is a sequence of null terminated CStrings.
  • Loading branch information
Greg Solberg committed Sep 12, 2018
1 parent 18ff86c commit fcb8002
Showing 1 changed file with 33 additions and 6 deletions.
39 changes: 33 additions & 6 deletions src/pe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use alloc::vec::Vec;
use std::slice;

use goblin::pe;
use scroll::Pread;

use {
Machine, Object, ObjectSection, ObjectSegment, SectionKind, Symbol, SymbolKind, SymbolMap,
Expand All @@ -12,6 +13,7 @@ use {
#[derive(Debug)]
pub struct PeFile<'data> {
pe: pe::PE<'data>,
symbol_table_offset: usize,
data: &'data [u8],
}

Expand Down Expand Up @@ -76,7 +78,27 @@ impl<'data> PeFile<'data> {
/// Parse the raw PE file data.
pub fn parse(data: &'data [u8]) -> Result<Self, &'static str> {
let pe = pe::PE::parse(data).map_err(|_| "Could not parse PE header")?;
Ok(PeFile { pe, data })
// get offset to secret symbol table that follows the COFF symbol table

This comment has been minimized.

Copy link
@jon-turney

jon-turney Sep 20, 2018

This is called the "string table" in the PE/COFF spec

See https://docs.microsoft.com/en-gb/windows/desktop/Debug/pe-format#coff-string-table

This comment has been minimized.

Copy link
@gsolberg

gsolberg Sep 20, 2018

Owner

Ah, not so secret after all! This fix will hopefully not be needed once support has been added to Goblin: m4b/goblin#100

let symbol_table_offset = (
pe.header.coff_header.pointer_to_symbol_table +
pe.header.coff_header.number_of_symbol_table * 18
) as usize;
Ok(PeFile { pe, symbol_table_offset, data })
}

/// Get section name from special PE symbol table
fn get_section_name(
&self,
section: &'data pe::section_table::SectionTable,
) -> Option<&'data str> {
let mut name = section.name().ok()?;
// if name start with "/" then it's an index into the secret symbol table
let mut name_chars = name.chars();
if name_chars.next() == Some('/') {
let index = name_chars.as_str().parse::<usize>().ok()?;
name = self.data.pread(self.symbol_table_offset + index).ok()?;
};
Some(name)
}
}

Expand Down Expand Up @@ -108,11 +130,11 @@ where

fn section_data_by_name(&self, section_name: &str) -> Option<Cow<'data, [u8]>> {
for section in &self.pe.sections {
if let Ok(name) = section.name() {
if let Some(name) = self.get_section_name(&section) {
if name == section_name {
return Some(Cow::from(
&self.data[section.pointer_to_raw_data as usize..]
[..section.size_of_raw_data as usize],
[..section.virtual_size as usize],
));
}
}
Expand Down Expand Up @@ -156,10 +178,15 @@ where
true
}

#[inline]
fn has_debug_symbols(&self) -> bool {
// TODO: look at what the mingw toolchain does with DWARF-in-PE, and also
// whether CodeView-in-PE still works?
// TODO: check if CodeView-in-PE still works
for section in &self.pe.sections {
if let Some(name) = self.get_section_name(&section) {
if name == ".debug_info" {
return true;
}
}
}
false
}

Expand Down

0 comments on commit fcb8002

Please sign in to comment.