Skip to content

Conversation

@roddyrap
Copy link

Also regenerated the file, which is almost exactly the same.

brobecke and others added 30 commits May 26, 2024 08:57
Now that the GDB 15 branch has been created,
this commit bumps the version number in gdb/version.in to
15.0.90.DATE-git

For the record, the GDB 15 branch was created
from commit 3a624d9.
This is done by setting the "development" variable to "false"
in bfd/development.sh.
This commit changes the title of the section to refer to the actual
release version number, now that all changes listed are confirmed
to be part of the upcoming GDB 15 release.
This commit changes gdb/version.in to 15.0.90.
While preparing the new release it was discovered that commit:

  commit 824083f
  Date:   Fri Apr 12 17:47:20 2024 +0100

      gdb/doc: use silent-rules.mk in the Makefile

was causing problems.  Given a release tar file, an attempt to build
and install GDB would give an error like this:

  [...]
    TEXI2POD gdb.pod
  cannot find GDBvn.texi at ../../../gdb-15.0.50.20240508/gdb/doc/../../etc/texi2pod.pl line 251, <GEN0> line 16.
  make[5]: *** [Makefile:663: gdb.pod] Error 2

The problem here is how the man pages are built, and how they are
distributed within a release.

Within the development (git) tree, the man page files are not part of
the source tree, these files are built as needed.  Within a release
tar file though, the man pages are included.  The idea being that a
user can build and install GDB, including getting the man pages,
without having to install the tools needed to generate the man pages.

The man pages are generated in a two step process.  First the .texi
file is processed with texi2pod to create a .pod file, then this .pod
file is processed to create the .1 or .5 man file.

Prior to the above commit these two steps were combined into a single
recipe, this meant that when a user performed a build/install from a
release tree all of the dependencies, as well as the final result,
were all present in the source tree, and so nothing needed to be
rebuilt.

However, the above commit split the two steps apart.  Now we had a
separate rule for building the .pod files, and the .1/.5 man page
files depended on the relevant .pod file.

As the .pod files are not shipped in a GDB release, this meant that
one of the dependencies of the man page files was now missing.  As a
result if a user tried to install from a release tree a rebuild of the
.pod files would be attempted, and if that succeeded then building the
man pages would follow that.

Unfortunately, building the .pod files would fail as the GDBvn.texi
file, though present in the source tree, was not present in the build
tree, which is where it is needed for the .pod file generation to
work.

To fix this, I propose merging the .pod creation and the .1/.5 man
page creation back into a single recipe.  Having these two steps split
is probably the "cleaner" solution, but makes it harder for us to
achieve our goal of shipping the prebuilt man page files.  I've added
a comment explaining what's going on (such a comment would have
prevented this mistake having been made in the first place).

One possibly weird thing here is that I have left both an
ECHO_TEXI2POD and a ECHO_TEXI2MAN in the rule $(MAN1S) and $(MAN5S)
recipes.  This is 100% not going to break anything, these just print
two different progress messages while executing the recipes, but I'm
not sure if this is considered poor style or not.  Maybe we're only
supposed to have a single ECHO_* per recipe?

Anyway, even if this is poor style, I figure it really is just a style
thing.  We can tweak this later as needed.  Otherwise, this commit
should fix the current issue blocking the next GDB release.

Approved-By: Tom Tromey <tom@tromey.com>
This commit changes gdb/version.in to 15.0.91.
This commit changes gdb/version.in to 15.0.91.DATE-git.
In commit:

  commit 824083f
  Date:   Fri Apr 12 17:47:20 2024 +0100

      gdb/doc: use silent-rules.mk in the Makefile

I rewrote the rules for building the man pages.  While doing this I
accidentally switched from using MAN2POD5 to MAN2POD1 for generating
the file gdbinit.5.

Restore use of MAN2POD5 where appropriate.
The AArch64 MOPS (Memory Operation) instructions provide a standardised
instruction sequence to perform a memset, memcpy or memmove.  A sequence is
always composed of three instructions: a prologue instruction, a main
instruction and an epilogue instruction.  As an illustration, here are the
implementations of these memory operations in glibc 2.39:

  (gdb) disassemble/r
  Dump of assembler code for function __memset_mops:
  => 0x0000fffff7e8d780 <+0>:     d503201f        nop
     0x0000fffff7e8d784 <+4>:     aa0003e3        mov     x3, x0
     0x0000fffff7e8d788 <+8>:     19c10443        setp    [x3]!, x2!, x1
     0x0000fffff7e8d78c <+12>:    19c14443        setm    [x3]!, x2!, x1
     0x0000fffff7e8d790 <+16>:    19c18443        sete    [x3]!, x2!, x1
     0x0000fffff7e8d794 <+20>:    d65f03c0        ret
  End of assembler dump.

  (gdb) disassemble/r
  Dump of assembler code for function __memcpy_mops:
  => 0x0000fffff7e8c580 <+0>:     d503201f        nop
     0x0000fffff7e8c584 <+4>:     aa0003e3        mov     x3, x0
     0x0000fffff7e8c588 <+8>:     19010443        cpyfp   [x3]!, [x1]!, x2!
     0x0000fffff7e8c58c <+12>:    19410443        cpyfm   [x3]!, [x1]!, x2!
     0x0000fffff7e8c590 <+16>:    19810443        cpyfe   [x3]!, [x1]!, x2!
     0x0000fffff7e8c594 <+20>:    d65f03c0        ret
  End of assembler dump.

  (gdb) disassemble/r
  Dump of assembler code for function __memmove_mops:
  => 0x0000fffff7e8d180 <+0>:     d503201f        nop
     0x0000fffff7e8d184 <+4>:     aa0003e3        mov     x3, x0
     0x0000fffff7e8d188 <+8>:     1d010443        cpyp    [x3]!, [x1]!, x2!
     0x0000fffff7e8d18c <+12>:    1d410443        cpym    [x3]!, [x1]!, x2!
     0x0000fffff7e8d190 <+16>:    1d810443        cpye    [x3]!, [x1]!, x2!
     0x0000fffff7e8d194 <+20>:    d65f03c0        ret
  End of assembler dump.

The Arm Architecture Reference Manual says that "the prologue, main, and
epilogue instructions are expected to be run in succession and to appear
consecutively in memory".  Therefore this patch disables displaced stepping
on them.

The testcase verifies that MOPS sequences are correctly single-stepped.

PR tdep/31666
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31666
Approved-By: Luis Machado <luis.machado@arm.com>
Tested-By: Luis Machado <luis.machado@arm.com>

(cherry picked from commit b995344)
There are two kinds of MOPS instructions: set instructions and copy
instructions.  Within each group there are variants with minor
differences in how they read or write to memory — e.g., non-temporal
read and/or write, unprivileged read and/or write and permutations of
those — but they work in the same way in terms of the registers and
regions of memory that they modify.

The new gdb.reverse/aarch64-mops.exp testcase verifies that MOPS
instructions are recorded and correctly reversed.  Not all variants of the
copy and set instructions are tested, since there are many and the record
and replay target processes them in the same way.

PR tdep/31666
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31666
Approved-By: Luis Machado <luis.machado@arm.com>
Tested-By: Luis Machado <luis.machado@arm.com>

