]> git.proxmox.com Git - mirror_qemu.git/blame - contrib/elf2dmp/pdb.c
contrib/elf2dmp: Fix error reporting style in pdb.c
[mirror_qemu.git] / contrib / elf2dmp / pdb.c
CommitLineData
3fa2d384
VP
1/*
2 * Copyright (c) 2018 Virtuozzo International GmbH
3 *
4 * Based on source of Wine project
5 *
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.
10 *
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.
15 *
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
19 */
20
21#include "qemu/osdep.h"
bbfff196 22
3fa2d384
VP
23#include "pdb.h"
24#include "err.h"
25
26static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx)
27{
9d9c06b1
VP
28 if (idx >= r->ds.toc->num_files) {
29 return 0;
30 }
31
3fa2d384
VP
32 return r->ds.toc->file_size[idx];
33}
34
35static pdb_seg *get_seg_by_num(struct pdb_reader *r, size_t n)
36{
37 size_t i = 0;
38 char *ptr;
39
40 for (ptr = r->segs; (ptr < r->segs + r->segs_size); ) {
41 i++;
42 ptr += 8;
43 if (i == n) {
44 break;
45 }
46 ptr += sizeof(pdb_seg);
47 }
48
49 return (pdb_seg *)ptr;
50}
51
52uint64_t pdb_find_public_v3_symbol(struct pdb_reader *r, const char *name)
53{
54 size_t size = pdb_get_file_size(r, r->symbols->gsym_file);
55 int length;
56 const union codeview_symbol *sym;
57 const uint8_t *root = r->modimage;
58 size_t i;
59
60 for (i = 0; i < size; i += length) {
61 sym = (const void *)(root + i);
62 length = sym->generic.len + 2;
63
64 if (!sym->generic.id || length < 4) {
65 break;
66 }
67
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;
73
6ec6e988 74 printf("%s: 0x%016x(%d:\'%.8s\') + 0x%08x = 0x%09"PRIx64"\n", name,
3fa2d384
VP
75 sect_rva, sym->public_v3.segment,
76 ((char *)segment - 8), sym->public_v3.offset, rva);
77 return rva;
78 }
79 }
80
81 return 0;
82}
83
84uint64_t pdb_resolve(uint64_t img_base, struct pdb_reader *r, const char *name)
85{
86 uint64_t rva = pdb_find_public_v3_symbol(r, name);
87
88 if (!rva) {
89 return 0;
90 }
91
92 return img_base + rva;
93}
94
95static void pdb_reader_ds_exit(struct pdb_reader *r)
96{
2a052b4e 97 g_free(r->ds.toc);
3fa2d384
VP
98}
99
100static void pdb_exit_symbols(struct pdb_reader *r)
101{
2a052b4e
SS
102 g_free(r->modimage);
103 g_free(r->symbols);
3fa2d384
VP
104}
105
106static void pdb_exit_segments(struct pdb_reader *r)
107{
2a052b4e 108 g_free(r->segs);
3fa2d384
VP
109}
110
111static void *pdb_ds_read(const PDB_DS_HEADER *header,
112 const uint32_t *block_list, int size)
113{
114 int i, nBlocks;
115 uint8_t *buffer;
116
117 if (!size) {
118 return NULL;
119 }
120
121 nBlocks = (size + header->block_size - 1) / header->block_size;
122
2a052b4e 123 buffer = g_malloc(nBlocks * header->block_size);
3fa2d384
VP
124
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);
128 }
129
130 return buffer;
131}
132
133static void *pdb_ds_read_file(struct pdb_reader* r, uint32_t file_number)
134{
135 const uint32_t *block_list;
136 uint32_t block_size;
137 const uint32_t *file_size;
138 size_t i;
139
140 if (!r->ds.toc || file_number >= r->ds.toc->num_files) {
141 return NULL;
142 }
143
144 file_size = r->ds.toc->file_size;
145 r->file_used[file_number / 32] |= 1 << (file_number % 32);
146
147 if (file_size[file_number] == 0 || file_size[file_number] == 0xFFFFFFFF) {
148 return NULL;
149 }
150
151 block_list = file_size + r->ds.toc->num_files;
152 block_size = r->ds.header->block_size;
153
154 for (i = 0; i < file_number; i++) {
155 block_list += (file_size[i] + block_size - 1) / block_size;
156 }
157
158 return pdb_ds_read(r->ds.header, block_list, file_size[file_number]);
159}
160
b1250455 161static bool pdb_init_segments(struct pdb_reader *r)
3fa2d384 162{
231f6a7d 163 unsigned stream_idx = r->segments;
3fa2d384 164
9d9c06b1
VP
165 r->segs = pdb_ds_read_file(r, stream_idx);
166 if (!r->segs) {
b1250455 167 return false;
3fa2d384
VP
168 }
169
3fa2d384 170 r->segs_size = pdb_get_file_size(r, stream_idx);
9d9c06b1 171 if (!r->segs_size) {
b1250455 172 return false;
9d9c06b1 173 }
3fa2d384 174
b1250455 175 return true;
3fa2d384
VP
176}
177
b1250455 178static bool pdb_init_symbols(struct pdb_reader *r)
3fa2d384 179{
3fa2d384 180 PDB_SYMBOLS *symbols;
3fa2d384
VP
181
182 symbols = pdb_ds_read_file(r, 3);
183 if (!symbols) {
b1250455 184 return false;
3fa2d384
VP
185 }
186
187 r->symbols = symbols;
188
231f6a7d 189 r->segments = *(uint16_t *)((const char *)symbols + sizeof(PDB_SYMBOLS) +
3fa2d384
VP
190 symbols->module_size + symbols->offset_size +
191 symbols->hash_size + symbols->srcmodule_size +
231f6a7d
VP
192 symbols->pdbimport_size + symbols->unknown2_size +
193 offsetof(PDB_STREAM_INDEXES, segments));
3fa2d384
VP
194
195 /* Read global symbol table */
196 r->modimage = pdb_ds_read_file(r, symbols->gsym_file);
197 if (!r->modimage) {
3fa2d384
VP
198 goto out_symbols;
199 }
200
b1250455 201 return true;
3fa2d384
VP
202
203out_symbols:
2a052b4e 204 g_free(symbols);
3fa2d384 205
b1250455 206 return false;
3fa2d384
VP
207}
208
b1250455 209static bool pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
3fa2d384 210{
f015cbb5 211 if (hdr->block_size == 0) {
b1250455 212 return false;
f015cbb5
PM
213 }
214
3fa2d384
VP
215 memset(r->file_used, 0, sizeof(r->file_used));
216 r->ds.header = hdr;
217 r->ds.toc = pdb_ds_read(hdr, (uint32_t *)((uint8_t *)hdr +
218 hdr->toc_page * hdr->block_size), hdr->toc_size);
219
220 if (!r->ds.toc) {
b1250455 221 return false;
3fa2d384
VP
222 }
223
b1250455 224 return true;
3fa2d384
VP
225}
226
b1250455 227static bool pdb_reader_init(struct pdb_reader *r, void *data)
3fa2d384 228{
3fa2d384
VP
229 const char pdb7[] = "Microsoft C/C++ MSF 7.00";
230
231 if (memcmp(data, pdb7, sizeof(pdb7) - 1)) {
b1250455 232 return false;
3fa2d384
VP
233 }
234
b1250455
AO
235 if (!pdb_reader_ds_init(r, data)) {
236 return false;
3fa2d384
VP
237 }
238
239 r->ds.root = pdb_ds_read_file(r, 1);
240 if (!r->ds.root) {
3fa2d384
VP
241 goto out_ds;
242 }
243
b1250455 244 if (!pdb_init_symbols(r)) {
3fa2d384
VP
245 goto out_root;
246 }
247
b1250455 248 if (!pdb_init_segments(r)) {
3fa2d384
VP
249 goto out_sym;
250 }
251
b1250455 252 return true;
3fa2d384
VP
253
254out_sym:
255 pdb_exit_symbols(r);
256out_root:
2a052b4e 257 g_free(r->ds.root);
3fa2d384
VP
258out_ds:
259 pdb_reader_ds_exit(r);
260
b1250455 261 return false;
3fa2d384
VP
262}
263
264static void pdb_reader_exit(struct pdb_reader *r)
265{
266 pdb_exit_segments(r);
267 pdb_exit_symbols(r);
2a052b4e 268 g_free(r->ds.root);
3fa2d384
VP
269 pdb_reader_ds_exit(r);
270}
271
b1250455 272bool pdb_init_from_file(const char *name, struct pdb_reader *reader)
3fa2d384 273{
4ea1a21d 274 GError *gerr = NULL;
3fa2d384 275 void *map;
3fa2d384 276
4ea1a21d
VP
277 reader->gmf = g_mapped_file_new(name, TRUE, &gerr);
278 if (gerr) {
279 eprintf("Failed to map PDB file \'%s\'\n", name);
0c4c8671 280 g_error_free(gerr);
b1250455 281 return false;
3fa2d384 282 }
3fa2d384 283
4ea1a21d
VP
284 reader->file_size = g_mapped_file_get_length(reader->gmf);
285 map = g_mapped_file_get_contents(reader->gmf);
b1250455 286 if (!pdb_reader_init(reader, map)) {
3fa2d384
VP
287 goto out_unmap;
288 }
289
b1250455 290 return true;
3fa2d384
VP
291
292out_unmap:
4ea1a21d 293 g_mapped_file_unref(reader->gmf);
3fa2d384 294
b1250455 295 return false;
3fa2d384
VP
296}
297
298void pdb_exit(struct pdb_reader *reader)
299{
4ea1a21d 300 g_mapped_file_unref(reader->gmf);
3fa2d384
VP
301 pdb_reader_exit(reader);
302}