tsffs/os/windows/
pdb.rs

1use anyhow::{ensure, Result};
2use simics::ConfObject;
3
4use crate::os::windows::util::{
5    read_nul_terminated_string, read_nul_terminated_string_dtb, read_virtual, read_virtual_dtb,
6};
7
8#[derive(Debug, Clone)]
9#[repr(C)]
10/// The GUID structure in a CV 7.0 header
11pub struct Guid {
12    pub data0: u32,
13    pub data1: u16,
14    pub data2: u16,
15    pub data3: u64,
16}
17
18#[derive(Debug, Clone)]
19/// The header of a CV (coreview) 7.0 file
20pub struct CvInfoPdb70 {
21    pub cv_signature: u32,
22    pub signature: Guid,
23    pub age: u32,
24    pub file_name: String,
25}
26
27impl CvInfoPdb70 {
28    /// Parse a CV 7.0 header from a given address
29    pub fn new(processor: *mut ConfObject, address: u64) -> Result<Self> {
30        let cv_signature = read_virtual::<u32>(processor, address)?;
31        let signature =
32            read_virtual::<Guid>(processor, address + std::mem::size_of::<u32>() as u64)?;
33        let age = read_virtual::<u32>(
34            processor,
35            address + std::mem::size_of::<u32>() as u64 + std::mem::size_of::<Guid>() as u64,
36        )?;
37        let file_name = read_nul_terminated_string(
38            processor,
39            address
40                + std::mem::size_of::<u32>() as u64
41                + std::mem::size_of::<Guid>() as u64
42                + std::mem::size_of::<u32>() as u64,
43        )?;
44
45        ensure!(cv_signature == 0x53445352, "Invalid CV signature");
46
47        Ok(Self {
48            cv_signature,
49            signature,
50            age,
51            file_name,
52        })
53    }
54
55    /// Parse a CV 7.0 header from a given address with a DTB
56    pub fn new_dtb(
57        processor: *mut ConfObject,
58        directory_table_base: u64,
59        address: u64,
60    ) -> Result<Self> {
61        let cv_signature = read_virtual_dtb::<u32>(processor, directory_table_base, address)?;
62        let signature = read_virtual_dtb::<Guid>(
63            processor,
64            directory_table_base,
65            address + std::mem::size_of::<u32>() as u64,
66        )?;
67        let age = read_virtual_dtb::<u32>(
68            processor,
69            directory_table_base,
70            address + std::mem::size_of::<u32>() as u64 + std::mem::size_of::<Guid>() as u64,
71        )?;
72        let file_name = read_nul_terminated_string_dtb(
73            processor,
74            directory_table_base,
75            address
76                + std::mem::size_of::<u32>() as u64
77                + std::mem::size_of::<Guid>() as u64
78                + std::mem::size_of::<u32>() as u64,
79        )?;
80
81        ensure!(cv_signature == 0x53445352, "Invalid CV signature");
82
83        Ok(Self {
84            cv_signature,
85            signature,
86            age,
87            file_name,
88        })
89    }
90
91    pub fn guid(&self) -> String {
92        // Reverse the order of data3
93        let data3 = u64::from_be_bytes(self.signature.data3.to_le_bytes());
94
95        format!(
96            "{:08X}{:04X}{:04X}{:016X}{:01X}",
97            self.signature.data0, self.signature.data1, self.signature.data2, data3, self.age
98        )
99    }
100
101    pub fn file_name(&self) -> &str {
102        &self.file_name
103    }
104}
105
106#[derive(Debug, Clone)]
107/// An export from a PE file
108pub struct Export {
109    pub name: Option<String>,
110    pub offset: Option<usize>,
111    pub rva: usize,
112    pub size: usize,
113}
114
115impl From<goblin::pe::export::Export<'_>> for Export {
116    fn from(export: goblin::pe::export::Export) -> Self {
117        Self {
118            name: export.name.map(|s| s.to_string()),
119            offset: export.offset,
120            rva: export.rva,
121            size: export.size,
122        }
123    }
124}
125
126impl From<&goblin::pe::export::Export<'_>> for Export {
127    fn from(export: &goblin::pe::export::Export) -> Self {
128        Self {
129            name: export.name.map(|s| s.to_string()),
130            offset: export.offset,
131            rva: export.rva,
132            size: export.size,
133        }
134    }
135}