Age | Commit message (Collapse) | Author | Files | Lines |
|
When running the dap tests on a system with tcl 8.5, we run into:
...
ERROR: tcl error sourcing gdb/testsuite/gdb.dap/memory.exp.
ERROR: bad class "entier": must be alnum, alpha, ascii, control, boolean, \
digit, double, false, graph, integer, list, lower, print, punct, space, \
true, upper, wideinteger, wordchar, or xdigit
while executing
"string is entier $num"
(procedure "num" line 16)
invoked from within
...
Fix this by:
- requiring tcl 8.6 in allow_dap_tests, and
- adding the missing require allow_dap_tests in gdb.dap/memory.exp.
Tested on x86_64-linux.
|
|
When running the gdb.dlang test-cases, and forcing gdb_find_gdc to be used
rather than dejagnu's copy (mimicing what happens with an older dejagnu
without find_gdc), I run into these debug prints:
...
Tool Root: /data/vries/gdb/leap-15-4/build
CC: gdc
...
Remove these.
Tested on x86_64-linux.
|
|
[ Changes in v2:
- rebase on trunk
Changes in v3:
- add test-case ]
We should exclude matches to the ending PC to prevent false matches with the
next function, as prologue_end is located at the end PC.
<fun1>:
0x00: ... <-- start_pc
0x04: ...
0x08: ... <-- breakpoint
0x0c: ret
<fun2>:
0x10: ret <-- end_pc | prologue_end of fun2
Tested on x86_64-linux.
Co-Authored-By: WANG Rui <r@hev.cc> (fix, tiny change [1])
Co-Authored-By: Tom de Vries <tdevries@suse.de> (test-case)
Approved-by: Kevin Buettner <kevinb@redhat.com>
[1] https://www.gnu.org/prep/maintain/html_node/Legally-Significant.html
PR symtab/30369
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30369
|
|
Directory gdb/testsuite/boards contains a number of host/target boards, which
run a test-case (or test-cases) in a different way.
The benefits of using these boards are:
- improving test coverage of gdb,
- making the testsuite more robust, and
- making sure the test-cases work for non-native and remote setups, if
possible.
Each board is slightly different, and developers need to learn how to use each
one, what parameters to pass and how, and which ones can be used in
combination with each other. This is a threshold to start using them.
And then there quite a few, so I suppose typically only a few will be used by
each developer.
Add script gdb/testsuite/make-check-all.sh, that's intended to function as a
drop-in replacement of make check, while excercising all host/target boards in
gdb/testsuite/boards.
An example of make-check-all.sh for one test-case is:
...
$ ~/gdb/src/gdb/testsuite/make-check-all.sh gdb.base/advance.exp
LOCAL:
# of expected passes 8
TARGET BOARD: cc-with-gdb-index
# of expected passes 8
...
HOST BOARD: local-remote-host-notty, TARGET BOARD: remote-stdio-gdbserver
# of expected passes 8
HOST/TARGET BOARD: local-remote-host-native
# of expected passes 8
...
Shell-checked and tested on x86_64-linux.
Co-Authored-By: Simon Marchi <simon.marchi@efficios.com>
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
|
|
call_site_target::iterate_over_addresses may look up a minimal symbol.
On platforms like PPC64 that use function descriptors, this may find
an unexpected address. The fix is to use gdbarch_convert_from_func_ptr_addr
to convert from a function descriptor to the address recorded at the
call site.
I've added a new test case that is based on the internal AdaCore test
that provoked this bug. However, I'm unable to test it as-is on
PPC64.
|
|
Change-Id: I849d10d69c254342bf01e955ffe62a2b60f9de4b
|
|
Prior to this patch, it's not possible for GDB to debug GPU code in fork
children or after an exec. The amd-dbgapi target attaches to processes
when an inferior appears due to a "run" or "attach" command, but not
after a fork or exec. This patch adds support for that, such that it's
possible to for an inferior to fork and for GDB to debug the GPU code in
the child.
To achieve that, use the inferior_forked and inferior_execd observers.
In the case of fork, we have nothing to do if `child_inf` is nullptr,
meaning that GDB won't debug the child. We also don't attach if the
inferior has vforked. We are already attached to the parent's address
space, which is shared with the child, so trying to attach would cause
problems. And anyway, the inferior can't do anything other than exec or
exit, it certainly won't start GPU kernels before exec'ing.
In the case of exec, we detach from the exec'ing inferior and attach to
the following inferior. This works regardless of whether they are the
same or not. If they are the same, meaning the execution continues in
the existing inferior, we need to do a detach/attach anyway, as
amd-dbgapi needs to be aware of the new address space created by the
exec.
Note that we use observers and not target_ops::follow_{fork,exec} here.
When the amd-dbgapi target is compiled in, it will attach (in the
amd_dbgapi_process_attach sense, not the ptrace sense) to native
inferiors when they appear, but won't push itself on the inferior's
target stack just yet. It only pushes itself if the inferior
initializes the ROCm runtime. So, if a non-GPU-using inferior calls
fork, an amd_dbgapi_target::follow_fork method would not get called.
Same for exec. A previous version of the code had the amd-dbgapi target
pushed all the time, in which case we could use the target methods. But
we prefer having the target pushed only when necessary, it's less
intrusive when doing native debugging that doesn't involve the GPU.
Change-Id: I5819c151c371120da8bab2fa9cbfa8769ba1d6f9
Reviewed-By: Pedro Alves <pedro@palves.net>
|
|
This adds support for 128-bit integers to the Ada parser.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30188
|
|
These helper functions in the Ada parser don't seem all that
worthwhile to me, so this patch removes them.
|
|
This adds support for 128-bit integers to the Rust parser.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=21185
|
|
With DWARF 5, it's possible to produce an empty file name in the File Name
Table of the .debug_line section:
...
The File Name Table (offset 0x112, lines 1, columns 2):
Entry Dir Name
0 1 (indirect line string, offset: 0x2d):
...
Currently, when gdb reads an exec containing such debug info, it segfaults:
...
Thread 1 "gdb" received signal SIGSEGV, Segmentation fault.
0x000000000072cd38 in dwarf2_start_subfile (cu=0x2badc50, fe=..., lh=...) at \
gdb/dwarf2/read.c:18716
18716 if (!IS_ABSOLUTE_PATH (filename) && dirname != NULL)
...
because read_direct_string transforms "" into a nullptr, and we end up
dereferencing the nullptr.
Note that the behaviour of read_direct_string has been present since repo
creation.
Fix this in read_formatted_entries, by transforming nullptr filenames in to ""
filenames.
Tested on x86_64-linux.
Reviewed-By: Tom Tromey <tom@tromey.com>
PR symtab/30357
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30357
|
|
This commit changes mi_make_breakpoint_pending to accept the 'script'
and 'times' arguments.
I've then added a new test that makes use of 'scripts' in
gdb.mi/mi-pending.exp and gdb.mi/mi-dprintf-pending.exp.
There is already a test in gdb.mi/mi-pending.exp that uses the 'times'
argument -- previously this argument was being ignored, but is now
used.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
Commit:
commit c569a946f6925d3f210c3eaf74dcda56843350ef
Date: Fri Mar 24 10:45:37 2023 +0100
[gdb/testsuite] Fix unbalanced quotes in mi_expect_stop argument
Introduced the use of {"} in mi-support.exp. There is absolutely
nothing wrong with this in any way. However, this is causing my
editor to get the syntax highlighting of this file wrong after this
point.
Maybe the real answer is to use a better editor, or fix my current
editor.... but I'm hoping I can instead take the lazy approach of just
changing {"} to "\"", which is handled fine, and means exactly the
same as far as I understand it.
There should be no change in what is tested after this commit.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
(1) Description of problem
In the current code, when execute the following test on LoongArch:
$make check-gdb TESTS="gdb.base/dump.exp"
```
FAIL: gdb.base/dump.exp: dump array as value, intel hex
FAIL: gdb.base/dump.exp: dump struct as value, intel hex
FAIL: gdb.base/dump.exp: dump array as memory, ihex
FAIL: gdb.base/dump.exp: dump struct as memory, ihex
```
These tests passed on the X86_64,
(2) Root cause
On LoongArch, variable intarray address 0x120008068 out of range for IHEX,
so dump ihex test failed.
gdb.base/dump.exp has the following code to check 64-bit address
```
# Check the address of a variable. If it is bigger than 32-bit,
# assume our target has 64-bit addresses that are not supported by SREC,
# IHEX and TEKHEX. We skip those tests then.
set max_32bit_address "0xffffffff"
set data_address [get_hexadecimal_valueof "&intarray" 0x100000000]
if {${data_address} > ${max_32bit_address}} {
set is64bitonly "yes"
}
```
We check the "&intarray" on different target as follow:
```
$gdb gdb/testsuite/outputs/gdb.base/dump/dump
...
(gdb) start
...
On X86_64:
(gdb) print /x &intarray
$1 = 0x404060
On LoongArch:
(gdb) print /x &intarray
$1 = 0x120008068
```
The variable address difference here is due to the link script
of linker.
```
On X86_64:
$ld --verbose
...
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000));
. = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
On LoongArch:
$ld --verbose
...
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x120000000));
. = SEGMENT_START("text-segment", 0x120000000) + SIZEOF_HEADERS;
```
(3) How to fix
Because 64-bit variable address out of range for IHEX, it's not an
functional problem for LoongArch. Refer to the handling of 64-bit
targets in this testsuite, use the "is64bitonly" flag to skip those
tests for the target has 64-bit addresses.
Signed-off-by: Hui Li <lihui@loongson.cn>
Approved-By: Tom Tromey <tom@tromey.com>
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
|
|
Add regression tests for PR30325, one for the asm window and one for the
source window.
Use maint set tui-left-margin verbose to make the extend of the left margin
clear.
Tested on x86_64-linux.
Approved-By: Andrew Burgess <aburgess@redhat.com>
|
|
I found a couple of tests that check gnatmake_version_at_least using
"if" where "require" would be a little cleaner. This patch converts
these.
|
|
Spotted a small typo in gdb_breakpoint proc, we use $gdb_name_name
instead of $gdb_test_name in one place. Fixed in this commit.
|
|
On amd64 (at least) if a user sets a watchpoint before the inferior
has started then GDB will assume that a hardware watchpoint can be
created.
When the inferior starts there is a chance that the watchpoint can't
actually be create as a hardware watchpoint, in which case (currently)
GDB will silently convert the watchpoint to a software watchpoint.
Here's an example session:
(gdb) p sizeof var
$1 = 4000
(gdb) watch var
Hardware watchpoint 1: var
(gdb) info watchpoints
Num Type Disp Enb Address What
1 hw watchpoint keep y var
(gdb) starti
Starting program: /home/andrew/tmp/watch
Program stopped.
0x00007ffff7fd3110 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) info watchpoints
Num Type Disp Enb Address What
1 watchpoint keep y var
(gdb)
Notice that before the `starti` command the watchpoint is showing as a
hardware watchpoint, but afterwards it is showing as a software
watchpoint. Additionally, note that we clearly told the user we
created a hardware watchpoint:
(gdb) watch var
Hardware watchpoint 1: var
I think this is bad. I used `starti`, but if the user did `start` or
even `run` then the inferior is going to be _very_ slow, which will be
unexpected -- after all, we clearly told the user that we created a
hardware watchpoint, and the manual clearly says that hardware
watchpoints are fast (at least compared to s/w watchpoints).
In this patch I propose adding a new warning which will be emitted
when GDB downgrades a h/w watchpoint to s/w. The session now looks
like this:
(gdb) p sizeof var
$1 = 4000
(gdb) watch var
Hardware watchpoint 1: var
(gdb) info watchpoints
Num Type Disp Enb Address What
1 hw watchpoint keep y var
(gdb) starti
Starting program: /home/andrew/tmp/watch
warning: watchpoint 1 downgraded to software watchpoint
Program stopped.
0x00007ffff7fd3110 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) info watchpoints
Num Type Disp Enb Address What
1 watchpoint keep y var
(gdb)
The important line is:
warning: watchpoint 1 downgraded to software watchpoint
It's not much, but hopefully it will be enough to indicate to the user
that something unexpected has occurred, and hopefully, they will not
be surprised when the inferior runs much slower than they expected.
I've added an amd64 only test in gdb.arch/, I didn't want to try
adding this as a global test as other architectures might be able to
support the watchpoint request in h/w.
Also the test is skipped for extended-remote boards as there's a
different set of options for limiting hardware watchpoints on remote
targets, and this test isn't about them.
Reviewed-By: Lancelot Six <lancelot.six@amd.com>
|
|
I was seeing some failures in gdb.threads/omp-par-scope.exp when run
on a riscv64 target. It turns out the cause of the problem is that I
didn't have debug information installed for libgomp.so, which this
test makes use of. The test requires GDB to backtrace through a
libgomp function, and the riscv prologue unwinder was failing to
unwind this particular stack frame.
The reason for the failure to unwind was that the function prologue
includes a c.li (compressed load immediate) instruction, and the riscv
prologue scanning unwinder doesn't know what to do with this
instruction, though the unwinder does understand c.lui (compressed
load unsigned immediate).
This commit adds support for c.li. After this GDB is able to unwind
through libgomp, and I no longer see any unexpected failures in
gdb.threads/omp-par-scope.exp.
I've also included a new test in gdb.arch/ which specifically checks
for our c.li support.
|
|
I noticed there aren't any Ada test cases for setting a breakpoint
using a label. This patch adds one, adapted from the AdaCore test
suite.
|
|
Whenever we start gdb in the testsuite, we have the rather verbose:
...
$ gdb
GNU gdb (GDB) 14.0.50.20230405-git
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb)
...
This makes gdb.log longer than necessary and harder to read.
We do need to test that the output is produced, but that should be limited to
one or a few test-cases.
Fix this by adding -q to INTERNAL_GDBFLAGS, such that we simply have:
...
$ gdb -q
(gdb)
...
Tested on x86_64-linux.
|
|
gdb.arch/amd64-disp-step-self-call.exp
For test-case gdb.arch/amd64-disp-step-self-call.exp I get:
...
gdb compile failed, ld: warning: amd64-disp-step-self-call0.o: \
missing .note.GNU-stack section implies executable stack
ld: NOTE: This behaviour is deprecated and will be removed in a future \
version of the linker
...
Fix this by adding the missing .note.GNU-stack.
Likewise for gdb.arch/i386-disp-step-self-call.exp.
Tested on x86_64-linux.
|
|
This commit:
commit cf141dd8ccd36efe833aae3ccdb060b517cc1112
Date: Wed Feb 22 12:15:34 2023 +0000
gdb: fix reg corruption from displaced stepping on amd64
Added two test scripts gdb.arch/amd64-disp-step-self-call.exp and
gdb.arch/i386-disp-step-self-call.exp. These scripts contained a test
that included a stack address in the test name, this makes it harder
to compare results between runs.
This commit gives the tests proper names that doesn't include an
address.
Also in gdb.arch/i386-disp-step-self-call.exp I noticed that we were
writing 8-bytes rather than 4 in order to clear the return address
entry on the stack. This is also fixed in this commit.
|
|
Clang with LTO (clang -flto) garbage collects unused global variables,
Thus, gdb.base/align-c.exp and gdb.base/align-c++.exp fail with
hundreds of FAILs like so:
$ make check \
TESTS="gdb.*/align-*.exp" \
RUNTESTFLAGS="CC_FOR_TARGET='clang -flto' CXX_FOR_TARGET='clang++ -flto'"
...
FAIL: gdb.base/align-c.exp: get integer valueof "a_char"
FAIL: gdb.base/align-c.exp: print _Alignof(char)
FAIL: gdb.base/align-c.exp: get integer valueof "a_char_x_char"
FAIL: gdb.base/align-c.exp: print _Alignof(struct align_pair_char_x_char)
FAIL: gdb.base/align-c.exp: get integer valueof "a_char_x_unsigned_char"
...
AIX GCC has the same issue, and there the easier way of adding
__attribute__((used)) to globals does not help.
So add explicit uses of all globals to the generated code.
For the C++ test, that reveals that the static variable members of the
generated structs are not defined anywhere, leading to undefined
references. Fixed by emitting initialization for all static members.
Lastly, I noticed that CXX_FOR_TARGET was being ignored -- that's
because the align-c++.exp testcase is compiling with the C compiler
driver. Fixed by passing "c++" as option to prepare_for_testing.
Change-Id: I874b717afde7b6fb1e45e526912b518a20a12716
|
|
This commit allows Frame.read_var to accept named arguments, and also
improves (I think) some of the error messages emitted when values of
the wrong type are passed to this function.
The read_var method takes two arguments, one a variable, which is
either a gdb.Symbol or a string, while the second, optional, argument
is always a gdb.Block.
I'm now using 'O!' as the format specifier for the second argument,
which allows the argument type to be checked early on. Currently, if
the second argument is of the wrong type then we get this error:
(gdb) python print(gdb.selected_frame().read_var("a1", "xxx"))
Traceback (most recent call last):
File "<string>", line 1, in <module>
RuntimeError: Second argument must be block.
Error while executing Python code.
(gdb)
After this commit, we now get an error like this:
(gdb) python print(gdb.selected_frame().read_var("a1", "xxx"))
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: argument 2 must be gdb.Block, not str
Error while executing Python code.
(gdb)
Changes are:
1. Exception type is TypeError not RuntimeError, this is unfortunate
as user code _could_ be relying on this, but I think the improvement
is worth the risk, user code relying on the exact exception type is
likely to be pretty rare,
2. New error message gives argument position and expected argument
type, as well as the type that was passed.
If the first argument, the variable, has the wrong type then the
previous exception was already a TypeError, however, I've updated the
text of the exception to more closely match the "standard" error
message we see above. If the first argument has the wrong type then
before this commit we saw this:
(gdb) python print(gdb.selected_frame().read_var(123))
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: Argument must be a symbol or string.
Error while executing Python code.
(gdb)
And after we see this:
(gdb) python print(gdb.selected_frame().read_var(123))
Traceback (most recent call last):
File "<string>", line 1, in <module>
TypeError: argument 1 must be gdb.Symbol or str, not int
Error while executing Python code.
(gdb)
For existing code that doesn't use named arguments and doesn't rely on
exceptions, there will be no changes after this commit.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
Following on from the previous commit, this updates
Frame.read_register to accept named arguments. As with the previous
commit there's no huge benefit for the users in accepting named
arguments here -- this function only takes a single argument after
all.
But I do think it is worth keeping Frame.read_register method in sync
with the PendingFrame.read_register method, this allows for the
possibility that the user has some code that can operate on either a
Frame or a Pending frame.
Minor update to allow for named arguments, and an extra test to check
the new functionality.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
Update the two gdb.PendingFrame methods gdb.PendingFrame.read_register
and gdb.PendingFrame.create_unwind_info to accept keyword arguments.
There's no huge benefit for making this change, both of these methods
only take a single argument, so it is (maybe) less likely that a user
will take advantage of the keyword arguments in these cases, but I
think it's nice to be consistent, and I don't see any particular draw
backs to making this change.
For PendingFrame.read_register I've changed the argument name from
'reg' to 'register' in the documentation and used 'register' as the
argument name in GDB. My preference for APIs is to use full words
where possible, and given we didn't support named arguments before
this change should not break any existing code.
There should be no user visible changes (for existing code) after this
commit.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
Update gdb.UnwindInfo.add_saved_register to accept named keyword
arguments.
As part of this update we now use gdb_PyArg_ParseTupleAndKeywords
instead of PyArg_UnpackTuple to parse the function arguments.
By switching to gdb_PyArg_ParseTupleAndKeywords, we can now use 'O!'
as the argument format for the function's value argument. This means
that we can check the argument type (is gdb.Value) as part of the
argument processing rather than manually performing the check later in
the function. One result of this is that we now get a better error
message (at least, I think so). Previously we would get something
like:
ValueError: Bad register value
Now we get:
TypeError: argument 2 must be gdb.Value, not XXXX
It's unfortunate that the exception type changed, but I think the new
exception type actually makes more sense.
My preference for argument names is to use full words where that's not
too excessive. As such, I've updated the name of the argument from
'reg' to 'register' in the documentation, which is the argument name
I've made GDB look for here.
For existing unwinder code that doesn't throw any exceptions nothing
should change with this commit. It is possible that a user has some
code that throws and catches the ValueError, and this code will break
after this commit, but I think this is going to be sufficiently rare
that we can take the risk here.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
This commit aims to address a problem that exists with the current
approach to displaced stepping, and was identified in PR gdb/22921.
Displaced stepping is currently supported on AArch64, ARM, amd64,
i386, rs6000 (ppc), and s390. Of these, I believe there is a problem
with the current approach which will impact amd64 and ARM, and can
lead to random register corruption when the inferior makes use of
asynchronous signals and GDB is using displaced stepping.
The problem can be found in displaced_step_buffers::finish in
displaced-stepping.c, and is this; after GDB tries to perform a
displaced step, and the inferior stops, GDB classifies the stop into
one of two states, either the displaced step succeeded, or the
displaced step failed.
If the displaced step succeeded then gdbarch_displaced_step_fixup is
called, which has the job of fixing up the state of the current
inferior as if the step had not been performed in a displaced manner.
This all seems just fine.
However, if the displaced step is considered to have not completed
then GDB doesn't call gdbarch_displaced_step_fixup, instead GDB
remains in displaced_step_buffers::finish and just performs a minimal
fixup which involves adjusting the program counter back to its
original value.
The problem here is that for amd64 and ARM setting up for a displaced
step can involve changing the values in some temporary registers. If
the displaced step succeeds then this is fine; after the step the
temporary registers are restored to their original values in the
architecture specific code.
But if the displaced step does not succeed then the temporary
registers are never restored, and they retain their modified values.
In this context a temporary register is simply any register that is
not otherwise used by the instruction being stepped that the
architecture specific code considers safe to borrow for the lifetime
of the instruction being stepped.
In the bug PR gdb/22921, the amd64 instruction being stepped is
an rip-relative instruction like this:
jmp *0x2fe2(%rip)
When we displaced step this instruction we borrow a register, and
modify the instruction to something like:
jmp *0x2fe2(%rcx)
with %rcx having its value adjusted to contain the original %rip
value.
Now if the displaced step does not succeed, then %rcx will be left
with a corrupted value. Obviously corrupting any register is bad; in
the bug report this problem was spotted because %rcx is used as a
function argument register.
And finally, why might a displaced step not succeed? Asynchronous
signals provides one reason. GDB sets up for the displaced step and,
at that precise moment, the OS delivers a signal (SIGALRM in the bug
report), the signal stops the inferior at the address of the displaced
instruction. GDB cancels the displaced instruction, handles the
signal, and then tries again with the displaced step. But it is that
first cancellation of the displaced step that causes the problem; in
that case GDB (correctly) sees the displaced step as having not
completed, and so does not perform the architecture specific fixup,
leaving the register corrupted.
The reason why I think AArch64, rs600, i386, and s390 are not effected
by this problem is that I don't believe these architectures make use
of any temporary registers, so when a displaced step is not completed
successfully, the minimal fix up is sufficient.
On amd64 we use at most one temporary register.
On ARM, looking at arm_displaced_step_copy_insn_closure, we could
modify up to 16 temporary registers, and the instruction being
displaced stepped could be expanded to multiple replacement
instructions, which increases the chances of this bug triggering.
This commit only aims to address the issue on amd64 for now, though I
believe that the approach I'm proposing here might be applicable for
ARM too.
What I propose is that we always call gdbarch_displaced_step_fixup.
We will now pass an extra argument to gdbarch_displaced_step_fixup,
this a boolean that indicates whether GDB thinks the displaced step
completed successfully or not.
When this flag is false this indicates that the displaced step halted
for some "other" reason. On ARM GDB can potentially read the
inferior's program counter in order figure out how far through the
sequence of replacement instructions we got, and from that GDB can
figure out what fixup needs to be performed.
On targets like amd64 the problem is slightly easier as displaced
stepping only uses a single replacement instruction. If the displaced
step didn't complete the GDB knows that the single instruction didn't
execute.
The point is that by always calling gdbarch_displaced_step_fixup, each
architecture can now ensure that the inferior state is fixed up
correctly in all cases, not just the success case.
On amd64 this ensures that we always restore the temporary register
value, and so bug PR gdb/22921 is resolved.
In order to move all architectures to this new API, I have moved the
minimal roll-back version of the code inside the architecture specific
fixup functions for AArch64, rs600, s390, and ARM. For all of these
except ARM I think this is good enough, as no temporaries are used all
that's needed is the program counter restore anyway.
For ARM the minimal code is no worse than what we had before, though I
do consider this architecture's displaced-stepping broken.
I've updated the gdb.arch/amd64-disp-step.exp test to cover the
'jmpq*' instruction that was causing problems in the original bug, and
also added support for testing the displaced step in the presence of
asynchronous signal delivery.
I've also added two new tests (for amd64 and i386) that check that GDB
can correctly handle displaced stepping over a single instruction that
branches to itself. I added these tests after a first version of this
patch relied too much on checking the program-counter value in order
to see if the displaced instruction had executed. This works fine in
almost all cases, but when an instruction branches to itself a pure
program counter check is not sufficient. The new tests expose this
problem.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=22921
Approved-By: Pedro Alves <pedro@palves.net>
|
|
The stabs debug format is obsolete and there's no reason to think that
toolchains still have good support for it. Therefore, if a specific debug
format wasn't set in asm-source.exp then leave it to the assembler to
decide which one to use.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
This adds the DAP readMemory and writeMemory requests. A small change
to the evaluation code is needed in order to test this -- this is one
of the few ways for a client to actually acquire a memory reference.
|
|
Consider the following session:
(gdb) list some_func
1 int
2 some_func ()
3 {
4 int *p = 0;
5 return *p;
6 }
7
8 void
9 foo ()
10 {
(gdb) break foo if (some_func ())
Breakpoint 1 at 0x40111e: file bpcond.c, line 11.
(gdb) r
Starting program: /tmp/bpcond
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401116 in some_func () at bpcond.c:5
5 return *p;
Error in testing condition for breakpoint 1:
The program being debugged stopped while in a function called from GDB.
Evaluation of the expression containing the function
(some_func) will be abandoned.
When the function is done executing, GDB will silently stop.
Breakpoint 1, 0x0000000000401116 in some_func () at bpcond.c:5
5 return *p;
(gdb)
What happens here is the breakpoint condition includes a call to an
inferior function, and the inferior function segfaults. We can see
that GDB reports the segfault, and then gives an error message that
indicates that an inferior function call was interrupted.
After this GDB appears to report that it is stopped at Breakpoint 1,
inside some_func.
I find this second stop report a little confusing. While it is true
that GDB stopped as a result of hitting breakpoint 1, I think the
message GDB currently prints might give the impression that GDB is
actually stopped at a location of breakpoint 1, which is not the case.
Also, I find the second stop message draws attention away from
the "Program received signal SIGSEGV, Segmentation fault" stop
message, and this second stop might be thought of as replacing in
someway the earlier message.
In short, I think things would be clearer if the second stop message
were not reported at all, so the output should, I think, look like
this:
(gdb) list some_func
1 int
2 some_func ()
3 {
4 int *p = 0;
5 return *p;
6 }
7
8 void
9 foo ()
10 {
(gdb) break foo if (some_func ())
Breakpoint 1 at 0x40111e: file bpcond.c, line 11.
(gdb) r
Starting program: /tmp/bpcond
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401116 in some_func () at bpcond.c:5
5 return *p;
Error in testing condition for breakpoint 1:
The program being debugged stopped while in a function called from GDB.
Evaluation of the expression containing the function
(some_func) will be abandoned.
When the function is done executing, GDB will silently stop.
(gdb)
The user can still find the number of the breakpoint that triggered
the initial stop in this line:
Error in testing condition for breakpoint 1:
But there's now only one stop reason reported, the SIGSEGV, which I
think is much clearer.
To achieve this change I set the bpstat::print field when:
(a) a breakpoint condition evaluation failed, and
(b) the $pc of the thread changed during condition evaluation.
I've updated the existing tests that checked the error message printed
when a breakpoint condition evaluation failed.
|
|
Consider the following case:
(gdb) list some_func
1 int
2 some_func ()
3 {
4 int *p = 0;
5 return *p;
6 }
7
8 void
9 foo ()
10 {
(gdb) break foo if (some_func ())
Breakpoint 1 at 0x40111e: file bpcond.c, line 11.
(gdb) r
Starting program: /tmp/bpcond
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401116 in some_func () at bpcond.c:5
5 return *p;
Error in testing breakpoint condition:
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(some_func) will be abandoned.
When the function is done executing, GDB will silently stop.
Program received signal SIGSEGV, Segmentation fault.
Breakpoint 1, 0x0000000000401116 in some_func () at bpcond.c:5
5 return *p;
(gdb)
Notice that this line:
Program received signal SIGSEGV, Segmentation fault.
Appears twice in the output. The first time is followed by the
current location. The second time is a little odd, why do we print
that?
Printing that line is controlled, in part, by a global variable,
stopped_by_random_signal. This variable is reset to zero in
handle_signal_stop, and is set if/when GDB figures out that the
inferior stopped due to some random signal.
The problem is, in our case, GDB first stops at the breakpoint for
foo, and enters handle_signal_stop and the stopped_by_random_signal
global is reset to 0.
Later within handle_signal_stop GDB calls bpstat_stop_status, it is
within this function (via bpstat_check_breakpoint_conditions) that the
breakpoint condition is checked, and, we end up calling the inferior
function (some_func in our example above).
In our case above the thread performing the inferior function call
segfaults in some_func. GDB catches the SIGSEGV and handles the stop,
this causes us to reenter handle_signal_stop. The global variable
stopped_by_random_signal is updated, this time it is set to true
because the thread stopped due to SIGSEGV. As a result of this we
print the first instance of the line (as seen above in the example).
Finally we unwind GDB's call stack, the inferior function call is
complete, and we return to the original handle_signal_stop. However,
the stopped_by_random_signal global is still carrying the value as
computed for the inferior function call's stop, which is why we now
print a second instance of the line, as seen in the example.
To prevent this, I propose adding a scoped_restore before we start an
inferior function call. This will save and restore the global
stopped_by_random_signal value.
With this done, the output from our example is now this:
(gdb) list some_func
1 int
2 some_func ()
3 {
4 int *p = 0;
5 return *p;
6 }
7
8 void
9 foo ()
10 {
(gdb) break foo if (some_func ())
Breakpoint 1 at 0x40111e: file bpcond.c, line 11.
(gdb) r
Starting program: /tmp/bpcond
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401116 in some_func () at bpcond.c:5
5 return *p;
Error in testing condition for breakpoint 1:
The program being debugged stopped while in a function called from GDB.
Evaluation of the expression containing the function
(some_func) will be abandoned.
When the function is done executing, GDB will silently stop.
Breakpoint 1, 0x0000000000401116 in some_func () at bpcond.c:5
5 return *p;
(gdb)
We now only see the 'Program received signal SIGSEGV, ...' line once,
which I think makes more sense.
Finally, I'm aware that the last few lines, that report the stop as
being at 'Breakpoint 1', when this is not where the thread is actually
located anymore, is not great. I'll address that in the next commit.
|
|
This commit extends gdbserver to take account of a failed memory
access from agent_mem_read, and to return a new eval_result_type
expr_eval_invalid_memory_access.
I have only updated the agent_mem_read calls related directly to
reading memory, I have not updated any of the calls related to
tracepoint data collection. This is just because I'm not familiar
with that area of gdb/gdbserver, and I don't want to break anything,
so leaving the existing behaviour untouched seems like the safest
approach.
I've then updated gdb.base/bp-cond-failure.exp to test evaluating the
breakpoints on the target, and have also extended the test so that it
checks for different sizes of memory access.
|
|
When GDB fails to test the condition of a conditional breakpoint, for
whatever reason, the error message looks like this:
(gdb) break foo if (*(int *) 0) == 1
Breakpoint 1 at 0x40111e: file bpcond.c, line 11.
(gdb) r
Starting program: /tmp/bpcond
Error in testing breakpoint condition:
Cannot access memory at address 0x0
Breakpoint 1, foo () at bpcond.c:11
11 int a = 32;
(gdb)
The line I'm interested in for this commit is this one:
Error in testing breakpoint condition:
In the case above we can figure out that the problematic breakpoint
was #1 because in the final line of the message GDB reports the stop
at breakpoint #1.
However, in the next few patches I plan to change this. In some cases
I don't think it makes sense for GDB to report the stop as being at
breakpoint #1, consider this case:
(gdb) list some_func
1 int
2 some_func ()
3 {
4 int *p = 0;
5 return *p;
6 }
7
8 void
9 foo ()
10 {
(gdb) break foo if (some_func ())
Breakpoint 1 at 0x40111e: file bpcond.c, line 11.
(gdb) r
Starting program: /tmp/bpcond
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401116 in some_func () at bpcond.c:5
5 return *p;
Error in testing breakpoint condition:
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(some_func) will be abandoned.
When the function is done executing, GDB will silently stop.
Program received signal SIGSEGV, Segmentation fault.
Breakpoint 1, 0x0000000000401116 in some_func () at bpcond.c:5
5 return *p;
(gdb)
Notice that, the final lines of output reports the stop as being at
breakpoint #1, even though the inferior in not located within
some_func, and it's certainly not located at the breakpoint location.
I find this behaviour confusing, and propose that this should be
changed. However, if I make that change then every reference to
breakpoint #1 will be lost from the error message.
So, in this commit, in preparation for the later commits, I propose to
change the 'Error in testing breakpoint condition:' line to this:
Error in testing condition for breakpoint NUMBER:
where NUMBER will be filled in as appropriate. Here's the first
example with the updated error:
(gdb) break foo if (*(int *) 0) == 0
Breakpoint 1 at 0x40111e: file bpcond.c, line 11.
(gdb) r
Starting program: /tmp/bpcond
Error in testing condition for breakpoint 1:
Cannot access memory at address 0x0
Breakpoint 1, foo () at bpcond.c:11
11 int a = 32;
(gdb)
The breakpoint number does now appear twice in the output, but I don't
see that as a negative.
This commit just changes the one line of the error, and updates the
few tests that either included the old error in comments, or actually
checked for the error in the expected output.
As the only test that checked the line I modified is a Python test,
I've added a new test that doesn't rely on Python that checks the
error message in detail.
While working on the new test, I spotted that it would fail when run
with native-gdbserver and native-extended-gdbserver target boards.
This turns out to be due to a gdbserver bug. To avoid cluttering this
commit I've added a work around to the new test script so that the
test passes for the remote boards, in the next few commits I will fix
gdbserver, and update the test script to remove the work around.
|
|
This commit follows on from the following two commits:
commit 80dc83fd0e70f4d522a534bc601df5e05b81d564
Date: Fri Jun 11 11:30:47 2021 +0100
gdb/remote: handle target dying just before a stepi
And:
commit 079f190d4cfc6aa9c934b00a9134bc0fcc172d53
Date: Thu Mar 9 10:45:03 2023 +0100
[gdb/testsuite] Fix gdb.server/server-kill.exp for remote target
The first of these commits fixed an issue in GDB and tried to extend
the gdb.server/server-kill.exp test to cover the GDB fix.
Unfortunately, the changes to gdb.server/server-kill.exp were not
correct, and were causing problems when trying to run with the
remote-gdbserver-on-localhost board file.
The second commit reverts some of the gdb.server/server-kill.exp
changes introduced in the first commit so that the test will now work
correctly with the remote-gdbserver-on-localhost board file.
The second commit is just about GDB's testing infrastructure -- it's
not about the original fix to GDB from the first commit, the actual
GDB change was fine.
While reviewing the second commit I wanted to check that the problem
fixed in the first commit is still being tested by the
gdb.server/server-kill.exp script, so I reverted the change to
breakpoint.c that is the core of the first commit and ran the test
script ..... and saw no failures.
The first commit is about GDB discovering that gdbserver has died
while trying to insert a breakpoint. As soon as GDB spots that
gdbserver is gone we mourn the remote inferior, which ends up deleting
all the breakpoints associated with the remote inferiors. We then
throw an exception which is caught in the insert breakpoints code, and
we try to display an error that includes the breakpoint number
.... but the breakpoint has already been deleted ... and so GDB
crashes.
After digging a little, what I found is that today, when the test does
'stepi' the first thing we end up doing is calculating the frame-id as
part of the stepi logic, it is during this frame-id calculation that
we mourn the remote inferior, delete the breakpoints, and throw an
exception. The exception is caught by the top level interpreter loop,
and so we never try to print the breakpoint number which is what
caused the original crash.
If I add an 'info frame' command to the test script, prior to killing
gdbserver, then now when we 'stepi' GDB already has the frame-id
calculated, and the first thing we do is try to insert the
breakpoints, this will trigger the original bug.
In order to reproduce this experiment you'll need to change a function
in breakpoint.c, like this:
static void
rethrow_on_target_close_error (const gdb_exception &e)
{
return;
}
Then run gdb.server/server-kill.exp with and without this patch. You
should find that without this patch there are zero test failures,
while with this patch there will be one failure like this:
(gdb) PASS: gdb.server/server-kill.exp: test_stepi: info frame
Executing on target: kill -9 4513 (timeout = 300)
builtin_spawn -ignore SIGHUP kill -9 4513
stepi
../../src/gdb/breakpoint.c:2863: internal-error: insert_bp_location: Assertion `bl->owner != nullptr' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
----- Backtrace -----
...
|
|
A potential test failure was introduced with commit:
commit 6bf5f25bb150c0fbcb125e3ee466ba8f9680310b
Date: Wed Mar 8 16:11:30 2023 +0000
gdb/python: make the gdb.unwinder.Unwinder class more robust
In this commit a new test was added, however the expected output
pattern varies depending on which Python version GDB is linked
against.
Older versions of Python result in output like this:
(gdb) python global_test_unwinder.name = "foo"
Traceback (most recent call last):
File "<string>", line 1, in <module>
AttributeError: can't set attribute
Error while executing Python code.
(gdb)
While more recent versions of Python give a similar, but slightly more
verbose error message, like this:
(gdb) python global_test_unwinder.name = "foo"
Traceback (most recent call last):
File "<string>", line 1, in <module>
AttributeError: can't set attribute 'name'
Error while executing Python code.
(gdb)
The test was only accepting the first version of the output. This
commit extends the test pattern so that either version will be
accepted.
|
|
GDB expected PC should point right after the SVC instruction when the
syscall is active. But some active syscalls keep PC pointing to the SVC
instruction itself.
This leads to a broken backtrace like:
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
#0 0xb6f8681c in pthread_cond_timedwait@@GLIBC_2.4 () from /lib/arm-linux-gnueabihf/libpthread.so.0
#1 0xb6e21f80 in ?? ()
The reason is that .ARM.exidx unwinder gives up if PC does not point
right after the SVC (syscall) instruction. I did not investigate why but
some syscalls will point PC to the SVC instruction itself. This happens
for the "futex" syscall used by pthread_cond_timedwait.
That normally does not matter as ARM prologue unwinder gets called
instead of the .ARM.exidx one. Unfortunately some glibc calls have more
complicated prologue where the GDB unwinder fails to properly determine
the return address (that is in fact an orthogonal GDB bug). I expect it
is due to the "vpush" there in this case but I did not investigate it more:
Dump of assembler code for function pthread_cond_timedwait@@GLIBC_2.4:
0xb6f8757c <+0>: push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
0xb6f87580 <+4>: mov r10, r2
0xb6f87584 <+8>: vpush {d8}
Regression tested on armv7l kernel 5.15.32-v7l+ (Raspbian 11).
Approved-By: Luis Machado <luis.machado@arm.com>
|
|
With test-case gdb.base/trace-commands.exp and editing off, I run into fails
because multi-line commands are issued using gdb_test_sequence, which
doesn't handle them correctly.
Fix this by using gdb_test instead.
Tested on x86_64-linux.
PR testsuite/30288
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30288
|
|
With test-case gdb.threads/threadapply.exp and editing set to on, we have:
...
(gdb) define remove^M
Type commands for definition of "remove".^M
End with a line saying just "end".^M
>remove-inferiors 3^M
>end^M
(gdb)
...
but with editing set to off, we run into:
...
(gdb) define remove^M
Type commands for definition of "remove".^M
End with a line saying just "end".^M
>remove-inferiors 3^M
end^M
>(gdb) FAIL: gdb.threads/threadapply.exp: thread_set=all: try remove: \
define remove (timeout)
...
The commands are issued by this test:
...
gdb_define_cmd "remove" {
"remove-inferiors 3"
}
...
which does:
- gdb_test_multiple "define remove", followed by
- gdb_test_multiple "remove-inferiors 3\nend".
Proc gdb_test_multiple has special handling for multi-line commands, which
splits it up into subcommands, and for each subcommand issues it and then
waits for the resulting prompt (the secondary prompt ">" for all but the last
subcommand).
However, that doesn't work as expected in this case because the initial
gdb_test_multiple "define remove" fails to match all resulting output, and
consequently the secondary prompt resulting from "define remove" is counted as
if it was the one resulting from "remove-inferiors 3".
Fix this by matching the entire output of "define remove", including the
secondary prompt.
Tested on x86_64-linux.
PR testsuite/30288
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30288
|
|
Allow consumers of GDB to extract the name of the main method. This is
most useful for Fortran programs which have a variable main method.
Used by both MAP and DDT e.g. it is used to detect the presence of debug
information.
Co-Authored-By: Maciej W. Rozycki <macro@embecosm.com>
|
|
In the case where a Fortran program has a program name of "main" and
there is also a minimal symbol called main, such as with programs built
with GCC version 4.4.7 or below, the backtrace will erroneously stop at
the minimal symbol rather than the user specified main, e.g.:
(gdb) bt
#0 bar () at .../gdb/testsuite/gdb.fortran/backtrace.f90:17
#1 0x0000000000402556 in foo () at .../gdb/testsuite/gdb.fortran/backtrace.f90:21
#2 0x0000000000402575 in main () at .../gdb/testsuite/gdb.fortran/backtrace.f90:31
#3 0x00000000004025aa in main ()
(gdb)
This patch fixes this issue by increasing the precedence of the full
symbol when the language of the current frame is Fortran.
Newer versions of GCC transform the program name to "MAIN__" in this
case, avoiding the problem.
Co-Authored-By: Maciej W. Rozycki <macro@embecosm.com>
|
|
When writing an unwinder it is necessary to create a new class to act
as a frame-id. This new class is almost certainly just going to set a
'sp' and 'pc' attribute within the instance.
This commit adds a little helper class gdb.unwinder.FrameId that does
this job. Users can make use of this to avoid having to write out
standard boilerplate code any time they write an unwinder.
Of course, if the user wants their FrameId class to be more
complicated in some way, then they can still write their own class,
just like they could before.
I've simplified the example code in the documentation to now use the
new helper class, and I've also made use of this helper within the
testsuite.
Any existing user code will continue to work just as it did before
after this change.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
Currently when creating a gdb.UnwindInfo object a user must call
gdb.PendingFrame.create_unwind_info and pass a frame-id object.
The frame-id object should have at least a 'sp' attribute, and
probably a 'pc' attribute too (it can also, in some cases have a
'special' attribute).
Currently all of these frame-id attributes need to be gdb.Value
objects, but the only reason for that requirement is that we have some
code in py-unwind.c that only handles gdb.Value objects.
If instead we switch to using get_addr_from_python in py-utils.c then
we will support both gdb.Value objects and also raw numbers, which
might make things simpler in some cases.
So, I started rewriting pyuw_object_attribute_to_pointer (in
py-unwind.c) to use get_addr_from_python. However, while looking at
the code I noticed a problem.
The pyuw_object_attribute_to_pointer function returns a boolean flag,
if everything goes OK we return true, but we return false in two
cases, (1) when the attribute is not present, which might be
acceptable, or might be an error, and (2) when we get an error trying
to extract the attribute value, in which case a Python error will have
been set.
Now in pending_framepy_create_unwind_info we have this code:
if (!pyuw_object_attribute_to_pointer (pyo_frame_id, "sp", &sp))
{
PyErr_SetString (PyExc_ValueError,
_("frame_id should have 'sp' attribute."));
return NULL;
}
Notice how we always set an error. This will override any error that
is already set.
So, if you create a frame-id object that has an 'sp' attribute, but
the attribute is not a gdb.Value, then currently we fail to extract
the attribute value (it's not a gdb.Value) and set this error in
pyuw_object_attribute_to_pointer:
rc = pyuw_value_obj_to_pointer (pyo_value.get (), addr);
if (!rc)
PyErr_Format (
PyExc_ValueError,
_("The value of the '%s' attribute is not a pointer."),
attr_name);
Then we return to pending_framepy_create_unwind_info and immediately
override this error with the error about 'sp' being missing.
This all feels very confused.
Here's my proposed solution: pyuw_object_attribute_to_pointer will now
return a tri-state enum, with states OK, MISSING, or ERROR. The
meanings of these states are:
OK - Attribute exists and was extracted fine,
MISSING - Attribute doesn't exist, no Python error was set.
ERROR - Attribute does exist, but there was an error while
extracting it, a Python error was set.
We need to update pending_framepy_create_unwind_info, the only user of
pyuw_object_attribute_to_pointer, but now I think things are much
clearer. Errors from lower levels are not blindly overridden with the
generic meaningless error message, but we still get the "missing 'sp'
attribute" error when appropriate.
This change also includes the switch to get_addr_from_python which was
what started this whole journey.
For well behaving user code there should be no visible changes after
this commit.
For user code that hits an error, hopefully the new errors should be
more helpful in figuring out what's gone wrong.
Additionally, users can now use integers for the 'sp' and 'pc'
attributes in their frame-id objects if that is useful.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
It is not currently possible to directly create gdb.UnwindInfo
instances, they need to be created by calling
gdb.PendingFrame.create_unwind_info so that the newly created
UnwindInfo can be linked to the pending frame.
As such there's no tp_init method defined for UnwindInfo.
A consequence of all this is that it doesn't really make sense to
allow sub-classing of gdb.UnwindInfo. Any sub-class can't call the
parents __init__ method to correctly link up the PendingFrame
object (there is no parent __init__ method). And any instances that
sub-classes UnwindInfo but doesn't call the parent __init__ is going
to be invalid for use in GDB.
This commit removes the Py_TPFLAGS_BASETYPE flag from the UnwindInfo
class, which prevents the class being sub-classed. Then I've added a
test to check that this is indeed prevented.
Any functional user code will not have any issues with this change.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
Having a useful __repr__ method can make debugging Python code that
little bit easier. This commit adds __repr__ for gdb.PendingFrame and
gdb.UnwindInfo classes, along with some tests.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
The gdb.Frame class has far more methods than gdb.PendingFrame. Given
that a PendingFrame hasn't yet been claimed by an unwinder, there is a
limit to which methods we can add to it, but many of the methods that
the Frame class has, the PendingFrame class could also support.
In this commit I've added those methods to PendingFrame that I believe
are safe.
In terms of implementation: if I was starting from scratch then I
would implement many of these (or most of these) as attributes rather
than methods. However, given both Frame and PendingFrame are just
different representation of a frame, I think there is value in keeping
the interface for the two classes the same. For this reason
everything here is a method -- that's what the Frame class does.
The new methods I've added are:
- gdb.PendingFrame.is_valid: Return True if the pending frame
object is valid.
- gdb.PendingFrame.name: Return the name for the frame's function,
or None.
- gdb.PendingFrame.pc: Return the $pc register value for this
frame.
- gdb.PendingFrame.language: Return a string containing the
language for this frame, or None.
- gdb.PendingFrame.find_sal: Return a gdb.Symtab_and_line object
for the current location within the pending frame, or None.
- gdb.PendingFrame.block: Return a gdb.Block for the current
pending frame, or None.
- gdb.PendingFrame.function: Return a gdb.Symbol for the current
pending frame, or None.
In every case I've just copied the implementation over from gdb.Frame
and cleaned the code slightly e.g. NULL to nullptr. Additionally each
function required a small update to reflect the PendingFrame type, but
that's pretty minor.
There are tests for all the new methods.
For more extensive testing, I added the following code to the file
gdb/python/lib/command/unwinders.py:
from gdb.unwinder import Unwinder
class TestUnwinder(Unwinder):
def __init__(self):
super().__init__("XXX_TestUnwinder_XXX")
def __call__(self,pending_frame):
lang = pending_frame.language()
try:
block = pending_frame.block()
assert isinstance(block, gdb.Block)
except RuntimeError as rte:
assert str(rte) == "Cannot locate block for frame."
function = pending_frame.function()
arch = pending_frame.architecture()
assert arch is None or isinstance(arch, gdb.Architecture)
name = pending_frame.name()
assert name is None or isinstance(name, str)
valid = pending_frame.is_valid()
pc = pending_frame.pc()
sal = pending_frame.find_sal()
assert sal is None or isinstance(sal, gdb.Symtab_and_line)
return None
gdb.unwinder.register_unwinder(None, TestUnwinder())
This registers a global unwinder that calls each of the new
PendingFrame methods and checks the result is of an acceptable type.
The unwinder never claims any frames though, so shouldn't change how
GDB actually behaves.
I then ran the testsuite. There was only a single regression, a test
that uses 'disable unwinder' and expects a single unwinder to be
disabled -- the extra unwinder is now disabled too, which changes the
test output. So I'm reasonably confident that the new methods are not
going to crash GDB.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
This commit copies the pattern that is present in many other py-*.c
files: having a single macro to check that the Python object is still
valid.
This cleans up the code a little throughout the py-unwind.c file.
Some of the exception messages will change slightly with this commit,
though the type of the exceptions is still ValueError in all cases.
I started writing some tests for this change and immediately ran into
a problem: GDB would crash. It turns out that the PendingFrame
objects are not being marked as invalid!
In pyuw_sniffer where the pending frames are created, we make use of a
scoped_restore to invalidate the pending frame objects. However, this
only restores the pending_frame_object::frame_info field to its
previous value -- and it turns out we never actually give this field
an initial value, it's left undefined.
So, when the scoped_restore (called invalidate_frame) performs its
cleanup, it actually restores the frame_info field to an undefined
value. If this undefined value is not nullptr then any future
accesses to the PendingFrame object result in undefined behaviour and
most likely, a crash.
As part of this commit I now initialize the frame_info field, which
ensures all the new tests now pass.
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
This commit makes a few related changes to the gdb.unwinder.Unwinder
class attributes:
1. The 'name' attribute is now a read-only attribute. This prevents
user code from changing the name after registering the unwinder. It
seems very unlikely that any user is actually trying to do this in
the wild, so I'm not very worried that this will upset anyone,
2. We now validate that the name is a string in the
Unwinder.__init__ method, and throw an error if this is not the
case. Hopefully nobody was doing this in the wild. This should
make it easier to ensure the 'info unwinder' command shows sane
output (how to display a non-string name for an unwinder?),
3. The 'enabled' attribute is now implemented with a getter and
setter. In the setter we ensure that the new value is a boolean,
but the real important change is that we call
'gdb.invalidate_cached_frames()'. This means that the backtrace
will be updated if a user manually disables an unwinder (rather than
calling the 'disable unwinder' command). It is not unreasonable to
think that a user might register multiple unwinders (relating to
some project) and have one command that disables/enables all the
related unwinders. This command might operate by poking the enabled
attribute of each unwinder object directly, after this commit, this
would now work correctly.
There's tests for all the changes, and lots of documentation updates
that both cover the new changes, but also further improve (I think)
the general documentation for GDB's Unwinder API.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Tom Tromey <tom@tromey.com>
|
|
The test case in this patch shows an unusual situation: an Ada array
has a dynamic bound, but the bound comes from a frame that's referred
to by the static link. This frame is correctly found when evaluating
the array variable itself, but is lost when evaluating the array's
bounds.
This patch fixes the problem by passing this frame through to
value_at_lazy in the DWARF expression evaluator.
|