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