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 return r
->ds
.toc
->file_size
[idx
];
31 static pdb_seg
*get_seg_by_num(struct pdb_reader
*r
, size_t n
)
36 for (ptr
= r
->segs
; (ptr
< r
->segs
+ r
->segs_size
); ) {
42 ptr
+= sizeof(pdb_seg
);
45 return (pdb_seg
*)ptr
;
48 uint64_t pdb_find_public_v3_symbol(struct pdb_reader
*r
, const char *name
)
50 size_t size
= pdb_get_file_size(r
, r
->symbols
->gsym_file
);
52 const union codeview_symbol
*sym
;
53 const uint8_t *root
= r
->modimage
;
56 for (i
= 0; i
< size
; i
+= length
) {
57 sym
= (const void *)(root
+ i
);
58 length
= sym
->generic
.len
+ 2;
60 if (!sym
->generic
.id
|| length
< 4) {
64 if (sym
->generic
.id
== S_PUB_V3
&&
65 !strcmp(name
, sym
->public_v3
.name
)) {
66 pdb_seg
*segment
= get_seg_by_num(r
, sym
->public_v3
.segment
);
67 uint32_t sect_rva
= segment
->dword
[1];
68 uint64_t rva
= sect_rva
+ sym
->public_v3
.offset
;
70 printf("%s: 0x%016x(%d:\'%.8s\') + 0x%08x = 0x%09"PRIx64
"\n", name
,
71 sect_rva
, sym
->public_v3
.segment
,
72 ((char *)segment
- 8), sym
->public_v3
.offset
, rva
);
80 uint64_t pdb_resolve(uint64_t img_base
, struct pdb_reader
*r
, const char *name
)
82 uint64_t rva
= pdb_find_public_v3_symbol(r
, name
);
88 return img_base
+ rva
;
91 static void pdb_reader_ds_exit(struct pdb_reader
*r
)
96 static void pdb_exit_symbols(struct pdb_reader
*r
)
102 static void pdb_exit_segments(struct pdb_reader
*r
)
107 static void *pdb_ds_read(const PDB_DS_HEADER
*header
,
108 const uint32_t *block_list
, int size
)
117 nBlocks
= (size
+ header
->block_size
- 1) / header
->block_size
;
119 buffer
= malloc(nBlocks
* header
->block_size
);
124 for (i
= 0; i
< nBlocks
; i
++) {
125 memcpy(buffer
+ i
* header
->block_size
, (const char *)header
+
126 block_list
[i
] * header
->block_size
, header
->block_size
);
132 static void *pdb_ds_read_file(struct pdb_reader
* r
, uint32_t file_number
)
134 const uint32_t *block_list
;
136 const uint32_t *file_size
;
139 if (!r
->ds
.toc
|| file_number
>= r
->ds
.toc
->num_files
) {
143 file_size
= r
->ds
.toc
->file_size
;
144 r
->file_used
[file_number
/ 32] |= 1 << (file_number
% 32);
146 if (file_size
[file_number
] == 0 || file_size
[file_number
] == 0xFFFFFFFF) {
150 block_list
= file_size
+ r
->ds
.toc
->num_files
;
151 block_size
= r
->ds
.header
->block_size
;
153 for (i
= 0; i
< file_number
; i
++) {
154 block_list
+= (file_size
[i
] + block_size
- 1) / block_size
;
157 return pdb_ds_read(r
->ds
.header
, block_list
, file_size
[file_number
]);
160 static int pdb_init_segments(struct pdb_reader
*r
)
163 unsigned stream_idx
= r
->sidx
.segments
;
165 segs
= pdb_ds_read_file(r
, stream_idx
);
171 r
->segs_size
= pdb_get_file_size(r
, stream_idx
);
176 static int pdb_init_symbols(struct pdb_reader
*r
)
179 PDB_SYMBOLS
*symbols
;
180 PDB_STREAM_INDEXES
*sidx
= &r
->sidx
;
182 memset(sidx
, -1, sizeof(*sidx
));
184 symbols
= pdb_ds_read_file(r
, 3);
189 r
->symbols
= symbols
;
191 if (symbols
->stream_index_size
!= sizeof(PDB_STREAM_INDEXES
)) {
196 memcpy(sidx
, (const char *)symbols
+ sizeof(PDB_SYMBOLS
) +
197 symbols
->module_size
+ symbols
->offset_size
+
198 symbols
->hash_size
+ symbols
->srcmodule_size
+
199 symbols
->pdbimport_size
+ symbols
->unknown2_size
, sizeof(*sidx
));
201 /* Read global symbol table */
202 r
->modimage
= pdb_ds_read_file(r
, symbols
->gsym_file
);
216 static int pdb_reader_ds_init(struct pdb_reader
*r
, PDB_DS_HEADER
*hdr
)
218 if (hdr
->block_size
== 0) {
222 memset(r
->file_used
, 0, sizeof(r
->file_used
));
224 r
->ds
.toc
= pdb_ds_read(hdr
, (uint32_t *)((uint8_t *)hdr
+
225 hdr
->toc_page
* hdr
->block_size
), hdr
->toc_size
);
234 static int pdb_reader_init(struct pdb_reader
*r
, void *data
)
237 const char pdb7
[] = "Microsoft C/C++ MSF 7.00";
239 if (memcmp(data
, pdb7
, sizeof(pdb7
) - 1)) {
243 if (pdb_reader_ds_init(r
, data
)) {
247 r
->ds
.root
= pdb_ds_read_file(r
, 1);
253 if (pdb_init_symbols(r
)) {
258 if (pdb_init_segments(r
)) {
270 pdb_reader_ds_exit(r
);
275 static void pdb_reader_exit(struct pdb_reader
*r
)
277 pdb_exit_segments(r
);
280 pdb_reader_ds_exit(r
);
283 int pdb_init_from_file(const char *name
, struct pdb_reader
*reader
)
289 reader
->gmf
= g_mapped_file_new(name
, TRUE
, &gerr
);
291 eprintf("Failed to map PDB file \'%s\'\n", name
);
296 reader
->file_size
= g_mapped_file_get_length(reader
->gmf
);
297 map
= g_mapped_file_get_contents(reader
->gmf
);
298 if (pdb_reader_init(reader
, map
)) {
306 g_mapped_file_unref(reader
->gmf
);
311 void pdb_exit(struct pdb_reader
*reader
)
313 g_mapped_file_unref(reader
->gmf
);
314 pdb_reader_exit(reader
);