qemu_elf.c (3527B)
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 g_error_free(gerr); 130 return 1; 131 } 132 133 qe->map = g_mapped_file_get_contents(qe->gmf); 134 qe->size = g_mapped_file_get_length(qe->gmf); 135 136 if (init_states(qe)) { 137 eprintf("Failed to extract QEMU CPU states\n"); 138 err = 1; 139 goto out_unmap; 140 } 141 142 return 0; 143 144out_unmap: 145 g_mapped_file_unref(qe->gmf); 146 147 return err; 148} 149 150void QEMU_Elf_exit(QEMU_Elf *qe) 151{ 152 exit_states(qe); 153 g_mapped_file_unref(qe->gmf); 154}