Merge tag 'v9.0.0-rc3'
[qemu/ar7.git] / contrib / elf2dmp / qemu_elf.c
blobc9bad6e82cf3809e32305d4bc9d24dd298948223
1 /*
2 * Copyright (c) 2018 Virtuozzo International GmbH
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
6 */
8 #include "qemu/osdep.h"
9 #include "qemu/host-utils.h"
10 #include "err.h"
11 #include "qemu_elf.h"
13 #define QEMU_NOTE_NAME "QEMU"
15 #ifndef ROUND_UP
16 #define ROUND_UP(n, d) (((n) + (d) - 1) & -(0 ? (n) : (d)))
17 #endif
19 int is_system(QEMUCPUState *s)
21 return s->gs.base >> 63;
24 Elf64_Phdr *elf64_getphdr(void *map)
26 Elf64_Ehdr *ehdr = map;
27 Elf64_Phdr *phdr = (void *)((uint8_t *)map + ehdr->e_phoff);
29 return phdr;
32 Elf64_Half elf_getphdrnum(void *map)
34 Elf64_Ehdr *ehdr = map;
36 return ehdr->e_phnum;
39 static bool advance_note_offset(uint64_t *offsetp, uint64_t size, uint64_t end)
41 uint64_t offset = *offsetp;
43 if (uadd64_overflow(offset, size, &offset) || offset > UINT64_MAX - 3) {
44 return false;
47 offset = ROUND_UP(offset, 4);
49 if (offset > end) {
50 return false;
53 *offsetp = offset;
55 return true;
58 static bool init_states(QEMU_Elf *qe)
60 Elf64_Phdr *phdr = elf64_getphdr(qe->map);
61 Elf64_Nhdr *nhdr;
62 GPtrArray *states;
63 QEMUCPUState *state;
64 uint32_t state_size;
65 uint64_t offset;
66 uint64_t end_offset;
67 char *name;
69 if (phdr[0].p_type != PT_NOTE) {
70 eprintf("Failed to find PT_NOTE\n");
71 return false;
74 qe->has_kernel_gs_base = 1;
75 offset = phdr[0].p_offset;
76 states = g_ptr_array_new();
78 if (uadd64_overflow(offset, phdr[0].p_memsz, &end_offset) ||
79 end_offset > qe->size) {
80 end_offset = qe->size;
83 while (offset < end_offset) {
84 nhdr = (void *)((uint8_t *)qe->map + offset);
86 if (!advance_note_offset(&offset, sizeof(*nhdr), end_offset)) {
87 break;
90 name = (char *)qe->map + offset;
92 if (!advance_note_offset(&offset, nhdr->n_namesz, end_offset)) {
93 break;
96 state = (void *)((uint8_t *)qe->map + offset);
98 if (!advance_note_offset(&offset, nhdr->n_descsz, end_offset)) {
99 break;
102 if (!strcmp(name, QEMU_NOTE_NAME) &&
103 nhdr->n_descsz >= offsetof(QEMUCPUState, kernel_gs_base)) {
104 state_size = MIN(state->size, nhdr->n_descsz);
106 if (state_size < sizeof(*state)) {
107 eprintf("CPU #%u: QEMU CPU state size %u doesn't match\n",
108 states->len, state_size);
110 * We assume either every QEMU CPU state has KERNEL_GS_BASE or
111 * no one has.
113 qe->has_kernel_gs_base = 0;
115 g_ptr_array_add(states, state);
119 printf("%u CPU states has been found\n", states->len);
121 qe->state_nr = states->len;
122 qe->state = (void *)g_ptr_array_free(states, FALSE);
124 return true;
127 static void exit_states(QEMU_Elf *qe)
129 g_free(qe->state);
132 static bool check_ehdr(QEMU_Elf *qe)
134 Elf64_Ehdr *ehdr = qe->map;
135 uint64_t phendoff;
137 if (sizeof(Elf64_Ehdr) > qe->size) {
138 eprintf("Invalid input dump file size\n");
139 return false;
142 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
143 eprintf("Invalid ELF signature, input file is not ELF\n");
144 return false;
147 if (ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
148 ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
149 eprintf("Invalid ELF class or byte order, must be 64-bit LE\n");
150 return false;
153 if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
154 eprintf("Invalid ELF version\n");
155 return false;
158 if (ehdr->e_machine != EM_X86_64) {
159 eprintf("Invalid input dump architecture, only x86_64 is supported\n");
160 return false;
163 if (ehdr->e_type != ET_CORE) {
164 eprintf("Invalid ELF type, must be core file\n");
165 return false;
169 * ELF dump file must contain one PT_NOTE and at least one PT_LOAD to
170 * restore physical address space.
172 if (ehdr->e_phnum < 2) {
173 eprintf("Invalid number of ELF program headers\n");
174 return false;
177 if (umul64_overflow(ehdr->e_phnum, sizeof(Elf64_Phdr), &phendoff) ||
178 uadd64_overflow(phendoff, ehdr->e_phoff, &phendoff) ||
179 phendoff > qe->size) {
180 eprintf("phdrs do not fit in file\n");
181 return false;
184 return true;
187 static bool QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
189 #ifdef CONFIG_LINUX
190 struct stat st;
191 int fd;
193 printf("Using Linux mmap\n");
195 fd = open(filename, O_RDONLY, 0);
196 if (fd == -1) {
197 eprintf("Failed to open ELF dump file \'%s\'\n", filename);
198 return false;
201 if (fstat(fd, &st)) {
202 eprintf("Failed to get size of ELF dump file\n");
203 close(fd);
204 return false;
206 qe->size = st.st_size;
208 qe->map = mmap(NULL, qe->size, PROT_READ | PROT_WRITE,
209 MAP_PRIVATE | MAP_NORESERVE, fd, 0);
210 if (qe->map == MAP_FAILED) {
211 eprintf("Failed to map ELF file\n");
212 close(fd);
213 return false;
216 close(fd);
217 #else
218 GError *gerr = NULL;
220 printf("Using GLib mmap\n");
222 qe->gmf = g_mapped_file_new(filename, TRUE, &gerr);
223 if (gerr) {
224 eprintf("Failed to map ELF dump file \'%s\'\n", filename);
225 g_error_free(gerr);
226 return false;
229 qe->map = g_mapped_file_get_contents(qe->gmf);
230 qe->size = g_mapped_file_get_length(qe->gmf);
231 #endif
233 return true;
236 static void QEMU_Elf_unmap(QEMU_Elf *qe)
238 #ifdef CONFIG_LINUX
239 munmap(qe->map, qe->size);
240 #else
241 g_mapped_file_unref(qe->gmf);
242 #endif
245 bool QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
247 if (!QEMU_Elf_map(qe, filename)) {
248 return false;
251 if (!check_ehdr(qe)) {
252 eprintf("Input file has the wrong format\n");
253 QEMU_Elf_unmap(qe);
254 return false;
257 if (!init_states(qe)) {
258 eprintf("Failed to extract QEMU CPU states\n");
259 QEMU_Elf_unmap(qe);
260 return false;
263 return true;
266 void QEMU_Elf_exit(QEMU_Elf *qe)
268 exit_states(qe);
269 QEMU_Elf_unmap(qe);