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
= g_malloc(nBlocks
* header
->block_size
);
125 for (i
= 0; i
< nBlocks
; i
++) {
126 memcpy(buffer
+ i
* header
->block_size
, (const char *)header
+
127 block_list
[i
] * header
->block_size
, header
->block_size
);
133 static void *pdb_ds_read_file(struct pdb_reader
* r
, uint32_t file_number
)
135 const uint32_t *block_list
;
137 const uint32_t *file_size
;
140 if (!r
->ds
.toc
|| file_number
>= r
->ds
.toc
->num_files
) {
144 file_size
= r
->ds
.toc
->file_size
;
145 r
->file_used
[file_number
/ 32] |= 1 << (file_number
% 32);
147 if (file_size
[file_number
] == 0 || file_size
[file_number
] == 0xFFFFFFFF) {
151 block_list
= file_size
+ r
->ds
.toc
->num_files
;
152 block_size
= r
->ds
.header
->block_size
;
154 for (i
= 0; i
< file_number
; i
++) {
155 block_list
+= (file_size
[i
] + block_size
- 1) / block_size
;
158 return pdb_ds_read(r
->ds
.header
, block_list
, file_size
[file_number
]);
161 static int pdb_init_segments(struct pdb_reader
*r
)
163 unsigned stream_idx
= r
->segments
;
165 r
->segs
= pdb_ds_read_file(r
, stream_idx
);
170 r
->segs_size
= pdb_get_file_size(r
, stream_idx
);
178 static int pdb_init_symbols(struct pdb_reader
*r
)
181 PDB_SYMBOLS
*symbols
;
183 symbols
= pdb_ds_read_file(r
, 3);
188 r
->symbols
= symbols
;
190 r
->segments
= *(uint16_t *)((const char *)symbols
+ sizeof(PDB_SYMBOLS
) +
191 symbols
->module_size
+ symbols
->offset_size
+
192 symbols
->hash_size
+ symbols
->srcmodule_size
+
193 symbols
->pdbimport_size
+ symbols
->unknown2_size
+
194 offsetof(PDB_STREAM_INDEXES
, segments
));
196 /* Read global symbol table */
197 r
->modimage
= pdb_ds_read_file(r
, symbols
->gsym_file
);
211 static int pdb_reader_ds_init(struct pdb_reader
*r
, PDB_DS_HEADER
*hdr
)
213 if (hdr
->block_size
== 0) {
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
)
284 reader
->gmf
= g_mapped_file_new(name
, TRUE
, &gerr
);
286 eprintf("Failed to map PDB file \'%s\'\n", name
);
291 reader
->file_size
= g_mapped_file_get_length(reader
->gmf
);
292 map
= g_mapped_file_get_contents(reader
->gmf
);
293 if (pdb_reader_init(reader
, map
)) {
301 g_mapped_file_unref(reader
->gmf
);
306 void pdb_exit(struct pdb_reader
*reader
)
308 g_mapped_file_unref(reader
->gmf
);
309 pdb_reader_exit(reader
);