cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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