Patchwork [RFC,06/14,v7] target-i386: Add API to write cpu status to core file

login
register
mail settings
Submitter Wen Congyang
Date March 1, 2012, 2:48 a.m.
Message ID <4F4EE371.6000601@cn.fujitsu.com>
Download mbox | patch
Permalink /patch/143879/
State New
Headers show

Comments

Wen Congyang - March 1, 2012, 2:48 a.m.
The core file has register's value. But it does not include all register.
Store the cpu status into QEMU note, and the user can get more information
from vmcore.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 cpu-all.h               |   20 ++++++
 target-i386/arch_dump.c |  154 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 174 insertions(+), 0 deletions(-)
HATAYAMA Daisuke - March 1, 2012, 5:01 a.m.
From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

> +struct QEMUCPUState {
> +    uint32_t version;
> +    uint32_t size;
> +    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
> +    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
> +    uint64_t rip, rflags;
> +    QEMUCPUSegment cs, ds, es, fs, gs, ss;
> +    QEMUCPUSegment ldt, tr, gdt, idt;
> +    uint64_t cr[5];
> +};
> +
> +typedef struct QEMUCPUState QEMUCPUState;
<cut>
> +static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
> +{
> +    memset(s, 0, sizeof(QEMUCPUState));
> +
> +    s->version = 1;

It seems to me better to prepare a macro:

  #define QEMUCPUSTATE_VERSION (1)

and use it as:

  s->version = QEMUCPUSTATE_VERSION;

and add comment above the macro definition indicating: please count up
QEMUCPUSTATE_VERSION if you have changed definition of QEMUCPUState,
and modify the tools using this information accordingly.

Thanks.
HATAYAMA, Daisuke
Wen Congyang - March 1, 2012, 5:05 a.m.
At 03/01/2012 01:01 PM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
> Date: Thu, 01 Mar 2012 10:48:17 +0800
> 
>> +struct QEMUCPUState {
>> +    uint32_t version;
>> +    uint32_t size;
>> +    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
>> +    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
>> +    uint64_t rip, rflags;
>> +    QEMUCPUSegment cs, ds, es, fs, gs, ss;
>> +    QEMUCPUSegment ldt, tr, gdt, idt;
>> +    uint64_t cr[5];
>> +};
>> +
>> +typedef struct QEMUCPUState QEMUCPUState;
> <cut>
>> +static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
>> +{
>> +    memset(s, 0, sizeof(QEMUCPUState));
>> +
>> +    s->version = 1;
> 
> It seems to me better to prepare a macro:
> 
>   #define QEMUCPUSTATE_VERSION (1)
> 
> and use it as:
> 
>   s->version = QEMUCPUSTATE_VERSION;
> 
> and add comment above the macro definition indicating: please count up
> QEMUCPUSTATE_VERSION if you have changed definition of QEMUCPUState,
> and modify the tools using this information accordingly.

Yes, I will fix it.

PS: Do you have any comment about QEMUCPUState? I think the content is enough
to calculate phys_base now.

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
>
HATAYAMA Daisuke - March 1, 2012, 5:10 a.m.
From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

> +int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
> +                             target_phys_addr_t *offset, void *opaque)
> +{
> +    QEMUCPUState state;
> +    Elf64_Nhdr *note;
> +    char *buf;
> +    int descsz, note_size, name_size = 5;
> +    const char *name = "QEMU";
> +    int ret;
> +
> +    qemu_get_cpustate(&state, env);
> +
> +    descsz = sizeof(state);
> +    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
> +                (descsz + 3) / 4) * 4;
> +    note = g_malloc(note_size);
> +
> +    memset(note, 0, note_size);
> +    note->n_namesz = cpu_to_le32(name_size);
> +    note->n_descsz = cpu_to_le32(descsz);
> +    note->n_type = 0;
> +    buf = (char *)note;
> +    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
> +    memcpy(buf, name, name_size);
> +    buf += ((name_size + 3) / 4) * 4;
> +    memcpy(buf, &state, sizeof(state));

x86_64_write_elf64_note() and x86_write_elf64_note() does the same
processing for note data. Is it better to do this in helper functions
in common?

Thanks.
HATAYAMA, Daisuke
Wen Congyang - March 1, 2012, 5:22 a.m.
At 03/01/2012 01:10 PM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
> Date: Thu, 01 Mar 2012 10:48:17 +0800
> 
>> +int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
>> +                             target_phys_addr_t *offset, void *opaque)
>> +{
>> +    QEMUCPUState state;
>> +    Elf64_Nhdr *note;
>> +    char *buf;
>> +    int descsz, note_size, name_size = 5;
>> +    const char *name = "QEMU";
>> +    int ret;
>> +
>> +    qemu_get_cpustate(&state, env);
>> +
>> +    descsz = sizeof(state);
>> +    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
>> +                (descsz + 3) / 4) * 4;
>> +    note = g_malloc(note_size);
>> +
>> +    memset(note, 0, note_size);
>> +    note->n_namesz = cpu_to_le32(name_size);
>> +    note->n_descsz = cpu_to_le32(descsz);
>> +    note->n_type = 0;
>> +    buf = (char *)note;
>> +    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
>> +    memcpy(buf, name, name_size);
>> +    buf += ((name_size + 3) / 4) * 4;
>> +    memcpy(buf, &state, sizeof(state));
> 
> x86_64_write_elf64_note() and x86_write_elf64_note() does the same
> processing for note data. Is it better to do this in helper functions
> in common?

