1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22#include "pdb.h"
23#include "err.h"
24
25static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx)
26{
27 return r->ds.toc->file_size[idx];
28}
29
30static pdb_seg *get_seg_by_num(struct pdb_reader *r, size_t n)
31{
32 size_t i = 0;
33 char *ptr;
34
35 for (ptr = r->segs; (ptr < r->segs + r->segs_size); ) {
36 i++;
37 ptr += 8;
38 if (i == n) {
39 break;
40 }
41 ptr += sizeof(pdb_seg);
42 }
43
44 return (pdb_seg *)ptr;
45}
46
47uint64_t pdb_find_public_v3_symbol(struct pdb_reader *r, const char *name)
48{
49 size_t size = pdb_get_file_size(r, r->symbols->gsym_file);
50 int length;
51 const union codeview_symbol *sym;
52 const uint8_t *root = r->modimage;
53 size_t i;
54
55 for (i = 0; i < size; i += length) {
56 sym = (const void *)(root + i);
57 length = sym->generic.len + 2;
58
59 if (!sym->generic.id || length < 4) {
60 break;
61 }
62
63 if (sym->generic.id == S_PUB_V3 &&
64 !strcmp(name, sym->public_v3.name)) {
65 pdb_seg *segment = get_seg_by_num(r, sym->public_v3.segment);
66 uint32_t sect_rva = segment->dword[1];
67 uint64_t rva = sect_rva + sym->public_v3.offset;
68
69 printf("%s: 0x%016x(%d:\'%.8s\') + 0x%08x = 0x%09lx\n", name,
70 sect_rva, sym->public_v3.segment,
71 ((char *)segment - 8), sym->public_v3.offset, rva);
72 return rva;
73 }
74 }
75
76 return 0;
77}
78
79uint64_t pdb_resolve(uint64_t img_base, struct pdb_reader *r, const char *name)
80{
81 uint64_t rva = pdb_find_public_v3_symbol(r, name);
82
83 if (!rva) {
84 return 0;
85 }
86
87 return img_base + rva;
88}
89
90static void pdb_reader_ds_exit(struct pdb_reader *r)
91{
92 free(r->ds.toc);
93}
94
95static void pdb_exit_symbols(struct pdb_reader *r)
96{
97 free(r->modimage);
98 free(r->symbols);
99}
100
101static void pdb_exit_segments(struct pdb_reader *r)
102{
103 free(r->segs);
104}
105
106static void *pdb_ds_read(const PDB_DS_HEADER *header,
107 const uint32_t *block_list, int size)
108{
109 int i, nBlocks;
110 uint8_t *buffer;
111
112 if (!size) {
113 return NULL;
114 }
115
116 nBlocks = (size + header->block_size - 1) / header->block_size;
117
118 buffer = malloc(nBlocks * header->block_size);
119 if (!buffer) {
120 return NULL;
121 }
122
123 for (i = 0; i < nBlocks; i++) {
124 memcpy(buffer + i * header->block_size, (const char *)header +
125 block_list[i] * header->block_size, header->block_size);
126 }
127
128 return buffer;
129}
130
131static void *pdb_ds_read_file(struct pdb_reader* r, uint32_t file_number)
132{
133 const uint32_t *block_list;
134 uint32_t block_size;
135 const uint32_t *file_size;
136 size_t i;
137
138 if (!r->ds.toc || file_number >= r->ds.toc->num_files) {
139 return NULL;
140 }
141
142 file_size = r->ds.toc->file_size;
143 r->file_used[file_number / 32] |= 1 << (file_number % 32);
144
145 if (file_size[file_number] == 0 || file_size[file_number] == 0xFFFFFFFF) {
146 return NULL;
147 }
148
149 block_list = file_size + r->ds.toc->num_files;
150 block_size = r->ds.header->block_size;
151
152 for (i = 0; i < file_number; i++) {
153 block_list += (file_size[i] + block_size - 1) / block_size;
154 }
155
156 return pdb_ds_read(r->ds.header, block_list, file_size[file_number]);
157}
158
159static int pdb_init_segments(struct pdb_reader *r)
160{
161 char *segs;
162 unsigned stream_idx = r->sidx.segments;
163
164 segs = pdb_ds_read_file(r, stream_idx);
165 if (!segs) {
166 return 1;
167 }
168
169 r->segs = segs;
170 r->segs_size = pdb_get_file_size(r, stream_idx);
171
172 return 0;
173}
174
175static int pdb_init_symbols(struct pdb_reader *r)
176{
177 int err = 0;
178 PDB_SYMBOLS *symbols;
179 PDB_STREAM_INDEXES *sidx = &r->sidx;
180
181 memset(sidx, -1, sizeof(*sidx));
182
183 symbols = pdb_ds_read_file(r, 3);
184 if (!symbols) {
185 return 1;
186 }
187
188 r->symbols = symbols;
189
190 if (symbols->stream_index_size != sizeof(PDB_STREAM_INDEXES)) {
191 err = 1;
192 goto out_symbols;
193 }
194
195 memcpy(sidx, (const char *)symbols + sizeof(PDB_SYMBOLS) +
196 symbols->module_size + symbols->offset_size +
197 symbols->hash_size + symbols->srcmodule_size +
198 symbols->pdbimport_size + symbols->unknown2_size, sizeof(*sidx));
199
200
201 r->modimage = pdb_ds_read_file(r, symbols->gsym_file);
202 if (!r->modimage) {
203 err = 1;
204 goto out_symbols;
205 }
206
207 return 0;
208
209out_symbols:
210 free(symbols);
211
212 return err;
213}
214
215static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
216{
217 memset(r->file_used, 0, sizeof(r->file_used));
218 r->ds.header = hdr;
219 r->ds.toc = pdb_ds_read(hdr, (uint32_t *)((uint8_t *)hdr +
220 hdr->toc_page * hdr->block_size), hdr->toc_size);
221
222 if (!r->ds.toc) {
223 return 1;
224 }
225
226 return 0;
227}
228
229static int pdb_reader_init(struct pdb_reader *r, void *data)
230{
231 int err = 0;
232 const char pdb7[] = "Microsoft C/C++ MSF 7.00";
233
234 if (memcmp(data, pdb7, sizeof(pdb7) - 1)) {
235 return 1;
236 }
237
238 if (pdb_reader_ds_init(r, data)) {
239 return 1;
240 }
241
242 r->ds.root = pdb_ds_read_file(r, 1);
243 if (!r->ds.root) {
244 err = 1;
245 goto out_ds;
246 }
247
248 if (pdb_init_symbols(r)) {
249 err = 1;
250 goto out_root;
251 }
252
253 if (pdb_init_segments(r)) {
254 err = 1;
255 goto out_sym;
256 }
257
258 return 0;
259
260out_sym:
261 pdb_exit_symbols(r);
262out_root:
263 free(r->ds.root);
264out_ds:
265 pdb_reader_ds_exit(r);
266
267 return err;
268}
269
270static void pdb_reader_exit(struct pdb_reader *r)
271{
272 pdb_exit_segments(r);
273 pdb_exit_symbols(r);
274 free(r->ds.root);
275 pdb_reader_ds_exit(r);
276}
277
278int pdb_init_from_file(const char *name, struct pdb_reader *reader)
279{
280 int err = 0;
281 int fd;
282 void *map;
283 struct stat st;
284
285 fd = open(name, O_RDONLY, 0);
286 if (fd == -1) {
287 eprintf("Failed to open PDB file \'%s\'\n", name);
288 return 1;
289 }
290 reader->fd = fd;
291
292 fstat(fd, &st);
293 reader->file_size = st.st_size;
294
295 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
296 if (map == MAP_FAILED) {
297 eprintf("Failed to map PDB file\n");
298 err = 1;
299 goto out_fd;
300 }
301
302 if (pdb_reader_init(reader, map)) {
303 err = 1;
304 goto out_unmap;
305 }
306
307 return 0;
308
309out_unmap:
310 munmap(map, st.st_size);
311out_fd:
312 close(fd);
313
314 return err;
315}
316
317void pdb_exit(struct pdb_reader *reader)
318{
319 munmap(reader->ds.header, reader->file_size);
320 close(reader->fd);
321 pdb_reader_exit(reader);
322}
323