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

login
register
mail settings
Submitter Wen Congyang
Date March 14, 2012, 2:09 a.m.
Message ID <4F5FFDD6.2000300@cn.fujitsu.com>
Download mbox | patch
Permalink /patch/146526/
State New
Headers show

Comments

Wen Congyang - March 14, 2012, 2:09 a.m.
The core file has register's value. But it does not include all registers value.
Store the cpu status into QEMU note, and the user can get more information
from vmcore. If you change QEMUCPUState, please count up QEMUCPUSTATE_VERSION.

Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 cpu-all.h               |   20 ++++++
 target-i386/arch_dump.c |  150 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+), 0 deletions(-)
HATAYAMA Daisuke - March 16, 2012, 1:48 a.m.
From: Wen Congyang <wency@cn.fujitsu.com>
Subject: [RFC][PATCH 08/14 v9] target-i386: Add API to write cpu status to core file
Date: Wed, 14 Mar 2012 10:09:26 +0800

> +    memset(note, 0, note_size);
> +    if (type == 0) {
> +        note32 = note;
> +        note32->n_namesz = cpu_to_le32(name_size);
> +        note32->n_descsz = cpu_to_le32(descsz);
> +        note32->n_type = 0;
> +    } else {
> +        note64 = note;
> +        note64->n_namesz = cpu_to_le32(name_size);
> +        note64->n_descsz = cpu_to_le32(descsz);
> +        note64->n_type = 0;
> +    }

Why not give new type for this note information an explicit name?
Like NT_QEMUCPUSTATE? There might be another type in the future. This
way there's also a merit that we can know all the existing notes
relevant to qemu dump by looking at the names in a header file.

Thanks.
HATAYAMA, Daisuke
Wen Congyang - March 16, 2012, 6:50 a.m.
At 03/16/2012 09:48 AM, HATAYAMA Daisuke Wrote:
> From: Wen Congyang <wency@cn.fujitsu.com>
> Subject: [RFC][PATCH 08/14 v9] target-i386: Add API to write cpu status to core file
> Date: Wed, 14 Mar 2012 10:09:26 +0800
> 
>> +    memset(note, 0, note_size);
>> +    if (type == 0) {
>> +        note32 = note;
>> +        note32->n_namesz = cpu_to_le32(name_size);
>> +        note32->n_descsz = cpu_to_le32(descsz);
>> +        note32->n_type = 0;
>> +    } else {
>> +        note64 = note;
>> +        note64->n_namesz = cpu_to_le32(name_size);
>> +        note64->n_descsz = cpu_to_le32(descsz);
>> +        note64->n_type = 0;
>> +    }
> 
> Why not give new type for this note information an explicit name?
> Like NT_QEMUCPUSTATE? There might be another type in the future. This
> way there's also a merit that we can know all the existing notes
> relevant to qemu dump by looking at the names in a header file.

Hmm, how to add a new type? Does someont manage this?

Thanks
Wen Congyang

> 
> Thanks.
> HATAYAMA, Daisuke
> 
>
HATAYAMA Daisuke - March 19, 2012, 1:09 a.m.
From: Wen Congyang <wency@cn.fujitsu.com>
Subject: Re: [RFC][PATCH 08/14 v9] target-i386: Add API to write cpu status to core file
Date: Fri, 16 Mar 2012 14:50:06 +0800

> At 03/16/2012 09:48 AM, HATAYAMA Daisuke Wrote:
>> From: Wen Congyang <wency@cn.fujitsu.com>
>> Subject: [RFC][PATCH 08/14 v9] target-i386: Add API to write cpu status to core file
>> Date: Wed, 14 Mar 2012 10:09:26 +0800
>> 
>>> +    memset(note, 0, note_size);
>>> +    if (type == 0) {
>>> +        note32 = note;
>>> +        note32->n_namesz = cpu_to_le32(name_size);
>>> +        note32->n_descsz = cpu_to_le32(descsz);
>>> +        note32->n_type = 0;
>>> +    } else {
>>> +        note64 = note;
>>> +        note64->n_namesz = cpu_to_le32(name_size);
>>> +        note64->n_descsz = cpu_to_le32(descsz);
>>> +        note64->n_type = 0;
>>> +    }
>> 
>> Why not give new type for this note information an explicit name?
>> Like NT_QEMUCPUSTATE? There might be another type in the future. This
>> way there's also a merit that we can know all the existing notes
>> relevant to qemu dump by looking at the names in a header file.
> 
> Hmm, how to add a new type? Does someont manage this?
> 

