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