elf2dmp: check array bounds in pdb_get_file_size
[qemu/ar7.git] / contrib / elf2dmp / pdb.c
blob8e3c18c82f782616551052658aa89f010df6399f
1 /*
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"
23 #include "pdb.h"
24 #include "err.h"
26 static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx)
28 if (idx >= r->ds.toc->num_files) {
29 return 0;
32 return r->ds.toc->file_size[idx];
35 static pdb_seg *get_seg_by_num(struct pdb_reader *r, size_t n)
37 size_t i = 0;
38 char *ptr;
40 for (ptr = r->segs; (ptr < r->segs + r->segs_size); ) {
41 i++;
42 ptr += 8;
43 if (i == n) {
44 break;
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);
55 int length;
56 const union codeview_symbol *sym;
57 const uint8_t *root = r->modimage;
58 size_t i;
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) {
65 break;
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);
77 return rva;
81 return 0;
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);
88 if (!rva) {
89 return 0;
92 return img_base + rva;
95 static void pdb_reader_ds_exit(struct pdb_reader *r)
97 free(r->ds.toc);
100 static void pdb_exit_symbols(struct pdb_reader *r)
102 free(r->modimage);
103 free(r->symbols);
106 static void pdb_exit_segments(struct pdb_reader *r)
108 free(r->segs);
111 static void *pdb_ds_read(const PDB_DS_HEADER *header,
112 const uint32_t *block_list, int size)
114 int i, nBlocks;
115 uint8_t *buffer;
117 if (!size) {
118 return NULL;
121 nBlocks = (size + header->block_size - 1) / header->block_size;
123 buffer = malloc(nBlocks * header->block_size);
124 if (!buffer) {
125 return NULL;
128 for (i = 0; i < nBlocks; i++) {
129 memcpy(buffer + i * header->block_size, (const char *)header +
130 block_list[i] * header->block_size, header->block_size);
133 return buffer;
136 static void *pdb_ds_read_file(struct pdb_reader* r, uint32_t file_number)
138 const uint32_t *block_list;
139 uint32_t block_size;
140 const uint32_t *file_size;
141 size_t i;
143 if (!r->ds.toc || file_number >= r->ds.toc->num_files) {
144 return NULL;
147 file_size = r->ds.toc->file_size;
148 r->file_used[file_number / 32] |= 1 << (file_number % 32);
150 if (file_size[file_number] == 0 || file_size[file_number] == 0xFFFFFFFF) {
151 return NULL;
154 block_list = file_size + r->ds.toc->num_files;
155 block_size = r->ds.header->block_size;
157 for (i = 0; i < file_number; i++) {
158 block_list += (file_size[i] + block_size - 1) / block_size;
161 return pdb_ds_read(r->ds.header, block_list, file_size[file_number]);
164 static int pdb_init_segments(struct pdb_reader *r)
166 unsigned stream_idx = r->segments;
168 r->segs = pdb_ds_read_file(r, stream_idx);
169 if (!r->segs) {
170 return 1;
173 r->segs_size = pdb_get_file_size(r, stream_idx);
174 if (!r->segs_size) {
175 return 1;
178 return 0;
181 static int pdb_init_symbols(struct pdb_reader *r)
183 int err = 0;
184 PDB_SYMBOLS *symbols;
186 symbols = pdb_ds_read_file(r, 3);
187 if (!symbols) {
188 return 1;
191 r->symbols = symbols;
193 r->segments = *(uint16_t *)((const char *)symbols + sizeof(PDB_SYMBOLS) +
194 symbols->module_size + symbols->offset_size +
195 symbols->hash_size + symbols->srcmodule_size +
196 symbols->pdbimport_size + symbols->unknown2_size +
197 offsetof(PDB_STREAM_INDEXES, segments));
199 /* Read global symbol table */
200 r->modimage = pdb_ds_read_file(r, symbols->gsym_file);
201 if (!r->modimage) {
202 err = 1;
203 goto out_symbols;
206 return 0;
208 out_symbols:
209 free(symbols);
211 return err;
214 static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr)
216 if (hdr->block_size == 0) {
217 return 1;
220 memset(r->file_used, 0, sizeof(r->file_used));
221 r->ds.header = hdr;
222 r->ds.toc = pdb_ds_read(hdr, (uint32_t *)((uint8_t *)hdr +
223 hdr->toc_page * hdr->block_size), hdr->toc_size);
225 if (!r->ds.toc) {
226 return 1;
229 return 0;
232 static int pdb_reader_init(struct pdb_reader *r, void *data)
234 int err = 0;
235 const char pdb7[] = "Microsoft C/C++ MSF 7.00";
237 if (memcmp(data, pdb7, sizeof(pdb7) - 1)) {
238 return 1;
241 if (pdb_reader_ds_init(r, data)) {
242 return 1;
245 r->ds.root = pdb_ds_read_file(r, 1);
246 if (!r->ds.root) {
247 err = 1;
248 goto out_ds;
251 if (pdb_init_symbols(r)) {
252 err = 1;
253 goto out_root;
256 if (pdb_init_segments(r)) {
257 err = 1;
258 goto out_sym;
261 return 0;
263 out_sym:
264 pdb_exit_symbols(r);
265 out_root:
266 free(r->ds.root);
267 out_ds:
268 pdb_reader_ds_exit(r);
270 return err;
273 static void pdb_reader_exit(struct pdb_reader *r)
275 pdb_exit_segments(r);
276 pdb_exit_symbols(r);
277 free(r->ds.root);
278 pdb_reader_ds_exit(r);
281 int pdb_init_from_file(const char *name, struct pdb_reader *reader)
283 GError *gerr = NULL;
284 int err = 0;
285 void *map;
287 reader->gmf = g_mapped_file_new(name, TRUE, &gerr);
288 if (gerr) {
289 eprintf("Failed to map PDB file \'%s\'\n", name);
290 g_error_free(gerr);
291 return 1;
294 reader->file_size = g_mapped_file_get_length(reader->gmf);
295 map = g_mapped_file_get_contents(reader->gmf);
296 if (pdb_reader_init(reader, map)) {
297 err = 1;
298 goto out_unmap;
301 return 0;
303 out_unmap:
304 g_mapped_file_unref(reader->gmf);
306 return err;
309 void pdb_exit(struct pdb_reader *reader)
311 g_mapped_file_unref(reader->gmf);
312 pdb_reader_exit(reader);