public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Andrew Burgess <aburgess@redhat.com>
To: Luis Machado <luis.machado@arm.com>,
	John Baldwin <jhb@FreeBSD.org>,
	gdb-patches@sourceware.org
Subject: Re: [PATCH 5/5] gdb: native target invalid architecture detection
Date: Mon, 06 Jun 2022 18:48:55 +0100	[thread overview]
Message-ID: <87ee01hed4.fsf@redhat.com> (raw)
In-Reply-To: <87ilpdhn73.fsf@redhat.com>

Andrew Burgess <aburgess@redhat.com> writes:

> Luis Machado via Gdb-patches <gdb-patches@sourceware.org> writes:
>
>> On 5/31/22 17:51, Andrew Burgess via Gdb-patches wrote:
>>> John Baldwin <jhb@FreeBSD.org> writes:
>>> 
>>>> On 5/31/22 7:30 AM, Andrew Burgess via Gdb-patches wrote:
>>>>> If GDB is asked to start a new inferior, or attach to an existing
>>>>> process, using a binary file for an architecture that does not match
>>>>> the current native target, then, currently, GDB will assert.  Here's
>>>>> an example session using current HEAD of master with GDB built for an
>>>>> x86-64 GNU/Linux native target, the binary being used is a RISC-V ELF:
>>>>>
>>>>>     $ ./gdb/gdb -q --data-directory ./gdb/data-directory/
>>>>>     (gdb) file /tmp/hello.rv32imc.x
>>>>>     Reading symbols from /tmp/hello.rv32imc.x...
>>>>>     (gdb) start
>>>>>     Temporary breakpoint 1 at 0x101b2: file hello.rv32.c, line 23.
>>>>>     Starting program: /tmp/hello.rv32imc.x
>>>>>     ../../src/gdb/gdbarch.h:166: internal-error: gdbarch_tdep: Assertion `dynamic_cast<TDepType *> (tdep) != nullptr' failed.
>>>>>     A problem internal to GDB has been detected,
>>>>>     further debugging may prove unreliable.
>>>>>
>>>>> The same error is encountered if, instead of starting a new inferior,
>>>>> the user tries to attach to an x86-64 process with a RISC-V binary set
>>>>> as the current executable.
>>>>>
>>>>> These errors are not specific to the x86-64/RISC-V pairing I'm using
>>>>> here, any attempt to use a binary for one architecture with a native
>>>>> target of a different architecture will result in a similar error.
>>>>>
>>>>> Clearly, attempting to use this cross-architecture combination is a
>>>>> user error, but I think GDB should do better than an assert; ideally a
>>>>> nice error should be printed.
>>>>>
>>>>> The problem we run into is that, when the user starts a new inferior,
>>>>> or attaches to an inferior, the inferior stops.  At this point GDB
>>>>> attempts to handle the stop, and this involves reading registers from
>>>>> the inferior.
>>>>>
>>>>> These register reads end up being done through the native target, so
>>>>> in the example above, we end up in the amd64_supply_fxsave function.
>>>>> However, these functions need a gdbarch.  The gdbarch is fetched from
>>>>> the register set, which was constructed using the gdbarch from the
>>>>> binary currently in use.  And so we end up in amd64_supply_fxsave
>>>>> using a RISC-V gdbarch.
>>>>>
>>>>> When we call:
>>>>>
>>>>>     i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
>>>>>
>>>>> this will assert as the gdbarch_tdep data within the RISC-V gdbarch is
>>>>> of the type riscv_gdbarch_tdep not i386_gdbarch_tdep.
>>>>>
>>>>> The solution I propose in this commit is to add a new target_ops
>>>>> method supports_architecture_p.  This method will return true if a
>>>>> target can safely be used with a specific architecture, otherwise, the
>>>>> method returns false.
>>>>>
>>>>> I imagine that a result of true from this method doesn't guarantee
>>>>> that GDB can start an inferior of a given architecture, it just means
>>>>> that GDB will not crash if such an attempt is made.  A result of false
>>>>> is a hard stop; attempting to use this target with this architecture
>>>>> is not supported, and may cause GDB to crash.
>>>>>
>>>>> This distinction is important I think for things like remote targets,
>>>>> and possibly simulator targets.  We might imagine that GDB can ask a
>>>>> remote (or simulator) to start with a particular executable, and the
>>>>> target might still refuse for some reason.  But my thinking is that
>>>>> these refusals should be well handled (i.e. GDB should give a user
>>>>> friendly error), rather than crashing, as is the case with the native
>>>>> targets.
>>>>>
>>>>> For example, if I start gdbserver on an x86-64 machine like this:
>>>>>
>>>>>     gdbserver --multi :54321
>>>>>
>>>>> Then make use of this from a GDB session like this:
>>>>>
>>>>>     $ ./gdb/gdb -q --data-directory ./gdb/data-directory/
>>>>>     (gdb) file /tmp/hello.rv32imc.x
>>>>>     Reading symbols from /tmp/hello.rv32imc.x...
>>>>>     (gdb) target extended-remote :54321
>>>>>     Remote debugging using :54321
>>>>>     (gdb) run
>>>>>     Starting program: /tmp/hello.rv32imc.x
>>>>>     Running the default executable on the remote target failed; try "set remote exec-file"?
>>>>>     (gdb)
>>>>>
>>>>> Though the error is not very helpful in diagnosing the problem, we can
>>>>> see that GDB has not crashed, but has given the user an error.
>>>>>
>>>>> And so, the supports_architecture_p method is created to return true
>>>>> by default, then I override this in inf_child_target, where I compare
>>>>> the architecture in question with the default_bfd_arch.
>>>>>
>>>>> Finally, I've added calls to supports_architecture_p for the
>>>>> run (which covers run, start, starti) and attach commands.
>>>>>
>>>>> You will notice a lack of tests for this change.  I'm not sure of a
>>>>> good way that I can build a binary for a different architecture as
>>>>> part of a test, but if anyone has any ideas then I'll be happy to add
>>>>> a test here.
>>>>
>>>> Have you considered multi-arch cases such as running i386 binaries on an x86-64
>>>> host or 32-bit arm binaries on an AArch64 host?  Will we need to override this
>>>> method in certain targets (e.g. x86-linux-nat.c or x86-fbsd-nat.c) to support
>>>> such cases?
>>> 
>>> For the x86 examples you gave, I think these all have the bfd_arch_i386
>>> bfd architecture, so should work just fine.
>>> 
>>> But for the aarch64 case, I admit I don't know how this works.  A 32-bit
>>> ARM binary is going to have bfd_arch_arm, while the AArch64 target will
>>> be expecting a gdbarch with bfd_arch_aarch64.  But how GDB supports
>>> running the former on the latter, I don't know.
>>> 
>>> I notice there's aarch64-linux-nat.c and aarch32-linux-nat.c, I wonder
>>> if this has something to do with it...
>>
>> aarch32 is the 32-bit state of aarch64, but the BFD architecture is
>> different. So this won't work out-of-the-box.
>
> If I understand correctly a aarch64 binary will have bfd_arch_aarch64,
> and a aarch32 (armv7?) binary will be bfd_arch_arm.
>
> What I don't understand, is how this all hangs together when running on
> an aarch64 machine, using a native target.
>
> Unless I'm missing something (please let me know if I am) then there's
> just a single native linux target, the_aarch64_linux_nat_target, which
> is registered from _initialize_aarch64_linux_nat in
> aarch64-linux-nat.c.
>
> In aarch64_linux_nat_target::fetch_registers, we assume the gdbarch_tdep
> is of type aarch64_gdbarch_tdep, so this will only work for
> bfd_arch_aarch64 binaries.
>
> Then there's the_arm_linux_nat_target, from arm-linux-nat.c, which has
> arm_linux_nat_target::fetch_registers, which assumed gdbarch_tdep will
> be of type arm_gdbarch_tdep, so will only work for bfd_arch_arm targets.
>
> So, I guess, if we can debug bfd_arch_arm and bfd_arch_aarch64 binaries
> on a native aarch64 target, we must somehow be switching the current
> native target object between these two, right?  But I can't figure out
> where that's happening...
>
>>
>>> 
>>> Maybe someone with more ARM/AArch64 knowledge will chip in to fill in
>>> some of the blanks.
>>
>> When attempting to run a 32-bit binary in 64-bit state, I get...
>
> Does this mean you're on an aarch64 machine, start GDB with an aarch32
> (armv7?) binary, and then "run" to start the process?
>
>>
>> The target does not support architecture "armv7".
>
> I'd be really interested to know if you only take the first 4 patches
> from this series, can you still run armv7 binaries using an aarch64 GDB?
> I'm wonderinging if the assert added in patch #4 will trigger.

I managed to get a setup where I'm running on an aarch64 machine, and
using GDB to debug an ARMv7 binary.

I'm a little confused as to what's going on, so I'm hoping I can
describe what I'm seeing, and you can tell me if GDB is supposed to do
better than this or not.

First, I'm using a modified version of patch #4 of my series (i.e. I've
applied patches #1, #2, #3, and #4, but modified #4), in gdbarch.h I've
replaced the _function_ gdbarch_tdep with this:

  template<typename TDepType>
  static inline TDepType *
  gdbarch_tdep (struct gdbarch *gdbarch)
  {
    TDepType *tdep = dynamic_cast<TDepType *> (gdbarch_tdep_1 (gdbarch));
    if (tdep == nullptr)
      {
        fprintf (stderr, "XXX: Incorrect cast performed!\n");
        return static_cast<TDepType *> (gdbarch_tdep_1 (gdbarch));
      }
    return tdep;
  }

Here's my GDB session then, debugging a 32-bit ARMv7 binary;

  $ file /tmp/ubuntu-16.04-armhf/bin/true
  /tmp/ubuntu-16.04-armhf/bin/true: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=c80229c22d4b6b30b71ab1b1b5a1de6b86b6aadf, stripped
  $ ./gdb/gdb -q --data-directory ./gdb/data-directory/ /tmp/ubuntu-16.04-armhf/bin/true
  Reading symbols from /tmp/ubuntu-16.04-armhf/bin/true...
  (No debugging symbols found in /tmp/ubuntu-16.04-armhf/bin/true)
  (gdb) show architecture 
  The target architecture is set to "auto" (currently "armv7").
  (gdb) starti
  Starting program: /tmp/ubuntu-16.04-armhf/bin/true 
  XXX: Incorrect cast performed!
  XXX: Incorrect cast performed!
  warning: Unable to determine the number of hardware watchpoints available.
  warning: Unable to determine the number of hardware breakpoints available.
  XXX: Incorrect cast performed!
  
  Program stopped.
  0x0000000000000006 in ?? ()
  (gdb) show architecture 
  The target architecture is set to "auto" (currently "aarch64").
  (gdb) pipe maintenance print xml-tdesc | head -n 20
  <?xml version="1.0"?>
  <!DOCTYPE target SYSTEM "gdb-target.dtd">
  <target>
    <architecture>arm</architecture>
    <feature name="org.gnu.gdb.arm.core">
      <reg name="r0" bitsize="32" type="uint32" regnum="0"/>
      <reg name="r1" bitsize="32" type="uint32" regnum="1"/>
      <reg name="r2" bitsize="32" type="uint32" regnum="2"/>
      <reg name="r3" bitsize="32" type="uint32" regnum="3"/>
      <reg name="r4" bitsize="32" type="uint32" regnum="4"/>
      <reg name="r5" bitsize="32" type="uint32" regnum="5"/>
      <reg name="r6" bitsize="32" type="uint32" regnum="6"/>
      <reg name="r7" bitsize="32" type="uint32" regnum="7"/>
      <reg name="r8" bitsize="32" type="uint32" regnum="8"/>
      <reg name="r9" bitsize="32" type="uint32" regnum="9"/>
      <reg name="r10" bitsize="32" type="uint32" regnum="10"/>
      <reg name="r11" bitsize="32" type="uint32" regnum="11"/>
      <reg name="r12" bitsize="32" type="uint32" regnum="12"/>
      <reg name="sp" bitsize="32" type="data_ptr" regnum="13"/>
      <reg name="lr" bitsize="32" type="int" regnum="14"/>
  (gdb) info registers 
  x0             0x0                 0
  x1             0x0                 0
  x2             0x0                 0
  x3             0x0                 0
  x4             0x0                 0
  x5             0x0                 0
  x6             0xfffef6a000000000  -291782898221056
  x7             0xf77d0b4100000000  -613321600451739648
  x8             0x30                48
  x9             0x8d03c8            9241544
  x10            0x23cad1e8          600494568
  x11            0x7fd7d9dce8        549082225896
  x12            0x7fd7d9dd00        549082225920
  x13            0x7fa10128d0        548162054352
  x14            0x23c3d8a0          600037536
  x15            0x0                 0
  x16            0xd32a70            13838960
  x17            0xd32aa0            13839008
  x18            0x0                 0
  x19            0x0                 0
  x20            0x0                 0
  x21            0x0                 0
  x22            0x0                 0
  x23            0x0                 0
  x24            0x7fd7d9dd50        549082226000
  x25            0x412694            4269716
  x26            0x7cdf14            8183572
  x27            0x23b60ca0          599133344
  x28            0x4105e0            4261344
  x29            0x0                 0
  x30            0x7fd7d9dd50        549082226000
  sp             0x23c3d8a0          0x23c3d8a0
  pc             0x6                 0x6
  cpsr           0x6                 [ EL=1 BTYPE=0 ]
  Unable to fetch vFP/SIMD registers.: Invalid argument.
  (gdb) 

There's a couple of weird things I notice here.  First, obviously we're
casting the tdep field incorrectly 3 times.  This happens because,
initially, the GDB inferior has a gdbarch selected based on the ELF, so
it will be an ARM gdbarch with an arm_gdbarch_tdep.  However, I believe
that the native target will be aarch64_linux_nat_target.

So, when we first stop, after the target is created, we will call
aarch64_linux_nat_target::fetch_registers as part of the stop process,
this will perform one of the invalid casts.  I haven't (yet) tracked
down the others.

The next weird thing is that, after starting, the architecture has
changed to aarch64.  I have no idea why this is the case (I haven't
looked yet).

My expectation was that after the first stop GDB would ask the native
target for a target description, we'd get an ARMv7 target description,
and we'd then use that description to update the gdbarch.  It appears I
was partially correct, as you can see that the xml-tdesc is for ARM,
however, the current architect still switches to aarch64, and I have no
idea why that is.

Finally, in the 'info registes' we appear to be displaying aarch64
register names, rather than the ARMv7 names from the xml-tdesc, which
seems weird (again, I haven't looked yet), and then, at the end of the
'info registers' output we appear to try and fetch some registers that
the target doens't support.

If I try the same experiment using an aarch64 test binary then the
architecture starts as aarch64 and remains so after the 'starti' (as
you'd expect, and the 'info registers' output still displays the aarch64
names (as you'd expect), but the warning about 'Unable to fetch vfP/SIMD
registers' is no longer present - so that issue is something specific
relating to running the ARMv7 binary.

I think there's a lot here for me to look into, but I'm hoping you might
be able to let me know if me experiences above are the "expected"
behaviour, or if I'm not configured/built GDB correctly, or maybe I'm
just not using GDB correctly in this ARMv7/ARMv8 situation.

Thanks,
Andrew


  reply	other threads:[~2022-06-06 17:49 UTC|newest]

Thread overview: 83+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-31 14:30 [PATCH 0/5] Handle trying to use a native target with the wrong binary Andrew Burgess
2022-05-31 14:30 ` [PATCH 1/5] gdb/arm: move fetch of arm_gdbarch_tdep to a more inner scope Andrew Burgess
2022-06-01  7:58   ` Luis Machado
2022-05-31 14:30 ` [PATCH 2/5] gdb/mips: rewrite show_mask_address Andrew Burgess
2022-05-31 14:30 ` [PATCH 3/5] gdb: move the type cast into gdbarch_tdep Andrew Burgess
2022-06-01  8:01   ` Luis Machado
2022-05-31 14:30 ` [PATCH 4/5] gdb: ensure the cast in gdbarch_tdep is valid Andrew Burgess
2022-05-31 16:04   ` John Baldwin
2022-05-31 17:22     ` Andrew Burgess
2022-05-31 14:30 ` [PATCH 5/5] gdb: native target invalid architecture detection Andrew Burgess
2022-05-31 16:08   ` John Baldwin
2022-05-31 16:51     ` Andrew Burgess
2022-06-01  8:25       ` Luis Machado
2022-06-01 21:06         ` John Baldwin
2022-06-01 21:21           ` Christophe Lyon
2022-06-02 14:56             ` John Baldwin
2022-06-06 14:38         ` Andrew Burgess
2022-06-06 17:48           ` Andrew Burgess [this message]
2022-06-07 11:03             ` Luis Machado
2022-06-07 18:42               ` Pedro Alves
2022-06-07 20:15                 ` Pedro Alves
2022-06-08  8:18                   ` Luis Machado
2022-06-08 10:17                     ` Pedro Alves
2022-06-08  7:54                 ` Luis Machado
2022-06-08 10:12                   ` Pedro Alves
2022-06-08 11:20                     ` [PATCH v2] aarch64: Add fallback if ARM_CC_FOR_TARGET not set (was: Re: [PATCH 5/5] gdb: native target invalid architecture detection) Pedro Alves
2022-06-08 12:50                       ` Luis Machado
2022-06-08 13:23                         ` Pedro Alves
2022-06-08 13:38                       ` Andrew Burgess
2022-06-08 19:01                       ` John Baldwin
2022-06-08 21:48                         ` Pedro Alves
2022-06-09 16:31                           ` John Baldwin
2022-06-10 13:08 ` [PATCHv2 0/6] Handle trying to use a native target with the wrong binary Andrew Burgess
2022-06-10 13:08   ` [PATCHv2 1/6] gdb/arm: move fetch of arm_gdbarch_tdep to a more inner scope Andrew Burgess
2022-06-10 13:08   ` [PATCHv2 2/6] gdb/mips: rewrite show_mask_address Andrew Burgess
2022-06-10 13:08   ` [PATCHv2 3/6] gdb/arm: avoid undefined behaviour in arm_frame_is_thumb Andrew Burgess
2022-06-10 15:21     ` Luis Machado
2022-06-10 15:49       ` Andrew Burgess
2022-06-10 16:29         ` Luis Machado
2022-06-10 13:08   ` [PATCHv2 4/6] gdb: move the type cast into gdbarch_tdep Andrew Burgess
2022-06-10 16:35     ` Luis Machado
2022-06-10 13:08   ` [PATCHv2 5/6] gdb: ensure the cast in gdbarch_tdep is valid Andrew Burgess
2022-06-10 13:08   ` [PATCHv2 6/6] gdb: native target invalid architecture detection Andrew Burgess
2022-06-10 16:20     ` John Baldwin
2022-06-10 16:31     ` Luis Machado
2022-06-13 16:15   ` [PATCHv3 0/6] Handle trying to use a native target with the wrong binary Andrew Burgess
2022-06-13 16:15     ` [PATCHv3 1/6] gdb/arm: move fetch of arm_gdbarch_tdep to a more inner scope Andrew Burgess
2022-06-13 16:15     ` [PATCHv3 2/6] gdb/mips: rewrite show_mask_address Andrew Burgess
2022-06-13 16:15     ` [PATCHv3 3/6] gdb: select suitable thread for gdbarch_adjust_breakpoint_address Andrew Burgess
2022-06-14  9:45       ` Luis Machado
2022-06-14 14:05         ` Andrew Burgess
2022-06-24 16:58       ` Pedro Alves
2022-06-13 16:15     ` [PATCHv3 4/6] gdb: move the type cast into gdbarch_tdep Andrew Burgess
2022-06-13 16:15     ` [PATCHv3 5/6] gdb: ensure the cast in gdbarch_tdep is valid Andrew Burgess
2022-06-24 18:15       ` Pedro Alves
2022-06-13 16:15     ` [PATCHv3 6/6] gdb: native target invalid architecture detection Andrew Burgess
2022-06-24 19:23       ` Pedro Alves
2022-06-27 16:27         ` Andrew Burgess
2022-06-27 21:38           ` Pedro Alves
2022-06-28 10:37             ` Andrew Burgess
2022-06-28 12:42               ` [PATCH v2] gdb+gdbserver/Linux: avoid reading registers while going through shell (was: Re: [PATCHv3 6/6] gdb: native target invalid architecture detection) Pedro Alves
2022-06-28 14:21                 ` Andrew Burgess
2022-06-29 15:17                 ` Simon Marchi
2022-06-29 16:22                   ` [PATCH] Fix GDBserver regression due to change to avoid reading shell registers Pedro Alves
2022-06-29 16:38                     ` Simon Marchi
2022-06-30  9:33             ` [PATCHv3 6/6] gdb: native target invalid architecture detection Andrew Burgess
2022-06-30 11:44               ` Pedro Alves
2022-07-11 10:47                 ` Andrew Burgess
2022-06-24 10:15     ` [PATCHv3 0/6] Handle trying to use a native target with the wrong binary Andrew Burgess
2022-06-28 14:28     ` [PATCHv4 0/6] Detect invalid casts of gdbarch_tdep structures Andrew Burgess
2022-06-28 14:28       ` [PATCHv4 1/6] gdb/arm: move fetch of arm_gdbarch_tdep to a more inner scope Andrew Burgess
2022-06-28 14:28       ` [PATCHv4 2/6] gdb/mips: rewrite show_mask_address Andrew Burgess
2022-06-28 14:28       ` [PATCHv4 3/6] gdb: select suitable thread for gdbarch_adjust_breakpoint_address Andrew Burgess
2022-06-28 14:28       ` [PATCHv4 4/6] gdb: move the type cast into gdbarch_tdep Andrew Burgess
2022-06-28 14:28       ` [PATCHv4 5/6] gdbsupport: add checked_static_cast Andrew Burgess
2022-06-28 14:28       ` [PATCHv4 6/6] gdb: ensure the cast in gdbarch_tdep is valid Andrew Burgess
2022-07-11 10:46       ` [PATCHv4 0/6] Detect invalid casts of gdbarch_tdep structures Andrew Burgess
2022-07-21 18:21         ` Andrew Burgess
2022-07-22  0:50           ` Luis Machado
2022-07-23  0:02             ` [PATCH] Rename gdbarch_tdep template function to gdbarch_tdep_cast for g++ 4.8 Mark Wielaard
2022-07-25 11:19               ` Andrew Burgess
2022-07-25 11:27                 ` Mark Wielaard
2022-07-26 11:05                   ` Andrew Burgess

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87ee01hed4.fsf@redhat.com \
    --to=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.org \
    --cc=jhb@FreeBSD.org \
    --cc=luis.machado@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).