[PATCH v2] gdb: add support for handling core dumps on arm-none-eabi

Alan Hayward Alan.Hayward@arm.com
Mon Oct 5 13:24:10 GMT 2020



> On 5 Oct 2020, at 13:58, Luis Machado via Gdb-patches <gdb-patches@sourceware.org> wrote:
> 
> Hi,
> 
> I'll go through the new patch soon. I think this was has already been said, but it would be nice to have the core format as close as the Linux Kernel one as possible, but then have a different ABI marker or some other identifiable tag so we can tell those apart.
> 
> If we are adding support for this, we should have in mind it should be flexible enough to accommodate other targets and future changes, not just a one-off.
> 

Been going back and too on my opinion here.
Should we be defining a format ourselves here - And if we do, who else would
use it. But having something is better than nothing. And if it’s simple and
obvious, based on existing standards, then maybe that’s all that’s needed.

+1 for GDB being able to generate the files. That’s fairly crucial.

+1 for Documentation. Maybe even outside of GDB. But I’m not entirely sure
where that would be.

Where it makes sense, sharing code between arm-linux and arm-none would be
good too.


Alan.

> On 10/3/20 3:14 PM, Paul Mathieu via Gdb-patches wrote:
>> Thanks Simon for the super helpful feedback!
>> A few answers inline, and hopefully a properly formatted patch at the
>> bottom.
>>> Note that I am unable to apply this patch either because long lines were
>>> again wrapped by your email client.  Please use git-send-email.  You can
>>> still reply in the thread by using --in-reply-to.
>> Couldn't get git send-email to work with my SMTP, but I got some version
>> of mutt to comply. Hopefully you can apply the patch this time.
>>> Ok, so that answers the question in my other email, about which tool
>>> produces this format of core.  The answer is this specific python
>>> script, and the format is "Paul's ARM core format" :).
>> It was some team work between what gdb understood "natively" and what
>> the patch does.
>> More specifically, this patch only seems to tell gdb to get the
>> registers from the core file the way it would normally do, and then
>> supply them almost verbatim to the regcache.
>> The struct for these registers is nothing special either, you can find
>> it in the kernel code as well:
>> https://elixir.bootlin.com/linux/latest/source/arch/arm/include/uapi/asm/ptrace.h#L135
>>> I don't know what Luis thinks about this, but I would be a bit hesitant
>>> to add support in GDB for a core format that's not standard nor the
>>> output of some "well-known" tool (which would be a de facto standard).
>>> 
>>> Is there a format that already exists in the ARM ecosystem for core
>>> dumps of bare-metal systems, we could base our stuff on?
>> I'm not aware of anything that does that. There are tools that generate
>> memory dumps and CPU register dumps into their own proprietary format,
>> but nothing that I know that you could call a 'core file'.
>> Are there other tools besides gdb that deal with core dumps? Maybe that
>> could help me find other formats.
>> That being said, the format used here is "well-known" in the sense that
>> it's the exact same format the linux kernel would use to dump cores on
>> arm-linux-*
>>> Alternatively, do you think you could implement GDB's generate-core-file
>>> command for bare-metal ARM?  First, it would make sense for GDB to be
>>> able to produce a core in some format and be able to ingest it again.
>>> And it would act as some kind of documentation / reference
>>> implementation of what GDB expects, and that could become some de facto
>>> standard.  People who would like to have their core readable by GDB
>>> would produce it in this format.
>> I had never cloned the gdb source repo until 2 days ago. I have no idea
>> how much work that would be, given that I know next to nothing about the
>> gdb codebase.
>> I do agree that this seems like a better way to do it, since there are
>> already many integrations with a gdb server talking to a live bare-metal
>> target over a physical debugger.
>> As long as gdb already supports primitives to grab memory dumps and cpu
>> registers of a remote target, I'd imagine generating a core file
>> shouldn't be too much work. I'm quite sure most of that functionality
>> already exists for extremely similar targets.
>>>> +void _initialize_arm_none_tdep (void);
>>>> +void
>>>> +_initialize_arm_none_tdep (void)
>>>> +{
>>>> +  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_LINUX,
>>>> +                          arm_none_elf_init_abi);
>>> 
>>> I don't think this is what you want to do.  This "declares" that
>>> combination of architecture ARM and osabi Linux exists, and that
>>> arm_none_elf_init_abi should be called when such a combo is detected to
>>> initialize the gdbarch object.
>>> 
>>> However, such a combo is already registered somewhere else, as you can
>>> guess:
>>> 
>>>   https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/arm-linux-tdep.c;h=f60cb51763f1c5b14811494b646acf54b62d1f10;hb=HEAD#l2010
>>> 
>>> So I presume that if you build a GDB configured with
>>> --enable-targets=all (which will include arm-linux-tdep.c), you will hit
>>> this assertion:
>>> 
>>>   https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/osabi.c;h=e8a813b62f268417edf5f0ad164c9c942bd43b1e;hb=HEAD#l179
>> Ah, I was afraid of that. Thanks for the pointers.
>>> What I think you want is to register an osabi sniffer, whose job is to
>>> try to guess an osabi given a bfd.  Apparently that bfd can sometimes
>>> represent the ELF core file, so you can look up sections and see if that
>>> file looks like a core file you can handle.  And if so, return
>>> GDB_OSABI_NONE.
>>> 
>>> And then, you'd need to register (with gdbarch_register_osabi) osabi
>>> GDB_OSABI_NONE with the arm architecture (same as you did, but with
>>> GDB_OSABI_NONE instead of GDB_OSABI_LINUX) with the callback to call
>>> when this combo is detected:
>>> 
>>>   gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_NONE,
>>>                           arm_none_elf_init_abi);
>>> 
>>> I'm not sure about that part, but I think it's the right direction.
>>> 
>>> Now, the question is how to recognize one of these cores?  As an
>>> example, to recognize Cygwin core dumps (which use ELF files as a
>>> container without a recognizable ABI tag, so it's kind of the same
>>> situation as you), we use the .reg section size to determine if the BFD
>>> is a Cygwin core:
>>> 
>>>   https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/amd64-windows-tdep.c;h=e427c20538961bda2a1a0f033207eebce64c4729;hb=HEAD#l1387
>>> 
>>> So, you can do that, although I think we all agree that it's not ideal.
>>> If there was some way of identifying that the core is in the format we
>>> recognize (say, if there was some special section with a tag), it would
>>> make it much easier to identify it without having to guess.
>> Having a sniffer for GDB_OSABI_NONE seems like the right way to do this.
>> Since the format isn't specified (yet), I can still freely control it. I
>> imagine I could add some sort of OSABI marker in the core file to mark
>> it as an arm-none-eabi core.o
>> My first guess was to set the EI_OSABI e_ident elf header field to
>> ELFOSABI_NONE, but that happens to be the same enum value as
>> ELFOSABI_SYSV, which is afaik broadly used by the linux kernel for core
>> files. So it wouldn't be a good marker.
>> Not sure what a better way would be to not abuse the ELF structure and
>> produce reasonable ELF core dumps (since they already work so well with
>> gdb).
>> Paul
>> gdb/Changelog
>> 2018-09-29  Robin Haberkorn <robin.haberkorn@googlemail.com>
>> 2020-10-02  Paul Mathieu <paulmathieu@google.com>
>> 	* arm-none-tdep.c: Source file added. Provide CPU registers from a core
>> 	file
>> 	* floating point registers not yet supported (FIXME)
>> ---
>>  gdb/Makefile.in     |   2 +
>>  gdb/arm-none-tdep.c | 106 ++++++++++++++++++++++++++++++++++++++++++++
>>  gdb/configure.tgt   |   2 +-
>>  3 files changed, 109 insertions(+), 1 deletion(-)
>>  create mode 100644 gdb/arm-none-tdep.c
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index dbede7a9cf..7f0e3ea0b0 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -720,6 +720,7 @@ ALL_TARGET_OBS = \
>>  	arm-obsd-tdep.o \
>>  	arm-pikeos-tdep.o \
>>  	arm-symbian-tdep.o \
>> +	arm-none-tdep.o \
>>  	arm-tdep.o \
>>  	arm-wince-tdep.o \
>>  	avr-tdep.o \
>> @@ -2150,6 +2151,7 @@ ALLDEPFILES = \
>>  	arm-nbsd-tdep.c \
>>  	arm-obsd-tdep.c \
>>  	arm-symbian-tdep.c \
>> +	arm-none-tdep.c \
>>  	arm-tdep.c \
>>  	avr-tdep.c \
>>  	bfin-linux-tdep.c \
>> diff --git a/gdb/arm-none-tdep.c b/gdb/arm-none-tdep.c
>> new file mode 100644
>> index 0000000000..21743c40a0
>> --- /dev/null
>> +++ b/gdb/arm-none-tdep.c
>> @@ -0,0 +1,106 @@
>> +/* Native-dependent code for GDB targetting bare-metal ARM.
>> +
>> +   Copyright (C) 2020 Free Software Foundation, Inc.
>> +
>> +   This file is part of GDB.
>> +
>> +   This program is free software; you can redistribute it and/or modify
>> +   it under the terms of the GNU General Public License as published by
>> +   the Free Software Foundation; either version 3 of the License, or
>> +   (at your option) any later version.
>> +
>> +   This program is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +   GNU General Public License for more details.
>> +
>> +   You should have received a copy of the GNU General Public License
>> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>> +
>> +#include "defs.h"
>> +#include "osabi.h"
>> +
>> +#include "arch/arm.h"
>> +#include "arm-tdep.h"
>> +#include "gdbarch.h"
>> +#include "regcache.h"
>> +#include "regset.h"
>> +
>> +struct arm_none_reg
>> +{
>> +  uint32_t reg[13];
>> +  uint32_t sp;
>> +  uint32_t lr;
>> +  uint32_t pc;
>> +  uint32_t cpsr;
>> +  uint32_t orig_r0;
>> +};
>> +
>> +static void
>> +arm_none_supply_gregset (const struct regset *regset,
>> +                         struct regcache *regcache, int regnum,
>> +                         const void *gregs, size_t len)
>> +{
>> +  const arm_none_reg *gregset = static_cast<const arm_none_reg *> (gregs);
>> +  gdb_assert (len >= sizeof (arm_none_reg));
>> +
>> +  /* Integer registers.  */
>> +  for (int i = ARM_A1_REGNUM; i < ARM_SP_REGNUM; i++)
>> +    if (regnum == -1 || regnum == i)
>> +      regcache->raw_supply (i, (char *)&gregset->reg[i]);
>> +
>> +  if (regnum == -1 || regnum == ARM_SP_REGNUM)
>> +    regcache->raw_supply (ARM_SP_REGNUM, (char *)&gregset->sp);
>> +
>> +  if (regnum == -1 || regnum == ARM_LR_REGNUM)
>> +    regcache->raw_supply (ARM_LR_REGNUM, (char *)&gregset->lr);
>> +
>> +  if (regnum == -1 || regnum == ARM_PC_REGNUM)
>> +    {
>> +      CORE_ADDR r_pc
>> +        = gdbarch_addr_bits_remove (regcache->arch (), gregset->pc);
>> +      regcache->raw_supply (ARM_PC_REGNUM, (char *)&r_pc);
>> +    }
>> +
>> +  if (regnum == -1 || regnum == ARM_PS_REGNUM)
>> +    {
>> +      if (arm_apcs_32)
>> +        regcache->raw_supply (ARM_PS_REGNUM, (char *)&gregset->cpsr);
>> +      else
>> +        regcache->raw_supply (ARM_PS_REGNUM, (char *)&gregset->pc);
>> +    }
>> +}
>> +
>> +static const struct regset arm_none_regset
>> +    = { nullptr, arm_none_supply_gregset,
>> +        /* We don't need a collect function because we only use this reading
>> +           registers (via iterate_over_regset_sections and
>> +           fetch_regs/fetch_register).  */
>> +        nullptr, 0 };
>> +
>> +static void
>> +arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch,
>> +                                       iterate_over_regset_sections_cb *cb,
>> +                                       void *cb_data,
>> +                                       const struct regcache *regcache)
>> +{
>> +  cb (".reg", sizeof (arm_none_reg), sizeof (arm_none_reg), &arm_none_regset,
>> +      NULL, cb_data);
>> +}
>> +
>> +static void arm_none_elf_init_abi (struct gdbarch_info info,
>> +                                   struct gdbarch *gdbarch);
>> +static void
>> +arm_none_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>> +{
>> +  set_gdbarch_iterate_over_regset_sections (
>> +      gdbarch, arm_none_iterate_over_regset_sections);
>> +}
>> +
>> +void _initialize_arm_none_tdep (void);
>> +void
>> +_initialize_arm_none_tdep (void)
>> +{
>> +  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_LINUX,
>> +                          arm_none_elf_init_abi);
>> +}
>> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
>> index a3e11c4b9b..0cf05efdd1 100644
>> --- a/gdb/configure.tgt
>> +++ b/gdb/configure.tgt
>> @@ -189,7 +189,7 @@ arm*-*-symbianelf*)
>>  	;;
>>  arm*-*-*)
>>  	# Target: ARM embedded system
>> -	gdb_target_obs="arm-pikeos-tdep.o"
>> +	gdb_target_obs="arm-pikeos-tdep.o arm-none-tdep.o"
>>  	gdb_sim=../sim/arm/libsim.a
>>  	;;
>> --
>> 2.28.0.806.g8561365e88-goog



More information about the Gdb-patches mailing list