Skip to content

Commit

Permalink
Add ability to parse pdb info from PE file (#298)
Browse files Browse the repository at this point in the history
Just like we can get the UUID from macho files and the build-id from ELF
files, this change allows users to pull out the PDB info (path, age, and
GUID) from PE files.

macho and ELF files will return `Ok(None)`
  • Loading branch information
schultetwin1 authored May 7, 2021
1 parent 45cc193 commit 2e0af3f
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 6 deletions.
10 changes: 10 additions & 0 deletions examples/objdump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ fn dump_object(data: &[u8]) {
Ok(None) => {}
Err(e) => println!("Failed to parse GNU debug alt link: {}", e),
}
match file.pdb_info() {
Ok(Some(info)) => println!(
"PDB file: {}, GUID: {:x?}, Age: {}",
String::from_utf8_lossy(info.path()),
info.guid(),
info.age()
),
Ok(None) => {}
Err(e) => println!("Failed to parse PE CodeView info: {}", e),
}

for segment in file.segments() {
println!("{:x?}", segment);
Expand Down
9 changes: 7 additions & 2 deletions src/read/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use crate::read::pe;
#[cfg(feature = "wasm")]
use crate::read::wasm;
use crate::read::{
self, Architecture, BinaryFormat, ComdatKind, CompressedData, CompressedFileRange, Error,
Export, FileFlags, FileKind, Import, Object, ObjectComdat, ObjectMap, ObjectSection,
self, Architecture, BinaryFormat, CodeView, ComdatKind, CompressedData, CompressedFileRange,
Error, Export, FileFlags, FileKind, Import, Object, ObjectComdat, ObjectMap, ObjectSection,
ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadRef, Relocation, Result, SectionFlags,
SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapName,
SymbolScope, SymbolSection,
Expand Down Expand Up @@ -399,6 +399,11 @@ where
with_inner!(self.inner, FileInternal, |x| x.gnu_debugaltlink())
}

#[inline]
fn pdb_info(&self) -> Result<Option<CodeView>> {
with_inner!(self.inner, FileInternal, |x| x.pdb_info())
}

fn entry(&self) -> u64 {
with_inner!(self.inner, FileInternal, |x| x.entry())
}
Expand Down
28 changes: 28 additions & 0 deletions src/read/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,34 @@ impl<'data> Export<'data> {
}
}

/// PDB Information
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CodeView<'data> {
guid: [u8; 16],
path: ByteString<'data>,
age: u32,
}

impl<'data> CodeView<'data> {
/// The path to the PDB as stored in CodeView
#[inline]
pub fn path(&self) -> &'data [u8] {
self.path.0
}

/// The age of the PDB
#[inline]
pub fn age(&self) -> u32 {
self.age
}

/// The GUID of the PDB.
#[inline]
pub fn guid(&self) -> [u8; 16] {
self.guid
}
}

/// The target referenced by a relocation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RelocationTarget {
Expand Down
57 changes: 56 additions & 1 deletion src/read/pe/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ use alloc::vec::Vec;
use core::fmt::Debug;
use core::{mem, str};

use core::convert::TryInto;

use crate::read::coff::{CoffCommon, CoffSymbol, CoffSymbolIterator, CoffSymbolTable, SymbolTable};
use crate::read::{
self, Architecture, ComdatKind, Error, Export, FileFlags, Import, NoDynamicRelocationIterator,
Object, ObjectComdat, ReadError, ReadRef, Result, SectionIndex, SymbolIndex,
};
use crate::{pe, ByteString, Bytes, LittleEndian as LE, Pod, U16Bytes, U32Bytes, U32, U64};
use crate::{
pe, ByteString, Bytes, CodeView, LittleEndian as LE, Pod, U16Bytes, U32Bytes, U32, U64,
};

use super::{PeSection, PeSectionIterator, PeSegment, PeSegmentIterator, SectionTable};

Expand Down Expand Up @@ -328,6 +332,57 @@ where
Ok(exports)
}

fn pdb_info(&self) -> Result<Option<CodeView>> {
let data_dir = match self.data_directory(pe::IMAGE_DIRECTORY_ENTRY_DEBUG) {
Some(data_dir) => data_dir,
None => return Ok(None),
};
let debug_data = data_dir.data(self.data, &self.common.sections).map(Bytes)?;
let debug_dir = debug_data
.read_at::<pe::ImageDebugDirectory>(0)
.read_error("Invalid PE debug dir size")?;

if debug_dir.typ.get(LE) != pe::IMAGE_DEBUG_TYPE_CODEVIEW {
return Ok(None);
}

let info = self
.data
.read_slice_at::<u8>(
debug_dir.pointer_to_raw_data.get(LE) as u64,
debug_dir.size_of_data.get(LE) as usize,
)
.read_error("Invalid CodeView Info address")?;

let mut info = Bytes(info);

let sig = info
.read_bytes(4)
.read_error("Invalid CodeView signature")?;
if sig.0 != b"RSDS" {
return Ok(None);
}

let guid: [u8; 16] = info
.read_bytes(16)
.read_error("Invalid CodeView GUID")?
.0
.try_into()
.unwrap();

let age = info.read::<U32<LE>>().read_error("Invalid CodeView Age")?;

let path = info
.read_string()
.read_error("Invalid CodeView file path")?;

Ok(Some(CodeView {
path: ByteString(path),
guid,
age: age.get(LE),
}))
}

fn has_debug_symbols(&self) -> bool {
self.section_by_name(".debug_info").is_some()
}
Expand Down
12 changes: 9 additions & 3 deletions src/read/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use alloc::borrow::Cow;
use alloc::vec::Vec;

use crate::read::{
self, Architecture, ComdatKind, CompressedData, CompressedFileRange, Export, FileFlags, Import,
ObjectMap, Relocation, Result, SectionFlags, SectionIndex, SectionKind, SymbolFlags,
SymbolIndex, SymbolKind, SymbolMap, SymbolMapName, SymbolScope, SymbolSection,
self, Architecture, CodeView, ComdatKind, CompressedData, CompressedFileRange, Export,
FileFlags, Import, ObjectMap, Relocation, Result, SectionFlags, SectionIndex, SectionKind,
SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapName, SymbolScope, SymbolSection,
};
use crate::Endianness;

Expand Down Expand Up @@ -199,6 +199,12 @@ pub trait Object<'data: 'file, 'file>: read::private::Sealed {
Ok(None)
}

/// The filename and GUID from the PE CodeView section
#[inline]
fn pdb_info(&self) -> Result<Option<CodeView>> {
Ok(None)
}

/// File flags that are specific to each file format.
fn flags(&self) -> FileFlags;
}
Expand Down

0 comments on commit 2e0af3f

Please sign in to comment.