]> git.proxmox.com Git - mirror_qemu.git/blame - contrib/elf2dmp/pdb.c
nbd/server: Trace client noncompliance on unaligned requests
[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
6ec6e988
VP
21#include <inttypes.h>
22
3fa2d384
VP
23#include "qemu/osdep.h"
24#include "pdb.h"
25#include "err.h"
26
27static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx)
28{
29 return r->ds.toc->file_size[idx];
30}
31
32static pdb_seg *get_seg_by_num(struct pdb_reader *r, size_t n)
33{
34 size_t i = 0;
35 char *ptr;
36
37 for (ptr = r->segs; (ptr < r->segs + r->segs_size); ) {
38 i++;
39 ptr += 8;
40 if (i == n) {
41 break;
42 }
43 ptr += sizeof(pdb_seg);
44 }
45
46 return (pdb_seg *)ptr;
47}
48
49uint64_t pdb_find_public_v3_symbol(struct pdb_reader *r, const char *name)
50{
51 size_t size = pdb_get_file_size(r, r->symbols->gsym_file);
52 int length;
53 const union codeview_symbol *sym;
54 const uint8_t *root = r->modimage;
55 size_t i;
56
57 for (i = 0; i < size; i += length) {
58 sym = (const void *)(root + i);
59 length = sym->generic.len + 2;
60
61 if (!sym->generic.id || length < 4) {
62 break;
63 }
64
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;
70
6ec6e988 71 printf("%s: 0x%016x(%d:\'%.8s\') + 0x%08x = 0x%09"PRIx64"\n", name,
3fa2d384
VP
72 sect_rva, sym->public_v3.segment,
73 ((char *)segment - 8), sym->public_v3.offset, rva);
74 return rva;
75 }
76 }
77
78 return 0;
79}
80
81uint64_t pdb_resolve(uint64_t img_base, struct pdb_reader *r, const char *name)
82{
83 uint64_t rva = pdb_find_public_v3_symbol(r, name);
84
85 if (!rva) {
86 return 0;
87 }
88
89 return img_base + rva;
90}
91
92static void pdb_reader_ds_exit(struct pdb_reader *r)
93{
94 free(r->ds.toc);
95}
96
97static void pdb_exit_symbols(struct pdb_reader *r)
98{
99 free(r->modimage);
100 free(r->symbols);
101}
102
103static void pdb_exit_segments(struct pdb_reader *r)
104{
105 free(r->segs);
106}
107
108static void *pdb_ds_read(const PDB_DS_HEADER *header,
109 const uint32_t *block_list, int size)
110{
111 int i, nBlocks;
112 uint8_t *buffer;
113
114 if (!size) {
115 return NULL;
116 }
117
118 nBlocks = (size + header->block_size - 1) / header->block_size;
119
120 buffer = malloc(nBlocks * header->block_size);
121 if (!buffer) {
122 return NULL;
123 }
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
161static int pdb_init_segments(struct pdb_reader *r)
162{
163 char *segs;
164 unsigned stream_idx = r->sidx.segments;
165
166 segs = pdb_ds_read_file(r, stream_idx);
167 if (!segs) {
168 return 1;
169 }
170
171 r->segs = segs;
172 r->segs_size = pdb_get_file_size(r, stream_idx);
173
174 return 0;
175}
176
177static int pdb_init_symbols(struct pdb_reader *r)
178{
179 int err = 0;
180 PDB_SYMBOLS *symbols;
181 PDB_STREAM_INDEXES *sidx = &r->sidx;
182
183 memset(sidx, -1, sizeof(*sidx));
184
185 symbols = pdb_ds_read_file(r, 3);
186 if (!symbols) {
187 return 1;
188 }
189
190 r->symbols = symbols;
191
192 if (symbols->stream_index_size != sizeof(PDB_STREAM_INDEXES)) {
193 err = 1;
194 goto out_symbols;
195 }
196
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));
201
202 /* Read global symbol table */
203 r->modimage = pdb_ds_read_file(r, symbols->gsym_file);
204 if (!r->modimage) {
205 err = 1;
206 goto out_symbols;
207 }
208
209 return 0;
210
211out_symbols:
212 free(symbols);
213
214 return err;
215}
216
217static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
218{
219 memset(r->file_used, 0, sizeof(r->file_used));
220 r->ds.header = hdr;
221 r->ds.toc = pdb_ds_read(hdr, (uint32_t *)((uint8_t *)hdr +
222 hdr->toc_page * hdr->block_size), hdr->toc_size);
223
224 if (!r->ds.toc) {
225 return 1;
226 }
227
228 return 0;
229}
230
231static int pdb_reader_init(struct pdb_reader *r, void *data)
232{
233 int err = 0;
234 const char pdb7[] = "Microsoft C/C++ MSF 7.00";
235
236 if (memcmp(data, pdb7, sizeof(pdb7) - 1)) {
237 return 1;
238 }
239
240 if (pdb_reader_ds_init(r, data)) {
241 return 1;
242 }
243
244 r->ds.root = pdb_ds_read_file(r, 1);
245 if (!r->ds.root) {
246 err = 1;
247 goto out_ds;
248 }
249
250 if (pdb_init_symbols(r)) {
251 err = 1;
252 goto out_root;
253 }
254
255 if (pdb_init_segments(r)) {
256 err = 1;
257 goto out_sym;
258 }
259
260 return 0;
261
262out_sym:
263 pdb_exit_symbols(r);
264out_root:
265 free(r->ds.root);
266out_ds:
267 pdb_reader_ds_exit(r);
268
269 return err;
270}
271
272static void pdb_reader_exit(struct pdb_reader *r)
273{
274 pdb_exit_segments(r);
275 pdb_exit_symbols(r);
276 free(r->ds.root);
277 pdb_reader_ds_exit(r);
278}
279
280int pdb_init_from_file(const char *name, struct pdb_reader *reader)
281{
4ea1a21d 282 GError *gerr = NULL;
3fa2d384 283 int err = 0;
3fa2d384 284 void *map;
3fa2d384 285
4ea1a21d
VP
286 reader->gmf = g_mapped_file_new(name, TRUE, &gerr);
287 if (gerr) {
288 eprintf("Failed to map PDB file \'%s\'\n", name);
3fa2d384
VP
289 return 1;
290 }
3fa2d384 291
4ea1a21d
VP
292 reader->file_size = g_mapped_file_get_length(reader->gmf);
293 map = g_mapped_file_get_contents(reader->gmf);
3fa2d384
VP
294 if (pdb_reader_init(reader, map)) {
295 err = 1;
296 goto out_unmap;
297 }
298
299 return 0;
300
301out_unmap:
4ea1a21d 302 g_mapped_file_unref(reader->gmf);
3fa2d384
VP
303
304 return err;
305}
306
307void pdb_exit(struct pdb_reader *reader)
308{
4ea1a21d 309 g_mapped_file_unref(reader->gmf);
3fa2d384
VP
310 pdb_reader_exit(reader);
311}