qemu/contrib/elf2dmp/qemu_elf.c
<<
>>
Prefs
   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
  27int is_system(QEMUCPUState *s)
  28{
  29    return s->gs.base >> 63;
  30}
  31
  32static char *nhdr_get_name(Elf64_Nhdr *nhdr)
  33{
  34    return (char *)nhdr + ROUND_UP(sizeof(*nhdr), 4);
  35}
  36
  37static void *nhdr_get_desc(Elf64_Nhdr *nhdr)
  38{
  39    return nhdr_get_name(nhdr) + ROUND_UP(nhdr->n_namesz, 4);
  40}
  41
  42static 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
  48Elf64_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
  56Elf64_Half elf_getphdrnum(void *map)
  57{
  58    Elf64_Ehdr *ehdr = map;
  59
  60    return ehdr->e_phnum;
  61}
  62
  63static 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
 116static void exit_states(QEMU_Elf *qe)
 117{
 118    free(qe->state);
 119}
 120
 121int QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
 122{
 123    GError *gerr = NULL;
 124    int err = 0;
 125
 126    qe->gmf = g_mapped_file_new(filename, TRUE, &gerr);
 127    if (gerr) {
 128        eprintf("Failed to map ELF dump file \'%s\'\n", filename);
 129        return 1;
 130    }
 131
 132    qe->map = g_mapped_file_get_contents(qe->gmf);
 133    qe->size = g_mapped_file_get_length(qe->gmf);
 134
 135    if (init_states(qe)) {
 136        eprintf("Failed to extract QEMU CPU states\n");
 137        err = 1;
 138        goto out_unmap;
 139    }
 140
 141    return 0;
 142
 143out_unmap:
 144    g_mapped_file_unref(qe->gmf);
 145
 146    return err;
 147}
 148
 149void QEMU_Elf_exit(QEMU_Elf *qe)
 150{
 151    exit_states(qe);
 152    g_mapped_file_unref(qe->gmf);
 153}
 154