Downstream, AMD is carrying a testcase
(gdb.rocm/continue-over-kernel-exit.exp) that exposes a couple issues
with the amd-dbgapi target's handling of exited threads. The test
can't be added upstream yet, unfortunately, due to dependency on DWARF
extensions that can't be upstreamed yet. However, it can be found on
the mailing list on the same series as this patch.
The test spawns a kernel with a number of waves. The waves do nothing
but exit. There is a breakpoint on the s_endpgm instruction. Once
that breakpoint is hit, the test issues a "continue" command. We
should see one breakpoint hit per wave, and then the whole program
exiting. We do see that, however we also see this:
[New AMDGPU Wave ?:?:?:1 (?,?,?)/?]
[AMDGPU Wave ?:?:?:1 (?,?,?)/? exited]
*repeat for other waves*
...
[Thread 0x7ffff626f640 (LWP 3048491) exited]
[Thread 0x7fffeb7ff640 (LWP 3048488) exited]
[Inferior 1 (process 3048475) exited normally]
That "New AMDGPU Wave" output comes from infrun.c itself adding the
thread to the GDB thread list, because it got an event for a thread
not on the thread list yet. The output shows "?"s instead of proper
coordinates, because the event was a TARGET_WAITKIND_THREAD_EXITED,
i.e., the wave was already gone when infrun.c added the thread to the
thread list.
That shouldn't ever happen for the amd-dbgapi target, threads should
only ever be added by the backend.
Note "New AMDGPU Wave ?:?:?:1" is for wave 1. What happened was that
wave 1 terminated previously, and a previous call to
amd_dbgapi_target::update_thread_list() noticed the wave had vanished
and removed it from the GDB thread list. However, because the wave
was stepping when it terminated (due to the displaced step over the
s_endpgm) instruction, it is guaranteed that the amd-dbgapi library
queues a WAVE_COMMAND_TERMINATED event for the exit.
When we process that WAVE_COMMAND_TERMINATED event, in
amd-dbgapi-target.c:process_one_event, we return it to the core as a
TARGET_WAITKIND_THREAD_EXITED event:
static void
process_one_event (amd_dbgapi_event_id_t event_id,
amd_dbgapi_event_kind_t event_kind)
{
...
if (status == AMD_DBGAPI_STATUS_ERROR_INVALID_WAVE_ID
&& event_kind == AMD_DBGAPI_EVENT_KIND_WAVE_COMMAND_TERMINATED)
ws.set_thread_exited (0);
...
}
Recall the wave is already gone from the GDB thread list. So when GDB
sees that TARGET_WAITKIND_THREAD_EXITED event for a thread it doesn't
know about, it adds the thread to the thread list, resulting in that:
[New AMDGPU Wave ?:?:?:1 (?,?,?)/?]
and then, because it was a TARGET_WAITKIND_THREAD_EXITED event, GDB
marks the thread exited right afterwards:
[AMDGPU Wave ?:?:?:1 (?,?,?)/? exited]
The fix is to make amd_dbgapi_target::update_thread_list() _not_
delete vanishing waves iff they were stepping or in progress of being
stopped. These two cases are the ones dbgapi guarantees will result
in a WAVE_COMMAND_TERMINATED event if the wave terminates:
/**
* A command for a wave was not able to complete because the wave has
* terminated.
*
* Commands that can result in this event are ::amd_dbgapi_wave_stop and
* ::amd_dbgapi_wave_resume in single step mode. Since the wave terminated
* before stopping, this event will be reported instead of
* ::AMD_DBGAPI_EVENT_KIND_WAVE_STOP.
*
* The wave that terminated is available by the ::AMD_DBGAPI_EVENT_INFO_WAVE
* query. However, the wave will be invalid since it has already terminated.
* It is the client's responsibility to know what command was being performed
* and was unable to complete due to the wave terminating.
*/
AMD_DBGAPI_EVENT_KIND_WAVE_COMMAND_TERMINATED = 2,
As the comment says, it's GDB's responsability to know whether the
wave was stepping or being stopped. Since we now have a wave_info map
with one entry for each wave, that seems like the place to store that
information. However, I still decided to put all the coordinate
information in its own structure. I.e., basically renamed the
existing wave_info to wave_coordinates, and then added a new wave_info
structure that holds the new state, plus a wave_coordinates object.
This seemed cleaner as there are places where we only need to
instantiate a wave_coordinates object.
There's an extra twist. The testcase also exercises stopping at a new
kernel right after the first kernel fully exits. In that scenario, we
were hitting this assertion after the first kernel fully exits and the
hit of the breakpoint at the second kernel is handled:
[amd-dbgapi] process_event_queue: Pulled event from dbgapi: event_id.handle = 26, event_kind = WAVE_STOP
[amd-dbgapi-lib] suspending queue_3, queue_2, queue_1 (refresh wave list)
../../src/gdb/amd-dbgapi-target.c:1625: internal-error: amd_dbgapi_thread_deleted: Assertion `it != info->wave_info_map.end ()' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
This is the exact same problem as above, just a different
manifestation. In this scenario, we end up in update_thread_list
successfully deleting the exited thread (because it was no longer the
current thread) that was incorrectly added by infrun.c. Because it
was added by infrun.c and not by amd-dbgapi-target.c:add_gpu_thread,
it doesn't have an entry in the wave_info map, so
amd_dbgapi_thread_deleted trips on this assertion:
gdb_assert (it != info->wave_info_map.end ());
here:
...
-> stop_all_threads
-> update_thread_list
-> target_update_thread_list
-> amd_dbgapi_target::update_thread_list
-> thread_db_target::update_thread_list
-> linux_nat_target::update_thread_list
-> delete_exited_threads
-> delete_thread
-> delete_thread_1
-> gdb::observers::observable<thread_info*>::notify
-> amd_dbgapi_thread_deleted
-> internal_error_loc
The testcase thus tries both running to exit after the first kernel
exits, and running to a breakpoint in a second kernel after the first
kernel exits.
Approved-By: Lancelot Six <lancelot.six@amd.com> (amdgpu)
Change-Id: I43a66f060c35aad1fe0d9ff022ce2afd0537f028
Currently, if you step over kernel exit, you see:
stepi
[AMDGPU Wave ?:?:?:1 (?,?,?)/? exited]
Command aborted, thread exited.
(gdb)
Those '?' are because the thread/wave is already gone by the time GDB
prints the "exited" notification, we can't ask dbgapi for any info
about the wave anymore.
This commit fixes it by caching the wave's coordinates as soon as GDB
sees the wave for the first time, and making
amd_dbgapi_target::pid_to_str use the cached info.
At first I thought of clearing the wave_info object from a
thread_exited observer. However, that is too soon, resulting in this:
(gdb) si
[AMDGPU Wave 1:4:1:1 (0,0,0)/0 exited]
Command aborted, thread exited.
(gdb) thread
[Current thread is 6 (AMDGPU Wave ?:?:?:0 (?,?,?)/?) (exited)]
We need instead to clear the wave info when the thread is ultimately
deleted, so we get:
(gdb) si
[AMDGPU Wave 1:4:1:1 (0,0,0)/0 exited]
Command aborted, thread exited.
(gdb) thread
[Current thread is 6 (AMDGPU Wave 1:4:1:1 (0,0,0)/0) (exited)]
And for that, we need a new thread_deleted observable.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Approved-By: Lancelot Six <lancelot.six@amd.com> (amdgpu)
Change-Id: I6c3e22541f051e1205f75eb657b04dc15e547580
With AMD GPU debugging, I noticed that when stepping over a breakpoint
placed on top of the s_endpgm instruction inline (displaced=off), GDB
would behave differently -- it wouldn't print the wave exit. E.g:
With displaced stepping, or no breakpoint at all:
stepi
[AMDGPU Wave 1:4:1:1 (0,0,0)/0 exited]
Command aborted, thread exited.
(gdb)
With inline stepping:
stepi
Command aborted, thread exited.
(gdb)
In the cases we see the "exited" notification, handle_thread_exit is
what first called delete_thread on the exiting thread, which is
non-silent.
With inline stepping, however, handle_thread_exit ends up in
update_thread_list (via restart_threads) before any delete_thread
call. Thus, amd_dbgapi_target::update_thread_list notices that the
wave is gone and deletes it with delete_thread_silent.
This commit fixes it, by making handle_thread_exited call
set_thread_exited (with the default silent=false) early, which emits
the user-visible notification.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Change-Id: I22ab3145e18d07c99dace45576307b9f9d5d966f
displaced_step_finish can be called with event_status.kind ==
TARGET_WAITKIND_THREAD_EXITED, and in that case it is not possible to
get at the already-exited thread's registers.
This patch moves the get_thread_regcache calls to branches that
actually need it, where we know the thread is still alive.
It also adds an assertion to get_thread_regcache, to help catching
these broken cases sooner.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Change-Id: I63b5eacb3e02a538fc5087c270d8025adfda88c3
While making step over thread exit work properly on AMDGPU, I noticed
that if there's a breakpoint on top of the exit syscall, and,
displaced stepping is off, then when GDB reports "Command aborted,
thread exited.", GDB also switches focus to a random thread, instead
of leaving the exited thread as selected:
(gdb) thread
[Current thread is 6, lane 0 (AMDGPU Lane 1:4:1:1/0 (0,0,0)[0,0,0])]
(gdb) si
Command aborted, thread exited.
(gdb) thread
[Current thread is 5 (Thread 0x7ffff626f640 (LWP 3248392))]
(gdb)
The previous patch extended gdb.threads/step-over-thread-exit.exp to
exercise this on GNU/Linux (on the CPU side), and there, after that
"si", we always end up with the exiting thread as selected even
without this fix, but that's just a concidence, there's a code path
that happens to select the exiting thread for an unrelated reason.
This commit add the explict switch, fixing the latent problem for
GNU/Linux, and the actual problem on AMDGPU. I wrote a gdb.rocm/
testcase for this, but it can't be upstreamed yet, until more pieces
of the DWARF machinery are upstream as well.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Change-Id: I6ff57a79514ac0142bba35c749fe83d53d9e4e51
This commit makes the following improvements to
gdb.threads/step-over-thread-exit.exp:
- Add a third axis to stepping over the breakpoint with displaced vs
inline stepping -- also test with no breakpoint at all.
- Check that when GDB reports "Command aborted, thread exited.", the
selected thread is the thread that exited. This is always true
currently on GNU/Linux by coincidence, but a similar testcase on AMD
GPU exposed a problem here. Better make the testcase catch any
potential regression.
- Fixes a race that Simon ran into with GDBserver testing.
(gdb) next
[New Thread 2143071.2143438]
Thread 3 "step-over-threa" hit Breakpoint 2, 0x000055555555524e in my_exit_syscall () at .../testsuite/lib/my-syscalls.S:74
74 SYSCALL (my_exit, __NR_exit)
(gdb) FAIL: gdb.threads/step-over-thread-exit.exp: displaced-stepping=auto: non-stop=on: target-non-stop=on: schedlock=off: cmd=next: ns_stop_all=0: command aborts when thread exits
I was not able to reproduce it, but I believe that what happens is
the following:
Once we continue, the thread 2 exits, and the main thread thus
unblocks from its pthread_join, and spawns a new thread. That new
thread may hit the breakpoint at my_exit_syscall very quickly. GDB
could then see/process that breakpoint event before the thread exit
event for the thread we care about, which would result in the
failure seen above.
The fix here is to not loop and start a new thread at all in the
scenario where the race can happen. We only need to loop and spawn
new threads when testing with "cmd=continue" and schedlock off, in
which case GDB doesn't abort the command when the thread exits.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Change-Id: I90c95c32f00630a3f682b1541c23aff52451f9b6
By inspection, I noticed that the previous patch went too far, here:
@@ -7705,7 +7713,8 @@ remote_target::discard_pending_stop_replies (struct inferior *inf)
if (rs->remote_desc == NULL)
return;
- reply = (struct stop_reply *) rns->pending_event[notif_client_stop.id];
+ stop_reply_up reply
+ = as_stop_reply_up (std::move (rns->pending_event[notif_client_stop.id]));
/* Discard the in-flight notification. */
if (reply != NULL && reply->ptid.pid () == inf->pid)
That is always moving the stop reply from pending_event, when we only
really want to peek into it. The code further below that even says:
/* Discard the in-flight notification. */
if (reply != NULL && reply->ptid.pid () == inf->pid)
{
/* Leave the notification pending, since the server expects that
we acknowledge it with vStopped. But clear its contents, so
that later on when we acknowledge it, we also discard it. */
This commit reverts that hunk back, adjusted to use unique_ptr::get().
Change-Id: Ifc809d1a8225150a4656889f056d51267100ee24
We already use unique_ptr with notif_event and stop_reply in some
places around the remote target, but not fully. There are several
code paths that still use raw pointers. This commit makes all of the
ownership of these objects tracked by unique pointers, making the
lifetime flow much more obvious, IMHO.
I notice that it fixes a leak -- in remote_notif_stop_ack, We weren't
destroying the stop_reply object if it was of TARGET_WAITKIND_IGNORE
kind.
Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: Id81daf39653d8792c8795b2a145772176bfae77c
struct cached_reg_t owns its data buffer, but currently that is
managed manually. Convert it to use a unique_xmalloc_ptr.
Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: I05a107098b717299e76de76aaba00d7fbaeac77b
tdesc_data is not part of a union, since commit 4f3681cc33 ("Fix thread's
gdbarch when SVE vector length changes"). Remove the stale comment and
constructor.
Change-Id: Ie895ce36614930e8bd9c4967174c8bf1b321c503
Here, we write single complete registers, we don't need the
functionality of put_frame_register_bytes, use put_frame_register
instead.
Change-Id: I987867a27249db4f792a694b47ecb21c44f64d08
Approved-By: Tom Tromey <tom@tromey.com>
This comment is no longer relevant, put_frame_register_bytes now accepts
the "next frame".
Change-Id: I077933a03f8bdb886f8ba10a98d1202a38bce0a9
Approved-By: Tom Tromey <tom@tromey.com>
gdbarches usually register functions to check when a frame is destroyed
which is used with software watchpoints, since the expression of the
watchpoint is no longer vlaid at this point. On amd64, this wasn't done
anymore because GCC started using CFA for variable locations instead.
However, clang doesn't use the CFA and instead relies on specifying when
an epilogue has started, meaning software watchpoints get a spurious hit
when a frame is destroyed. This patch re-adds the code to register the
function that detects when a frame is destroyed, but only uses this when
the producer is LLVM, so gcc code isn't affected. The logic that
identifies the epilogue has been factored out into the new function
amd64_stack_frame_destroyed_p_1, so the frame sniffer can call it
directly, and its behavior isn't changed.
This can also remove the XFAIL added to gdb.python/pq-watchpoint tests
that handled this exact flaw in clang.
Co-Authored-By: Andrew Burgess <aburgess@redhat.com>
Approved-By: Andrew Burgess <aburgess@redhat.com>
The gdb.threads/thread-specific-bp.exp test has been a little
problematic, see commits:
commit 89702edd93
Date: Thu Mar 9 12:31:26 2023 +0100
[gdb/testsuite] Fix gdb.threads/thread-specific-bp.exp on native-gdbserver
and
commit 2e5843d87c
Date: Fri Nov 19 14:33:39 2021 +0100
[gdb/testsuite] Fix gdb.threads/thread-specific-bp.exp
But I recently saw a test failure for that test, which looked like
this:
...
(gdb) PASS: gdb.threads/thread-specific-bp.exp: non_stop=on: thread 1 selected
continue -a
Continuing.
Thread 1 "thread-specific" hit Breakpoint 4, end () at /tmp/binutils-gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.threads/thread-specific-bp.c:29
29 }
(gdb) [Thread 0x7ffff7c5c700 (LWP 1552086) exited]
Thread-specific breakpoint 3 deleted - thread 2 no longer in the thread list.
FAIL: gdb.threads/thread-specific-bp.exp: non_stop=on: continue to end (timeout)
...
This only crops up (for me) when running on a loaded machine, and
still only occurs sometimes. I've had to leave the test running in a
loop for 10+ minutes sometimes in order to see the failure.
The problem is that we use gdb_test_multiple to try and match two
patterns:
(1) The 'Thread-specific breakpoint 3 deleted ....' message, and
(2) The GDB prompt.
As written in the test, we understand that these patterns can occur in
any order, and we have a flag for each pattern. Once both patterns
have been seen then we PASS the test.
The problem is that once expect has matched a pattern, everything up
to, and including the matched text is discarded from the input
buffer. Thus, if the input buffer contains:
<PATTERN 2><PATTERN 1>
Then expect will first try to match <PATTERN 1>, which succeeds, and
then expect discards the entire input buffer up to the end of the
<PATTERN 1>. As a result, we will never spot <PATTERN 2>.
Obviously we can't just reorder the patterns within the
gdb_test_multiple, as the output can legitimately (and most often
does) occur in the other order, in which case the test would mostly
fail, and only occasionally pass!
I think the easiest solution here is just to have the
gdb_test_multiple contain two patterns, each pattern consists of the
two parts, but in the alternative orders, thus, for a particular
output configuration, only one regexp will match. With this change in
place, I no longer see the intermittent failure.
Approved-By: Tom Tromey <tom@tromey.com>
PR28987 notes that optimized code sometimes shows the wrong
value of variables at the entry point of a function, if some
code was optimized away and the variable has multiple values
stored in the debug info for this location.
In this example:
```
void foo()
{
int l_3 = 5, i = 0;
for (; i < 8; i++)
;
test(l_3, i);
}
```
When compiled with optimization, the entry point of foo is at
the test() function call, since everything else is optimized
away.
The debug info of i looks like this:
```
(gdb) info address i
Symbol "i" is multi-location:
Base address 0x140001600 Range 0x13fd41600-0x13fd41600: the constant 0
Range 0x13fd41600-0x13fd41600: the constant 1
Range 0x13fd41600-0x13fd41600: the constant 2
Range 0x13fd41600-0x13fd41600: the constant 3
Range 0x13fd41600-0x13fd41600: the constant 4
Range 0x13fd41600-0x13fd41600: the constant 5
Range 0x13fd41600-0x13fd41600: the constant 6
Range 0x13fd41600-0x13fd41600: the constant 7
Range 0x13fd41600-0x13fd4160f: the constant 8
(gdb) p i
$1 = 0
```
Currently, when at the entry point of a function, it will
always show the initial value (here 0), while the user would
expect the last value (here 8).
This logic was introduced for showing the entry-values of
function arguments if they are available, but for some
reason this was added for non-entry-values as well.
One of the tests of amd64-entry-value.exp shows the same
problem for function arguments, if you "break stacktest"
in the following example, you stop at this line:
```
124 static void __attribute__((noinline, noclone))
125 stacktest (int r1, int r2, int r3, int r4, int r5, int r6, int s1, int s2,
126 double d1, double d2, double d3, double d4, double d5, double d6,
127 double d7, double d8, double d9, double da)
128 {
129 s1 = 3;
130 s2 = 4;
131 d9 = 3.5;
132 da = 4.5;
133 -> e (v, v);
134 asm ("breakhere_stacktest:");
135 e (v, v);
136 }
```
But `bt` still shows the entry values:
```
s1=s1@entry=11, s2=s2@entry=12, ..., d9=d9@entry=11.5, da=da@entry=12.5
```
I've fixed this by only using the initial values when
explicitely looking for entry values.
Now the local variable of the first example is as expected:
```
(gdb) p i
$1 = 8
```
And the test of amd64-entry-value.exp shows the expected
current and entry values of the function arguments:
```
s1=3, s1@entry=11, s2=4, s2@entry=12, ..., d9=3.5, d9@entry=11.5, da=4.5, da@entry=12.5
```
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28987
Tested-By: Guinevere Larsen <blarsen@redhat.com>
Approved-By: Tom Tromey <tom@tromey.com>
Commit deb1ba4e38 ("[gdb/tui] Fix TUI resizing for TERM=ansi") introduced a
dependency on readline private variable _rl_term_autowrap.
There is precedent for this, but it's something we want to get rid of
(PR build/10723).
Remove the dependency on _rl_term_autowrap, and instead calculate
readline_hidden_cols by comparing the environment variable COLS with cols as
returned by rl_get_screen_size.
Tested on x86_64-linux.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=10723
When starting gdb in CLI mode, running to main and switching into the TUI regs
layout:
...
$ gdb -q a.out -ex start -ex "layout regs"
...
we get:
...
+---------------------------------+
| |
| [ Register Values Unavailable ] |
| |
+---------------------------------+
...
Fix this by handling this case in tui_data_window::rerender.
Tested on x86_64-linux.
Approved-By: Tom Tromey <tom@tromey.com>
PR tui/28600
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28600
While experimenting with can_box () == false by default, I noticed two places
in tui-regs.c where we can replace a hardcoded 1 with box_width ().
It also turned out to be necessary to set scrollok to false, otherwise writing
the last char of the last line with register info will cause a scroll.
Tested on x86_64-linux.
Approved-By: Tom Tromey <tom@tromey.com>
Currently, the overload handling in Ada assumes that any two array
types are compatible. However, this is obviously untrue, and a user
reported an oddity where comparing two Ada strings resulted in a call
to the "=" function for packed boolean arrays.
This patch improves the situation somewhat, by requiring that the two
arrays have the same arity and compatible base element types. This is
still over-broad, but it seems safe and is better than the status quo.
Spotted what appears to be a copy&paste error in string_option_def,
the code for string handling writes the address fetching callback
function into the option_def::var_address::enumeration location,
rather than option_def::var_address::string.
Of course, this works just fine as option_def::var_address is a union,
and all of its members are function pointers, so they're going to be
the same size on every target GDB cares about.
But it doesn't hurt to be correct, so fixed in this commit.
There should be no user visible changes after this commit.
This patch adds tests to exercise the previous patches' changes.
All three tests:
- aarch64-pseudo-unwind
- amd64-pseudo-unwind
- arm-pseudo-unwind
follow the same pattern, just with different registers.
The other test, arm-pseudo-unwind-legacy, tests the special case where
the unwind information contains an entry for a register considered a
pseudo-register by GDB.
Change-Id: Ic29ac040c5eb087b4a0d79f9d02f65b7979df30f
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Reviewed-by: Luis Machado <luis.machado@arm.com>
Approved-By: Luis Machado <luis.machado@arm.com> (aarch64/arm)
Tested-By: Luis Machado <luis.machado@arm.com> (aarch64/arm)
Make arm use the new gdbarch_pseudo_register_write. This fixes writing
pseudo registers to non-current frames for that architecture.
Change-Id: Icb2a649ab6394817844230e9e94c3d0564d2f765
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Approved-by: Luis Machado <luis.machado@arm.com>
Make arm use the "newer" gdbarch_pseudo_register_read_value. This fixes
reading pseudo registers in non-current frames on that architecture.
Change-Id: Ic4d3d5d96957a4addfa3443c7b567dc4a31794a9
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Approved-by: Luis Machado <luis.machado@arm.com>
Make aarch64 use the new gdbarch_pseudo_register_write. This fixes
writing pseudo registers to non-current frames on this architecture.
Change-Id: Ic012a0b95ae728d45a7121f77a79d604c23a849e
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Approved-By: Luis Machado <luis.machado@arm.com>
Tested-By: Luis Machado <luis.machado@arm.com>
It seems like the intention here is to read the contents of the ZA
register and only write part of it. However, there's no actual read of
the ZA register, so it looks like we'll write uninitialized bytes to the
target, for the portion of the raw register where we don't write the
pseudo register. Add a call to raw_read to fix this.
I don't know how to test this though.
Change-Id: I7548240bd4324f6a3b729a1ebf7502fae5a46e9e
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Approved-by: Luis Machado <luis.machado@arm.com>
This is not necessary, but it seems more natural to me to make
aarch64_za_offsets_from_regnum return a za_offsets object, rather than
fill an instance passed by parameter.
Change-Id: I40a185f055727da887ce7774be193eef1f4b9147
Approved-by: Luis Machado <luis.machado@arm.com>
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Make i386 and amd64 use the new gdbarch_pseudo_register_write. This
fixes writing to pseudo registers in non-current frames for those
architectures.
Change-Id: I4977e8fe12d2cef116f8834c34cdf6fec618554f
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Add a new variant of gdbarch_pseudo_register_write that takes a
frame_info in order to write raw registers. Use this new method when
available:
- in put_frame_register, when trying to write a pseudo register to a given frame
- in regcache::cooked_write
No implementation is migrated to use this new method (that will come in
subsequent patches), so no behavior change is expected here.
The objective is to fix writing pseudo registers to non-current
frames. See previous commit "gdb: read pseudo register through
frame" for a more detailed explanation.
Change-Id: Ie7fe364a15a4d86c2ecb09de2b4baa08c45555ac
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
The next patch introduces a new variant of gdbarch_pseudo_register_write
that takes a frame instead of a regcache for implementations to write
raw registers. Rename to old one to make it clear it's deprecated.
Change-Id: If8872c89c6f8a1edfcab983eb064248fd5ff3115
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Change gdbarch_pseudo_register_read_value to take a frame instead of a
regcache. The frame (and formerly the regcache) is used to read raw
registers needed to make up the pseudo register value. The problem with
using the regcache is that it always provides raw register values for
the current frame (frame 0).
Let's say the user wants to read the ebx register on amd64. ebx is a pseudo
register, obtained by reading the bottom half (bottom 4 bytes) of the
rbx register, which is a raw register. If the currently selected frame
is frame 0, it works fine:
(gdb) frame 0
#0 break_here_asm () at /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S:36
36 in /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S
(gdb) p/x $ebx
$1 = 0x24252627
(gdb) p/x $rbx
$2 = 0x2021222324252627
But if the user is looking at another frame, and the raw register behind
the pseudo register has been saved at some point in the call stack, then
we get a wrong answer:
(gdb) frame 1
#1 0x000055555555517d in caller () at /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S:56
56 in /home/smarchi/src/binutils-gdb/gdb/testsuite/gdb.arch/amd64-pseudo-unwind-asm.S
(gdb) p/x $ebx
$3 = 0x24252627
(gdb) p/x $rbx
$4 = 0x1011121314151617
Here, the value of ebx was computed using the value of rbx in frame 0
(through the regcache), it should have been computed using the value of
rbx in frame 1.
In other to make this work properly, make the following changes:
- Make dwarf2_frame_prev_register return nullptr if it doesn't know how
to unwind a register and that register is a pseudo register.
Previously, it returned `frame_unwind_got_register`, meaning, in our
example, "the value of ebx in frame 1 is the same as the value of ebx
in frame 0", which is obviously false. Return nullptr as a way to
say "I don't know".
- In frame_unwind_register_value, when prev_register (for instance
dwarf2_frame_prev_register) returns nullptr, and we are trying to
read a pseudo register, try to get the register value through
gdbarch_pseudo_register_read_value or gdbarch_pseudo_register_read.
If using gdbarch_pseudo_register_read, the behavior is known to be
broken. Implementations should be migrated to use
gdbarch_pseudo_register_read_value to fix that.
- Change gdbarch_pseudo_register_read_value to take a frame_info
instead of a regcache, update implementations (aarch64, amd64, i386).
In i386-tdep.c, I made a copy of i386_mmx_regnum_to_fp_regnum that
uses a frame instead of a regcache. The version using the regcache
is still used by i386_pseudo_register_write. It will get removed in
a subsequent patch.
- Add some helpers in value.{c,h} to implement the common cases of
pseudo registers: taking part of a raw register and concatenating
multiple raw registers.
- Update readable_regcache::{cooked_read,cooked_read_value} to pass the
current frame to gdbarch_pseudo_register_read_value. Passing the
current frame will give the same behavior as before: for frame 0, raw
registers will be read from the current thread's regcache.
Notes:
- I do not plan on changing gdbarch_pseudo_register_read to receive a
frame instead of a regcache. That method is considered deprecated.
Instead, we should be working on migrating implementations to use
gdbarch_pseudo_register_read_value instead.
- In frame_unwind_register_value, we still ask the unwinder to try to
unwind pseudo register values. It's apparently possible for the
debug info to provide information about [1] pseudo registers, so we
want to try that first, before falling back to computing them
ourselves.
[1] https://inbox.sourceware.org/gdb-patches/20180528174715.A954AD804AD@oc3748833570.ibm.com/
Change-Id: Id6ef1c64e19090a183dec050e4034d8c2394e7ca
Reviewed-by: John Baldwin <jhb@FreeBSD.org>
Add value::allocate_register, to facilitate allocating a value
representing a register in a given frame (or rather, in the given
frame's previous frame). It will be used in a subsequent patch. I
changed one relatively obvious spot that could use it, to at least
exercise the code path.
Change-Id: Icd4960f5e471a74b657bb3596c88d89679ef3772
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Similar to the previous patches, change get_frame_register_bytes to take
the "next frame" instead of "this frame".
Change-Id: Ie8f35042bfa6e93565fcefaee71b6b3903f0fe9f
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Similar to the previous patches, change put_frame_register_bytes to take
the "next frame" instead of "this frame".
Change-Id: I27bcb26573686d99b231230823cff8db6405a788
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Similar to the previous patches, change put_frame_register to take the
"next frame" instead of "this frame".
Change-Id: I062fd4663b8f54f0fc7bbf39c860b7341363821b
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
I was going to change frame_register to take the "next frame", but I
realized that doing so would make it a useless wrapper around
frame_register_unwind. So, just remove frame_register and replace uses
with frame_register_unwind.
Change-Id: I185868bc69f8e098124775d0550d069220a4678a
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Some functions related to the handling of registers in frames accept
"this frame", for which we want to read or write the register values,
while other functions accept "the next frame", which is the frame next
to that. The later is needed because we sometimes need to read register
values for a frame that does not exist yet (usually when trying to
unwind that frame-to-be).
value_of_register and value_of_register_lazy both take "this frame",
even if what they ultimately want internally is "the next frame". This
is annoying if you are in a spot that currently has "the next frame" and
need to call one of these functions (which happens later in this
series). You need to get the previous frame only for those functions to
get the next frame again. This is more manipulations, more chances of
mistake.
I propose to change these functions (and a few more functions in the
subsequent patches) to operate on "the next frame". Things become a bit
less awkward when all these functions agree on which frame they take.
So, in this patch, change value_of_register_lazy and value_of_register
to take "the next frame" instead of "this frame". This adds a lot of
get_next_frame_sentinel_okay, but if we convert the user registers API
to also use "the next frame" instead of "this frame", it will get simple
again.
Change-Id: Iaa24815e648fbe5ae3c214c738758890a91819cd
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Change put_frame_register to take an array_view instead of a raw
pointer.
Add an assertion to verify that the number of bytes we try to write
matches the length of the register.
Change-Id: Ib75a9c8a12b47e203097621643eaa2c1830591ae
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
I found this only by inspection: the myaddr pointer in
{get,put}_frame_register_bytes is reset to `buffer.data ()` at each
iteration. This means that we will always use the bytes at the
beginning of `buffer` to read or write to the registers, instead of
progressing in `buffer`.
Fix this by re-writing the functions to chip away the beginning of the
buffer array_view as we progress in reading or writing the data.
These bugs was introduced almost 3 years ago [1], and yet nobody
complained. I'm wondering which architecture relies on that register
"overflow" behavior (reading or writing multiple consecutive registers
with one {get,put}_frame_register_bytes calls), and in which situation.
I find these functions a bit dangerous, if a caller mis-calculates
things, it could end up silently reading or writing to the next
register, even if it's not the intent.
If I could change it, I would prefer to have functions specifically made
for that ({get,put}_frame_register_bytes_consecutive or something like
that) and make {get,put}_frame_register_bytes only able to write within
a single register (which I presume represents most of the use cases of
the current {get,put}_frame_register_bytes). If a caller mis-calculates
things and an overflow occurs while calling
{get,put}_frame_register_bytes, it would hit an assert. The problem is
knowing which callers rely on the overflow behavior and which don't.
[1] bdec2917b1
Change-Id: I43bd4a9f7fa8419d388a2b20bdc57d652688ddf8
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Approved-By: Andrew Burgess <aburgess@redhat.com>
Change most of regcache (and base classes) to use array_view when
possible, instead of raw pointers. By propagating the use of array_view
further, it enables having some runtime checks to make sure the what we
read from or write to regcaches has the expected length (such as the one
in the `copy(array_view, array_view)` function. It also integrates well
when connecting with other APIs already using gdb::array_view.
Add some overloads of the methods using raw pointers to avoid having to
change all call sites at once (which is both a lot of work and risky).
I tried to do this change in small increments, but since many of these
functions use each other, it ended up simpler to do it in one shot than
having a lot of intermediary / transient changes.
This change extends into gdbserver as well, because there is some part
of the regcache interface that is shared.
Changing the reg_buffer_common interface to use array_view caused some
build failures in nat/aarch64-scalable-linux-ptrace.c. That file
currently "takes advantage" of the fact that
reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which
IMO is dangerous. It uses raw_supply/raw_collect directly on
uint64_t's, which I guess is fine because it is expected that native
code will have the same endianness as the debugged process. To
accomodate that, add some overloads of raw_collect and raw_supply that
work on uint64_t.
This file also uses raw_collect and raw_supply on `char` pointers.
Change it to use `gdb_byte` pointers instead. Add overloads of
raw_collect and raw_supply that work on `gdb_byte *` and make an
array_view on the fly using the register's size. Those call sites could
be converted to use array_view with not much work, in which case these
overloads could be removed, but I didn't want to do it in this patch, to
avoid starting to dig in arch-specific code.
During development, I inadvertently changed reg_buffer::raw_compare's
behavior to not accept an offset equal to the register size. This
behavior (effectively comparing 0 bytes, returning true) change was
caught by the AArch64 SME core tests. Add a selftest to make sure that
this raw_compare behavior is preserved in the future.
Change-Id: I9005f04114543ddff738949e12d85a31855304c2
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Make a few simplifications in these functions.
1. When checking if we need to do nothing, if the length is 0, we don't
need to do anything, regardless of the value of offset. Remove the
offset check.
2. When check if transferring the whole register, if the length is equal
to the register size, then we transfer the whole register, no need to
check the offset. Remove the offset check.
3. In the gdb_asserts, it is unnecessary to check for:
offset <= reg_size
given that right after we check for:
len >= 0 && offset + len <= reg_size
If `offset + len` is <= reg_size and len is >= 0, then necessarily
offset is <= reg_size. Remove the `offset <= reg_size` check.
Change-Id: I30a73acdc7bf432c45a07f5f177224d1cdc298e8
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Change store_integer, store_signed_integer and store_unsigned_integer to
accept an array_view. Add some backwards compatibility overloads to
avoid changing all callers at once.
Change-Id: Ibb1381228ab1cb65fc7e2e4b92cf9ab1047cdc03
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Right now, gdbsupport/common-regcache.h contains two abstractons for a
regcache. An opaque type `regcache` (gdb and gdbserver both have their
own regcache that is the concrete version of this) and an abstract base
class `reg_buffer_common`, that is the base of regcaches on both sides.
These abstractions allow code to be written for both gdb and gdbserver,
for instance in the gdb/arch sub-directory.
However, having two
different abstractions is impractical. If some common code has a regcache,
and wants to use an operation defined on reg_buffer_common, it can't.
It would be better to have just one. Change all instances of `regcache
*` in gdbsupport/common-regcache.h to be `reg_buffer_common *`, then fix
fallouts.
Implementations in gdb and gdbserver now need to down-cast (using
gdb::checked_static_cast) from reg_buffer_common to their concrete
regcache type. Some of them could be avoided by changing free functions
(like regcache_register_size) to be virtual methods on
reg_buffer_common. I tried it, it seems to work, but I did not include
it in this series to avoid adding unnecessary changes.
Change-Id: Ia5503adb6b5509a0f4604bd2a68b4642cc5283fd
Reviewed-by: John Baldwin <jhb@FreeBSD.org>
I think that i386 k registers are raw registers, and therefore shouldn't
be handled in the various functions handling pseudo registers.
What tipped me off is the code in i386_pseudo_register_read_into_value:
else if (i386_k_regnum_p (gdbarch, regnum))
{
regnum -= tdep->k0_regnum;
/* Extract (always little endian). */
status = regcache->raw_read (tdep->k0_regnum + regnum, raw_buf);
We take regnum (the pseudo register number we want to read), subtract
k0_regnum, add k0_regnum, and pass the result to raw_read. So we would
end up calling raw_read with the same regnum as the function received
which is supposedly a pseudo register number.
Other hints are:
- The command `maint print raw-registers` shows the k registers.
- Printing $k0 doesn't cause i386_pseudo_register_read_into_value to be
called.
- There's code in i387-tdep.c to save/restore the k registers.
Remove handling of the k registers from:
- i386_pseudo_register_read_into_value
- i386_pseudo_register_write
- i386_ax_pseudo_register_collect
Change-Id: Ic97956ed59af6099fef6d36a0b61464172694562
Reviewed-by: John Baldwin <jhb@FreeBSD.org>
Currently, it's not possible to call a variadic C++ function:
```
(gdb) print sum_vararg_int(1, 10)
Cannot resolve function sum_vararg_int to any overloaded instance
(gdb) print sum_vararg_int(2, 20, 30)
Cannot resolve function sum_vararg_int to any overloaded instance
```
It's because all additional arguments get the TOO_FEW_PARAMS_BADNESS
rank by rank_function, which disqualifies the function.
To fix this, I've created the new VARARG_BADNESS rank, which is
used only for additional arguments of variadic functions, allowing
them to be called:
```
(gdb) print sum_vararg_int(1, 10)
$1 = 10
(gdb) print sum_vararg_int(2, 20, 30)
$2 = 50
```
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28589
Approved-By: Tom Tromey <tom@tromey.com>
The bindings for the reverse execution commands are the same letters
as the forward execution command, but with the opposite case. This way
one can simply hold down the Shift modifier key or tap the Caps Lock key
to change the direction of execution.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
In python/py-gdb-readline.c we make use of _PyOS_ReadlineTState,
however, this variable is no longer public in Python 3.13, and so GDB
no longer builds.
We are making use of _PyOS_ReadlineTState in order to re-acquire the
Python Global Interpreter Lock (GIL). The _PyOS_ReadlineTState
variable is set in Python's outer readline code prior to calling the
user (GDB) supplied readline callback function, which for us is
gdbpy_readline_wrapper. The gdbpy_readline_wrapper function is called
without the GIL held.
Instead of using _PyOS_ReadlineTState, I propose that we switch to
calling PyGILState_Ensure() and PyGILState_Release(). These functions
will acquire the GIL based on the current thread. I think this should
be sufficient; I can't imagine why we'd be running
gdbpy_readline_wrapper on one thread on behalf of a different Python
thread.... that would be unexpected I think.
Approved-By: Tom Tromey <tom@tromey.com>