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"
26 static uint32_t pdb_get_file_size(const struct pdb_reader
*r
, unsigned idx
)
28 if (idx
>= r
->ds
.toc
->num_files
) {
32 return r
->ds
.toc
->file_size
[idx
];
35 static pdb_seg
*get_seg_by_num(struct pdb_reader
*r
, size_t n
)
40 for (ptr
= r
->segs
; (ptr
< r
->segs
+ r
->segs_size
); ) {
46 ptr
+= sizeof(pdb_seg
);
49 return (pdb_seg
*)ptr
;
52 uint64_t pdb_find_public_v3_symbol(struct pdb_reader
*r
, const char *name
)
54 size_t size
= pdb_get_file_size(r
, r
->symbols
->gsym_file
);
56 const union codeview_symbol
*sym
;
57 const uint8_t *root
= r
->modimage
;
60 for (i
= 0; i
< size
; i
+= length
) {
61 sym
= (const void *)(root
+ i
);
62 length
= sym
->generic
.len
+ 2;
64 if (!sym
->generic
.id
|| length
< 4) {
68 if (sym
->generic
.id
== S_PUB_V3
&&
69 !strcmp(name
, sym
->public_v3
.name
)) {
70 pdb_seg
*segment
= get_seg_by_num(r
, sym
->public_v3
.segment
);
71 uint32_t sect_rva
= segment
->dword
[1];
72 uint64_t rva
= sect_rva
+ sym
->public_v3
.offset
;
74 printf("%s: 0x%016x(%d:\'%.8s\') + 0x%08x = 0x%09"PRIx64
"\n", name
,
75 sect_rva
, sym
->public_v3
.segment
,
76 ((char *)segment
- 8), sym
->public_v3
.offset
, rva
);
84 uint64_t pdb_resolve(uint64_t img_base
, struct pdb_reader
*r
, const char *name
)
86 uint64_t rva
= pdb_find_public_v3_symbol(r
, name
);
92 return img_base
+ rva
;
95 static void pdb_reader_ds_exit(struct pdb_reader
*r
)
100 static void pdb_exit_symbols(struct pdb_reader
*r
)
106 static void pdb_exit_segments(struct pdb_reader
*r
)
111 static void *pdb_ds_read(const PDB_DS_HEADER
*header
,
112 const uint32_t *block_list
, int size
)
121 nBlocks
= (size
+ header
->block_size
- 1) / header
->block_size
;
123 buffer
= malloc(nBlocks
* header
->block_size
);
128 for (i
= 0; i
< nBlocks
; i
++) {
129 memcpy(buffer
+ i
* header
->block_size
, (const char *)header
+
130 block_list
[i
] * header
->block_size
, header
->block_size
);
136 static void *pdb_ds_read_file(struct pdb_reader
* r
, uint32_t file_number
)
138 const uint32_t *block_list
;
140 const uint32_t *file_size
;
143 if (!r
->ds
.toc
|| file_number
>= r
->ds
.toc
->num_files
) {
147 file_size
= r
->ds
.toc
->file_size
;
148 r
->file_used
[file_number
/ 32] |= 1 << (file_number
% 32);
150 if (file_size
[file_number
] == 0 || file_size
[file_number
] == 0xFFFFFFFF) {
154 block_list
= file_size
+ r
->ds
.toc
->num_files
;
155 block_size
= r
->ds
.header
->block_size
;
157 for (i
= 0; i
< file_number
; i
++) {
158 block_list
+= (file_size
[i
] + block_size
- 1) / block_size
;
161 return pdb_ds_read(r
->ds
.header
, block_list
, file_size
[file_number
]);
164 static int pdb_init_segments(struct pdb_reader
*r
)
166 unsigned stream_idx
= r
->segments
;
168 r
->segs
= pdb_ds_read_file(r
, stream_idx
);
173 r
->segs_size
= pdb_get_file_size(r
, stream_idx
);
181 static int pdb_init_symbols(struct pdb_reader
*r
)
184 PDB_SYMBOLS
*symbols
;
186 symbols
= pdb_ds_read_file(r
, 3);
191 r
->symbols
= symbols
;
193 r
->segments
= *(uint16_t *)((const char *)symbols
+ sizeof(PDB_SYMBOLS
) +
194 symbols
->module_size
+ symbols
->offset_size
+
195 symbols
->hash_size
+ symbols
->srcmodule_size
+
196 symbols
->pdbimport_size
+ symbols
->unknown2_size
+
197 offsetof(PDB_STREAM_INDEXES
, segments
));
199 /* Read global symbol table */
200 r
->modimage
= pdb_ds_read_file(r
, symbols
->gsym_file
);
214 static int pdb_reader_ds_init(struct pdb_reader
*r
, PDB_DS_HEADER
*hdr
)
216 if (hdr
->block_size
== 0) {
220 memset(r
->file_used
, 0, sizeof(r
->file_used
));
222 r
->ds
.toc
= pdb_ds_read(hdr
, (uint32_t *)((uint8_t *)hdr
+
223 hdr
->toc_page
* hdr
->block_size
), hdr
->toc_size
);
232 static int pdb_reader_init(struct pdb_reader
*r
, void *data
)
235 const char pdb7
[] = "Microsoft C/C++ MSF 7.00";
237 if (memcmp(data
, pdb7
, sizeof(pdb7
) - 1)) {
241 if (pdb_reader_ds_init(r
, data
)) {
245 r
->ds
.root
= pdb_ds_read_file(r
, 1);
251 if (pdb_init_symbols(r
)) {
256 if (pdb_init_segments(r
)) {
268 pdb_reader_ds_exit(r
);
273 static void pdb_reader_exit(struct pdb_reader
*r
)
275 pdb_exit_segments(r
);
278 pdb_reader_ds_exit(r
);
281 int pdb_init_from_file(const char *name
, struct pdb_reader
*reader
)
287 reader
->gmf
= g_mapped_file_new(name
, TRUE
, &gerr
);
289 eprintf("Failed to map PDB file \'%s\'\n", name
);
294 reader
->file_size
= g_mapped_file_get_length(reader
->gmf
);
295 map
= g_mapped_file_get_contents(reader
->gmf
);
296 if (pdb_reader_init(reader
, map
)) {
304 g_mapped_file_unref(reader
->gmf
);
309 void pdb_exit(struct pdb_reader
*reader
)
311 g_mapped_file_unref(reader
->gmf
);
312 pdb_reader_exit(reader
);