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