(cherry picked from commit ebd06ca)
Test behaviour of watchpoints triggered by MOPS instructions.  This test
is similar to gdb.base/memops-watchpoint.exp, but specifically for MOPS
instructions rather than whatever instructions are used in the libc's
implementation of memset/memcpy/memmove.

There's a separate watched variable for each set of instructions so that
the testcase can test whether GDB correctly identified the watchpoint
that triggered in each case.

Approved-By: Luis Machado <luis.machado@arm.com>
Tested-By: Luis Machado <luis.machado@arm.com>
(cherry picked from commit 55e3fcf)
See https://sourceware.org/pipermail/gdb-patches/2024-June/209726.html
for the details.

Approved-By: Tom Tromey <tom@tromey.com>
(cherry picked from commit e222ed2)
On macOS sonoma, printing a string would only print the first
character. For instance, if there was a 'const char *s = "foobar"',
then the 'print s' command would print '$1 = "f"' rather than the
expected '$1 = "foobar"'.

It seems that this is due to Apple silently replacing the version
of libiconv they ship with the OS to one which silently fails to
handle the 'outbytesleft' parameter correctly when using 'wchar_t'
as a target encoding.

This specifically causes issues when using iterating through a
string as wchar_iterator does.

This bug is visible even if you build for an old version of macOS,
but then run on Sonoma. Therefore this fix in the code applies
generally to macOS, and not specific to building on Sonoma. Building
for an older version and expecting forwards compatibility is a
common situation on macOS.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31853
Approved-By: Tom Tromey <tom@tromey.com>

(cherry picked from commit bb29817)
GDB Administrator and others added 22 commits September 16, 2024 00:00
With gdb 15.1, python sys.exit no longer makes gdb exit:
...
$ gdb -q -batch -ex "python sys.exit(2)" -ex "print 123"; echo $?
Python Exception <class 'SystemExit'>: 2
Error occurred in Python: 2
$1 = 123
0
...

This is a change in behaviour since commit a207f6b ("Rewrite "python"
command exception handling"), first available in gdb 15.1.

This patch reverts to the old behaviour by handling PyExc_SystemExit in
gdbpy_handle_exception, such what we have instead:
...
$ gdb -q -batch -ex "python sys.exit(2)" -ex "print 123"; echo $?
2
...

Tested on x86_64-linux, with python 3.6 and 3.13.

Tested-By: Guinevere Larsen <blarsen@redhat.com>
Approved-By: Tom Tromey <tom@tromey.com>

PR python/31946
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31946
This commit changes gdb/version.in to 15.2.
They are irrelevant since we are statically compiling and freezing all
of the required dependencies.
Python's freezing doesn't set up the __file__ variable, so we cannot
assume it exists and use it.
@roddyrap roddyrap closed this Jan 17, 2025
OriginCode pushed a commit to AOSC-Tracking/binutils-gdb that referenced this pull request Jan 18, 2025
On Windows gcore is not implemented, and if you try it, you get an
heap-use-after-free error:

(gdb) gcore C:/gdb/build64/gdb-git-python3/gdb/testsuite/outputs/gdb.base/gcore-buffer-overflow/gcore-buffer-overflow.test
warning: cannot close "=================================================================
==10108==ERROR: AddressSanitizer: heap-use-after-free on address 0x1259ea503110 at pc 0x7ff6806e3936 bp 0x0062e01ed990 sp 0x0062e01ed140
READ of size 111 at 0x1259ea503110 thread T0
    #0 0x7ff6806e3935 in strlen C:/gcc/src/gcc-14.2.0/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:391
    bminor#1 0x7ff6807169c4 in __pformat_puts C:/gcc/src/mingw-w64-v12.0.0/mingw-w64-crt/stdio/mingw_pformat.c:558
    bminor#2 0x7ff6807186c1 in __mingw_pformat C:/gcc/src/mingw-w64-v12.0.0/mingw-w64-crt/stdio/mingw_pformat.c:2514
    bminor#3 0x7ff680713614 in __mingw_vsnprintf C:/gcc/src/mingw-w64-v12.0.0/mingw-w64-crt/stdio/mingw_vsnprintf.c:41
    bminor#4 0x7ff67f34419f in vsnprintf(char*, unsigned long long, char const*, char*) C:/msys64/mingw64/x86_64-w64-mingw32/include/stdio.h:484
    bminor#5 0x7ff67f34419f in string_vprintf[abi:cxx11](char const*, char*) C:/gdb/src/gdb.git/gdbsupport/common-utils.cc:106
    bminor#6 0x7ff67b37b739 in cli_ui_out::do_message(ui_file_style const&, char const*, char*) C:/gdb/src/gdb.git/gdb/cli-out.c:227
    bminor#7 0x7ff67ce3d030 in ui_out::call_do_message(ui_file_style const&, char const*, ...) C:/gdb/src/gdb.git/gdb/ui-out.c:571
    bminor#8 0x7ff67ce4255a in ui_out::vmessage(ui_file_style const&, char const*, char*) C:/gdb/src/gdb.git/gdb/ui-out.c:740
    bminor#9 0x7ff67ce2c873 in ui_file::vprintf(char const*, char*) C:/gdb/src/gdb.git/gdb/ui-file.c:73
    bminor#10 0x7ff67ce7f83d in gdb_vprintf(ui_file*, char const*, char*) C:/gdb/src/gdb.git/gdb/utils.c:1881
    bminor#11 0x7ff67ce7f83d in vwarning(char const*, char*) C:/gdb/src/gdb.git/gdb/utils.c:181
    bminor#12 0x7ff67f3530eb in warning(char const*, ...) C:/gdb/src/gdb.git/gdbsupport/errors.cc:33
    bminor#13 0x7ff67baed27f in gdb_bfd_close_warning C:/gdb/src/gdb.git/gdb/gdb_bfd.c:437
    bminor#14 0x7ff67baed27f in gdb_bfd_close_or_warn C:/gdb/src/gdb.git/gdb/gdb_bfd.c:646
    bminor#15 0x7ff67baed27f in gdb_bfd_unref(bfd*) C:/gdb/src/gdb.git/gdb/gdb_bfd.c:739
    bminor#16 0x7ff68094b6f2 in gdb_bfd_ref_policy::decref(bfd*) C:/gdb/src/gdb.git/gdb/gdb_bfd.h:82
    bminor#17 0x7ff68094b6f2 in gdb::ref_ptr<bfd, gdb_bfd_ref_policy>::~ref_ptr() C:/gdb/src/gdb.git/gdbsupport/gdb_ref_ptr.h:91
    #18 0x7ff67badf4d2 in gcore_command C:/gdb/src/gdb.git/gdb/gcore.c:176

0x1259ea503110 is located 16 bytes inside of 4064-byte region [0x1259ea503100,0x1259ea5040e0)
freed by thread T0 here:
    #0 0x7ff6806b1687 in free C:/gcc/src/gcc-14.2.0/libsanitizer/asan/asan_malloc_win.cpp:90
    bminor#1 0x7ff67f2ae807 in objalloc_free C:/gdb/src/gdb.git/libiberty/objalloc.c:187
    bminor#2 0x7ff67d7f56e3 in _bfd_free_cached_info C:/gdb/src/gdb.git/bfd/opncls.c:247
    bminor#3 0x7ff67d7f2782 in _bfd_delete_bfd C:/gdb/src/gdb.git/bfd/opncls.c:180
    bminor#4 0x7ff67d7f5df9 in bfd_close_all_done C:/gdb/src/gdb.git/bfd/opncls.c:960
    bminor#5 0x7ff67d7f62ec in bfd_close C:/gdb/src/gdb.git/bfd/opncls.c:925
    bminor#6 0x7ff67baecd27 in gdb_bfd_close_or_warn C:/gdb/src/gdb.git/gdb/gdb_bfd.c:643
    bminor#7 0x7ff67baecd27 in gdb_bfd_unref(bfd*) C:/gdb/src/gdb.git/gdb/gdb_bfd.c:739
    bminor#8 0x7ff68094b6f2 in gdb_bfd_ref_policy::decref(bfd*) C:/gdb/src/gdb.git/gdb/gdb_bfd.h:82
    bminor#9 0x7ff68094b6f2 in gdb::ref_ptr<bfd, gdb_bfd_ref_policy>::~ref_ptr() C:/gdb/src/gdb.git/gdbsupport/gdb_ref_ptr.h:91
    bminor#10 0x7ff67badf4d2 in gcore_command C:/gdb/src/gdb.git/gdb/gcore.c:176

It happens because gdb_bfd_close_or_warn uses a bfd-internal name for
the failing-close warning, after the close is finished, and the name
already freed:

static int
gdb_bfd_close_or_warn (struct bfd *abfd)
{
  int ret;
  const char *name = bfd_get_filename (abfd);

  for (asection *sect : gdb_bfd_sections (abfd))
    free_one_bfd_section (sect);

  ret = bfd_close (abfd);

  if (!ret)
    gdb_bfd_close_warning (name,
			   bfd_errmsg (bfd_get_error ()));

  return ret;
}

Fixed by making a copy of the name for the warning.

Approved-By: Andrew Burgess <aburgess@redhat.com>
mikpe pushed a commit to mikpe/binutils-gdb that referenced this pull request Jun 9, 2025
I decided to try to build and test gdb on Windows.

I found a page on the wiki [1] suggesting three ways of building gdb:
- MinGW,
- MinGW on Cygwin, and
- Cygwin.

I picked Cygwin, because I've used it before (though not recently).

I managed to install Cygwin and sufficient packages to build gdb and start the
testsuite.

However, testsuite progress ground to a halt at gdb.base/branch-to-self.exp.
[ AFAICT, similar problems reported here [2]. ]

I managed to reproduce this hang by running just the test-case.

I attempted to kill the hanging processes by:
- first killing the inferior process, using the cygwin "kill -9" command, and
- then killing the gdb process, likewise.

But the gdb process remained, and I had to point-and-click my way through task
manager to actually kill the gdb process.

I investigated this by attaching to the hanging gdb process.  Looking at the
main thread, I saw it was stopped in a call to WaitForSingleObject, with
the dwMilliseconds parameter set to INFINITE.

The backtrace in more detail:
...
(gdb) bt
 #0  0x00007fff196fc044 in ntdll!ZwWaitForSingleObject () from
     /cygdrive/c/windows/SYSTEM32/ntdll.dll
 #1  0x00007fff16bbcdcf in WaitForSingleObjectEx () from
     /cygdrive/c/windows/System32/KERNELBASE.dll
 #2  0x0000000100998065 in wait_for_single (handle=0x1b8, howlong=4294967295) at
     gdb/windows-nat.c:435
 #3  0x0000000100999aa7 in
     windows_nat_target::do_synchronously(gdb::function_view<bool ()>)
       (this=this@entry=0xa001c6fe0, func=...) at gdb/windows-nat.c:487
 #4  0x000000010099a7fb in windows_nat_target::wait_for_debug_event_main_thread
     (event=<optimized out>, this=0xa001c6fe0)
     at gdb/../gdbsupport/function-view.h:296
 bminor#5  windows_nat_target::kill (this=0xa001c6fe0) at gdb/windows-nat.c:2917
 bminor#6  0x00000001008f2f86 in target_kill () at gdb/target.c:901
 bminor#7  0x000000010091fc46 in kill_or_detach (from_tty=0, inf=0xa000577d0)
     at gdb/top.c:1658
 bminor#8  quit_force (exit_arg=<optimized out>, from_tty=from_tty@entry=0)
     at gdb/top.c:1759
 bminor#9  0x00000001004f9ea8 in quit_command (args=args@entry=0x0,
     from_tty=from_tty@entry=0) at gdb/cli/cli-cmds.c:483
 bminor#10 0x000000010091c6d0 in quit_cover () at gdb/top.c:295
 bminor#11 0x00000001005e3d8a in async_disconnect (arg=<optimized out>)
     at gdb/event-top.c:1496
 bminor#12 0x0000000100499c45 in invoke_async_signal_handlers ()
     at gdb/async-event.c:233
 bminor#13 0x0000000100eb23d6 in gdb_do_one_event (mstimeout=mstimeout@entry=-1)
     at gdbsupport/event-loop.cc:198
 bminor#14 0x00000001006df94a in interp::do_one_event (mstimeout=-1,
     this=<optimized out>) at gdb/interps.h:87
 bminor#15 start_event_loop () at gdb/main.c:402
 bminor#16 captured_command_loop () at gdb/main.c:466
 bminor#17 0x00000001006e2865 in captured_main (data=0x7ffffcba0) at gdb/main.c:1346
 #18 gdb_main (args=args@entry=0x7ffffcc10) at gdb/main.c:1365
 #19 0x0000000100f98c70 in main (argc=10, argv=0xa000129f0) at gdb/gdb.c:38
