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 26 static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx) 27 { 28 if (idx >= r->ds.toc->num_files) { 29 return 0; 30 } 31 32 return r->ds.toc->file_size[idx]; 33 } 34 35 static 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 52 uint64_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 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; 78 } 79 } 80 81 return 0; 82 } 83 84 uint64_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 95 static void pdb_reader_ds_exit(struct pdb_reader *r) 96 { 97 free(r->ds.toc); 98 } 99 100 static void pdb_exit_symbols(struct pdb_reader *r) 101 { 102 free(r->modimage); 103 free(r->symbols); 104 } 105 106 static void pdb_exit_segments(struct pdb_reader *r) 107 { 108 free(r->segs); 109 } 110 111 static 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 123 buffer = malloc(nBlocks * header->block_size); 124 if (!buffer) { 125 return NULL; 126 } 127 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); 131 } 132 133 return buffer; 134 } 135 136 static void *pdb_ds_read_file(struct pdb_reader* r, uint32_t file_number) 137 { 138 const uint32_t *block_list; 139 uint32_t block_size; 140 const uint32_t *file_size; 141 size_t i; 142 143 if (!r->ds.toc || file_number >= r->ds.toc->num_files) { 144 return NULL; 145 } 146 147 file_size = r->ds.toc->file_size; 148 r->file_used[file_number / 32] |= 1 << (file_number % 32); 149 150 if (file_size[file_number] == 0 || file_size[file_number] == 0xFFFFFFFF) { 151 return NULL; 152 } 153 154 block_list = file_size + r->ds.toc->num_files; 155 block_size = r->ds.header->block_size; 156 157 for (i = 0; i < file_number; i++) { 158 block_list += (file_size[i] + block_size - 1) / block_size; 159 } 160 161 return pdb_ds_read(r->ds.header, block_list, file_size[file_number]); 162 } 163 164 static int pdb_init_segments(struct pdb_reader *r) 165 { 166 unsigned stream_idx = r->segments; 167 168 r->segs = pdb_ds_read_file(r, stream_idx); 169 if (!r->segs) { 170 return 1; 171 } 172 173 r->segs_size = pdb_get_file_size(r, stream_idx); 174 if (!r->segs_size) { 175 return 1; 176 } 177 178 return 0; 179 } 180 181 static int pdb_init_symbols(struct pdb_reader *r) 182 { 183 int err = 0; 184 PDB_SYMBOLS *symbols; 185 186 symbols = pdb_ds_read_file(r, 3); 187 if (!symbols) { 188 return 1; 189 } 190 191 r->symbols = symbols; 192 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)); 198 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; 204 } 205 206 return 0; 207 208 out_symbols: 209 free(symbols); 210 211 return err; 212 } 213 214 static int pdb_reader_ds_init(struct pdb_reader *r, PDB_DS_HEADER *hdr) 215 { 216 if (hdr->block_size == 0) { 217 return 1; 218 } 219 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); 224 225 if (!r->ds.toc) { 226 return 1; 227 } 228 229 return 0; 230 } 231 232 static int pdb_reader_init(struct pdb_reader *r, void *data) 233 { 234 int err = 0; 235 const char pdb7[] = "Microsoft C/C++ MSF 7.00"; 236 237 if (memcmp(data, pdb7, sizeof(pdb7) - 1)) { 238 return 1; 239 } 240 241 if (pdb_reader_ds_init(r, data)) { 242 return 1; 243 } 244 245 r->ds.root = pdb_ds_read_file(r, 1); 246 if (!r->ds.root) { 247 err = 1; 248 goto out_ds; 249 } 250 251 if (pdb_init_symbols(r)) { 252 err = 1; 253 goto out_root; 254 } 255 256 if (pdb_init_segments(r)) { 257 err = 1; 258 goto out_sym; 259 } 260 261 return 0; 262 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); 269 270 return err; 271 } 272 273 static void pdb_reader_exit(struct pdb_reader *r) 274 { 275 pdb_exit_segments(r); 276 pdb_exit_symbols(r); 277 free(r->ds.root); 278 pdb_reader_ds_exit(r); 279 } 280 281 int pdb_init_from_file(const char *name, struct pdb_reader *reader) 282 { 283 GError *gerr = NULL; 284 int err = 0; 285 void *map; 286 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; 292 } 293 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; 299 } 300 301 return 0; 302 303 out_unmap: 304 g_mapped_file_unref(reader->gmf); 305 306 return err; 307 } 308 309 void pdb_exit(struct pdb_reader *reader) 310 { 311 g_mapped_file_unref(reader->gmf); 312 pdb_reader_exit(reader); 313 } 314