Skip to content

Commit

Permalink
Add support for Codeview PDB 2.0 debug directory format
Browse files Browse the repository at this point in the history
  • Loading branch information
joschock committed May 6, 2024
1 parent f025d49 commit 358dce9
Showing 1 changed file with 75 additions and 0 deletions.
75 changes: 75 additions & 0 deletions src/pe/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::pe::utils;
pub struct DebugData<'a> {
pub image_debug_directory: ImageDebugDirectory,
pub codeview_pdb70_debug_info: Option<CodeviewPDB70DebugInfo<'a>>,
pub codeview_pdb20_debug_info: Option<CodeviewPDB20DebugInfo<'a>>,
}

impl<'a> DebugData<'a> {
Expand Down Expand Up @@ -39,10 +40,13 @@ impl<'a> DebugData<'a> {
ImageDebugDirectory::parse_with_opts(bytes, dd, sections, file_alignment, opts)?;
let codeview_pdb70_debug_info =
CodeviewPDB70DebugInfo::parse_with_opts(bytes, &image_debug_directory, opts)?;
let codeview_pdb20_debug_info =
CodeviewPDB20DebugInfo::parse_with_opts(bytes, &image_debug_directory, opts)?;

Ok(DebugData {
image_debug_directory,
codeview_pdb70_debug_info,
codeview_pdb20_debug_info,
})
}

Expand Down Expand Up @@ -184,3 +188,74 @@ impl<'a> CodeviewPDB70DebugInfo<'a> {
}
}
}

// http://llvm.org/doxygen/CVDebugRecord_8h_source.html
#[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default)]
pub struct CodeviewPDB20DebugInfo<'a> {
pub codeview_signature: u32,
pub codeview_offset: u32,
pub signature: u32,
pub age: u32,
pub filename: &'a [u8],
}

impl<'a> CodeviewPDB20DebugInfo<'a> {
pub fn parse(bytes: &'a [u8], idd: &ImageDebugDirectory) -> error::Result<Option<Self>> {
Self::parse_with_opts(bytes, idd, &options::ParseOptions::default())
}

pub fn parse_with_opts(
bytes: &'a [u8],
idd: &ImageDebugDirectory,
opts: &options::ParseOptions,
) -> error::Result<Option<Self>> {
if idd.data_type != IMAGE_DEBUG_TYPE_CODEVIEW {
// not a codeview debug directory
// that's not an error, but it's not a CodeviewPDB70DebugInfo either
return Ok(None);
}

// ImageDebugDirectory.pointer_to_raw_data stores a raw offset -- not a virtual offset -- which we can use directly
let mut offset: usize = match opts.resolve_rva {
true => idd.pointer_to_raw_data as usize,
false => idd.address_of_raw_data as usize,
};

// calculate how long the eventual filename will be, which doubles as a check of the record size
let filename_length = idd.size_of_data as isize - 16;
if filename_length < 0 {
// the record is too short to be plausible
return Err(error::Error::Malformed(format!(
"ImageDebugDirectory size of data seems wrong: {:?}",
idd.size_of_data
)));
}
let filename_length = filename_length as usize;

// check the codeview signature
let codeview_signature: u32 = bytes.gread_with(&mut offset, scroll::LE)?;
if codeview_signature != CODEVIEW_PDB20_MAGIC {
return Ok(None);
}
let codeview_offset: u32 = bytes.gread_with(&mut offset, scroll::LE)?;

// read the rest
let signature: u32 = bytes.gread_with(&mut offset, scroll::LE)?;
let age: u32 = bytes.gread_with(&mut offset, scroll::LE)?;
if let Some(filename) = bytes.get(offset..offset + filename_length) {
Ok(Some(CodeviewPDB20DebugInfo {
codeview_signature,
codeview_offset,
signature,
age,
filename,
}))
} else {
Err(error::Error::Malformed(format!(
"ImageDebugDirectory seems corrupted: {:?}",
idd
)))
}
}
}

0 comments on commit 358dce9

Please sign in to comment.