2 * Copyright (c) 2018 Virtuozzo International GmbH
4 * Based on source of Wine project
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "qemu/osdep.h"
25 static uint32_t pdb_get_file_size(const struct pdb_reader
*r
, unsigned idx
)
27 return r
->ds
.toc
->file_size
[idx
];
30 static pdb_seg
*get_seg_by_num(struct pdb_reader
*r
, size_t n
)
35 for (ptr
= r
->segs
; (ptr
< r
->segs
+ r
->segs_size
); ) {
41 ptr
+= sizeof(pdb_seg
);
44 return (pdb_seg
*)ptr
;
47 uint64_t pdb_find_public_v3_symbol(struct pdb_reader
*r
, const char *name
)
49 size_t size
= pdb_get_file_size(r
, r
->symbols
->gsym_file
);
51 const union codeview_symbol
*sym
;
52 const uint8_t *root
= r
->modimage
;
55 for (i
= 0; i
< size
; i
+= length
) {
56 sym
= (const void *)(root
+ i
);
57 length
= sym
->generic
.len
+ 2;
59 if (!sym
->generic
.id
|| length
< 4) {
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
;
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
);
79 uint64_t pdb_resolve(uint64_t img_base
, struct pdb_reader
*r
, const char *name
)
81 uint64_t rva
= pdb_find_public_v3_symbol(r
, name
);
87 return img_base
+ rva
;
90 static void pdb_reader_ds_exit(struct pdb_reader
*r
)
95 static void pdb_exit_symbols(struct pdb_reader
*r
)
101 static void pdb_exit_segments(struct pdb_reader
*r
)
106 static void *pdb_ds_read(const PDB_DS_HEADER
*header
,
107 const uint32_t *block_list
, int size
)
116 nBlocks
= (size
+ header
->block_size
- 1) / header
->block_size
;
118 buffer
= malloc(nBlocks
* header
->block_size
);
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
);
131 static void *pdb_ds_read_file(struct pdb_reader
* r
, uint32_t file_number
)
133 const uint32_t *block_list
;
135 const uint32_t *file_size
;
138 if (!r
->ds
.toc
|| file_number
>= r
->ds
.toc
->num_files
) {
142 file_size
= r
->ds
.toc
->file_size
;
143 r
->file_used
[file_number
/ 32] |= 1 << (file_number
% 32);
145 if (file_size
[file_number
] == 0 || file_size
[file_number
] == 0xFFFFFFFF) {
149 block_list
= file_size
+ r
->ds
.toc
->num_files
;
150 block_size
= r
->ds
.header
->block_size
;
152 for (i
= 0; i
< file_number
; i
++) {
153 block_list
+= (file_size
[i
] + block_size
- 1) / block_size
;
156 return pdb_ds_read(r
->ds
.header
, block_list
, file_size
[file_number
]);
159 static int pdb_init_segments(struct pdb_reader
*r
)
162 unsigned stream_idx
= r
->sidx
.segments
;
164 segs
= pdb_ds_read_file(r
, stream_idx
);
170 r
->segs_size
= pdb_get_file_size(r
, stream_idx
);
175 static int pdb_init_symbols(struct pdb_reader
*r
)
178 PDB_SYMBOLS
*symbols
;
179 PDB_STREAM_INDEXES
*sidx
= &r
->sidx
;
181 memset(sidx
, -1, sizeof(*sidx
));
183 symbols
= pdb_ds_read_file(r
, 3);
188 r
->symbols
= symbols
;
190 if (symbols
->stream_index_size
!= sizeof(PDB_STREAM_INDEXES
)) {
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
));
200 /* Read global symbol table */
201 r
->modimage
= pdb_ds_read_file(r
, symbols
->gsym_file
);
215 static int pdb_reader_ds_init(struct pdb_reader
*r
, PDB_DS_HEADER
*hdr
)
217 memset(r
->file_used
, 0, sizeof(r
->file_used
));
219 r
->ds
.toc
= pdb_ds_read(hdr
, (uint32_t *)((uint8_t *)hdr
+
220 hdr
->toc_page
* hdr
->block_size
), hdr
->toc_size
);
229 static int pdb_reader_init(struct pdb_reader
*r
, void *data
)
232 const char pdb7
[] = "Microsoft C/C++ MSF 7.00";
234 if (memcmp(data
, pdb7
, sizeof(pdb7
) - 1)) {
238 if (pdb_reader_ds_init(r
, data
)) {
242 r
->ds
.root
= pdb_ds_read_file(r
, 1);
248 if (pdb_init_symbols(r
)) {
253 if (pdb_init_segments(r
)) {
265 pdb_reader_ds_exit(r
);
270 static void pdb_reader_exit(struct pdb_reader
*r
)
272 pdb_exit_segments(r
);
275 pdb_reader_ds_exit(r
);
278 int pdb_init_from_file(const char *name
, struct pdb_reader
*reader
)
285 fd
= open(name
, O_RDONLY
, 0);
287 eprintf("Failed to open PDB file \'%s\'\n", name
);
293 reader
->file_size
= st
.st_size
;
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");
302 if (pdb_reader_init(reader
, map
)) {
310 munmap(map
, st
.st_size
);
317 void pdb_exit(struct pdb_reader
*reader
)
319 munmap(reader
->ds
.header
, reader
->file_size
);
321 pdb_reader_exit(reader
);