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