I forgot to merge them. I will fix it.

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
>
HATAYAMA Daisuke - March 2, 2012, 1:09 a.m.
From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 10:48:17 +0800

> +int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
> +                             target_phys_addr_t *offset, void *opaque)
> +{
> +    QEMUCPUState state;
> +    Elf64_Nhdr *note;

<cut>

> +    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +

                            ELF64_Nhdr?

Thanks.
HATAYAMA, Daisuke
HATAYAMA Daisuke - March 2, 2012, 1:30 a.m.
From: Wen Congyang <wency@cn.fujitsu.com>
Subject: Re: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
Date: Thu, 01 Mar 2012 13:05:31 +0800

> At 03/01/2012 01:01 PM, HATAYAMA Daisuke Wrote:
>> From: Wen Congyang <wency@cn.fujitsu.com>
>> Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
>> Date: Thu, 01 Mar 2012 10:48:17 +0800
>> 
>>> +struct QEMUCPUState {
>>> +    uint32_t version;
>>> +    uint32_t size;
>>> +    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
>>> +    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
>>> +    uint64_t rip, rflags;
>>> +    QEMUCPUSegment cs, ds, es, fs, gs, ss;
>>> +    QEMUCPUSegment ldt, tr, gdt, idt;
>>> +    uint64_t cr[5];
>>> +};
>>> +
>>> +typedef struct QEMUCPUState QEMUCPUState;
>> <cut>
>>> +static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
>>> +{
>>> +    memset(s, 0, sizeof(QEMUCPUState));
>>> +
>>> +    s->version = 1;
>> 
>> It seems to me better to prepare a macro:
>> 
>>   #define QEMUCPUSTATE_VERSION (1)
>> 
>> and use it as:
>> 
>>   s->version = QEMUCPUSTATE_VERSION;
>> 
>> and add comment above the macro definition indicating: please count up
>> QEMUCPUSTATE_VERSION if you have changed definition of QEMUCPUState,
>> and modify the tools using this information accordingly.
> 
> Yes, I will fix it.
> 
> PS: Do you have any comment about QEMUCPUState? I think the content is enough
> to calculate phys_base now.
> 

Yes, for the purpose it might be enough. But looking at CPUX86State,
there are still useful states for debugging to know guest machine
state at crash, such as device states, NMI states, TSC, etc.

For now, I think it's OK to pick up minimum kinds of registers
only. If they are classified sufficiently in their types such as
general registers, floating-point registers, control registers,
processor features and so on, it's possible to add new note later
easily.

Thanks.
HATAYAMA, Daisuke
Wen Congyang - March 2, 2012, 1:42 a.m.
At 03/02/2012 09:09 AM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 06/14 v7] target-i386: Add API to write cpu status to core file
> Date: Thu, 01 Mar 2012 10:48:17 +0800
> 
>> +int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
>> +                             target_phys_addr_t *offset, void *opaque)
>> +{
>> +    QEMUCPUState state;
>> +    Elf64_Nhdr *note;
> 
> <cut>
> 
>> +    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
> 
>                             ELF64_Nhdr?

Yes, it's my misss, and I will fix it.

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
>

Patch

diff --git a/cpu-all.h b/cpu-all.h
index f7c6321..ad69269 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -540,6 +540,10 @@  int cpu_write_elf64_note(write_core_dump_function f, CPUState *env, int cpuid,
                          target_phys_addr_t *offset, void *opaque);
 int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid,
                          target_phys_addr_t *offset, void *opaque);
