aboutsummaryrefslogtreecommitdiff
path: root/target-arm
diff options
context:
space:
mode:
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;