Enable support for the dump-guest-memory command on ARM and AArch64. The dumped files can be analyzed with crash or similar tools.
Signed-off-by: Rabin Vincent <ra...@rab.in> --- target-arm/Makefile.objs | 2 +- target-arm/arch_dump.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++ target-arm/cpu-qom.h | 8 +++ target-arm/cpu.c | 4 ++ 4 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 target-arm/arch_dump.c diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs index 9460b40..38ba48c 100644 --- a/target-arm/Makefile.objs +++ b/target-arm/Makefile.objs @@ -7,6 +7,6 @@ obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o obj-y += translate.o op_helper.o helper.o cpu.o obj-y += neon_helper.o iwmmxt_helper.o obj-y += gdbstub.o -obj-$(CONFIG_SOFTMMU) += psci.o +obj-$(CONFIG_SOFTMMU) += psci.o arch_dump.o obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o obj-y += crypto_helper.o diff --git a/target-arm/arch_dump.c b/target-arm/arch_dump.c new file mode 100644 index 0000000..4e7b9a2 --- /dev/null +++ b/target-arm/arch_dump.c @@ -0,0 +1,148 @@ +#include "cpu.h" + +#include "sysemu/dump.h" +#include "elf.h" + +/* Matches elf_prstatus in <linux/elfcore.h> */ + +typedef struct { + char pad1[24]; + uint32_t pid; + char pad2[44]; + uint32_t regs[18]; + char pad3[4]; +} arm_elf_prstatus; + +typedef struct { + char pad1[32]; + uint32_t pid; + char pad2[76]; + uint64_t regs[32]; + uint64_t pc; + uint64_t pstate; + char pad3[4]; +} aarch64_elf_prstatus; + +static size_t round4(size_t size) +{ + return ((size + 3) / 4) * 4; +} + +static int write_elf_note(const char *name, uint32_t type, + void *desc, size_t descsz, + WriteCoreDumpFunction f, void *opaque) +{ + size_t note_size, name_size, note_head_size; + DumpState *s = opaque; + int class = s->dump_info.d_class; + Elf64_Nhdr *note64; + Elf32_Nhdr *note32; + void *note; + char *buf; + int ret; + + name_size = strlen(name) + 1; + + if (class == ELFCLASS32) { + note_head_size = sizeof(Elf32_Nhdr); + } else { + note_head_size = sizeof(Elf64_Nhdr); + } + + note_size = note_head_size + round4(name_size) + descsz; + note = g_malloc0(note_size); + + if (class == ELFCLASS32) { + note32 = note; + note32->n_namesz = cpu_to_dump32(s, name_size); + note32->n_descsz = cpu_to_dump32(s, descsz); + note32->n_type = cpu_to_dump32(s, type); + } else { + note64 = note; + note64->n_namesz = cpu_to_dump64(s, name_size); + note64->n_descsz = cpu_to_dump64(s, descsz); + note64->n_type = cpu_to_dump64(s, type); + } + + buf = note; + buf += note_head_size; + + memcpy(buf, name, name_size); + buf += round4(name_size); + + memcpy(buf, desc, descsz); + + ret = f(note, note_size, opaque); + g_free(note); + + return ret; +} + +int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque) +{ + arm_elf_prstatus prstatus = {.pid = cpuid}; + ARMCPU *cpu = ARM_CPU(cs); + + memcpy(&(prstatus.regs), cpu->env.regs, sizeof(cpu->env.regs)); + prstatus.regs[16] = cpsr_read(&cpu->env); + + return write_elf_note("CORE", NT_PRSTATUS, + &prstatus, sizeof(prstatus), + f, opaque); +} + +int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque) +{ + aarch64_elf_prstatus prstatus = {.pid = cpuid}; + ARMCPU *cpu = ARM_CPU(cs); + + memcpy(&(prstatus.regs), cpu->env.xregs, sizeof(cpu->env.xregs)); + prstatus.pc = cpu->env.pc; + prstatus.pstate = cpu->env.pstate; + + return write_elf_note("CORE", NT_PRSTATUS, + &prstatus, sizeof(prstatus), + f, opaque); +} + +int arm_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque) +{ + return 0; +} + +int arm_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque) +{ + return 0; +} + +int cpu_get_dump_info(ArchDumpInfo *info, + const struct GuestPhysBlockList *guest_phys_blocks) +{ + info->d_machine = ELF_MACHINE; + info->d_class = (info->d_machine == EM_ARM) ? ELFCLASS32 : ELFCLASS64; + +#ifdef TARGET_WORDS_BIGENDIAN + info->d_endian = ELFDATA2MSB; +#else + info->d_endian = ELFDATA2LSB; +#endif + + return 0; +} + +ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) +{ + size_t elf_note_size = round4(sizeof("CORE")); + + if (machine == EM_ARM) { + elf_note_size += sizeof(Elf32_Nhdr) + sizeof(arm_elf_prstatus); + } else { + elf_note_size += sizeof(Elf64_Nhdr) + sizeof(aarch64_elf_prstatus); + } + + return elf_note_size * nr_cpus; +} diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index ed5a644..7de8ba1 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -205,6 +205,14 @@ bool arm_cpu_exec_interrupt(CPUState *cpu, int int_req); void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, int flags); +int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque); +int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque); +int arm_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque); +int arm_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque); hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 285947f..679387a 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -1188,6 +1188,10 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) #else cc->do_interrupt = arm_cpu_do_interrupt; cc->get_phys_page_debug = arm_cpu_get_phys_page_debug; + cc->write_elf32_note = arm_cpu_write_elf32_note; + cc->write_elf64_note = arm_cpu_write_elf64_note; + cc->write_elf32_qemunote = arm_cpu_write_elf32_qemunote; + cc->write_elf64_qemunote = arm_cpu_write_elf64_qemunote; cc->vmsd = &vmstate_arm_cpu; #endif cc->gdb_num_core_regs = 26; -- 2.1.3