qemu

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

qemu_elf.c (4858B)


      1 /*
      2  * Copyright (c) 2018 Virtuozzo International GmbH
      3  *
      4  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      5  *
      6  */
      7 
      8 #include "qemu/osdep.h"
      9 #include "err.h"
     10 #include "qemu_elf.h"
     11 
     12 #define QEMU_NOTE_NAME "QEMU"
     13 
     14 #ifndef ROUND_UP
     15 #define ROUND_UP(n, d) (((n) + (d) - 1) & -(0 ? (n) : (d)))
     16 #endif
     17 
     18 #ifndef DIV_ROUND_UP
     19 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
     20 #endif
     21 
     22 #define ELF_NOTE_SIZE(hdr_size, name_size, desc_size)   \
     23     ((DIV_ROUND_UP((hdr_size), 4) +                     \
     24       DIV_ROUND_UP((name_size), 4) +                    \
     25       DIV_ROUND_UP((desc_size), 4)) * 4)
     26 
     27 int is_system(QEMUCPUState *s)
     28 {
     29     return s->gs.base >> 63;
     30 }
     31 
     32 static char *nhdr_get_name(Elf64_Nhdr *nhdr)
     33 {
     34     return (char *)nhdr + ROUND_UP(sizeof(*nhdr), 4);
     35 }
     36 
     37 static void *nhdr_get_desc(Elf64_Nhdr *nhdr)
     38 {
     39     return nhdr_get_name(nhdr) + ROUND_UP(nhdr->n_namesz, 4);
     40 }
     41 
     42 static Elf64_Nhdr *nhdr_get_next(Elf64_Nhdr *nhdr)
     43 {
     44     return (void *)((uint8_t *)nhdr + ELF_NOTE_SIZE(sizeof(*nhdr),
     45                 nhdr->n_namesz, nhdr->n_descsz));
     46 }
     47 
     48 Elf64_Phdr *elf64_getphdr(void *map)
     49 {
     50     Elf64_Ehdr *ehdr = map;
     51     Elf64_Phdr *phdr = (void *)((uint8_t *)map + ehdr->e_phoff);
     52 
     53     return phdr;
     54 }
     55 
     56 Elf64_Half elf_getphdrnum(void *map)
     57 {
     58     Elf64_Ehdr *ehdr = map;
     59 
     60     return ehdr->e_phnum;
     61 }
     62 
     63 static int init_states(QEMU_Elf *qe)
     64 {
     65     Elf64_Phdr *phdr = elf64_getphdr(qe->map);
     66     Elf64_Nhdr *start = (void *)((uint8_t *)qe->map + phdr[0].p_offset);
     67     Elf64_Nhdr *end = (void *)((uint8_t *)start + phdr[0].p_memsz);
     68     Elf64_Nhdr *nhdr;
     69     size_t cpu_nr = 0;
     70 
     71     if (phdr[0].p_type != PT_NOTE) {
     72         eprintf("Failed to find PT_NOTE\n");
     73         return 1;
     74     }
     75 
     76     qe->has_kernel_gs_base = 1;
     77 
     78     for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
     79         if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
     80             QEMUCPUState *state = nhdr_get_desc(nhdr);
     81 
     82             if (state->size < sizeof(*state)) {
     83                 eprintf("CPU #%zu: QEMU CPU state size %u doesn't match\n",
     84                         cpu_nr, state->size);
     85                 /*
     86                  * We assume either every QEMU CPU state has KERNEL_GS_BASE or
     87                  * no one has.
     88                  */
     89                 qe->has_kernel_gs_base = 0;
     90             }
     91             cpu_nr++;
     92         }
     93     }
     94 
     95     printf("%zu CPU states has been found\n", cpu_nr);
     96 
     97     qe->state = malloc(sizeof(*qe->state) * cpu_nr);
     98     if (!qe->state) {
     99         return 1;
    100     }
    101 
    102     cpu_nr = 0;
    103 
    104     for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
    105         if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
    106             qe->state[cpu_nr] = nhdr_get_desc(nhdr);
    107             cpu_nr++;
    108         }
    109     }
    110 
    111     qe->state_nr = cpu_nr;
    112 
    113     return 0;
    114 }
    115 
    116 static void exit_states(QEMU_Elf *qe)
    117 {
    118     free(qe->state);
    119 }
    120 
    121 static bool check_ehdr(QEMU_Elf *qe)
    122 {
    123     Elf64_Ehdr *ehdr = qe->map;
    124 
    125     if (sizeof(Elf64_Ehdr) > qe->size) {
    126         eprintf("Invalid input dump file size\n");
    127         return false;
    128     }
    129 
    130     if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
    131         eprintf("Invalid ELF signature, input file is not ELF\n");
    132         return false;
    133     }
    134 
    135     if (ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
    136             ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
    137         eprintf("Invalid ELF class or byte order, must be 64-bit LE\n");
    138         return false;
    139     }
    140 
    141     if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
    142         eprintf("Invalid ELF version\n");
    143         return false;
    144     }
    145 
    146     if (ehdr->e_machine != EM_X86_64) {
    147         eprintf("Invalid input dump architecture, only x86_64 is supported\n");
    148         return false;
    149     }
    150 
    151     if (ehdr->e_type != ET_CORE) {
    152         eprintf("Invalid ELF type, must be core file\n");
    153         return false;
    154     }
    155 
    156     /*
    157      * ELF dump file must contain one PT_NOTE and at least one PT_LOAD to
    158      * restore physical address space.
    159      */
    160     if (ehdr->e_phnum < 2) {
    161         eprintf("Invalid number of ELF program headers\n");
    162         return false;
    163     }
    164 
    165     return true;
    166 }
    167 
    168 int QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
    169 {
    170     GError *gerr = NULL;
    171     int err = 0;
    172 
    173     qe->gmf = g_mapped_file_new(filename, TRUE, &gerr);
    174     if (gerr) {
    175         eprintf("Failed to map ELF dump file \'%s\'\n", filename);
    176         g_error_free(gerr);
    177         return 1;
    178     }
    179 
    180     qe->map = g_mapped_file_get_contents(qe->gmf);
    181     qe->size = g_mapped_file_get_length(qe->gmf);
    182 
    183     if (!check_ehdr(qe)) {
    184         eprintf("Input file has the wrong format\n");
    185         err = 1;
    186         goto out_unmap;
    187     }
    188 
    189     if (init_states(qe)) {
    190         eprintf("Failed to extract QEMU CPU states\n");
    191         err = 1;
    192         goto out_unmap;
    193     }
    194 
    195     return 0;
    196 
    197 out_unmap:
    198     g_mapped_file_unref(qe->gmf);
    199 
    200     return err;
    201 }
    202 
    203 void QEMU_Elf_exit(QEMU_Elf *qe)
    204 {
    205     exit_states(qe);
    206     g_mapped_file_unref(qe->gmf);
    207 }