1 use std::path::Path;
2 use std::sync::Once;
3
4 use pdb::{FallibleIterator, PdbInternalRva, PdbInternalSectionOffset, Rva};
5
6 // This test is intended to cover OMAP address translation:
7 // https://github.com/willglynn/pdb/issues/17
8
9 static DOWNLOADED: Once = Once::new();
open_file() -> std::fs::File10 fn open_file() -> std::fs::File {
11 let path = "fixtures/symbol_server/3844dbb920174967be7aa4a2c20430fa2-ntkrnlmp.pdb";
12 let url = "https://msdl.microsoft.com/download/symbols/ntkrnlmp.pdb/3844dbb920174967be7aa4a2c20430fa2/ntkrnlmp.pdb";
13
14 DOWNLOADED.call_once(|| {
15 if !Path::new(path).exists() {
16 let mut response = reqwest::get(url).expect("GET request");
17 let mut destination = std::fs::File::create(path).expect("create PDB");
18 response.copy_to(&mut destination).expect("download");
19 }
20 });
21
22 std::fs::File::open(path).expect("open PDB")
23 }
24
25 #[test]
test_omap_section_zero()26 fn test_omap_section_zero() {
27 // https://github.com/willglynn/pdb/issues/87
28
29 let mut pdb = pdb::PDB::open(open_file()).expect("opening pdb");
30
31 let address = pdb::PdbInternalSectionOffset {
32 offset: 0,
33 section: 0x1234,
34 };
35
36 let address_map = pdb.address_map().expect("address map");
37
38 assert_eq!(address.to_rva(&address_map), None);
39 }
40
41 #[test]
test_omap_symbol()42 fn test_omap_symbol() {
43 let mut pdb = pdb::PDB::open(open_file()).expect("opening pdb");
44
45 let global_symbols = pdb.global_symbols().expect("global_symbols");
46
47 // find the target symbol
48 let target_symbol = {
49 let target_name = pdb::RawString::from("NtWaitForSingleObject");
50 let mut iter = global_symbols.iter();
51 iter.find(|sym| {
52 let matches = sym
53 .parse()
54 .ok()
55 .and_then(|d| d.name())
56 .map_or(false, |n| n == target_name);
57 Ok(matches)
58 })
59 .expect("iterate symbols")
60 .expect("find target symbol")
61 };
62
63 // extract the PublicSymbol data
64 let pubsym = match target_symbol.parse().expect("parse symbol") {
65 pdb::SymbolData::Public(pubsym) => pubsym,
66 _ => panic!("expected public symbol"),
67 };
68
69 // ensure the symbol has the correct location
70 assert_eq!(
71 pubsym.offset,
72 PdbInternalSectionOffset {
73 section: 0xc,
74 offset: 0x0004_aeb0,
75 }
76 );
77
78 // translate the segment offset to an RVA
79 let address_map = pdb.address_map().expect("address map");
80 assert_eq!(pubsym.offset.to_rva(&address_map), Some(Rva(0x0037_68c0)));
81 assert_eq!(
82 Rva(0x0037_68c0).to_internal_offset(&address_map),
83 Some(pubsym.offset)
84 );
85 }
86
87 #[test]
test_omap_range()88 fn test_omap_range() {
89 let mut pdb = pdb::PDB::open(open_file()).expect("opening pdb");
90 let address_map = pdb.address_map().expect("address map");
91
92 // Range partially covered by OMAPs
93 // [
94 // OMAPRecord {
95 // source_address: 0x000010aa,
96 // target_address: 0x00015de6
97 // },
98 // OMAPRecord {
99 // source_address: 0x000010bd,
100 // target_address: 0x00000000
101 // },
102 // OMAPRecord {
103 // source_address: 0x000010c4,
104 // target_address: 0x0002da00
105 // },
106 // OMAPRecord {
107 // source_address: 0x000010c8,
108 // target_address: 0x0002da04
109 // },
110 // ]
111 let start = PdbInternalRva(0x10b0);
112 let end = PdbInternalRva(0x10c6);
113
114 assert_eq!(
115 address_map.rva_ranges(start..end).collect::<Vec<_>>(),
116 vec![
117 Rva(0x15dec)..Rva(0x15df9), // 0x10aa - 0x10bd
118 // 0x10bd - 0x10c4 omitted due to missing target address
119 Rva(0x2da00)..Rva(0x2da02), // 0x10c4 - 0x10c6
120 ],
121 );
122
123 // Range starting outside OMAPs
124 // [
125 // OMAPRecord {
126 // source_address: 0x00001000,
127 // target_address: 0x00000000
128 // },
129 // OMAPRecord {
130 // source_address: 0x00001008,
131 // target_address: 0x00015d44
132 // },
133 // ]
134 let start = PdbInternalRva(0x0);
135 let end = PdbInternalRva(0x1010);
136 assert_eq!(
137 address_map.rva_ranges(start..end).collect::<Vec<_>>(),
138 vec![Rva(0x15d44)..Rva(0x15d4c)],
139 );
140
141 // Range ending outside OMAPs
142 // [
143 // OMAPRecord {
144 // source_address: 0x005e40e0,
145 // target_address: 0x005e50e0
146 // },
147 // OMAPRecord {
148 // source_address: 0x005e5000,
149 // target_address: 0x00000000
150 // },
151 // OMAPRecord {
152 // source_address: 0x005e70c0,
153 // target_address: 0x00000000
154 // }
155 // ]
156 let start = PdbInternalRva(0x5e_4fe0);
157 let end = PdbInternalRva(0x5e_8000);
158 assert_eq!(
159 address_map.rva_ranges(start..end).collect::<Vec<_>>(),
160 vec![Rva(0x005e_5fe0)..Rva(0x5e_6000)],
161 );
162
163 // Range fully before OMAPs
164 let start = PdbInternalRva(0x0);
165 let end = PdbInternalRva(0x100);
166 assert_eq!(
167 address_map.rva_ranges(start..end).collect::<Vec<_>>(),
168 vec![],
169 );
170
171 // Range fully after OMAPs
172 let start = PdbInternalRva(0x005e_8000);
173 let end = PdbInternalRva(0x005e_9000);
174 assert_eq!(
175 address_map.rva_ranges(start..end).collect::<Vec<_>>(),
176 vec![], // last record targets 0, thus the range is omitted
177 );
178 }
179