isr_dl_pdb/
codeview.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use std::path::Path;

use object::{
    read::pe::{ImageNtHeaders, PeFile, PeFile32, PeFile64},
    FileKind, Object,
};

/// CodeView information extracted from a PDB file.
#[derive(Debug, Clone)]
pub struct CodeView {
    /// Path to the PDB file.
    pub path: String,

    /// PDB GUID.
    pub guid: String,
}

#[derive(thiserror::Error, Debug)]
pub enum Error {
    #[error(transparent)]
    Io(#[from] std::io::Error),

    #[error(transparent)]
    Object(#[from] object::Error),

    #[error("Unsupported architecture {0:?}")]
    UnsupportedArchitecture(object::FileKind),

    #[error("CodeView not found")]
    NotFound,
}

impl CodeView {
    pub fn from_pe<Pe>(pe: &PeFile<Pe>) -> Result<CodeView, Error>
    where
        Pe: ImageNtHeaders,
    {
        let cv = match pe.pdb_info()? {
            Some(cv) => cv,
            None => return Err(Error::NotFound),
        };

        let guid = cv.guid();
        let age = cv.age();
        let path = cv.path();

        let guid0 = u32::from_le_bytes(guid[0..4].try_into().unwrap());
        let guid1 = u16::from_le_bytes(guid[4..6].try_into().unwrap());
        let guid2 = u16::from_le_bytes(guid[6..8].try_into().unwrap());
        let guid3 = &guid[8..16];

        Ok(CodeView {
            path: String::from_utf8_lossy(path).to_string(),
            guid: format!(
                "{:08x}{:04x}{:04x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:01x}",
                guid0,
                guid1,
                guid2,
                guid3[0],
                guid3[1],
                guid3[2],
                guid3[3],
                guid3[4],
                guid3[5],
                guid3[6],
                guid3[7],
                age & 0xf,
            ),
        })
    }

    pub fn from_path(path: impl AsRef<Path>) -> Result<CodeView, Error> {
        let data = std::fs::read(path)?;

        match FileKind::parse(&data[..])? {
            FileKind::Pe32 => Self::from_pe(&PeFile32::parse(&data[..])?),
            FileKind::Pe64 => Self::from_pe(&PeFile64::parse(&data[..])?),
            kind => Err(Error::UnsupportedArchitecture(kind)),
        }
    }
}