+int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque);
+int cpu_write_elf32_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque);
 #else
 static inline int cpu_write_elf64_note(write_core_dump_function f,
                                        CPUState *env, int cpuid,
@@ -554,6 +558,22 @@  static inline int cpu_write_elf32_note(write_core_dump_function f,
 {
     return -1;
 }
+
+static inline int cpu_write_elf64_qemunote(write_core_dump_function f,
+                                           CPUState *env,
+                                           target_phys_addr_t *offset,
+                                           void *opaque);
+{
+    return -1;
+}
+
+static inline int cpu_write_elf32_qemunote(write_core_dump_function f,
+                                           CPUState *env,
+                                           target_phys_addr_t *offset,
+                                           void *opaque)
+{
+    return -1;
+}
 #endif
 
 #endif /* CPU_ALL_H */
diff --git a/target-i386/arch_dump.c b/target-i386/arch_dump.c
index 3239c40..560c8a3 100644
--- a/target-i386/arch_dump.c
+++ b/target-i386/arch_dump.c
@@ -247,3 +247,157 @@  int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid,
 
     return 0;
 }
+
+struct QEMUCPUSegment {
+    uint32_t selector;
+    uint32_t limit;
+    uint32_t flags;
+    uint32_t pad;
+    uint64_t base;
+};
+
+typedef struct QEMUCPUSegment QEMUCPUSegment;
+
+struct QEMUCPUState {
+    uint32_t version;
+    uint32_t size;
+    uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp;
+    uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
+    uint64_t rip, rflags;
+    QEMUCPUSegment cs, ds, es, fs, gs, ss;
+    QEMUCPUSegment ldt, tr, gdt, idt;
+    uint64_t cr[5];
+};
+
+typedef struct QEMUCPUState QEMUCPUState;
+
+static void copy_segment(QEMUCPUSegment *d, SegmentCache *s)
+{
+    d->pad = 0;
+    d->selector = s->selector;
+    d->limit = s->limit;
+    d->flags = s->flags;
+    d->base = s->base;
+}
+
+static void qemu_get_cpustate(QEMUCPUState *s, CPUState *env)
+{
+    memset(s, 0, sizeof(QEMUCPUState));
+
+    s->version = 1;
+    s->size = sizeof(QEMUCPUState);
+
+    s->rax = env->regs[R_EAX];
+    s->rbx = env->regs[R_EBX];
+    s->rcx = env->regs[R_ECX];
+    s->rdx = env->regs[R_EDX];
+    s->rsi = env->regs[R_ESI];
+    s->rdi = env->regs[R_EDI];
+    s->rsp = env->regs[R_ESP];
+    s->rbp = env->regs[R_EBP];
+#ifdef TARGET_X86_64
+    s->r8  = env->regs[8];
+    s->r9  = env->regs[9];
+    s->r10 = env->regs[10];
+    s->r11 = env->regs[11];
+    s->r12 = env->regs[12];
+    s->r13 = env->regs[13];
+    s->r14 = env->regs[14];
+    s->r15 = env->regs[15];
+#endif
+    s->rip = env->eip;
+    s->rflags = env->eflags;
+
+    copy_segment(&s->cs, &env->segs[R_CS]);
+    copy_segment(&s->ds, &env->segs[R_DS]);
+    copy_segment(&s->es, &env->segs[R_ES]);
+    copy_segment(&s->fs, &env->segs[R_FS]);
+    copy_segment(&s->gs, &env->segs[R_GS]);
+    copy_segment(&s->ss, &env->segs[R_SS]);
+    copy_segment(&s->ldt, &env->ldt);
+    copy_segment(&s->tr, &env->tr);
+    copy_segment(&s->gdt, &env->gdt);
+    copy_segment(&s->idt, &env->idt);
+
+    s->cr[0] = env->cr[0];
+    s->cr[1] = env->cr[1];
+    s->cr[2] = env->cr[2];
+    s->cr[3] = env->cr[3];
+    s->cr[4] = env->cr[4];
+}
+
+int cpu_write_elf64_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque)
+{
+    QEMUCPUState state;
+    Elf64_Nhdr *note;
+    char *buf;
+    int descsz, note_size, name_size = 5;
+    const char *name = "QEMU";
+    int ret;
+
+    qemu_get_cpustate(&state, env);
+
+    descsz = sizeof(state);
+    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+                (descsz + 3) / 4) * 4;
+    note = g_malloc(note_size);
+
+    memset(note, 0, note_size);
+    note->n_namesz = cpu_to_le32(name_size);
+    note->n_descsz = cpu_to_le32(descsz);
+    note->n_type = 0;
+    buf = (char *)note;
+    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
+    memcpy(buf, name, name_size);
+    buf += ((name_size + 3) / 4) * 4;
+    memcpy(buf, &state, sizeof(state));
+
+    ret = f(*offset, note, note_size, opaque);
+    g_free(note);
+    if (ret < 0) {
+        return -1;
+    }
+
+    *offset += note_size;
+
+    return 0;
+}
+
+int cpu_write_elf32_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque)
+{
+    QEMUCPUState state;
+    Elf32_Nhdr *note;
+    char *buf;
+    int descsz, note_size, name_size = 5;
+    const char *name = "QEMU";
+    int ret;
+
+    qemu_get_cpustate(&state, env);
+
+    descsz = sizeof(state);
+    note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
+                (descsz + 3) / 4) * 4;
+    note = g_malloc(note_size);
+
+    memset(note, 0, note_size);
+    note->n_namesz = cpu_to_le32(name_size);
+    note->n_descsz = cpu_to_le32(descsz);
+    note->n_type = 0;
+    buf = (char *)note;
+    buf += ((sizeof(Elf32_Nhdr) + 3) / 4) * 4;
+    memcpy(buf, name, name_size);
+    buf += ((name_size + 3) / 4) * 4;
+    memcpy(buf, &state, sizeof(state));
+
+    ret = f(*offset, note, note_size, opaque);
+    g_free(note);
+    if (ret < 0) {
+        return -1;
+    }
+
+    *offset += note_size;
+
+    return 0;
+}