1 | /* |
2 | * i386 memory mapping |
3 | * |
4 | * Copyright Fujitsu, Corp. 2011, 2012 |
5 | * |
6 | * Authors: |
7 | * Wen Congyang <wency@cn.fujitsu.com> |
8 | * |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
10 | * See the COPYING file in the top-level directory. |
11 | * |
12 | */ |
13 | |
14 | #include "qemu/osdep.h" |
15 | #include "cpu.h" |
16 | #include "sysemu/dump.h" |
17 | #include "elf.h" |
18 | #include "sysemu/memory_mapping.h" |
19 | |
20 | #define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \ |
21 | ((DIV_ROUND_UP((hdr_size), 4) \ |
22 | + DIV_ROUND_UP((name_size), 4) \ |
23 | + DIV_ROUND_UP((desc_size), 4)) * 4) |
24 | |
25 | #ifdef TARGET_X86_64 |
26 | typedef struct { |
27 | target_ulong r15, r14, r13, r12, rbp, rbx, r11, r10; |
28 | target_ulong r9, r8, rax, rcx, rdx, rsi, rdi, orig_rax; |
29 | target_ulong rip, cs, eflags; |
30 | target_ulong rsp, ss; |
31 | target_ulong fs_base, gs_base; |
32 | target_ulong ds, es, fs, gs; |
33 | } x86_64_user_regs_struct; |
34 | |
35 | typedef struct { |
36 | char pad1[32]; |
37 | uint32_t pid; |
38 | char pad2[76]; |
39 | x86_64_user_regs_struct regs; |
40 | char pad3[8]; |
41 | } x86_64_elf_prstatus; |
42 | |
43 | static int x86_64_write_elf64_note(WriteCoreDumpFunction f, |
44 | CPUX86State *env, int id, |
45 | void *opaque) |
46 | { |
47 | x86_64_user_regs_struct regs; |
48 | Elf64_Nhdr *note; |
49 | char *buf; |
50 | int descsz, note_size, name_size = 5; |
51 | const char *name = "CORE" ; |
52 | int ret; |
53 | |
54 | regs.r15 = env->regs[15]; |
55 | regs.r14 = env->regs[14]; |
56 | regs.r13 = env->regs[13]; |
57 | regs.r12 = env->regs[12]; |
58 | regs.r11 = env->regs[11]; |
59 | regs.r10 = env->regs[10]; |
60 | regs.r9 = env->regs[9]; |
61 | regs.r8 = env->regs[8]; |
62 | regs.rbp = env->regs[R_EBP]; |
63 | regs.rsp = env->regs[R_ESP]; |
64 | regs.rdi = env->regs[R_EDI]; |
65 | regs.rsi = env->regs[R_ESI]; |
66 | regs.rdx = env->regs[R_EDX]; |
67 | regs.rcx = env->regs[R_ECX]; |
68 | regs.rbx = env->regs[R_EBX]; |
69 | regs.rax = env->regs[R_EAX]; |
70 | regs.rip = env->eip; |
71 | regs.eflags = env->eflags; |
72 | |
73 | regs.orig_rax = 0; /* FIXME */ |
74 | regs.cs = env->segs[R_CS].selector; |
75 | regs.ss = env->segs[R_SS].selector; |
76 | regs.fs_base = env->segs[R_FS].base; |
77 | regs.gs_base = env->segs[R_GS].base; |
78 | regs.ds = env->segs[R_DS].selector; |
79 | regs.es = env->segs[R_ES].selector; |
80 | regs.fs = env->segs[R_FS].selector; |
81 | regs.gs = env->segs[R_GS].selector; |
82 | |
83 | descsz = sizeof(x86_64_elf_prstatus); |
84 | note_size = ELF_NOTE_SIZE(sizeof(Elf64_Nhdr), name_size, descsz); |
85 | note = g_malloc0(note_size); |
86 | note->n_namesz = cpu_to_le32(name_size); |
87 | note->n_descsz = cpu_to_le32(descsz); |
88 | note->n_type = cpu_to_le32(NT_PRSTATUS); |
89 | buf = (char *)note; |
90 | buf += ROUND_UP(sizeof(Elf64_Nhdr), 4); |
91 | memcpy(buf, name, name_size); |
92 | buf += ROUND_UP(name_size, 4); |
93 | memcpy(buf + 32, &id, 4); /* pr_pid */ |
94 | buf += descsz - sizeof(x86_64_user_regs_struct)-sizeof(target_ulong); |
95 | memcpy(buf, ®s, sizeof(x86_64_user_regs_struct)); |
96 | |
97 | ret = f(note, note_size, opaque); |
98 | g_free(note); |
99 | if (ret < 0) { |
100 | return -1; |
101 | } |
102 | |
103 | return 0; |
104 | } |
105 | #endif |
106 | |
107 | typedef struct { |
108 | uint32_t ebx, ecx, edx, esi, edi, ebp, eax; |
109 | unsigned short ds, __ds, es, __es; |
110 | unsigned short fs, __fs, gs, __gs; |
111 | uint32_t orig_eax, eip; |
112 | unsigned short cs, __cs; |
113 | uint32_t eflags, esp; |
114 | unsigned short ss, __ss; |
115 | } x86_user_regs_struct; |
116 | |
117 | typedef struct { |
118 | char pad1[24]; |
119 | uint32_t pid; |
120 | char pad2[44]; |
121 | x86_user_regs_struct regs; |
122 | char pad3[4]; |
123 | } x86_elf_prstatus; |
124 | |
125 | static void x86_fill_elf_prstatus(x86_elf_prstatus *prstatus, CPUX86State *env, |
126 | int id) |
127 | { |
128 | memset(prstatus, 0, sizeof(x86_elf_prstatus)); |
129 | prstatus->regs.ebp = env->regs[R_EBP] & 0xffffffff; |
130 | prstatus->regs.esp = env->regs[R_ESP] & 0xffffffff; |
131 | prstatus->regs.edi = env->regs[R_EDI] & 0xffffffff; |
132 | prstatus->regs.esi = env->regs[R_ESI] & 0xffffffff; |
133 | prstatus->regs.edx = env->regs[R_EDX] & 0xffffffff; |
134 | prstatus->regs.ecx = env->regs[R_ECX] & 0xffffffff; |
135 | prstatus->regs.ebx = env->regs[R_EBX] & 0xffffffff; |
136 | prstatus->regs.eax = env->regs[R_EAX] & 0xffffffff; |
137 | prstatus->regs.eip = env->eip & 0xffffffff; |
138 | prstatus->regs.eflags = env->eflags & 0xffffffff; |
139 | |
140 | prstatus->regs.cs = env->segs[R_CS].selector; |
141 | prstatus->regs.ss = env->segs[R_SS].selector; |
142 | prstatus->regs.ds = env->segs[R_DS].selector; |
143 | prstatus->regs.es = env->segs[R_ES].selector; |
144 | prstatus->regs.fs = env->segs[R_FS].selector; |
145 | prstatus->regs.gs = env->segs[R_GS].selector; |
146 | |
147 | prstatus->pid = id; |
148 | } |
149 | |
150 | static int x86_write_elf64_note(WriteCoreDumpFunction f, CPUX86State *env, |
151 | int id, void *opaque) |
152 | { |
153 | x86_elf_prstatus prstatus; |
154 | Elf64_Nhdr *note; |
155 | char *buf; |
156 | int descsz, note_size, name_size = 5; |
157 | const char *name = "CORE" ; |
158 | int ret; |
159 | |
160 | x86_fill_elf_prstatus(&prstatus, env, id); |
161 | descsz = sizeof(x86_elf_prstatus); |
162 | note_size = ELF_NOTE_SIZE(sizeof(Elf64_Nhdr), name_size, descsz); |
163 | note = g_malloc0(note_size); |
164 | note->n_namesz = cpu_to_le32(name_size); |
165 | note->n_descsz = cpu_to_le32(descsz); |
166 | note->n_type = cpu_to_le32(NT_PRSTATUS); |
167 | buf = (char *)note; |
168 | buf += ROUND_UP(sizeof(Elf64_Nhdr), 4); |
169 | memcpy(buf, name, name_size); |
170 | buf += ROUND_UP(name_size, 4); |
171 | memcpy(buf, &prstatus, sizeof(prstatus)); |
172 | |
173 | ret = f(note, note_size, opaque); |
174 | g_free(note); |
175 | if (ret < 0) { |
176 | return -1; |
177 | } |
178 | |
179 | return 0; |
180 | } |
181 | |
182 | int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, |
183 | int cpuid, void *opaque) |
184 | { |
185 | X86CPU *cpu = X86_CPU(cs); |
186 | int ret; |
187 | #ifdef TARGET_X86_64 |
188 | X86CPU *first_x86_cpu = X86_CPU(first_cpu); |
189 | bool lma = !!(first_x86_cpu->env.hflags & HF_LMA_MASK); |
190 | |
191 | if (lma) { |
192 | ret = x86_64_write_elf64_note(f, &cpu->env, cpuid, opaque); |
193 | } else { |
194 | #endif |
195 | ret = x86_write_elf64_note(f, &cpu->env, cpuid, opaque); |
196 | #ifdef TARGET_X86_64 |
197 | } |
198 | #endif |
199 | |
200 | return ret; |
201 | } |
202 | |
203 | int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, |
204 | int cpuid, void *opaque) |
205 | { |
206 | X86CPU *cpu = X86_CPU(cs); |
207 | x86_elf_prstatus prstatus; |
208 | Elf32_Nhdr *note; |
209 | char *buf; |
210 | int descsz, note_size, name_size = 5; |
211 | const char *name = "CORE" ; |
212 | int ret; |
213 | |
214 | x86_fill_elf_prstatus(&prstatus, &cpu->env, cpuid); |
215 | descsz = sizeof(x86_elf_prstatus); |
216 | note_size = ELF_NOTE_SIZE(sizeof(Elf32_Nhdr), name_size, descsz); |
217 | note = g_malloc0(note_size); |
218 | note->n_namesz = cpu_to_le32(name_size); |
219 | note->n_descsz = cpu_to_le32(descsz); |
220 | note->n_type = cpu_to_le32(NT_PRSTATUS); |
221 | buf = (char *)note; |
222 | buf += ROUND_UP(sizeof(Elf32_Nhdr), 4); |
223 | memcpy(buf, name, name_size); |
224 | buf += ROUND_UP(name_size, 4); |
225 | memcpy(buf, &prstatus, sizeof(prstatus)); |
226 | |
227 | ret = f(note, note_size, opaque); |
228 | g_free(note); |
229 | if (ret < 0) { |
230 | return -1; |
231 | } |
232 | |
233 | return 0; |
234 | } |
235 | |
236 | /* |
237 | * please count up QEMUCPUSTATE_VERSION if you have changed definition of |
238 | * QEMUCPUState, and modify the tools using this information accordingly. |
239 | */ |
240 | #define QEMUCPUSTATE_VERSION (1) |
241 | |
242 | struct QEMUCPUSegment { |
243 | uint32_t selector; |
244 | uint32_t limit; |
245 | uint32_t flags; |
246 | uint32_t pad; |
247 | uint64_t base; |
248 | }; |
249 | |
250 | typedef struct QEMUCPUSegment QEMUCPUSegment; |
251 | |
252 | struct QEMUCPUState { |
253 | uint32_t version; |
254 | uint32_t size; |
255 | uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp; |
256 | uint64_t r8, r9, r10, r11, r12, r13, r14, r15; |
257 | uint64_t rip, rflags; |
258 | QEMUCPUSegment cs, ds, es, fs, gs, ss; |
259 | QEMUCPUSegment ldt, tr, gdt, idt; |
260 | uint64_t cr[5]; |
261 | /* |
262 | * Fields below are optional and are being added at the end without |
263 | * changing the version. External tools may identify their presence |
264 | * by checking 'size' field. |
265 | */ |
266 | uint64_t kernel_gs_base; |
267 | }; |
268 | |
269 | typedef struct QEMUCPUState QEMUCPUState; |
270 | |
271 | static void copy_segment(QEMUCPUSegment *d, SegmentCache *s) |
272 | { |
273 | d->pad = 0; |
274 | d->selector = s->selector; |
275 | d->limit = s->limit; |
276 | d->flags = s->flags; |
277 | d->base = s->base; |
278 | } |
279 | |
280 | static void qemu_get_cpustate(QEMUCPUState *s, CPUX86State *env) |
281 | { |
282 | memset(s, 0, sizeof(QEMUCPUState)); |
283 | |
284 | s->version = QEMUCPUSTATE_VERSION; |
285 | s->size = sizeof(QEMUCPUState); |
286 | |
287 | s->rax = env->regs[R_EAX]; |
288 | s->rbx = env->regs[R_EBX]; |
289 | s->rcx = env->regs[R_ECX]; |
290 | s->rdx = env->regs[R_EDX]; |
291 | s->rsi = env->regs[R_ESI]; |
292 | s->rdi = env->regs[R_EDI]; |
293 | s->rsp = env->regs[R_ESP]; |
294 | s->rbp = env->regs[R_EBP]; |
295 | #ifdef TARGET_X86_64 |
296 | s->r8 = env->regs[8]; |
297 | s->r9 = env->regs[9]; |
298 | s->r10 = env->regs[10]; |
299 | s->r11 = env->regs[11]; |
300 | s->r12 = env->regs[12]; |
301 | s->r13 = env->regs[13]; |
302 | s->r14 = env->regs[14]; |
303 | s->r15 = env->regs[15]; |
304 | #endif |
305 | s->rip = env->eip; |
306 | s->rflags = env->eflags; |
307 | |
308 | copy_segment(&s->cs, &env->segs[R_CS]); |
309 | copy_segment(&s->ds, &env->segs[R_DS]); |
310 | copy_segment(&s->es, &env->segs[R_ES]); |
311 | copy_segment(&s->fs, &env->segs[R_FS]); |
312 | copy_segment(&s->gs, &env->segs[R_GS]); |
313 | copy_segment(&s->ss, &env->segs[R_SS]); |
314 | copy_segment(&s->ldt, &env->ldt); |
315 | copy_segment(&s->tr, &env->tr); |
316 | copy_segment(&s->gdt, &env->gdt); |
317 | copy_segment(&s->idt, &env->idt); |
318 | |
319 | s->cr[0] = env->cr[0]; |
320 | s->cr[1] = env->cr[1]; |
321 | s->cr[2] = env->cr[2]; |
322 | s->cr[3] = env->cr[3]; |
323 | s->cr[4] = env->cr[4]; |
324 | |
325 | #ifdef TARGET_X86_64 |
326 | s->kernel_gs_base = env->kernelgsbase; |
327 | #endif |
328 | } |
329 | |
330 | static inline int cpu_write_qemu_note(WriteCoreDumpFunction f, |
331 | CPUX86State *env, |
332 | void *opaque, |
333 | int type) |
334 | { |
335 | QEMUCPUState state; |
336 | Elf64_Nhdr *note64; |
337 | Elf32_Nhdr *note32; |
338 | void *note; |
339 | char *buf; |
340 | int descsz, note_size, name_size = 5, note_head_size; |
341 | const char *name = "QEMU" ; |
342 | int ret; |
343 | |
344 | qemu_get_cpustate(&state, env); |
345 | |
346 | descsz = sizeof(state); |
347 | if (type == 0) { |
348 | note_head_size = sizeof(Elf32_Nhdr); |
349 | } else { |
350 | note_head_size = sizeof(Elf64_Nhdr); |
351 | } |
352 | note_size = (DIV_ROUND_UP(note_head_size, 4) + DIV_ROUND_UP(name_size, 4) + |
353 | DIV_ROUND_UP(descsz, 4)) * 4; |
354 | note = g_malloc0(note_size); |
355 | if (type == 0) { |
356 | note32 = note; |
357 | note32->n_namesz = cpu_to_le32(name_size); |
358 | note32->n_descsz = cpu_to_le32(descsz); |
359 | note32->n_type = 0; |
360 | } else { |
361 | note64 = note; |
362 | note64->n_namesz = cpu_to_le32(name_size); |
363 | note64->n_descsz = cpu_to_le32(descsz); |
364 | note64->n_type = 0; |
365 | } |
366 | buf = note; |
367 | buf += ROUND_UP(note_head_size, 4); |
368 | memcpy(buf, name, name_size); |
369 | buf += ROUND_UP(name_size, 4); |
370 | memcpy(buf, &state, sizeof(state)); |
371 | |
372 | ret = f(note, note_size, opaque); |
373 | g_free(note); |
374 | if (ret < 0) { |
375 | return -1; |
376 | } |
377 | |
378 | return 0; |
379 | } |
380 | |
381 | int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cs, |
382 | void *opaque) |
383 | { |
384 | X86CPU *cpu = X86_CPU(cs); |
385 | |
386 | return cpu_write_qemu_note(f, &cpu->env, opaque, 1); |
387 | } |
388 | |
389 | int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cs, |
390 | void *opaque) |
391 | { |
392 | X86CPU *cpu = X86_CPU(cs); |
393 | |
394 | return cpu_write_qemu_note(f, &cpu->env, opaque, 0); |
395 | } |
396 | |
397 | int cpu_get_dump_info(ArchDumpInfo *info, |
398 | const GuestPhysBlockList *guest_phys_blocks) |
399 | { |
400 | bool lma = false; |
401 | GuestPhysBlock *block; |
402 | |
403 | #ifdef TARGET_X86_64 |
404 | X86CPU *first_x86_cpu = X86_CPU(first_cpu); |
405 | lma = first_cpu && (first_x86_cpu->env.hflags & HF_LMA_MASK); |
406 | #endif |
407 | |
408 | if (lma) { |
409 | info->d_machine = EM_X86_64; |
410 | } else { |
411 | info->d_machine = EM_386; |
412 | } |
413 | info->d_endian = ELFDATA2LSB; |
414 | |
415 | if (lma) { |
416 | info->d_class = ELFCLASS64; |
417 | } else { |
418 | info->d_class = ELFCLASS32; |
419 | |
420 | QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) { |
421 | if (block->target_end > UINT_MAX) { |
422 | /* The memory size is greater than 4G */ |
423 | info->d_class = ELFCLASS64; |
424 | break; |
425 | } |
426 | } |
427 | } |
428 | |
429 | return 0; |
430 | } |
431 | |
432 | ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) |
433 | { |
434 | int name_size = 5; /* "CORE" or "QEMU" */ |
435 | size_t elf_note_size = 0; |
436 | size_t qemu_note_size = 0; |
437 | int elf_desc_size = 0; |
438 | int qemu_desc_size = 0; |
439 | int note_head_size; |
440 | |
441 | if (class == ELFCLASS32) { |
442 | note_head_size = sizeof(Elf32_Nhdr); |
443 | } else { |
444 | note_head_size = sizeof(Elf64_Nhdr); |
445 | } |
446 | |
447 | if (machine == EM_386) { |
448 | elf_desc_size = sizeof(x86_elf_prstatus); |
449 | } |
450 | #ifdef TARGET_X86_64 |
451 | else { |
452 | elf_desc_size = sizeof(x86_64_elf_prstatus); |
453 | } |
454 | #endif |
455 | qemu_desc_size = sizeof(QEMUCPUState); |
456 | |
457 | elf_note_size = ELF_NOTE_SIZE(note_head_size, name_size, elf_desc_size); |
458 | qemu_note_size = ELF_NOTE_SIZE(note_head_size, name_size, qemu_desc_size); |
459 | |
460 | return (elf_note_size + qemu_note_size) * nr_cpus; |
461 | } |
462 | |