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