qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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 
     26 static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx)
     27 {
     28     return r->ds.toc->file_size[idx];
     29 }
     30 
     31 static 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 
     48 uint64_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 
     80 uint64_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 
     91 static void pdb_reader_ds_exit(struct pdb_reader *r)
     92 {
     93     free(r->ds.toc);
     94 }
     95 
     96 static void pdb_exit_symbols(struct pdb_reader *r)
     97 {
     98     free(r->modimage);
     99     free(r->symbols);
    100 }
    101 
    102 static void pdb_exit_segments(struct pdb_reader *r)
    103 {
    104     free(r->segs);
    105 }
    106 
    107 static 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 
    132 static 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 
    160 static 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 
    176 static 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 
    210 out_symbols:
    211     free(symbols);
    212 
    213     return err;
    214 }
    215 
    216 static 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 
    234 static 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 
    265 out_sym:
    266     pdb_exit_symbols(r);
    267 out_root:
    268     free(r->ds.root);
    269 out_ds:
    270     pdb_reader_ds_exit(r);
    271 
    272     return err;
    273 }
    274 
    275 static 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 
    283 int 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 
    305 out_unmap:
    306     g_mapped_file_unref(reader->gmf);
    307 
    308     return err;
    309 }
    310 
    311 void pdb_exit(struct pdb_reader *reader)
    312 {
    313     g_mapped_file_unref(reader->gmf);
    314     pdb_reader_exit(reader);
    315 }