aboutsummaryrefslogtreecommitdiff
path: root/target-arm
diff options
context:
space:
mode:
authorAndrew Jones <drjones@redhat.com>2016-01-11 20:56:25 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-01-15 14:55:16 +0000
commitade0d0c0d3a0444c626ec5f46ef75af7395236f6 (patch)
tree8a6c9f709a8713e12a89eebbf1eb31147a26440b /target-arm
parent7d68e47f1280f911df0ea87051d70a4ee52d701d (diff)
target-arm: dump-guest-memory: add vfp notes for arm
gdb won't actually dump these with 'info all-registers' since it first tries to confirm that it should by checking the VFP hwcap in the .auxv note. Well, we don't generate an .auxv note. Signed-off-by: Andrew Jones <drjones@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1452542185-10914-9-git-send-email-drjones@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-arm')
-rw-r--r--target-arm/arch_dump.c49
1 files changed, 46 insertions, 3 deletions
diff --git a/target-arm/arch_dump.c b/target-arm/arch_dump.c
index d7b63a0d7e..f45125ffe6 100644
--- a/target-arm/arch_dump.c
+++ b/target-arm/arch_dump.c
@@ -183,15 +183,28 @@ struct arm_elf_prstatus {
QEMU_BUILD_BUG_ON(sizeof(struct arm_elf_prstatus) != 148);
+/* struct user_vfp from arch/arm/include/asm/user.h */
+struct arm_user_vfp_state {
+ uint64_t vregs[32];
+ uint32_t fpscr;
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct arm_user_vfp_state) != 260);
+
struct arm_note {
Elf32_Nhdr hdr;
- char name[8]; /* align_up(sizeof("CORE"), 4) */
- struct arm_elf_prstatus prstatus;
+ char name[8]; /* align_up(sizeof("LINUX"), 4) */
+ union {
+ struct arm_elf_prstatus prstatus;
+ struct arm_user_vfp_state vfp;
+ };
} QEMU_PACKED;
#define ARM_NOTE_HEADER_SIZE offsetof(struct arm_note, prstatus)
#define ARM_PRSTATUS_NOTE_SIZE \
(ARM_NOTE_HEADER_SIZE + sizeof(struct arm_elf_prstatus))
+#define ARM_VFP_NOTE_SIZE \
+ (ARM_NOTE_HEADER_SIZE + sizeof(struct arm_user_vfp_state))
static void arm_note_init(struct arm_note *note, DumpState *s,
const char *name, Elf32_Word namesz,
@@ -206,17 +219,40 @@ static void arm_note_init(struct arm_note *note, DumpState *s,
memcpy(note->name, name, namesz);
}
+static int arm_write_elf32_vfp(WriteCoreDumpFunction f, CPUARMState *env,
+ int cpuid, DumpState *s)
+{
+ struct arm_note note;
+ int ret, i;
+
+ arm_note_init(&note, s, "LINUX", 6, NT_ARM_VFP, sizeof(note.vfp));
+
+ for (i = 0; i < 32; ++i) {
+ note.vfp.vregs[i] = cpu_to_dump64(s, float64_val(env->vfp.regs[i]));
+ }
+
+ note.vfp.fpscr = cpu_to_dump32(s, vfp_get_fpscr(env));
+
+ ret = f(&note, ARM_VFP_NOTE_SIZE, s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque)
{
struct arm_note note;
CPUARMState *env = &ARM_CPU(cs)->env;
DumpState *s = opaque;
- int ret, i;
+ int ret, i, fpvalid = !!arm_feature(env, ARM_FEATURE_VFP);
arm_note_init(&note, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus));
note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
+ note.prstatus.pr_fpvalid = cpu_to_dump32(s, fpvalid);
for (i = 0; i < 16; ++i) {
note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->regs[i]);
@@ -226,6 +262,8 @@ int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
ret = f(&note, ARM_PRSTATUS_NOTE_SIZE, s);
if (ret < 0) {
return -1;
+ } else if (fpvalid) {
+ return arm_write_elf32_vfp(f, env, cpuid, s);
}
return 0;
@@ -280,6 +318,8 @@ int cpu_get_dump_info(ArchDumpInfo *info,
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
{
+ ARMCPU *cpu = ARM_CPU(first_cpu);
+ CPUARMState *env = &cpu->env;
size_t note_size;
if (class == ELFCLASS64) {
@@ -287,6 +327,9 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
note_size += AARCH64_PRFPREG_NOTE_SIZE;
} else {
note_size = ARM_PRSTATUS_NOTE_SIZE;
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
+ note_size += ARM_VFP_NOTE_SIZE;
+ }
}
return note_size * nr_cpus;