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