xref: /openbmc/qemu/contrib/elf2dmp/qemu_elf.c (revision c1774bdb)
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 static int QEMU_Elf_map(QEMU_Elf *qe, const char *filename)
169 {
170 #ifdef CONFIG_LINUX
171     struct stat st;
172     int fd;
173 
174     printf("Using Linux mmap\n");
175 
176     fd = open(filename, O_RDONLY, 0);
177     if (fd == -1) {
178         eprintf("Failed to open ELF dump file \'%s\'\n", filename);
179         return 1;
180     }
181 
182     if (fstat(fd, &st)) {
183         eprintf("Failed to get size of ELF dump file\n");
184         close(fd);
185         return 1;
186     }
187     qe->size = st.st_size;
188 
189     qe->map = mmap(NULL, qe->size, PROT_READ | PROT_WRITE,
190             MAP_PRIVATE | MAP_NORESERVE, fd, 0);
191     if (qe->map == MAP_FAILED) {
192         eprintf("Failed to map ELF file\n");
193         close(fd);
194         return 1;
195     }
196 
197     close(fd);
198 #else
199     GError *gerr = NULL;
200 
201     printf("Using GLib mmap\n");
202 
203     qe->gmf = g_mapped_file_new(filename, TRUE, &gerr);
204     if (gerr) {
205         eprintf("Failed to map ELF dump file \'%s\'\n", filename);
206         g_error_free(gerr);
207         return 1;
208     }
209 
210     qe->map = g_mapped_file_get_contents(qe->gmf);
211     qe->size = g_mapped_file_get_length(qe->gmf);
212 #endif
213 
214     return 0;
215 }
216 
217 static void QEMU_Elf_unmap(QEMU_Elf *qe)
218 {
219 #ifdef CONFIG_LINUX
220     munmap(qe->map, qe->size);
221 #else
222     g_mapped_file_unref(qe->gmf);
223 #endif
224 }
225 
226 int QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
227 {
228     if (QEMU_Elf_map(qe, filename)) {
229         return 1;
230     }
231 
232     if (!check_ehdr(qe)) {
233         eprintf("Input file has the wrong format\n");
234         QEMU_Elf_unmap(qe);
235         return 1;
236     }
237 
238     if (init_states(qe)) {
239         eprintf("Failed to extract QEMU CPU states\n");
240         QEMU_Elf_unmap(qe);
241         return 1;
242     }
243 
244     return 0;
245 }
246 
247 void QEMU_Elf_exit(QEMU_Elf *qe)
248 {
249     exit_states(qe);
250     QEMU_Elf_unmap(qe);
251 }
252