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 <inttypes.h> 22 23 #include "qemu/osdep.h" 24 #include "pdb.h" 25 #include "err.h" 26 27 static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx) 28 { 29 return r->ds.toc->file_size[idx]; 30 } 31 32 static 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 49 uint64_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 71 printf("%s: 0x%016x(%d:\'%.8s\') + 0x%08x = 0x%09"PRIx64"\n", name, 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 81 uint64_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 92 static void pdb_reader_ds_exit(struct pdb_reader *r) 93 { 94 free(r->ds.toc); 95 } 96 97 static void pdb_exit_symbols(struct pdb_reader *r) 98 { 99 free(r->modimage); 100 free(r->symbols); 101 } 102 103 static void pdb_exit_segments(struct pdb_reader *r) 104 { 105 free(r->segs); 106 } 107 108 static 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 133 static 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 161 static 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 177 static 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 211 out_symbols: 212 free(symbols); 213 214 return err; 215 } 216 217 static 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 231 static 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 262 out_sym: 263 pdb_exit_symbols(r); 264 out_root: 265 free(r->ds.root); 266 out_ds: 267 pdb_reader_ds_exit(r); 268 269 return err; 270 } 271 272 static 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 280 int pdb_init_from_file(const char *name, struct pdb_reader *reader) 281 { 282 GError *gerr = NULL; 283 int err = 0; 284 void *map; 285 286 reader->gmf = g_mapped_file_new(name, TRUE, &gerr); 287 if (gerr) { 288 eprintf("Failed to map PDB file \'%s\'\n", name); 289 return 1; 290 } 291 292 reader->file_size = g_mapped_file_get_length(reader->gmf); 293 map = g_mapped_file_get_contents(reader->gmf); 294 if (pdb_reader_init(reader, map)) { 295 err = 1; 296 goto out_unmap; 297 } 298 299 return 0; 300 301 out_unmap: 302 g_mapped_file_unref(reader->gmf); 303 304 return err; 305 } 306 307 void pdb_exit(struct pdb_reader *reader) 308 { 309 g_mapped_file_unref(reader->gmf); 310 pdb_reader_exit(reader); 311 } 312