2 use scroll
::{Pread, Pwrite, SizeWith}
;
4 use crate::pe
::data_directories
;
5 use crate::pe
::section_table
;
8 #[derive(Debug, PartialEq, Copy, Clone, Default)]
9 pub struct DebugData
<'a
> {
10 pub image_debug_directory
: ImageDebugDirectory
,
11 pub codeview_pdb70_debug_info
: Option
<CodeviewPDB70DebugInfo
<'a
>>,
14 impl<'a
> DebugData
<'a
> {
17 dd
: data_directories
::DataDirectory
,
18 sections
: &[section_table
::SectionTable
],
20 ) -> error
::Result
<Self> {
21 let image_debug_directory
=
22 ImageDebugDirectory
::parse(bytes
, dd
, sections
, file_alignment
)?
;
23 let codeview_pdb70_debug_info
=
24 CodeviewPDB70DebugInfo
::parse(bytes
, &image_debug_directory
)?
;
27 image_debug_directory
,
28 codeview_pdb70_debug_info
,
32 /// Return this executable's debugging GUID, suitable for matching against a PDB file.
33 pub fn guid(&self) -> Option
<[u8; 16]> {
34 self.codeview_pdb70_debug_info
.map(|pdb70
| pdb70
.signature
)
38 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680307(v=vs.85).aspx
40 #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
41 pub struct ImageDebugDirectory
{
42 pub characteristics
: u32,
43 pub time_date_stamp
: u32,
44 pub major_version
: u16,
45 pub minor_version
: u16,
47 pub size_of_data
: u32,
48 pub address_of_raw_data
: u32,
49 pub pointer_to_raw_data
: u32,
52 pub const IMAGE_DEBUG_TYPE_UNKNOWN
: u32 = 0;
53 pub const IMAGE_DEBUG_TYPE_COFF
: u32 = 1;
54 pub const IMAGE_DEBUG_TYPE_CODEVIEW
: u32 = 2;
55 pub const IMAGE_DEBUG_TYPE_FPO
: u32 = 3;
56 pub const IMAGE_DEBUG_TYPE_MISC
: u32 = 4;
57 pub const IMAGE_DEBUG_TYPE_EXCEPTION
: u32 = 5;
58 pub const IMAGE_DEBUG_TYPE_FIXUP
: u32 = 6;
59 pub const IMAGE_DEBUG_TYPE_BORLAND
: u32 = 9;
61 impl ImageDebugDirectory
{
64 dd
: data_directories
::DataDirectory
,
65 sections
: &[section_table
::SectionTable
],
67 ) -> error
::Result
<Self> {
68 let rva
= dd
.virtual_address
as usize;
69 let offset
= utils
::find_offset(rva
, sections
, file_alignment
).ok_or_else(|| {
70 error
::Error
::Malformed(format
!(
71 "Cannot map ImageDebugDirectory rva {:#x} into offset",
75 let idd
: Self = bytes
.pread_with(offset
, scroll
::LE
)?
;
80 pub const CODEVIEW_PDB70_MAGIC
: u32 = 0x5344_5352;
81 pub const CODEVIEW_PDB20_MAGIC
: u32 = 0x3031_424e;
82 pub const CODEVIEW_CV50_MAGIC
: u32 = 0x3131_424e;
83 pub const CODEVIEW_CV41_MAGIC
: u32 = 0x3930_424e;
85 // http://llvm.org/doxygen/CVDebugRecord_8h_source.html
87 #[derive(Debug, PartialEq, Copy, Clone, Default)]
88 pub struct CodeviewPDB70DebugInfo
<'a
> {
89 pub codeview_signature
: u32,
90 pub signature
: [u8; 16],
92 pub filename
: &'a
[u8],
95 impl<'a
> CodeviewPDB70DebugInfo
<'a
> {
96 pub fn parse(bytes
: &'a
[u8], idd
: &ImageDebugDirectory
) -> error
::Result
<Option
<Self>> {
97 if idd
.data_type
!= IMAGE_DEBUG_TYPE_CODEVIEW
{
98 // not a codeview debug directory
99 // that's not an error, but it's not a CodeviewPDB70DebugInfo either
103 // ImageDebugDirectory.pointer_to_raw_data stores a raw offset -- not a virtual offset -- which we can use directly
104 let mut offset
: usize = idd
.pointer_to_raw_data
as usize;
106 // calculate how long the eventual filename will be, which doubles as a check of the record size
107 let filename_length
= idd
.size_of_data
as isize - 24;
108 if filename_length
< 0 || filename_length
> 1024 {
109 // the record is too short or too long to be plausible
110 return Err(error
::Error
::Malformed(format
!(
111 "ImageDebugDirectory size of data seems wrong: {:?}",
115 let filename_length
= filename_length
as usize;
117 // check the codeview signature
118 let codeview_signature
: u32 = bytes
.gread_with(&mut offset
, scroll
::LE
)?
;
119 if codeview_signature
!= CODEVIEW_PDB70_MAGIC
{
124 let mut signature
: [u8; 16] = [0; 16];
125 signature
.copy_from_slice(bytes
.gread_with(&mut offset
, 16)?
);
126 let age
: u32 = bytes
.gread_with(&mut offset
, scroll
::LE
)?
;
127 let filename
= &bytes
[offset
..offset
+ filename_length
];
129 Ok(Some(CodeviewPDB70DebugInfo
{