Sorry. I overlooked this.

For the first question, just prepare a name like NT_QEMUCPUSTATE, and
put it in elf.h.

For the second question, we will use it, and someone that will finds
another information worth being note information in qemu would extends
note informaiton. At least, crash needs to use CPU state information,
and Jan says he wants to use this information in his gdb extension.

Also, you've introduced new name "QEMU". The same type on different
name has different meaning. So, in theory, you don't have to worry
about collision of the new type with something else; they belong to
differnet namespace.

But, in reality, looking at elfcore_grok_note() in gdb that reads note
information of corefile, it don't see "CORE" name explicitly. It
regards everything as the one in "CORE" name if it doesn't belong to
any namespace other than "CORE" name. But in "CORE" core namespace,
indexing starts from 1, NT_PRSTATUS; no type 0 in "CORE".

/* Values of note segment descriptor types for core files.  */

#define NT_PRSTATUS     1               /* Contains copy of prstatus struct */
#define NT_FPREGSET     2               /* Contains copy of fpregset struct */
#define NT_PRPSINFO     3               /* Contains copy of prpsinfo struct */
#define NT_TASKSTRUCT   4               /* Contains copy of task struct */
#define NT_AUXV         6               /* Contains copy of Elfxx_auxv_t */
#define NT_PRXFPREG     0x46e62b7f      /* Contains a user_xfpregs_struct; */

It appears to me that type 0 is reserved in order to avoid confilicts.
So, you don't have to fix gdb for now as long as you introduce
NT_QEMUCPUSTATE only and index it with type 0.

Considering name "QEMU", QEMU in NT_QEMUCPUSTATE might be redundant.

Thanks.
HATAYAMA, Daisuke

Patch

diff --git a/cpu-all.h b/cpu-all.h
index 1d681f8..f30c822 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -539,6 +539,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,
@@ -553,6 +557,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..274bbec 100644
--- a/target-i386/arch_dump.c
+++ b/target-i386/arch_dump.c
@@ -247,3 +247,153 @@  int cpu_write_elf32_note(write_core_dump_function f, CPUState *env, int cpuid,
 
     return 0;
 }
+
+/*
+ * please count up QEMUCPUSTATE_VERSION if you have changed definition of
+ * QEMUCPUState, and modify the tools using this information accordingly.
+ */
+#define QEMUCPUSTATE_VERSION (1)
+
+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 = QEMUCPUSTATE_VERSION;
+    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];
+}
+
+static inline int cpu_write_qemu_note(write_core_dump_function f, CPUState *env,
+                                      target_phys_addr_t *offset, void *opaque,
+                                      int type)
+{
+    QEMUCPUState state;
+    Elf64_Nhdr *note64;
+    Elf32_Nhdr *note32;
+    void *note;
+    char *buf;
+    int descsz, note_size, name_size = 5, note_head_size;
+    const char *name = "QEMU";
+    int ret;
+
+    qemu_get_cpustate(&state, env);
+
+    descsz = sizeof(state);
+    if (type == 0) {
+        note_head_size = sizeof(Elf32_Nhdr);
+    } else {
+        note_head_size = sizeof(Elf64_Nhdr);
+    }
+    note_size = ((note_head_size + 3) / 4 + (name_size + 3) / 4 +
+                (descsz + 3) / 4) * 4;
+    note = g_malloc(note_size);
+
+    memset(note, 0, note_size);
+    if (type == 0) {
+        note32 = note;
+        note32->n_namesz = cpu_to_le32(name_size);
+        note32->n_descsz = cpu_to_le32(descsz);
+        note32->n_type = 0;
+    } else {
+        note64 = note;
+        note64->n_namesz = cpu_to_le32(name_size);
+        note64->n_descsz = cpu_to_le32(descsz);
+        note64->n_type = 0;
+    }
+    buf = note;
+    buf += ((note_head_size + 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_elf64_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque)
+{
+    return cpu_write_qemu_note(f, env, offset, opaque, 1);
+}
+
+int cpu_write_elf32_qemunote(write_core_dump_function f, CPUState *env,
+                             target_phys_addr_t *offset, void *opaque)
+{
+    return cpu_write_qemu_note(f, env, offset, opaque, 0);
+}