contrib/elf2dmp: Use GPtrArray
[qemu/armbru.git] / contrib / elf2dmp / qemu_elf.c
blob7d896cac5b15d3bbc6d398f395fab4188a148ef9
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 "err.h"
10 #include "qemu_elf.h"
12 #define QEMU_NOTE_NAME "QEMU"
14 #ifndef ROUND_UP
15 #define ROUND_UP(n, d) (((n) + (d) - 1) & -(0 ? (n) : (d)))
16 #endif
18 #ifndef DIV_ROUND_UP
19 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
20 #endif
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)
27 int is_system(QEMUCPUState *s)
29 return s->gs.base >> 63;
32 static char *nhdr_get_name(Elf64_Nhdr *nhdr)
34 return (char *)nhdr + ROUND_UP(sizeof(*nhdr), 4);
37 static void *nhdr_get_desc(Elf64_Nhdr *nhdr)
39 return nhdr_get_name(nhdr) + ROUND_UP(nhdr->n_namesz, 4);
42 static Elf64_Nhdr *nhdr_get_next(Elf64_Nhdr *nhdr)
44 return (void *)((uint8_t *)nhdr + ELF_NOTE_SIZE(sizeof(*nhdr),
45 nhdr->n_namesz, nhdr->n_descsz));
48 Elf64_Phdr *elf64_getphdr(void *map)
50 Elf64_Ehdr *ehdr = map;
51 Elf64_Phdr *phdr = (void *)((uint8_t *)map + ehdr->e_phoff);
53 return phdr;
56 Elf64_Half elf_getphdrnum(void *map)
58 Elf64_Ehdr *ehdr = map;
60 return ehdr->e_phnum;
63 static bool init_states(QEMU_Elf *qe)
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 GPtrArray *states;
71 if (phdr[0].p_type != PT_NOTE) {
72 eprintf("Failed to find PT_NOTE\n");
73 return false;
76 qe->has_kernel_gs_base = 1;
77 states = g_ptr_array_new();
79 for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
80 if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
81 QEMUCPUState *state = nhdr_get_desc(nhdr);
83 if (state->size < sizeof(*state)) {
84 eprintf("CPU #%u: QEMU CPU state size %u doesn't match\n",
85 states->len, state->size);
87 * We assume either every QEMU CPU state has KERNEL_GS_BASE or
88 * no one has.
90 qe->has_kernel_gs_base = 0;
92 g_ptr_array_add(states, state);
96 printf("%u CPU states has been found\n", states->len);
98 qe->state_nr = states->len;
99 qe->state = (void *)g_ptr_array_free(states, FALSE);
101 return true;
104 static void exit_states(QEMU_Elf *qe)
106 g_free(qe->state);
109 static bool check_ehdr(QEMU_Elf *qe)
111 Elf64_Ehdr *ehdr = qe->map;
113 if (sizeof(Elf64_Ehdr) > qe->size) {
114 eprintf("Invalid input dump file size\n");
115 return false;
118 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
119 eprintf("Invalid ELF signature, input file is not ELF\n");
120 return false;
123 if (ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
124 ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
125 eprintf("Invalid ELF class or byte order, must be 64-bit LE\n");
126 return false;
129 if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
130 eprintf("Invalid ELF version\n");
131 return false;
134 if (ehdr->e_machine != EM_X86_64) {
135 eprintf("Invalid input dump architecture, only x86_64 is supported\n");
136 return false;
139 if (ehdr->e_type != ET_CORE) {
140 eprintf("Invalid ELF type, must be core file\n");
141 return false;
145 * ELF dump file must contain one PT_NOTE and at least one PT_LOAD to
146 * restore physical address space.
148 if (ehdr->e_phnum < 2) {
149 eprintf("Invalid number of ELF program headers\n");
150 return false;
153 return true;
156 static bool QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
158 #ifdef CONFIG_LINUX
159 struct stat st;
160 int fd;
162 printf("Using Linux mmap\n");
164 fd = open(filename, O_RDONLY, 0);
165 if (fd == -1) {
166 eprintf("Failed to open ELF dump file \'%s\'\n", filename);
167 return false;
170 if (fstat(fd, &st)) {
171 eprintf("Failed to get size of ELF dump file\n");
172 close(fd);
173 return false;
175 qe->size = st.st_size;
177 qe->map = mmap(NULL, qe->size, PROT_READ | PROT_WRITE,
178 MAP_PRIVATE | MAP_NORESERVE, fd, 0);
179 if (qe->map == MAP_FAILED) {
180 eprintf("Failed to map ELF file\n");
181 close(fd);
182 return false;
185 close(fd);
186 #else
187 GError *gerr = NULL;
189 printf("Using GLib mmap\n");
191 qe->gmf = g_mapped_file_new(filename, TRUE, &gerr);
192 if (gerr) {
193 eprintf("Failed to map ELF dump file \'%s\'\n", filename);
194 g_error_free(gerr);
195 return false;
198 qe->map = g_mapped_file_get_contents(qe->gmf);
199 qe->size = g_mapped_file_get_length(qe->gmf);
200 #endif
202 return true;
205 static void QEMU_Elf_unmap(QEMU_Elf *qe)
207 #ifdef CONFIG_LINUX
208 munmap(qe->map, qe->size);
209 #else
210 g_mapped_file_unref(qe->gmf);
211 #endif
214 bool QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
216 if (!QEMU_Elf_map(qe, filename)) {
217 return false;
220 if (!check_ehdr(qe)) {
221 eprintf("Input file has the wrong format\n");
222 QEMU_Elf_unmap(qe);
223 return false;
226 if (!init_states(qe)) {
227 eprintf("Failed to extract QEMU CPU states\n");
228 QEMU_Elf_unmap(qe);
229 return false;
232 return true;
235 void QEMU_Elf_exit(QEMU_Elf *qe)
237 exit_states(qe);
238 QEMU_Elf_unmap(qe);