arm-none-eabi core dump support
Commit Message
Hello!
I had the idea of debugging my embedded ARM project (built with the
arm-none-eabi toolchain) using core dumps. Core dumps would be useful even on
embedded targets for several reasons as you might guess: They can be
automatically created during crashes, even if you don't have a debug probe
attached, stored and later retrieved. They can be created while your firmware is
running, without interrupting it. And most importantly, they allow debugging
when you cannot even use a debug probe, maybe because your JTAG port is already
locked.
While core dump creation on an embedded target turned out to be relatively
simple, I found that arm-none-eabi-gdb, at least as of
embedded-gdb-7.12-branch-2017q2, does not have a core dump handler and throws
the "no core file handler recognizes format" error.
What other people instead do is apparently to make memory and register dumps in
a custom format instead of real core dumps, transferring this file to the PC and
using a custom gdb remote debug stub to feed gdb.
This is at least what these guys are doing apparently:
https://github.com/adamgreen/CrashDebug
Searching the net, including the gdb mailing list, shows that reading core dumps
on arm-none-eabi-gdb is an often asked for feature.
Since I wasn't consent with inventing my own core dump format or integrating
CrashDebug, I simply hacked GDB to support core dump handling via core-regset.c.
See attachment. It applies on top of users/ARM/embedded-gdb-7.12-branch-2017q2,
but not on top of master.
Also, as I said, it's a hack. It modifies several architecture-independent
files. Floating point registers are currently not supported.
While this wont work for all applications, it should for most typical embedded
ARM projects and IMHO it's better than nothing.
I would like to improve this patch and get this upstreamed.
Can you give me some pointers on where the additional patched-in definitions
should be placed instead?
What about core-regset.c - it seems to have been removed in the master branch?
Best regards,
Robin
From 13b7c2d2a602c1830ad4a3f2a50a66e3c4f2f1a3 Mon Sep 17 00:00:00 2001
From: Robin Haberkorn <robin.haberkorn@googlemail.com>
Date: Thu, 12 Jul 2018 17:29:04 +0600
Subject: [PATCH] added support for handling core dumps on arm-none-eabi-gdb
(Embedded ARM)
* this is merely a hack and not yet upstreamable, as it modifies core-regset.c,
corelow.c and gregset.h with definitions taken from here and there.
* core-regset.c is missing the following definitions:
supply_gregset(), GDB_GREGSET_T, GDB_FPREGSET_T
* probably, they should be added as a new module, but I don't know where
it should be put. This should be discussed on the GDB mailing list.
* also floatin point register retrieval is still missing and has simply
been commented out.
---
gdb/configure.tgt | 2 +-
gdb/core-regset.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/corelow.c | 2 +-
gdb/gregset.h | 3 +++
4 files changed, 58 insertions(+), 2 deletions(-)
@@ -112,7 +112,7 @@ arm*-*-symbianelf*)
;;
arm*-*-*)
# Target: ARM embedded system
- gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o"
+ gdb_target_obs="arm.o arm-get-next-pcs.o arm-tdep.o core-regset.o"
gdb_sim=../sim/arm/libsim.a
;;
@@ -39,9 +39,60 @@
#include <sys/procfs.h>
#endif
+#include "arch/arm.h"
+
/* Prototypes for supply_gregset etc. */
#include "gregset.h"
+#define ARM_CPSR_GREGNUM 16
+extern int arm_apcs_32;
+
+#define ARM_LINUX_SIZEOF_GREGSET (18 * INT_REGISTER_SIZE)
+
+void
+arm_linux_supply_gregset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *gregs_buf, size_t len)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ const gdb_byte *gregs = (const gdb_byte *) gregs_buf;
+ int regno;
+ CORE_ADDR reg_pc;
+ gdb_byte pc_buf[INT_REGISTER_SIZE];
+
+ for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
+ if (regnum == -1 || regnum == regno)
+ regcache_raw_supply (regcache, regno,
+ gregs + INT_REGISTER_SIZE * regno);
+
+ if (regnum == ARM_PS_REGNUM || regnum == -1)
+ {
+ if (arm_apcs_32)
+ regcache_raw_supply (regcache, ARM_PS_REGNUM,
+ gregs + INT_REGISTER_SIZE * ARM_CPSR_GREGNUM);
+ else
+ regcache_raw_supply (regcache, ARM_PS_REGNUM,
+ gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
+ }
+
+ if (regnum == ARM_PC_REGNUM || regnum == -1)
+ {
+ reg_pc = extract_unsigned_integer (gregs
+ + INT_REGISTER_SIZE * ARM_PC_REGNUM,
+ INT_REGISTER_SIZE, byte_order);
+ reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
+ store_unsigned_integer (pc_buf, INT_REGISTER_SIZE, byte_order, reg_pc);
+ regcache_raw_supply (regcache, ARM_PC_REGNUM, pc_buf);
+ }
+}
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+ arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
+}
+
/* Provide registers to GDB from a core file.
CORE_REG_SECT points to an array of bytes, which are the contents
@@ -84,9 +135,11 @@ fetch_core_registers (struct regcache *regcache,
else
{
memcpy (&fpregset, core_reg_sect, sizeof (fpregset));
+#if 0
if (gdbarch_fp0_regnum (get_regcache_arch (regcache)) >= 0)
supply_fpregset (regcache,
(const gdb_fpregset_t *) fpregset_p);
+#endif
}
break;
@@ -541,7 +541,7 @@ get_core_register_section (struct regcache *regcache,
warning (_("Section `%s' in core file too small."), section_name);
return;
}
- if (size != min_size && !(regset->flags & REGSET_VARIABLE_SIZE))
+ if (size != min_size && regset && !(regset->flags & REGSET_VARIABLE_SIZE))
{
warning (_("Unexpected size of section `%s' in core file."),
section_name);
@@ -23,6 +23,9 @@
#include <sys/procfs.h>
#endif
+#define GDB_GREGSET_T struct { uint32_t reg[18]; }
+#define GDB_FPREGSET_T struct { uint32_t reg[18]; }
+
#ifndef GDB_GREGSET_T
#define GDB_GREGSET_T gregset_t
#endif
--
2.7.4