1use std::path::Path;
2
3use object::{
4 FileKind, Object,
5 read::pe::{ImageNtHeaders, PeFile, PeFile32, PeFile64},
6};
7
8#[derive(Debug, Clone)]
10pub struct CodeView {
11 pub path: String,
13
14 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}