...

In the docs [3], I read that using an INFINITE argument to WaitForSingleObject
might cause a system deadlock.

This prompted me to try this simple change in wait_for_single:
...
   while (true)
     {
-      DWORD r = WaitForSingleObject (handle, howlong);
+      DWORD r = WaitForSingleObject (handle,
+                                     howlong == INFINITE ? 100 : howlong);
+      if (howlong == INFINITE && r == WAIT_TIMEOUT)
+        continue;
...
with the timeout of 0.1 second estimated to be:
- small enough for gdb to feel reactive, and
- big enough not to consume too much cpu cycles with looping.

And indeed, the test-case, while still failing, now finishes in ~50 seconds.

While there may be an underlying bug that triggers this behaviour, the failure
mode is so severe that I consider it a bug in itself.

Fix this by avoiding calling WaitForSingleObject with INFINITE argument.

Tested on x86_64-cygwin, by running the testsuite past the test-case.

Approved-By: Pedro Alves <pedro@palves.net>

PR tdep/32894
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32894

[1] https://sourceware.org/gdb/wiki/BuildingOnWindows
[2] https://sourceware.org/pipermail/gdb-patches/2025-May/217949.html
[3] https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject
mikpe pushed a commit to mikpe/binutils-gdb that referenced this pull request Aug 31, 2025
For background, see this thread:

  https://inbox.sourceware.org/gdb-patches/20250612144607.27507-1-tdevries@suse.de

Tom describes the issue clearly in the above thread, here's what he
said:

  Once in a while, when running test-case gdb.base/bp-cmds-continue-ctrl-c.exp,
  I run into:
  ...
  Breakpoint 2, foo () at bp-cmds-continue-ctrl-c.c:23^M
  23        usleep (100);^M
  ^CFAIL: $exp: run: stop with control-c (unexpected) (timeout)
  FAIL: $exp: run: stop with control-c
  ...

  This is PR python/32167, observed both on x86_64-linux and powerpc64le-linux.

  This is not a timeout due to accidental slowness, gdb actually hangs.

  The backtrace at the hang is (on cfarm120 running AlmaLinux 9.6):
  ...
  (gdb) bt
   #0  0x00007fffbca9dd94 in __lll_lock_wait () from
       /lib64/glibc-hwcaps/power10/libc.so.6
   #1  0x00007fffbcaa6ddc in pthread_mutex_lock@@GLIBC_2.17 () from
       /lib64/glibc-hwcaps/power10/libc.so.6
   #2  0x000000001067aee8 in __gthread_mutex_lock ()
       at /usr/include/c++/11/ppc64le-redhat-linux/bits/gthr-default.h:749
   #3  0x000000001067afc8 in __gthread_recursive_mutex_lock ()
       at /usr/include/c++/11/ppc64le-redhat-linux/bits/gthr-default.h:811
   #4  0x000000001067b0d4 in std::recursive_mutex::lock ()
       at /usr/include/c++/11/mutex:108
   bminor#5  0x000000001067b380 in std::lock_guard<std::recursive_mutex>::lock_guard ()
       at /usr/include/c++/11/bits/std_mutex.h:229
   bminor#6  0x0000000010679d3c in set_quit_flag () at gdb/extension.c:865
   bminor#7  0x000000001066b6dc in handle_sigint () at gdb/event-top.c:1264
   bminor#8  0x00000000109e3b3c in handler_wrapper () at gdb/posix-hdep.c:70
   bminor#9  <signal handler called>
   bminor#10 0x00007fffbcaa6d14 in pthread_mutex_lock@@GLIBC_2.17 () from
       /lib64/glibc-hwcaps/power10/libc.so.6
   bminor#11 0x000000001067aee8 in __gthread_mutex_lock ()
       at /usr/include/c++/11/ppc64le-redhat-linux/bits/gthr-default.h:749
   bminor#12 0x000000001067afc8 in __gthread_recursive_mutex_lock ()
       at /usr/include/c++/11/ppc64le-redhat-linux/bits/gthr-default.h:811
   bminor#13 0x000000001067b0d4 in std::recursive_mutex::lock ()
       at /usr/include/c++/11/mutex:108
   bminor#14 0x000000001067b380 in std::lock_guard<std::recursive_mutex>::lock_guard ()
       at /usr/include/c++/11/bits/std_mutex.h:229
   bminor#15 0x00000000106799cc in set_active_ext_lang ()
       at gdb/extension.c:775
   bminor#16 0x0000000010b287ac in gdbpy_enter::gdbpy_enter ()
       at gdb/python/python.c:232
   bminor#17 0x0000000010a8e3f8 in bpfinishpy_handle_stop ()
       at gdb/python/py-finishbreakpoint.c:414
  ...

  What happens here is the following:
  - the gdbpy_enter constructor attempts to set the current extension language
    to python using set_active_ext_lang
  - set_active_ext_lang attempts to lock ext_lang_mutex
  - while doing so, it is interrupted by sigint_wrapper (the SIGINT handler),
    handling a SIGINT
  - sigint_wrapper calls handle_sigint, which calls set_quit_flag, which also
    tries to lock ext_lang_mutex
  - since std::recursive_mutex::lock is not async-signal-safe, things go wrong,
    resulting in a hang.

  The hang bisects to commit 8bb8f83 ("Fix gdb.interrupt race"), which
  introduced the lock, making PR python/32167 a regression since gdb 15.1.

  Commit 8bb8f83 fixes PR dap/31263, a race reported by ThreadSanitizer:
  ...
  WARNING: ThreadSanitizer: data race (pid=615372)

    Read of size 1 at 0x00000328064c by thread T19:
      #0 set_active_ext_lang(extension_language_defn const*) gdb/extension.c:755
      #1 scoped_disable_cooperative_sigint_handling::scoped_disable_cooperative_sigint_handling()
         gdb/extension.c:697
      #2 gdbpy_interrupt gdb/python/python.c:1106
      #3 cfunction_vectorcall_NOARGS <null>

    Previous write of size 1 at 0x00000328064c by main thread:
      #0 scoped_disable_cooperative_sigint_handling::scoped_disable_cooperative_sigint_handling()
         gdb/extension.c:704
      #1 fetch_inferior_event() gdb/infrun.c:4591
      ...

    Location is global 'cooperative_sigint_handling_disabled' of size 1 at 0x00000328064c

    ...

  SUMMARY: ThreadSanitizer: data race gdb/extension.c:755 in \
    set_active_ext_lang(extension_language_defn const*)
  ...

  The problem here is that gdb.interrupt is called from a worker thread, and its
  implementation, gdbpy_interrupt races with the main thread on some variable.

The fix presented here is based on the fix that Tom proposed, but
fills in the missing Mingw support.

The problem is basically split into two: hosts that support unix like
signals, and Mingw, which doesn't support signals.

For signal supporting hosts, I've adopted the approach that Tom
suggests, gdbpy_interrupt uses kill() to send SIGINT to the GDB
process.  This is then handled in the main thread as if the user had
pressed Ctrl+C.  For these hosts no locking is required, so the
existing lock is removed.  However, everywhere the lock currently
exists I've added an assert:

    gdb_assert (is_main_thread ());

If this assert ever triggers then we're setting or reading the quit
flag on a worker thread, this will be a problem without the mutex.

For Mingw, the current mutex is retained.  This is fine as there are
no signals, so no chance of the mutex acquisition being interrupted by
a signal, and so, deadlock shouldn't be an issue.

To manage the complexity of when we need an assert, and when we need
the mutex, I've created 'struct ext_lang_guard', which can be used as
a RAII object.  This object either performs the assertion check, or
acquires the mutex, depending on the host.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32167
Co-Authored-By: Tom de Vries <tdevries@suse.de>
Approved-By: Tom Tromey <tom@tromey.com>
cloudspurs pushed a commit to cloudspurs/binutils-gdb that referenced this pull request Sep 12, 2025
While reviewing and testing another patch I set a breakpoint on an
gnu ifunc function, then restarted the inferior, and this assert
triggered:

  ../../src/gdb/breakpoint.c:14747: internal-error: breakpoint_free_objfile: Assertion `loc->symtab == nullptr' failed.

The backtrace at the time of the assert is:

  bminor#6  0x00000000005ffee0 in breakpoint_free_objfile (objfile=0x4064b30) at ../../src/gdb/breakpoint.c:14747
  bminor#7  0x0000000000c33ff2 in objfile::~objfile (this=0x4064b30, __in_chrg=<optimized out>) at ../../src/gdb/objfiles.c:478
  bminor#8  0x0000000000c38da6 in std::default_delete<objfile>::operator() (this=0x7ffc1a49d538, __ptr=0x4064b30) at /usr/include/c++/9/bits/unique_ptr.h:81
  bminor#9  0x0000000000c3782a in std::unique_ptr<objfile, std::default_delete<objfile> >::~unique_ptr (this=0x7ffc1a49d538, __in_chrg=<optimized out>) at /usr/include/c++/9/bits/unique_ptr.h:292
  bminor#10 0x0000000000caf1bd in owning_intrusive_list<objfile, intrusive_base_node<objfile> >::erase (this=0x3790d68, i=...) at ../../src/gdb/../gdbsupport/owning_intrusive_list.h:111
  bminor#11 0x0000000000cacd0c in program_space::remove_objfile (this=0x3790c80, objfile=0x4064b30) at ../../src/gdb/progspace.c:192
  bminor#12 0x0000000000c33e1c in objfile::unlink (this=0x4064b30) at ../../src/gdb/objfiles.c:408
  bminor#13 0x0000000000c34fb9 in objfile_purge_solibs (pspace=0x3790c80) at ../../src/gdb/objfiles.c:729
  bminor#14 0x0000000000edf6f7 in no_shared_libraries (pspace=0x3790c80) at ../../src/gdb/solib.c:1359
  bminor#15 0x0000000000fb3f6c in target_pre_inferior () at ../../src/gdb/target.c:2466
  bminor#16 0x0000000000a724d7 in run_command_1 (args=0x0, from_tty=0, run_how=RUN_NORMAL) at ../../src/gdb/infcmd.c:390
  bminor#17 0x0000000000a72a97 in run_command (args=0x0, from_tty=0) at ../../src/gdb/infcmd.c:514
  #18 0x00000000006bbb3d in do_simple_func (args=0x0, from_tty=0, c=0x39124b0) at ../../src/gdb/cli/cli-decode.c:95
  #19 0x00000000006c1021 in cmd_func (cmd=0x39124b0, args=0x0, from_tty=0) at ../../src/gdb/cli/cli-decode.c:2827

The function breakpoint_free_objfile is being called when an objfile
representing a shared library is being unloaded ahead of the inferior
being restarted, the function is trying to remove references to
anything that could itself reference the objfile that is being
deleted.

The assert is making the claim that, for a bp_location, which has a
single address, the objfile of the symtab associated with the location
will be the same as the objfile associated with the section of the
location.

This seems reasonable to me now, as it did when I added the assert in
commit:

  commit 5066f36
  Date:   Mon Nov 11 21:45:17 2024 +0000

      gdb: do better in breakpoint_free_objfile

The bp_location::section is maintained, according to the comments in
breakpoint.h, to aid overlay debugging (is that even used any more),
and looking at the code, this does appear to be the case.

The problem in the above case arises when we are dealing with an ifunc
function.  What happens is that we end up with a section from one
objfile, but a symtab from a different objfile.

This problem originates from minsym_found (in linespec.c).  The user
asked for 'break gnu_ifunc' where 'gnu_ifunc' is an ifunc function.
What this means is that gnu_ifunc is actually a resolver function that
returns the address of the actual function to use.

In this particular test case, the resolver function is in a shared
library, and the actual function to use is in the main executable.

So, when GDB looks for 'gnu_ifunc' is finds the minimal_symbol with
that name, and spots that this has type mst_text_gnu_ifunc.  GDB then
uses this to figure out the actual address of the function that will
be run.

GDB then creates the symtab_and_line using the _real_ address and the
symtab in which that address lies, in our case this will all be
related to the main executable objfile.

But, finally, in minsym_found, GDB fills in the symtab_and_line's
section field, and this is done using the section containing the
original minimal_symbol, which is from the shared library objfile.

The minimal symbol and section are then use to initialise the
bp_location object, and this is how we end up in, what I think, is an
unexpected state.

So what to do about this?

The symtab_and_line::msymbol field is _only_ set within minsym_found,
and is then _only_ used to initialise the bp_location::msymbol field.

The bp_location::msymbol field is _only_ used in the function
set_breakpoint_location_function, and we only really care about the
msymbol type, we check to see if it's an ifunc symbol or not.  This
allows us to set the name of the function correctly.

The bp_location::section is used, as far as I can tell, extensively
for overlay handling.  It would seem to me, that this section should
be the section containing the actual breakpoint address.  If the
question we're asking is, is this breakpoint mapped in or not?  Then
surely we need to ask about the section holding the breakpoint's
address, and not the section holding some other code (e.g. the
resolver function).  In fact, in a memory constrained environment,
you'd expect the resolver functions to get mapped out pretty early on,
but while the actual functions might still be mapped in.

Finally, symtab_and_line::section.  This is mostly set using calls to
find_pc_overlay.  The minsym_found function is one of the few places
where we do things differently.  In the places where the section is
used, it is (almost?) always used in conjunction with the
symtab_and_line::pc to lookup information, e.g. calls to
block_for_pc_sect, or find_pc_sect_containing_function.  In all these
cases, it appears to me that the assumption is that the section will
be the section that contains the address.

So, where does this leave us?

I think what we need to do is update minsym_found to just use
find_pc_overlay, which is how the symtab_and_line::section is set in
most other cases.  What this actually means in practise is that the
section field will be set to NULL (see find_pc_overlay in symfile.c).
But given that this is how the section is computed in most other
cases, I don't see why it should be especially problematic for this
case.  In reality, I think this just means that the section is
calculated via a call to find_pc_section when it's needed, as an
example, see lookup_minimal_symbol_by_pc_section (minsyms.c).

I do wonder if we should be doing better when creating the
symtab_and_line, and insist that the section be calculated correctly
at that point, but I really don't want to open that can of worms right
now, so I think just changing minsym_found to "do it just like
everyone else" should be good enough.

I've extended the existing ifunc test to expose this issue, the
updated test fails without this patch, and passes with.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
mikpe pushed a commit to mikpe/binutils-gdb that referenced this pull request Sep 14, 2025
This patch proposes a fix for PR gdb/33147.  The bug can be reproduced
like this:

  gdb -q -ex 'file /bin/ls' \
         -ex 'run &' \
	 -ex 'add-inferior' \
	 -ex 'infer 2' \
	 -ex 'set sysroot' \
	 -ex 'target remote | gdbserver - ls'

Which will trigger an assertion failure:

  target.c:3760: internal-error: target_stop: Assertion `!proc_target->commit_resumed_state' failed.

The problem is that target_stop is being called for a target when
commit_resumed_state is true, the comment on
process_stratum_target::commit_resumed_state is pretty clear:

  To simplify the implementation of targets, the following methods
  are guaranteed to be called with COMMIT_RESUMED_STATE set to
  false:

     - resume
     - stop
     - wait

So clearly we're breaking a precondition of target_stop.  In this
example there are two target, the native target (inferior 1), and the
remote target (inferior 2).  It is the first, the native target, for
which commit_resumed_state is set incorrectly.

At the point target_stop is called looks like this:

  bminor#11 0x00000000009a3c19 in target_stop (ptid=...) at ../../src/gdb/target.c:3760
  bminor#12 target_stop (ptid=...) at ../../src/gdb/target.c:3756
  bminor#13 0x00000000007042f2 in stop_all_threads (reason=<optimized out>, inf=<optimized out>) at ../../src/gdb/infrun.c:5739
  bminor#14 0x0000000000711d3a in wait_for_inferior (inf=0x2b90fd0) at ../../src/gdb/infrun.c:4412
  bminor#15 start_remote (from_tty=from_tty@entry=1) at ../../src/gdb/infrun.c:3829
  bminor#16 0x0000000000897014 in remote_target::start_remote_1 (this=this@entry=0x2c4a520, from_tty=from_tty@entry=1, extended_p=extended_p@entry=0) at ../../src/gdb/remote.c:5350
  bminor#17 0x00000000008976e7 in remote_target::start_remote (extended_p=0, from_tty=1, this=0x2c4a520) at ../../src/gdb/remote.c:5441
  #18 remote_target::open_1 (name=<optimized out>, from_tty=1, extended_p=0) at ../../src/gdb/remote.c:6312
  #19 0x00000000009a815f in open_target (args=0x7fffffffa93c "| gdbserver - ls", from_tty=1, command=<optimized out>) at ../../src/gdb/target.c:838

For new inferiors commit_resumed_state starts set to false, for this
reason, if we only start a remote inferior, then when
wait_for_inferior is called commit_resumed_state will be false, and
everything will work.

Further, as target_stop is only called for running threads, if, when
the remote inferior is started, all other threads (in other targets)
are already stopped, then GDB will never need to call target_stop for
the other targets, and so GDB will not notice that
commit_resumed_state for those target is set to true.

In this case though, as the first (native) inferior is left running in
the background while the remote inferior is created, and because GDB
is running in all-stop mode (so needs to stop all threads in all
targets), then GDB does call target_stop for the other targets, and so
spots that commit_resumed_state is not set correctly and asserts.

The fix is to add scoped_disable_commit_resumed somewhere in the call
stack.  Initially I planned to add the scoped_disable_commit_resumed
in `wait_for_inferior`, however, this isn't good enough.  This
location would solve the problem as described in the bug, but when
writing the test I extended the problem to also cover non-stop mode,
and this runs into a second problem, the same assertion, but triggered
from a different call path.  For this new case the stack looks like
this:

  #1  0x0000000000fb0e50 in target_stop (ptid=...) at ../../src/gdb/target.c:3771
  #2  0x0000000000a7f0ae in stop_all_threads (reason=0x1d0ff74 "remote connect in all-stop", inf=0x0) at ../../src/gdb/infrun.c:5756
  #3  0x0000000000d9c028 in remote_target::process_initial_stop_replies (this=0x3e10670, from_tty=1) at ../../src/gdb/remote.c:5017
  #4  0x0000000000d9cdf0 in remote_target::start_remote_1 (this=0x3e10670, from_tty=1, extended_p=0) at ../../src/gdb/remote.c:5405
  bminor#5  0x0000000000d9d0d4 in remote_target::start_remote (this=0x3e10670, from_tty=1, extended_p=0) at ../../src/gdb/remote.c:5457
  bminor#6  0x0000000000d9e8ac in remote_target::open_1 (name=0x7fffffffa931 "| gdbserver - /bin/ls", from_tty=1, extended_p=0) at ../../src/gdb/remote.c:6329
  bminor#7  0x0000000000d9d167 in remote_target::open (name=0x7fffffffa931 "| gdbserver - /bin/ls", from_tty=1) at ../../src/gdb/remote.c:5479
  bminor#8  0x0000000000f9914d in open_target (args=0x7fffffffa931 "| gdbserver - /bin/ls", from_tty=1, command=0x35d1a40) at ../../src/gdb/target.c:838

So I'm now thinking that stop_all_threads would be the best place for
the scoped_disable_commit_resumed.  I did leave an assert in
wait_for_inferior as, having thought about the assert some, I do still
think the logic of it is true, and it doesn't hurt to leave it in
place I think.

However, it's not quite that simple, the test throws up yet another
bug when we 'maint set target-non-stop on', but then 'set non-stop
off'.  This bug leaves a stopped thread marked as "(running)" in the
'info threads' output.  I have a fix for this issue, but I'm leaving
that for the next commit.  For now I've just disabled part of the test
in the problem case.

I've also tagged this patch with PR gdb/27322.  That bug was created
before the above assert was added, but if you follow the steps to
reproduce for that bug today you will hit the above assert.  The
actual issue described in PR gdb/27322 is fixed in the next patch.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=27322
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33147
seantywork pushed a commit to seantywork/binutils-gdb that referenced this pull request Sep 25, 2025
A bug was reported to Red Hat where GDB was crashing with an assertion
failure, the assertion message is:

  ../../gdb/regcache.c:432: internal-error: get_thread_regcache: Assertion `thread->state != THREAD_EXITED' failed.

The backtrace for the crash is:

  bminor#5  0x000055a21da8a880 in internal_vproblem(internal_problem *, const char *, int, const char *, typedef __va_list_tag __va_list_tag *) (problem=problem@entry=0x55a21e289060 <internal_error_problem>, file=<optimized out>, line=<optimized out>, fmt=<optimized out>, ap=ap@entry=0x7ffec7576be0) at ../../gdb/utils.c:477
  bminor#6  0x000055a21da8aadf in internal_verror (file=<optimized out>, line=<optimized out>, fmt=<optimized out>, ap=ap@entry=0x7ffec7576be0) at ../../gdb/utils.c:503
  bminor#7  0x000055a21dcbd055 in internal_error_loc (file=file@entry=0x55a21dd33b71 "../../gdb/regcache.c", line=line@entry=432, fmt=<optimized out>) at ../../gdbsupport/errors.cc:57
  bminor#8  0x000055a21d8baaa9 in get_thread_regcache (thread=thread@entry=0x55a258de3a50) at ../../gdb/regcache.c:432
  bminor#9  0x000055a21d74fa18 in print_signal_received_reason (uiout=0x55a258b649b0, siggnal=GDB_SIGNAL_TRAP) at ../../gdb/infrun.c:9287
  bminor#10 0x000055a21d7daad9 in mi_interp::on_signal_received (this=0x55a258af5f60, siggnal=GDB_SIGNAL_TRAP) at ../../gdb/mi/mi-interp.c:372
  bminor#11 0x000055a21d76ef99 in interps_notify<void (interp::*)(gdb_signal), gdb_signal&> (method=&virtual table offset 88, this adjustment 974682) at ../../gdb/interps.c:369
  bminor#12 0x000055a21d76e58f in interps_notify_signal_received (sig=<optimized out>, sig@entry=GDB_SIGNAL_TRAP) at ../../gdb/interps.c:378
  bminor#13 0x000055a21d75074d in notify_signal_received (sig=GDB_SIGNAL_TRAP) at ../../gdb/infrun.c:6818
  bminor#14 0x000055a21d755af0 in normal_stop () at ../../gdb/gdbthread.h:432
  bminor#15 0x000055a21d768331 in fetch_inferior_event () at ../../gdb/infrun.c:4753

The user is using a build of GDB with 32-bit ARM support included, and
they gave the following description for what they were doing at the
time of the crash:

  Suspended the execution of the firmware in Eclipse.  The gdb was
  connected to JLinkGDBServer with activated FreeRTOS awareness JLink
  plugin.

So they are remote debugging with a non-gdbserver target.

Looking in normal_stop() we see this code:

  /* As we're presenting a stop, and potentially removing breakpoints,
     update the thread list so we can tell whether there are threads
     running on the target.  With target remote, for example, we can
     only learn about new threads when we explicitly update the thread
     list.  Do this before notifying the interpreters about signal
     stops, end of stepping ranges, etc., so that the "new thread"
     output is emitted before e.g., "Program received signal FOO",
     instead of after.  */
  update_thread_list ();

  if (last.kind () == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
    notify_signal_received (inferior_thread ()->stop_signal ());

Which accounts for the transition from frame bminor#14 to frame bminor#13.  But it
is the update_thread_list() call which interests me.  This call asks
the target (remote target in this case) for the current thread list,
and then marks threads exited based on the answer.

And so, if a (badly behaved) target (incorrectly) removes a thread
from the thread list, then the update_thread_list() call will mark the
impacted thread as exited, even if GDB is currently handling a signal
stop event for that target.

My guess for what's going on here then is this:

  1. Thread receives a signal.
  2. Remote target sends GDB a stop with signal packet.
  3. Remote decides that the thread is going away soon, and marks the
     thread as exited.
  4. GDB asks for the thread list.
  5. Remote sends back the thread list, which doesn't include the
     event thread, as the remote things this thread has exited.
  6. GDB marks the thread as exited, and then proceeds to try and
     print the signal stop event for the event thread.
  7. Printing the signal stop requires reading registers, which
     requires a regache.  We can only get a regcache for a non-exited
     thread, and so GDB raises an assertion.

Using the gdbreplay test frame work I was able to reproduce this
failure using gdbserver.  I create an inferior with two threads, the
main thread sends a signal to the second thread, GDB sees the signal
arrive and prints this information for the user.

Having captured the trace of this activity, I then find the thread
list reply in the log file, and modify it to remove the second thread.

Now, when I replay the modified log file I see the same assertion
complaining about an attempt to get a regcache for an exited thread.

I'm not entirely sure the best way to fix this.  Clearly the problem
here is a bad remote target.  But, replies from a remote target
should (in my opinion) not be considered trusted, as a consequence, we
should not be asserting based on data coming from a remote.  Instead,
we should be giving warnings or errors and have GDB handle the bad
data as best it can.

This is the second attempt to fix this issue, my first patch can be
seen here:

  https://inbox.sourceware.org/gdb-patches/062e438c8677e2ab28fac6183d2ea6d444cb9121.1747567717.git.aburgess@redhat.com

In the first patch I was to checking in normal_stop, immediately after
the call to update_thread_list, to see if the current thread was now
marked as exited.  However CI testing showed an issue with this
approach; I was already checking for many different TARGET_WAITKIND_*
kinds where the "is the current thread exited" question didn't make
sense, and it turns out that the list of kinds in my first attempt was
already insufficient.

Rather than trying to just adding to the list, in this revised patch
I'm proposing to move the "is this thread exited" check inside the
block which handles signal stop events.

Right now, the only part of normal_stop which I know relies on the
current thread not being exited is the call to notify_signal_received,
so before calling notify_signal_received I check to see if the current
thread is now exited.  If it is then I print a warning to indicate
that the thread has unexpectedly exited and that the current
command (continue/step/etc) has been cancelled, I then change the
current event type to TARGET_WAITKIND_SPURIOUS.

GDB's output now looks like this in all-stop mode:

  (gdb) continue
  Continuing.
  [New Thread 3483690.3483693]
  [Thread 3483690.3483693 exited]
  warning: Thread 3483690.3483693 unexpectedly exited after non-exit event
  [Switching to Thread 3483690.3483693]
  (gdb)

The non-stop output is identical, except we don't switch thread (stop
events never trigger a thread switch in non-stop mode).

The include test makes use of the gdbreplay framework, and tests in
all-stop and non-stop modes.  I would like to do more extensive
testing of GDB's state after the receiving the unexpected thread list,
but due to using gdbreplay for testing, this is quite hard.  Many
commands, especially those looking at thread state, are likely to
trigger additional packets being sent to the remote, which causes
gdbreplay to bail out as the new packet doesn't match the original
recorded state.  However, I really don't think it is a good idea to
change gdbserver in order to "fake" this error case, so for now, using
gdbreplay is the best idea I have.

Bug: https://bugzilla.redhat.com/show_bug.cgi?id=2366461
eyalitki pushed a commit to eyalitki/binutils-gdb that referenced this pull request Oct 4, 2025
PR gdb/33512 reports an assertion failure in test-case
gdb.ada/access_to_packed_array.exp on i386-linux:
...
(gdb) maint print symbols
gdb/frame.c:3400: internal-error: reinflate: \
  Assertion `m_cached_level >= -1' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) FAIL: $exp: \
  maint print symbols (GDB internal error)
...

I haven't been able to reproduce the failure by running the test-case on
x86_64-linux with target board unix/-m32, but I'm able to reproduce on
x86_64-linux by using the exec attached to the PR:
...
$ cat gdb.in
file foo
maint expand-symtabs
maint print symbols
$ gdb -q -batch -ex "set trace-commands on" -x gdb.in
   ...
         c_to: array (gdb/frame.c:3395: internal-error: reinflate: \
	                Assertion `m_cached_level >= -1' failed.
...

The problem happens when trying to print variable c_to:
...
 <4><f227>: Abbrev Number: 3 (DW_TAG_variable)
    <f228>   DW_AT_name        : c_to
    <f230>   DW_AT_type        : <0xf214>
...
with type:
...
 <4><f214>: Abbrev Number: 7 (DW_TAG_array_type)
    <f215>   DW_AT_type        : <0x9f39>
 <5><f21d>: Abbrev Number: 12 (DW_TAG_subrange_type)
    <f21e>   DW_AT_type        : <0x9d6c>
    <f222>   DW_AT_upper_bound : <0xf209>
...
with upper bound:
...
 <4><f209>: Abbrev Number: 89 (DW_TAG_variable)
    <f20a>   DW_AT_name        : system__os_lib__copy_file__copy_to__TTc_toSP1___U
    <f20e>   DW_AT_type        : <0x9d6c>
    <f212>   DW_AT_artificial  : 1
    <f212>   DW_AT_location    : 1 byte block: 57       (DW_OP_reg7 (edi))
...

The backtrace at the point of the assertion failure is:
...
 (gdb) bt
 #0  __pthread_kill_implementation (threadid=<optimized out>,
     signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
 bminor#1  0x00007ffff62a8e7f in __pthread_kill_internal (signo=6,
     threadid=<optimized out>) at pthread_kill.c:78
 bminor#2  0x00007ffff6257842 in __GI_raise (sig=sig@entry=6)
     at ../sysdeps/posix/raise.c:26
 bminor#3  0x00007ffff623f5cf in __GI_abort () at abort.c:79
 bminor#4  0x00000000010e7ac6 in dump_core () at gdb/utils.c:223
 bminor#5  0x00000000010e81b8 in internal_vproblem(internal_problem *, const char *, int, const char *, typedef __va_list_tag __va_list_tag *) (
     problem=0x2ceb0c0 <internal_error_problem>,
     file=0x1ad5a90 "gdb/frame.c", line=3395,
     fmt=0x1ad5a08 "%s: Assertion `%s' failed.", ap=0x7fffffffc3c0)
     at gdb/utils.c:475
 bminor#6  0x00000000010e82ac in internal_verror (
     file=0x1ad5a90 "gdb/frame.c", line=3395,
     fmt=0x1ad5a08 "%s: Assertion `%s' failed.", ap=0x7fffffffc3c0)
     at gdb/utils.c:501
 bminor#7  0x00000000019be79f in internal_error_loc (
     file=0x1ad5a90 "gdb/frame.c", line=3395,
     fmt=0x1ad5a08 "%s: Assertion `%s' failed.")
     at gdbsupport/errors.cc:57
 bminor#8  0x00000000009b5c16 in frame_info_ptr::reinflate (this=0x7fffffffc878)
     at gdb/frame.c:3395
 bminor#9  0x00000000009b66f9 in frame_info_ptr::operator-> (this=0x7fffffffc878)
     at gdb/frame.h:290
 bminor#10 0x00000000009b4bd5 in get_frame_arch (this_frame=...)
     at gdb/frame.c:3075
 bminor#11 0x000000000081dd89 in dwarf_expr_context::fetch_result (
     this=0x7fffffffc810, type=0x410d600, subobj_type=0x410d600,
     subobj_offset=0, as_lval=true)
     at gdb/dwarf2/expr.c:1006
 bminor#12 0x000000000081e2ef in dwarf_expr_context::evaluate (this=0x7fffffffc810,
     addr=0x7ffff459ce6b "W\aF\003", len=1, as_lval=true,
     per_cu=0x7fffd00053f0, frame=..., addr_info=0x7fffffffcc30, type=0x0,
     subobj_type=0x0, subobj_offset=0)
     at gdb/dwarf2/expr.c:1136
 bminor#13 0x0000000000877c14 in dwarf2_locexpr_baton_eval (dlbaton=0x3e99c18,
     frame=..., addr_stack=0x7fffffffcc30, valp=0x7fffffffcab0,
     push_values=..., is_reference=0x7fffffffc9b0)
     at gdb/dwarf2/loc.c:1604
 bminor#14 0x0000000000877f71 in dwarf2_evaluate_property (prop=0x3e99ce0,
     initial_frame=..., addr_stack=0x7fffffffcc30, value=0x7fffffffcab0,
     push_values=...) at gdb/dwarf2/loc.c:1668
 bminor#15 0x00000000009def76 in resolve_dynamic_range (dyn_range_type=0x3e99c50,
     addr_stack=0x7fffffffcc30, frame=..., rank=0, resolve_p=true)
     at gdb/gdbtypes.c:2198
 bminor#16 0x00000000009e0ded in resolve_dynamic_type_internal (type=0x3e99c50,
     addr_stack=0x7fffffffcc30, frame=..., top_level=true)
     at gdb/gdbtypes.c:2934
 bminor#17 0x00000000009e1079 in resolve_dynamic_type (type=0x3e99c50, valaddr=...,
     addr=0, in_frame=0x0) at gdb/gdbtypes.c:2989
 #18 0x0000000000488ebc in ada_discrete_type_low_bound (type=0x3e99c50)
     at gdb/ada-lang.c:710
 #19 0x00000000004eb734 in print_range (type=0x3e99c50, stream=0x30157b0,
     bounds_preferred_p=0) at gdb/ada-typeprint.c:156
 #20 0x00000000004ebffe in print_array_type (type=0x3e99d10, stream=0x30157b0,
     show=1, level=9, flags=0x1bdcf20 <type_print_raw_options>)
     at gdb/ada-typeprint.c:381
 #21 0x00000000004eda3c in ada_print_type (type0=0x3e99d10,
     varstring=0x401f710 "c_to", stream=0x30157b0, show=1, level=9,
     flags=0x1bdcf20 <type_print_raw_options>)
     at gdb/ada-typeprint.c:1015
 #22 0x00000000004b4627 in ada_language::print_type (
     this=0x2f949b0 <ada_language_defn>, type=0x3e99d10,
     varstring=0x401f710 "c_to", stream=0x30157b0, show=1, level=9,
     flags=0x1bdcf20 <type_print_raw_options>)
     at gdb/ada-lang.c:13681
 #23 0x0000000000f74646 in print_symbol (gdbarch=0x3256270, symbol=0x3e99db0,
     depth=9, outfile=0x30157b0) at gdb/symmisc.c:545
 #24 0x0000000000f737e6 in dump_symtab_1 (symtab=0x3ddd7e0, outfile=0x30157b0)
     at gdb/symmisc.c:313
 #25 0x0000000000f73a69 in dump_symtab (symtab=0x3ddd7e0, outfile=0x30157b0)
     at gdb/symmisc.c:370
 #26 0x0000000000f7420f in maintenance_print_symbols (args=0x0, from_tty=0)
     at gdb/symmisc.c:481
 #27 0x00000000006c7fde in do_simple_func (args=0x0, from_tty=0, c=0x321e270)
     at gdb/cli/cli-decode.c:94
 #28 0x00000000006ce65a in cmd_func (cmd=0x321e270, args=0x0, from_tty=0)
     at gdb/cli/cli-decode.c:2826
 #29 0x0000000001005b78 in execute_command (p=0x3f48fe3 "", from_tty=0)
     at gdb/top.c:564
 #30 0x0000000000966095 in command_handler (
     command=0x3f48fd0 "maint print symbols")
     at gdb/event-top.c:613
 #31 0x0000000001005141 in read_command_file (stream=0x3011a40)
     at gdb/top.c:333
 #32 0x00000000006e2a64 in script_from_file (stream=0x3011a40,
     file=0x7fffffffe21f "gdb.in")
     at gdb/cli/cli-script.c:1705
 #33 0x00000000006bb88c in source_script_from_stream (stream=0x3011a40,
     file=0x7fffffffe21f "gdb.in", file_to_open=0x7fffffffd760 "gdb.in")
     at gdb/cli/cli-cmds.c:706
 #34 0x00000000006bba12 in source_script_with_search (
     file=0x7fffffffe21f "gdb.in", from_tty=0, search_path=0)
     at gdb/cli/cli-cmds.c:751
 #35 0x00000000006bbab2 in source_script (file=0x7fffffffe21f "gdb.in",
     from_tty=0) at gdb/cli/cli-cmds.c:760
 #36 0x0000000000b835cb in catch_command_errors (
     command=0x6bba7e <source_script(char const*, int)>,
     arg=0x7fffffffe21f "gdb.in", from_tty=0, do_bp_actions=false)
     at gdb/main.c:510
 #37 0x0000000000b83803 in execute_cmdargs (cmdarg_vec=0x7fffffffd980,
     file_type=CMDARG_FILE, cmd_type=CMDARG_COMMAND, ret=0x7fffffffd8c8)
     at gdb/main.c:606
 #38 0x0000000000b84d79 in captured_main_1 (context=0x7fffffffdb90)
     at gdb/main.c:1349
 #39 0x0000000000b84fe4 in captured_main (context=0x7fffffffdb90)
     at gdb/main.c:1372
 #40 0x0000000000b85092 in gdb_main (args=0x7fffffffdb90)
     at gdb/main.c:1401
 #41 0x000000000041a382 in main (argc=9, argv=0x7fffffffdcc8)
     at gdb/gdb.c:38
 (gdb)
...

The immediate problem is in dwarf_expr_context::fetch_result where we're
calling get_frame_arch:
...
      switch (this->m_location)
	{
	case DWARF_VALUE_REGISTER:
	  {
	    gdbarch *f_arch = get_frame_arch (this->m_frame);
...
with a null frame:
...
(gdb) p this->m_frame.is_null ()
$1 = true
(gdb)
...

Fix this using ensure_have_frame in dwarf_expr_context::execute_stack_op for
DW_OP_reg<n> and DW_OP_regx, getting us instead:
...
         c_to: array (<>) of character; computed at runtime
...

Tested on x86_64-linux.

Approved-By: Tom Tromey <tom@tromey.com>

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33512
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.