summaryrefslogtreecommitdiffstats
path: root/third_party/rust/goblin/src/pe/debug.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/goblin/src/pe/debug.rs')
-rw-r--r--third_party/rust/goblin/src/pe/debug.rs186
1 files changed, 186 insertions, 0 deletions
diff --git a/third_party/rust/goblin/src/pe/debug.rs b/third_party/rust/goblin/src/pe/debug.rs
new file mode 100644
index 0000000000..311bc632cb
--- /dev/null
+++ b/third_party/rust/goblin/src/pe/debug.rs
@@ -0,0 +1,186 @@
+use crate::error;
+use scroll::{Pread, Pwrite, SizeWith};
+
+use crate::pe::data_directories;
+use crate::pe::options;
+use crate::pe::section_table;
+use crate::pe::utils;
+
+#[derive(Debug, PartialEq, Copy, Clone, Default)]
+pub struct DebugData<'a> {
+ pub image_debug_directory: ImageDebugDirectory,
+ pub codeview_pdb70_debug_info: Option<CodeviewPDB70DebugInfo<'a>>,
+}
+
+impl<'a> DebugData<'a> {
+ pub fn parse(
+ bytes: &'a [u8],
+ dd: data_directories::DataDirectory,
+ sections: &[section_table::SectionTable],
+ file_alignment: u32,
+ ) -> error::Result<Self> {
+ Self::parse_with_opts(
+ bytes,
+ dd,
+ sections,
+ file_alignment,
+ &options::ParseOptions::default(),
+ )
+ }
+
+ pub fn parse_with_opts(
+ bytes: &'a [u8],
+ dd: data_directories::DataDirectory,
+ sections: &[section_table::SectionTable],
+ file_alignment: u32,
+ opts: &options::ParseOptions,
+ ) -> error::Result<Self> {
+ let image_debug_directory =
+ ImageDebugDirectory::parse_with_opts(bytes, dd, sections, file_alignment, opts)?;
+ let codeview_pdb70_debug_info =
+ CodeviewPDB70DebugInfo::parse_with_opts(bytes, &image_debug_directory, opts)?;
+
+ Ok(DebugData {
+ image_debug_directory,
+ codeview_pdb70_debug_info,
+ })
+ }
+
+ /// Return this executable's debugging GUID, suitable for matching against a PDB file.
+ pub fn guid(&self) -> Option<[u8; 16]> {
+ self.codeview_pdb70_debug_info.map(|pdb70| pdb70.signature)
+ }
+}
+
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680307(v=vs.85).aspx
+#[repr(C)]
+#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
+pub struct ImageDebugDirectory {
+ pub characteristics: u32,
+ pub time_date_stamp: u32,
+ pub major_version: u16,
+ pub minor_version: u16,
+ pub data_type: u32,
+ pub size_of_data: u32,
+ pub address_of_raw_data: u32,
+ pub pointer_to_raw_data: u32,
+}
+
+pub const IMAGE_DEBUG_TYPE_UNKNOWN: u32 = 0;
+pub const IMAGE_DEBUG_TYPE_COFF: u32 = 1;
+pub const IMAGE_DEBUG_TYPE_CODEVIEW: u32 = 2;
+pub const IMAGE_DEBUG_TYPE_FPO: u32 = 3;
+pub const IMAGE_DEBUG_TYPE_MISC: u32 = 4;
+pub const IMAGE_DEBUG_TYPE_EXCEPTION: u32 = 5;
+pub const IMAGE_DEBUG_TYPE_FIXUP: u32 = 6;
+pub const IMAGE_DEBUG_TYPE_BORLAND: u32 = 9;
+
+impl ImageDebugDirectory {
+ #[allow(unused)]
+ fn parse(
+ bytes: &[u8],
+ dd: data_directories::DataDirectory,
+ sections: &[section_table::SectionTable],
+ file_alignment: u32,
+ ) -> error::Result<Self> {
+ Self::parse_with_opts(
+ bytes,
+ dd,
+ sections,
+ file_alignment,
+ &options::ParseOptions::default(),
+ )
+ }
+
+ fn parse_with_opts(
+ bytes: &[u8],
+ dd: data_directories::DataDirectory,
+ sections: &[section_table::SectionTable],
+ file_alignment: u32,
+ opts: &options::ParseOptions,
+ ) -> error::Result<Self> {
+ let rva = dd.virtual_address as usize;
+ let offset = utils::find_offset(rva, sections, file_alignment, opts).ok_or_else(|| {
+ error::Error::Malformed(format!(
+ "Cannot map ImageDebugDirectory rva {:#x} into offset",
+ rva
+ ))
+ })?;
+ let idd: Self = bytes.pread_with(offset, scroll::LE)?;
+ Ok(idd)
+ }
+}
+
+pub const CODEVIEW_PDB70_MAGIC: u32 = 0x5344_5352;
+pub const CODEVIEW_PDB20_MAGIC: u32 = 0x3031_424e;
+pub const CODEVIEW_CV50_MAGIC: u32 = 0x3131_424e;
+pub const CODEVIEW_CV41_MAGIC: u32 = 0x3930_424e;
+
+// http://llvm.org/doxygen/CVDebugRecord_8h_source.html
+#[repr(C)]
+#[derive(Debug, PartialEq, Copy, Clone, Default)]
+pub struct CodeviewPDB70DebugInfo<'a> {
+ pub codeview_signature: u32,
+ pub signature: [u8; 16],
+ pub age: u32,
+ pub filename: &'a [u8],
+}
+
+impl<'a> CodeviewPDB70DebugInfo<'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 - 24;
+ 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_PDB70_MAGIC {
+ return Ok(None);
+ }
+
+ // read the rest
+ let mut signature: [u8; 16] = [0; 16];
+ signature.copy_from_slice(bytes.gread_with(&mut offset, 16)?);
+ let age: u32 = bytes.gread_with(&mut offset, scroll::LE)?;
+ if let Some(filename) = bytes.get(offset..offset + filename_length) {
+ Ok(Some(CodeviewPDB70DebugInfo {
+ codeview_signature,
+ signature,
+ age,
+ filename,
+ }))
+ } else {
+ Err(error::Error::Malformed(format!(
+ "ImageDebugDirectory seems corrupted: {:?}",
+ idd
+ )))
+ }
+ }
+}