isr_dl_pdb/
codeview.rs

1use std::path::Path;
2
3use object::{
4    FileKind, Object,
5    read::pe::{ImageNtHeaders, PeFile, PeFile32, PeFile64},
6};
7
8/// CodeView information extracted from a PDB file.
9#[derive(Debug, Clone)]
10pub struct CodeView {
11    /// Path to the PDB file.
12    pub path: String,
13
14    /// PDB GUID.
15    pub guid: String,
16}
17
18#[derive(thiserror::Error, Debug)]
19pub enum Error {
20    #[error(transparent)]
21    Io(#[from] std::io::Error),
22
23    #[error(transparent)]
24    Object(#[from] object::Error),
25
26    #[error("Unsupported architecture {0:?}")]
27    UnsupportedArchitecture(object::FileKind),
28
29    #[error("CodeView not found")]
30    NotFound,
31}
32
33impl CodeView {
34    pub fn from_pe<Pe>(pe: &PeFile<Pe>) -> Result<CodeView, Error>
35    where
36        Pe: ImageNtHeaders,
37    {
38        let cv = match pe.pdb_info()? {
39            Some(cv) => cv,
40            None => return Err(Error::NotFound),
41        };
42
43        let guid = cv.guid();
44        let age = cv.age();
45        let path = cv.path();
46
47        let guid0 = u32::from_le_bytes(guid[0..4].try_into().unwrap());
48        let guid1 = u16::from_le_bytes(guid[4..6].try_into().unwrap());
49        let guid2 = u16::from_le_bytes(guid[6..8].try_into().unwrap());
50        let guid3 = &guid[8..16];
51
52        Ok(CodeView {
53            path: String::from_utf8_lossy(path).to_string(),
54            guid: format!(
55                "{:08x}{:04x}{:04x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:01x}",
56                guid0,
57                guid1,
58                guid2,
59                guid3[0],
60                guid3[1],
61                guid3[2],
62                guid3[3],
63                guid3[4],
64                guid3[5],
65                guid3[6],
66                guid3[7],
67                age & 0xf,
68            ),
69        })
70    }
71
72    pub fn from_path(path: impl AsRef<Path>) -> Result<CodeView, Error> {
73        let data = std::fs::read(path)?;
74
75        match FileKind::parse(&data[..])? {
76            FileKind::Pe32 => Self::from_pe(&PeFile32::parse(&data[..])?),
77            FileKind::Pe64 => Self::from_pe(&PeFile64::parse(&data[..])?),
78            kind => Err(Error::UnsupportedArchitecture(kind)),
79        }
80    }
81}