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
23 #include "qemu/osdep.h"
27 static uint32_t pdb_get_file_size(const struct pdb_reader
*r
, unsigned idx
)
29 return r
->ds
.toc
->file_size
[idx
];
32 static pdb_seg
*get_seg_by_num(struct pdb_reader
*r
, size_t n
)
37 for (ptr
= r
->segs
; (ptr
< r
->segs
+ r
->segs_size
); ) {
43 ptr
+= sizeof(pdb_seg
);
46 return (pdb_seg
*)ptr
;
49 uint64_t pdb_find_public_v3_symbol(struct pdb_reader
*r
, const char *name
)
51 size_t size
= pdb_get_file_size(r
, r
->symbols
->gsym_file
);
53 const union codeview_symbol
*sym
;
54 const uint8_t *root
= r
->modimage
;
57 for (i
= 0; i
< size
; i
+= length
) {
58 sym
= (const void *)(root
+ i
);
59 length
= sym
->generic
.len
+ 2;
61 if (!sym
->generic
.id
|| length
< 4) {
65 if (sym
->generic
.id
== S_PUB_V3
&&
66 !strcmp(name
, sym
->public_v3
.name
)) {
67 pdb_seg
*segment
= get_seg_by_num(r
, sym
->public_v3
.segment
);
68 uint32_t sect_rva
= segment
->dword
[1];
69 uint64_t rva
= sect_rva
+ sym
->public_v3
.offset
;
71 printf("%s: 0x%016x(%d:\'%.8s\') + 0x%08x = 0x%09"PRIx64
"\n", name
,
72 sect_rva
, sym
->public_v3
.segment
,
73 ((char *)segment
- 8), sym
->public_v3
.offset
, rva
);
81 uint64_t pdb_resolve(uint64_t img_base
, struct pdb_reader
*r
, const char *name
)
83 uint64_t rva
= pdb_find_public_v3_symbol(r
, name
);
89 return img_base
+ rva
;
92 static void pdb_reader_ds_exit(struct pdb_reader
*r
)
97 static void pdb_exit_symbols(struct pdb_reader
*r
)
103 static void pdb_exit_segments(struct pdb_reader
*r
)
108 static void *pdb_ds_read(const PDB_DS_HEADER
*header
,
109 const uint32_t *block_list
, int size
)
118 nBlocks
= (size
+ header
->block_size
- 1) / header
->block_size
;
120 buffer
= 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
)
164 unsigned stream_idx
= r
->sidx
.segments
;
166 segs
= pdb_ds_read_file(r
, stream_idx
);
172 r
->segs_size
= pdb_get_file_size(r
, stream_idx
);
177 static int pdb_init_symbols(struct pdb_reader
*r
)
180 PDB_SYMBOLS
*symbols
;
181 PDB_STREAM_INDEXES
*sidx
= &r
->sidx
;
183 memset(sidx
, -1, sizeof(*sidx
));
185 symbols
= pdb_ds_read_file(r
, 3);
190 r
->symbols
= symbols
;
192 if (symbols
->stream_index_size
!= sizeof(PDB_STREAM_INDEXES
)) {
197 memcpy(sidx
, (const char *)symbols
+ sizeof(PDB_SYMBOLS
) +
198 symbols
->module_size
+ symbols
->offset_size
+
199 symbols
->hash_size
+ symbols
->srcmodule_size
+
200 symbols
->pdbimport_size
+ symbols
->unknown2_size
, sizeof(*sidx
));
202 /* Read global symbol table */
203 r
->modimage
= pdb_ds_read_file(r
, symbols
->gsym_file
);
217 static int pdb_reader_ds_init(struct pdb_reader
*r
, PDB_DS_HEADER
*hdr
)
219 memset(r
->file_used
, 0, sizeof(r
->file_used
));
221 r
->ds
.toc
= pdb_ds_read(hdr
, (uint32_t *)((uint8_t *)hdr
+
222 hdr
->toc_page
* hdr
->block_size
), hdr
->toc_size
);
231 static int pdb_reader_init(struct pdb_reader
*r
, void *data
)
234 const char pdb7
[] = "Microsoft C/C++ MSF 7.00";
236 if (memcmp(data
, pdb7
, sizeof(pdb7
) - 1)) {
240 if (pdb_reader_ds_init(r
, data
)) {
244 r
->ds
.root
= pdb_ds_read_file(r
, 1);
250 if (pdb_init_symbols(r
)) {
255 if (pdb_init_segments(r
)) {
267 pdb_reader_ds_exit(r
);
272 static void pdb_reader_exit(struct pdb_reader
*r
)
274 pdb_exit_segments(r
);
277 pdb_reader_ds_exit(r
);
280 int pdb_init_from_file(const char *name
, struct pdb_reader
*reader
)
286 reader
->gmf
= g_mapped_file_new(name
, TRUE
, &gerr
);
288 eprintf("Failed to map PDB file \'%s\'\n", name
);
292 reader
->file_size
= g_mapped_file_get_length(reader
->gmf
);
293 map
= g_mapped_file_get_contents(reader
->gmf
);
294 if (pdb_reader_init(reader
, map
)) {
302 g_mapped_file_unref(reader
->gmf
);
307 void pdb_exit(struct pdb_reader
*reader
)
309 g_mapped_file_unref(reader
->gmf
);
310 pdb_reader_exit(reader
);