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