mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-10 09:33:36 +00:00
e92df1d0eb6c81bf11a93e5df0319c56d25bbed2
1629 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1ad8737b3c |
gdb: change inf_threads_iterator to yield references
When adding reference_to_pointer_iterator, I saw it as a temporary thing, to not have to do a codebase-wide change right away. Remove it from inf_threads_iterator and adjust all the users. It's very possible that I forgot to update some spots in the files I can't compile, but it will be very easy to fix if that happens. Change-Id: Iddc462fecfaafb6a9861d185b217bc714e7dc651 Approved-By: Tom Tromey <tom@tromey.com> |
||
|
|
3719472095 |
Use gnulib c-ctype module in gdb
PR ada/33217 points out that gdb incorrectly calls the <ctype.h>
functions. In particular, gdb feels free to pass a 'char' like:
char *str = ...;
... isdigit (*str)
This is incorrect as isdigit only accepts EOF and values that can be
represented as 'unsigned char' -- that is, a cast is needed here to
avoid undefined behavior when 'char' is signed and a character in the
string might be sign-extended. (As an aside, I think this API seems
obviously bad, but unfortunately this is what the standard says, and
some systems check this.)
Rather than adding casts everywhere, this changes all the code in gdb
that uses any <ctype.h> API to instead call the corresponding c-ctype
function.
Now, c-ctype has some limitations compared to <ctype.h>. It works as
if the C locale is in effect, so in theory some non-ASCII characters
may be misclassified. This would only affect a subset of character
sets, though, and in most places I think ASCII is sufficient -- for
example the many places in gdb that check for whitespace.
Furthermore, in practice most users are using UTF-8-based locales,
where these functions aren't really informative for non-ASCII
characters anyway; see the existing workarounds in gdb/c-support.h.
Note that safe-ctype.h cannot be used because it causes conflicts with
readline.h. And, we canot poison the <ctype.h> identifiers as this
provokes errors from some libstdc++ headers.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33217
Approved-By: Simon Marchi <simon.marchi@efficios.com>
|
||
|
|
1d5f884e50 |
gdb: rename gdbarch_software_single_step -> gdbarch_get_next_pcs
I spotted this while reviewing a patch adding a new gdbarch_software_single_step implementation. I find the name "software_single_step" a bit misleading or unclear. It makes it sounds as if the function executed a single step. In reality, this function returns the possible next PCs for current instructions. We have a similar concept in GDBserver: linux_process_target::low_get_next_pcs. I like that name, it's clear and straight to the point. Rename gdbarch_software_single_step to gdbarch_get_next_pcs. I find this name more indicative of what happens. There is some code for ARM shared between GDB and GDBserver to implement both sides, also called "get next pcs", so I think it all fits well together. Tested by rebuilding. Change-Id: Ide74011a5034ba11117b7e7c865a093ef0b1dece Approved-by: Kevin Buettner <kevinb@redhat.com> Acked-by: Luis Machado <luis.machado.foss@gmail.com> |
||
|
|
2f6db3e2e7 |
Revert "Call target_can_do_single_step from maybe_software_singlestep"
This reverts commit
|
||
|
|
14de1447c9 |
Call target_can_do_single_step from maybe_software_singlestep
When the PikeOS osabi sniffer was added, Pedro suggested that a target could omit stepping from its vCont? reply packet to tell gdb that software single-step must be used: https://sourceware.org/legacy-ml/gdb-patches/2018-09/msg00312.html This patch implements this idea by moving the call to target_can_do_single_step into maybe_software_singlestep. I've also removed some FIXME comments from gdbarch_components.py, and slightly updated the documentation for gdbarch_software_single_step. I think these comments are somewhat obsolete now that target_can_do_single_step exists -- the current approach isn't exactly what the comments intended, but on the other hand, it exists and works. Following review comments from Andrew, this version changes record-full to use maybe_software_singlestep, and then combines maybe_software_singlestep with insert_single_step_breakpoint. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28440 |
||
|
|
5fe70629ce |
Change file initialization to use INIT_GDB_FILE macro
This patch introduces a new macro, INIT_GDB_FILE. This is used to
replace the current "_initialize_" idiom when introducing a per-file
initialization function. That is, rather than write:
void _initialize_something ();
void
_initialize_something ()
{
...
}
... now you would write:
INIT_GDB_FILE (something)
{
...
}
The macro handles both the declaration and definition of the function.
The point of this approach is that it makes it harder to accidentally
cause an initializer to be omitted; see commit
|
||
|
|
831b11eab5 |
gdb: prevent assertion after 'set debug breakpoint on'
Turns out that using 'set debug breakpoint on' will trigger an
assertion for 'catch' style breakpoints, e.g.:
(gdb) file /tmp/hello.x
Reading symbols from /tmp/hello.x...
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) set debug breakpoint on
(gdb) start
[breakpoint] dump_condition_tokens: Tokens: { INFERIOR: "1" }
Temporary breakpoint 2 at 0x401198: file /tmp/hello.c, line 18.
[breakpoint] update_global_location_list: insert_mode = UGLL_MAY_INSERT
Starting program: /tmp/hello.x
[breakpoint] update_global_location_list: insert_mode = UGLL_MAY_INSERT
../../gdb-16.1/gdb/gdbarch-gen.c:1764: internal-error: gdbarch_addr_bit: Assertion `gdbarch != NULL' failed.
.... etc ...
The problem is that catch breakpoints don't set the
bp_location::gdbarch member variable, they a "dummy" location added
with a call to add_dummy_location (breakpoint.c).
The breakpoint_location_address_str function (which is only used for
breakpoint debug output) relies on bp_location::gdbarch being set in
order to call the paddress function.
I considered trying to ensure that the bp_location::gdbarch variable
is always set to sane value. For example, in add_dummy_location I
tried copying the gdbarch from the breakpoint object, and this does
work for the catchpoint case, but for some of the watchpoint cases,
even the breakpoint object has no gdbarch value set.
Now this seemed a little suspect, but, the more I thought about it, I
wondered if "fixing" the gdbarch was allowing me to solve the wrong
problem.
If the gdbarch was set, then this would allow us to print the address
field of the bp_location, which is going to be 0, after all, as this
is a dummy location, which has no address.
But does it really make sense to print the address 0? For some
targets, 0 is a valid address. But that wasn't an address we actually
selected, it's just the default value for dummy locations.
And we already have a helper function bl_address_is_meaningful, which
returns false for dummy locations.
So, I propose that in breakpoint_location_address_str, we use
bl_address_is_meaningful to detect dummy locations, and skip the
address printing code in that case.
For testing, I temporarily changed insert_bp_location so that
breakpoint_location_address_str was always called, even when
breakpoint debugging was off. I then ran the whole testsuite.
Without the fixes included in this commit I saw lots of assertion
failures, but with the fixes from this commit in place, I now see no
assertion failures.
I've added a new test which reveals the original assertion failure.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
|
||
|
|
2c3e1c3f74 |
gdb/solib: move solist.h content to solib.h
I don't think that the file solist.h is useful. It would make sense to have `struct solib` in solib.h. And then, all that would remain is `struct solib_ops` and some solib-related function declarations. So, move it all to solib.h. Change-Id: I20ecf19787c378066f2c7a6a8a737c1db7c55d9a Reviewed-By: Guinevere Larsen <guinevere@redhat.com> |
||
|
|
6896e62513 |
gdb/solib: remove so_ prefix from so_name and so_original_name
The `so_` prefix is unnecessary here, it's already clear by the fact that they are field of the solib type (and previously so_list). Change-Id: I2c6773afc121d7631901e602913ea8a068840d0b Reviewed-By: Guinevere Larsen <guinevere@redhat.com> |
||
|
|
6b4f72a01e |
[gdb/breakpoints] Stabilize info breakpoints output
With test-case gdb.multi/pending-bp-del-inferior.exp, occasionally I run into:
...
(gdb) info breakpoints^M
Num Type Disp Enb Address What^M
3 dprintf keep y <MULTIPLE> ^M
printf "in foo"^M
3.1 y 0x004004dc in foo at $c:21 inf 2^M
3.2 y 0x004004dc in foo at $c:21 inf 1^M
(gdb) FAIL: $exp: bp_pending=false: info breakpoints before inferior removal
...
The FAIL happens because the test-case expects:
- breakpoint location 3.1 to be in inferior 1, and
- breakpoint location 3.2 to be in inferior 2
but it's the other way around.
I managed to reproduce this with a trigger patch in
compare_symbols from gdb/linespec.c:
...
uia = (uintptr_t) a.symbol->symtab ()->compunit ()->objfile ()->pspace ();
uib = (uintptr_t) b.symbol->symtab ()->compunit ()->objfile ()->pspace ();
- if (uia < uib)
+ if (uia > uib)
return true;
- if (uia > uib)
+ if (uia < uib)
return false;
...
The order enforced by compare_symbols shows up in the "info breakpoints"
output because breakpoint::add_location doesn't enforce an ordering for equal
addresses:
...
auto ub = std::upper_bound (m_locations.begin (), m_locations.end (),
loc,
[] (const bp_location &left,
const bp_location &right)
{ return left.address < right.address; });
m_locations.insert (ub, loc);
...
Fix this by using new function bp_location_is_less_than
(forwarding to bp_location_ptr_is_less_than) in breakpoint::add_location.
Tested on x86_64-linux.
Reviewed-By: Guinevere Larsen <guinevere@redhat.com>
Approved-By: Andrew Burgess <aburgess@redhat.com>
PR gdb/32202
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32202
|
||
|
|
8dd54de0a8 |
[gdb/breakpoints] Rename bp_location_is_less_than to bp_location_ptr_is_less_than
In breakpoint.c, we have: ... /* A comparison function for bp_location AP and BP being interfaced to std::sort. Sort elements primarily by their ADDRESS (no matter what bl_address_is_meaningful says), secondarily by ordering first permanent elements and tertiarily just ensuring the array is sorted stable way despite std::sort being an unstable algorithm. */ static int bp_location_is_less_than (const bp_location *a, const bp_location *b) ... There are few problems here: - the return type is int. While std::sort allows this, because int is convertible to bool, it's clearer to use bool directly, - it's not abundantly clear from either function name or comment that we can use this to sort std::vector<bp_location *> but not std::vector<bp_location>, and - the comment mentions AP and BP, but there are no such parameters. Fix this by: - changing the return type to bool, - renaming the function to bp_location_ptr_is_less_than and mentioning std::vector<bp_location *> in the comment, and - updating the comment to use the correct parameter names. Tested on x86_64-linux. Reviewed-By: Guinevere Larsen <guinevere@redhat.com> Approved-By: Andrew Burgess <aburgess@redhat.com> |
||
|
|
9c1f84c9b4 |
[gdbsupport] Reimplement phex and phex_nz as templates
Gdbsupport functions phex and phex_nz have a parameter sizeof_l:
...
extern const char *phex (ULONGEST l, int sizeof_l);
extern const char *phex_nz (ULONGEST l, int sizeof_l);
...
and a lot of calls use:
...
phex (l, sizeof (l))
...
Make this easier by reimplementing the functions as a template, allowing us to
simply write:
...
phex (l)
...
Simplify existing code using:
...
$ find gdb* -type f \
| xargs sed -i 's/phex (\([^,]*\), sizeof (\1))/phex (\1)/'
$ find gdb* -type f \
| xargs sed -i 's/phex_nz (\([^,]*\), sizeof (\1))/phex_nz (\1)/'
...
and manually review:
...
$ find gdb* -type f | xargs grep "phex (.*, sizeof.*)"
$ find gdb* -type f | xargs grep "phex_nz (.*, sizeof.*)"
...
Tested on x86_64-linux.
Approved-By: Tom Tromey <tom@tromey.com>
|
||
|
|
d01e823438 |
Update copyright dates to include 2025
This updates the copyright headers to include 2025. I did this by running gdb/copyright.py and then manually modifying a few files as noted by the script. Approved-By: Eli Zaretskii <eliz@gnu.org> |
||
|
|
4bc72a4571 |
gdb: remove disable_breakpoints_in_shlibs function
I think there is a problem with the disable_breakpoints_in_shlibs
function: it can disable breakpoint locations without calling
notify_breakpoint_modified. This means that the Python API's
breakpoint_modified event will not trigger, nor will the MI send a
breakpoint modified event.
I started looking at disable_breakpoints_in_shlibs because of an
earlier commit:
commit
|
||
|
|
e83f612167 |
gdb: reduce breakpoint-modified events for dprintf b/p
Consider this backtrace within GDB: #0 notify_breakpoint_modified (b=0x57d31d0) at ../../src/gdb/breakpoint.c:1083 #1 0x00000000005b6406 in breakpoint_set_commands (b=0x57d31d0, commands=...) at ../../src/gdb/breakpoint.c:1523 #2 0x00000000005c8c63 in update_dprintf_command_list (b=0x57d31d0) at ../../src/gdb/breakpoint.c:8641 #3 0x00000000005d3c4e in dprintf_breakpoint::re_set (this=0x57d31d0) at ../../src/gdb/breakpoint.c:12476 #4 0x00000000005d6347 in breakpoint_re_set () at ../../src/gdb/breakpoint.c:13298 Whenever breakpoint_re_set is called we re-build the commands that the dprintf b/p will execute and store these into the breakpoint. The commands are re-built in update_dprintf_command_list and stored into the breakpoint object in breakpoint_set_commands. Now sometimes these commands can change, dprintf_breakpoint::re_set explains one case where this can occur, and I'm sure there must be others. But in most cases the commands we recalculate will not change. This means that the breakpoint modified event which is emitted from breakpoint_set_commands is redundant. This commit aims to eliminate the redundant breakpoint modified events for dprintf breakpoints. This is done by adding a commands_equal call to the start of breakpoint_set_commands. The commands_equal function is a new function which compares two command_line objects and returns true if they are identical. Using this function we can check if the new commands passed to breakpoint_set_commands are identical to the breakpoint's existing commands. If the new commands are equal then we don't need to change anything on the new breakpoint, and the breakpoint modified event can be skipped. The test for this commit stops at a dlopen() call in the inferior, sets up a dprintf breakpoint, then uses 'next' to step over the dlopen() call. When the library loads GDB call breakpoint_re_set, which calls dprintf_breakpoint::re_set. But in this case we don't expect the calculated command string to change, so we don't expect to see the breakpoint modified event. |
||
|
|
72a6691321 |
Use gdb unordered set in breakpoint.c
This changes breakpoint.c to use gdb:unordered_set. Approved-By: Simon Marchi <simon.marchi@efficios.com> |
||
|
|
58984e4ad2 |
Use gdb::function_view in iterate_over_threads
This C++-ifies iterate_over_threads, changing it to accept a gdb::function_view and to return bool. Approved-By: Simon Marchi <simon.marchi@efficios.com> |
||
|
|
5770f680c9 |
gdb: handle empty locspec when printing breakpoints
For background reading, please see the previous patch, and the patch before that! After the last two patches, internal breakpoints can now be marked as shlib_disabled if the library in which they are placed is unloaded. The patch before last discusses a situation related to the gdb.base/nostdlib.exp test, when run on a GNU/Linux glibc based system where executables are compiled as PIE by default. In this case it is observed that the dynamic linker will actually report itself as unloaded (i.e. remove itself from the list of currently loaded shared libraries). This behaviour is likely a bug in the dynamic linker, but this behaviour exists in released versions of the dynamic linker, so GDB should (if the cost is not too great) be changed to handle this situation. This commit handles a problem with the 'maint info breakpoints' command. When the dynamic linker is unloaded the 'shlib event' breakpoint is marked as shlib_disabled (i.e. placed into the pending state). When displaying the breakpoint in the 'maint info breakpoints' output, GDB will try to print the locspec (location_spec *) as a string Unfortunately, the locspec will be nullptr as the internal breakpoints are not created via a location_spec, this means that GDB ends up trying to call location_sepc::to_string() on a nullptr, resulting in undefined behaviour (and a crash). For most internal breakpoint types this is not a problem. If we consider bp_longjmp_master for example, if the shared library containing a breakpoint of this type is unloaded then first GDB marks the breakpoint as shlib_disabled, then after unloading the shared library breakpoint_re_set is called, which will delete the internal breakpoint, and then try to re-create it (if needed). As a result, the user never gets a change to run 'maint info breakpoints' on a bp_longjmp_master breakpoint in the shlib_disabled state. But bp_shlib_event and bp_thread_event breakpoints are not deleted and recreated like this (see internal_breakpoint::re_set), so it is possible, in rare cases, that we could end up trying to view one of these breakpoint in a shlib_disabled state, and it would be nice if GDB didn't crash as a result. I've updated the printing code to check for and handle this case, and I've updated the docs to mention this (rare) case. For testing, I've extended gdb.base/nostdlib.exp to compile as pie and nopie, and then run 'maint info breakpoints'. If we're running on a buggy glibc then this will trigger the crash. I don't know how I can trigger this problem without a buggy glibc as this would require forcing the dynamic linker to be unloaded. Reviewed-By: Eli Zaretskii <eliz@gnu.org> Approved-By: Tom Tromey <tom@tromey.com> |
||
|
|
4f578099f9 |
gdb: disable internal b/p when a solib is unloaded
Bug PR gdb/32079 highlights an issue where GDB will try to remove a breakpoint for a shared library that has been unloaded. This will trigger an error from GDB like: (gdb) next 61 dlclose (handle[dl]); (gdb) next warning: error removing breakpoint 0 at 0x7ffff78169b9 warning: error removing breakpoint 0 at 0x7ffff7730b57 warning: error removing breakpoint 0 at 0x7ffff7730ad3 54 for (dl = 0; dl < 4; ++dl) (gdb) What happens is that as the inferior steps over the dlclose() call, GDB notices that the library has been unloaded and calls disable_breakpoints_in_unloaded_shlib. However, this function only operates on user breakpoints and tracepoints. In the example above what is happening is that the test loads multiple copies of libc into different linker namespsaces. When we 'next' over the dlclose call one of the copies of libc is unloaded. As GDB placed longjmp master breakpoints within the copy of libc that was just unloaded, the warnings we see are GDB trying (and failing) to remove these breakpoints. I think the solution is for disable_breakpoints_in_unloaded_shlib to handle all breakpoints, even internal ones like the longjmp master breakpoints. If we do this then the breakpoint will be marked as shlib_disabled and also will be marked as not inserted. Later when we call breakpoint_re_set() and the longjmp breakpoints are deleted we will no longer try to remove them. This solution is inspired by a patch suggested in the bug report: https://sourceware.org/bugzilla/show_bug.cgi?id=32079#c3 There are some differences with my approach compared to the patch suggested in the bug. First I have no need to delete the breakpoint inside disable_breakpoints_in_unloaded_shlib as an earlier patch in this series arranged for breakpoint_re_set to be called when shared libraries are removed. Calling breakpoint_re_set will take care of deleting the breakpoint for us. For details see the earlier commit titled: gdb: fixes for code_breakpoint::disabled_by_cond logic Next, rather than only handling bp_longjmp and bp_longjmp_master, I allow all breakpoints to be handled. I also only give the warning about disabling breakpoints for user breakpoints, I don't see the point of warning the user about internal b/p changes. With this done the issues in PR gdb/32079 are resolved. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32079 Tested-By: Hannes Domani <ssbssa@yahoo.de> Approved-By: Tom Tromey <tom@tromey.com> |
||
|
|
0e9794f1f2 |
gdb: don't clear inserted flag in disable_breakpoints_in_unloaded_shlib
This commit removes the clearing of bp_location::inserted from disable_breakpoints_in_unloaded_shlib, my claim is that this call is not needed (any more), and with the next commit, this line actually causes some problems. The disable_breakpoints_in_unloaded_shlib function was added back in 2004 with commit |
||
|
|
8c48ec7a61 |
gdb: handle dprintf breakpoints when unloading a shared library
While working on the previous commit I realised that GDB would not
handle dprintf breakpoints correctly when a shared library was
unloaded.
Consider this example using the test binary from shlib-unload.exp. In
the function 'foo' we create a dprintf is in a shared library:
(gdb) b 59
Breakpoint 1 at 0x401215: file /tmp/projects/binutils-gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/shlib-unload.c, line 59.
(gdb) r
Starting program: /tmp/projects/binutils-gdb/build/gdb/testsuite/outputs/gdb.base/shlib-unload/shlib-unload
Breakpoint 1, main () at /tmp/projects/binutils-gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/shlib-unload.c:59
59 res = dlclose (handle); /* Break here. */
(gdb) dprintf foo,"In foo"
Dprintf 2 at 0x7ffff7fc50fd: file /tmp/projects/binutils-gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/shlib-unload-lib.c, line 23.
(gdb) n
Error in re-setting breakpoint 2: Function "foo" not defined.
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
Cannot remove breakpoints because program is no longer writable.
Further execution is probably impossible.
60 assert (res == 0);
(gdb)
What happens here is that as the inferior steps over the dlclose call
the shared library containing 'foo' is unloaded and
disable_breakpoints_in_unloaded_shlib is called. However in
disable_breakpoints_in_unloaded_shlib we have this check:
if (b.type != bp_breakpoint
&& b.type != bp_jit_event
&& b.type != bp_hardware_breakpoint
&& !is_tracepoint (&b))
continue;
As the dprintf has type bp_dprintf then this check triggers and we
ignore the dprintf, meaning the dprintf is not disabled. When the
inferior stops after the 'next' GDB tries to remove all breakpoints
but the dprintf can no longer be removed, the memory in which it was
placed has been unmapped from the inferior.
The fix is to start using is_breakpoint() in
disable_breakpoints_in_unloaded_shlib instead of the bp_breakpoint and
bp_hardware_breakpoint checks. The is_breakpoint() function also
checks for bp_dprintf.
With this fix in place GDB now correctly disables the breakpoint and
we no longer see the warning about removing the breakpoint.
During review it was pointed out that PR gdb/23149 and PR gdb/20208
both describe something similar, though for these bugs, the inferior
is restarted (which unloads all currently loaded shlib) rather than
passing over the dlclose. But the consequences are pretty similar.
I've included a test which covers this case.
One additional thing that these two bugs did show though is that
disable_breakpoints_in_shlibs also needs to start using is_breakpoint
for the same reason. Without this change, when an inferior is
restarted we get a warning like this for dprintf breakpoints:
warning: Temporarily disabling breakpoints for unloaded shared library "..."
but we don't get a similar warning for "normal" breakpoints. This is
because disable_breakpoints_in_shlibs is called from clear_solib,
which is called when an inferior is restarted.
It is best not to think too hard about disable_breakpoints_in_shlibs,
as this function is pretty broken, e.g. it doesn't call
notify_breakpoint_modified, despite modifying the breakpoints. But
for now I'm ignoring that, but fixing this is definitely on my list
for my next set of breakpoint related fixes, it's just that a lot of
these breakpoint fixes end up being depending on one another, but I
want to avoid making this series too long. So for now, I'm ignoring
the existing bug (missing breakpoint modified events), and fixing
disable_breakpoints_in_shlibs to cover dprintf.
With these fixes in place, the two bugs mentioned above should be
fixed.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23149
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=20208
Tested-By: Hannes Domani <ssbssa@yahoo.de>
Approved-By: Tom Tromey <tom@tromey.com>
|
||
|
|
e9709998ff |
gdb: restructure disable_breakpoints_in_unloaded_shlib
This commit rewrites disable_breakpoints_in_unloaded_shlib to be more like disable_breakpoints_in_freed_objfile. Instead of looping over all b/p locations, we instead loop over all b/p and then over all locations for each b/p. The advantage of doing this is that we can fix the small bug that was documented in a comment in the code: /* This may cause duplicate notifications for the same breakpoint. */ notify_breakpoint_modified (b); By calling notify_breakpoint_modified() as we modify each location we can potentially send multiple notifications for a single b/p. Is this a bug? Maybe not. After all, at each notification one of the locations will have changed, so its probably fine. But it's not ideal, and we can easily do better, so lets do that. There's a new test which checks that we only get a single notification when the shared library is unloaded. Note that the test is written as if there are multiple related but different tests within the same test file ... but there aren't currently! The next commit will add another test proc to this test script at which point the comments will make sense. I've done this to avoid unnecessary churn in the next commit. Tested-By: Hannes Domani <ssbssa@yahoo.de> Approved-By: Tom Tromey <tom@tromey.com> |
||
|
|
ffd09b625e |
gdb: fixes for code_breakpoint::disabled_by_cond logic
I spotted that the code_breakpoint::disabled_by_cond flag doesn't work
how I'd expect it too. The flag appears to be "sticky" in some
situations; once a code_breakpoint::disabled_by_cond flag is marked
true, then, in some cases the flag wont automatically become false
again, even when you'd think it should.
The problem is in update_breakpoint_locations. In this function,
which is called as a worker of code_breakpoint::re_set, GDB computes a
new set of locations for a breakpoint, the new locations are then
installed into the breakpoint.
However, before installing the new locations GDB attempts to copy the
bp_location::enabled and bp_location::disabled_by_cond flag from the
old locations into the new locations.
The reason for copying the ::enabled flag makes sense. This flag is
controlled by the user. When we create the new locations if GDB can
see that a new location is equivalent to one of the old locations, and
if the old location was disabled by the user, then the new location
should also be disabled.
However, I think the logic behind copying the ::disabled_by_cond flag
is wrong. The disabled_by_cond flag is controlled by GDB and should
toggle automatically. If the condition string can be parsed then the
flag should be false (b/p enabled), if the condition string can't be
parsed then the flag should be true (b/p disabled).
As we always parse the condition string in update_breakpoint_locations
before we try to copy the ::enabled flag value then the
::disabled_by_cond flag should already be correct, there's no need to
copy over the ::disabled_by_cond value from the old location.
As a concrete example, consider a b/p placed within the main
executable, but with a condition that depends on a variable within a
shared library.
When the b/p is initially created the b/p will be disabled as the
condition string will be invalid (the shared library variable isn't
available yet).
When the inferior starts the shared library is loaded and the
condition variable becomes available to GDB. When the shared library
is loaded breakpoint_re_set is called which (eventually) calls
update_breakpoint_locations.
A new location is computed for the breakpoint and the condition string
is parsed. As the shared library variable is now know the expression
parses correctly and ::disabled_by_cond is left false for the new
location.
But currently GDB spots that the new location is at the same address
as the old location and copies disabled_by_cond over from the old
location, which marks the b/p location as disabled. This is not what
I would expect.
The solution is simple, don't copy over disabled_by_cond.
While writing a test I found another problem though. The
disabled_by_cond flag doesn't get set true when it should! This is
the exact opposite of the above.
The problem here is in solib_add which is (despite the name) called
whenever the shared library set changes, including when a shared
library is unloaded.
Imagine an executable that uses dlopen/dlclose to load a shared
library. Given an example of a b/p in the main executable that has a
condition that uses a variable from our shared library, a library
which might be unloaded with dlclose.
My expectation is that, when the library is unloaded, GDB will
automatically mark the breakpoint as disabled_by_cond, however, this
was not happening.
The problem is that in solib_add we only call breakpoint_re_set when
shared libraries are added, not when shared libraries are removed.
The solution I think is to just call breakpoint_re_set in both cases,
now the disabled_by_cond flag is updated as I'd expect.
Unfortunately, making this change causes a regression when running:
make check-gdb \
TESTS="gdb.trace/change-loc.exp" \
RUNTESTFLAGS="--target_board=native-gdbserver"
This test unloads a shared library and expects breakpoints within the
shared library to enter the PENDING state (because the bp_location's
shlib_disabled flag will be set). However, the new call to
breakpoint_re_set means that this is no longer the case.
The breakpoint_re_set call means that update_breakpoint_locations is
called, which then checks if all locations for a breakpoint are
pending or not. In this test not all locations are pending, and so
GDB recalculates the locations of each breakpoint, this means that
pending locations are discarded.
There is a but report PR gdb/32404 which mentions the problems with
shlib_disabled pending breakpoints, and how they are prone to being
randomly deleted if the user can cause GDB to trigger a call to
breakpoint_re_set. This patch just adds another call to
breakpoint_re_set, which triggers this bug in this one test case.
For now I have marked this test as KFAIL. I do plan to try and
address the pending (shlib_disabled) breakpoint problem in the future,
but I'm not sure when that will be right now.
There are, of course, tests to cover all these cases.
During review I was pointed at bug PR gdb/32079 as something that this
commit might fix, or help in fixing.
And this commit is part of the fix for that bug, but is not the
complete solution. However, the remaining parts of the fix for that
bug are not really related to the content of this commit.
The problem in PR gdb/32079 is that the inferior maps multiple copies
of libc in different linker namespaces using dlmopen (actually libc is
loaded as a consequence of loading some other library into a different
namespace, but that's just a detail). The user then uses a 'next'
command to move the inferior forward.
GDB sets up internal breakpoints on the longjmp symbols, of which
there are multiple copies (there is a copy in every loaded libc).
However, the 'next' command is, in the problem case, stepping over a
dlclose call which unloads one of the loaded libc libraries.
In current HEAD GDB in solib_add we fail to call breakpoint_re_set()
when the library is unloaded; breakpoint_re_set() would delete and
then recreate the longjmp breakpoints. As breakpoint_re_set() is not
called GDB thinks that the the longjmp breakpoint in the now unloaded
libc still exists, and is still inserted.
When the inferior stops after the 'next' GDB tries to delete and
remove the longjmp breakpoint which fails as the libc in which the
breakpoint was inserted is no longer mapped in.
When the user tries to 'next' again GDB tries to re-insert the still
existing longjmp breakpoint which again fails as the memory in which
the b/p should be inserted is no longer part of the inferior memory
space.
This commit helps a little. Now when the libc library is unmapped GDB
does call breakpoint_re_set(). This deletes the longjmp breakpoints
including the one in the unmapped library, then, when we try to
recreate the longjmp breakpoints (at the end of breakpoint_re_set) we
don't create a b/p in the now unmapped copy of libc.
However GDB does still think that the deleted breakpoint is inserted.
The breakpoint location remains in GDB's data structures until the
next time the inferior stops, at which point GDB tries to remove the
breakpoint .... and fails.
However, as the b/p is now deleted, when the user tries to 'next' GDB
no longer tries to re-insert the b/p, and so one of the problems
reported in PR gdb/32079 is resolved.
I'll fix the remaining issues from PR gdb/32079 in a later commit in
this series.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32079
Tested-By: Hannes Domani <ssbssa@yahoo.de>
Approved-By: Tom Tromey <tom@tromey.com>
|
||
|
|
9da3b73547 |
gdb: include a still-mapped flag in solib unload notification
Consider the gdb.base/dlmopen.exp test case. The executable in this test uses dlmopen to load libraries into multiple linker namespaces. When a library is loaded into a separate namespace, its dependencies are also loaded into that namespace. This means that an inferior can have multiple copies of some libraries, including the dynamic linker, loaded at once. However, glibc optimises at least the dynamic linker case. Though the library appears to be mapped multiple times (it is in the inferior's solib list multiple times), there is really only one copy mapped into the inferior's address space. Here is the 'info sharedlibrary' output on an x86-64/Linux machine once all the libraries are loaded: (gdb) info sharedlibrary From To Syms Read Shared Object Library 0x00007ffff7fca000 0x00007ffff7ff03f5 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7eda3d0 0x00007ffff7f4e898 Yes /lib64/libm.so.6 0x00007ffff7d0e800 0x00007ffff7e6dccd Yes /lib64/libc.so.6 0x00007ffff7fbd040 0x00007ffff7fbd116 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib.1.so 0x00007ffff7fb8040 0x00007ffff7fb80f9 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib-dep.so 0x00007ffff7bfe3d0 0x00007ffff7c72898 Yes /lib64/libm.so.6 0x00007ffff7a32800 0x00007ffff7b91ccd Yes /lib64/libc.so.6 0x00007ffff7fca000 0x00007ffff7ff03f5 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7fb3040 0x00007ffff7fb3116 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib.1.so 0x00007ffff7fae040 0x00007ffff7fae0f9 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib-dep.so 0x00007ffff7ce1040 0x00007ffff7ce1116 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib.1.so 0x00007ffff7cdc040 0x00007ffff7cdc0f9 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib-dep.so 0x00007ffff79253d0 0x00007ffff7999898 Yes /lib64/libm.so.6 0x00007ffff7759800 0x00007ffff78b8ccd Yes /lib64/libc.so.6 0x00007ffff7fca000 0x00007ffff7ff03f5 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7cd7040 0x00007ffff7cd7116 Yes /tmp/build/gdb/testsuite/outputs/gdb.base/dlmopen/dlmopen-lib.2.so Notice that every copy of /lib64/ld-linux-x86-64.so.2 is mapped at the same address. As the inferior closes the libraries that it loaded, the various copies of the dynamic linker will also be unloaded. Currently, when this happens GDB calls notify_solib_unloaded, which triggers the gdb::observers::solib_unloaded observer. This observer will call disable_breakpoints_in_unloaded_shlib (in breakpoint.c), which disables any breakpoints in the unloaded solib. The problem with this, is that, when the dynamic linker (or any solib) is only really mapped once as is the case here, we only want to disable breakpoints in the library when the last instance of the library is unloaded. The first idea that comes to mind is that GDB should not emit the solib_unloaded notification if a shared library is still in use, however, this could break MI consumers. Currently, every time a copy of ld-linux-x86-64.so.2 is unloaded, GDB's MI interpreter will emit a =library-unloaded event. An MI consumer might use this to update the library list that it displays to the user, and fewer notify_solib_unloaded calls will mean fewer MI events, which will mean the MI consumer's library list could get out of sync with GDB. Instead I propose that we extend GDB's solib_unloaded event to add a new flag. The new flag indicates if the library mapping is still in use within the inferior. Now the MI will continue to emit the expected =library-unloaded events, but disable_breakpoints_in_unloaded_shlib can check the new flag, when it is true (indicating that the library is still mapped into the inferior), no breakpoints should be disabled. The other user of the solib_unloaded observer, in bsd-uthread.c, should, I think, do nothing if the mapping is still in use. This observer is also disabling breakpoints when a library is unloaded. Most of the changes in this commit relate to passing the new flag around for the event. The interesting changes are mostly in solib.c, where the flag value is determined, and in breakpoint.c and bsd-uthread.c, where the flag value is read. There's a new MI test, the source of which is mostly copied from the gdb.base/dlmopen.exp test. This new test is checking we see all the expected =library-unloaded events. |
||
|
|
59d25b31eb |
Don't let exception terminate 'rbreak'
'rbreak' searches symbols and then sets a number of breakpoints. If setting one of the breakpoints fails, then 'rbreak' will terminate before examining the remaining symbols. However, it seems to me that it is better for 'rbreak' to keep going in this situation. That is what this patch implements. This problem can be seen by writing an Ada program that uses "pragma import" to reference a symbol that does not have debug info. In this case, the program will link but setting a breakpoint on the imported name will not work. I don't think it's possible to write a reliable test for this, as it depends on the order in which symtabs are examined. New in v2: rbreak now shows how many breakpoints it made and also how many errors it encountered. Regression tested on x86-64 Fedora 40. Approved-By: Andrew Burgess <aburgess@redhat.com> |
||
|
|
9e69a2e127 |
Introduce "command" styling
This adds a new "command" style that is used when styling the name of a gdb command. Note that not every instance of a command name that is output by gdb is changed here. There is currently no way to style error() strings, and there is no way to mark up command help strings. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31747 Reviewed-By: Eli Zaretskii <eliz@gnu.org> Reviewed-By: Keith Seitz <keiths@redhat.com> Approved-By: Andrew Burgess <aburgess@redhat.com> |
||
|
|
ae2a96659a |
gdb: use 'const' more in a couple of small breakpoint functions
Make the 'struct breakpoint *' argument 'const' in user_breakpoint_p and pending_breakpoint_p. And make the 'struct bp_location *' argument 'const' in bl_address_is_meaningful. There should be no user visible changes after this commit. |
||
|
|
c8889b9131 |
gdb, gdbserver, gdbsupport: remove some unused gdb_vecs.h includes
Remove some includes reported as unused by clangd. Add some to files that actually need it. Change-Id: I01c61c174858c1ade5cb54fd7ee1f582b17c3363 |
||
|
|
e77c31d28d |
Convert breakpoint.c to new hash table
This converts breakpoint.c to use the new hash table. Change-Id: I6d997a6242969586a7f8f9eb22cc8dd8d3ac97ff Co-Authored-By: Tom Tromey <tom@tromey.com> Approved-By: Tom Tromey <tom@tromey.com> |
||
|
|
5066f36806 |
gdb: do better in breakpoint_free_objfile
The breakpoint_free_objfile function is called from the objfile destructor, and has the job of removing references to the soon to be deleted objfile from all breakpoint locations. The current implementation of breakpoint_free_objfile seems to miss lots of possible objfile references within bp_location. Currently we only check if bp_location::symtab is associated with the objfile in question, but there's bp_location::section and bp_location::probe, both of which might reference the soon to be deleted objfile. Additionally bp_location::symbol and bp_location::msymbol if set will surely be related to the objfile and should also be cleaned up. I'm not aware that this causes any problems, but it doesn't seem like a good idea to retain pointers to deleted state, so I propose that we improve breakpoint_free_objfile to set these pointers back to nullptr. In the future I plan to investigate the possibility of merging the functionality of breakpoint_free_objfile into disable_breakpoints_in_freed_objfile which is called via the gdb::observers::free_objfile event. However, I already have a patch series in progress which touches this area of GDB, and I'd like to avoid conflicting with that earlier series: https://inbox.sourceware.org/gdb-patches/cover.1724948606.git.aburgess@redhat.com Once this patch, and that earlier series have landed then I'll see if I can merge breakpoint_free_objfile, but I don't think that this needs to block this patch. There should be no user visible changes after this commit. |
||
|
|
df63932c96 |
gdb: remove an unnecessary scope block in update_breakpoint_locations
In update_breakpoint_locations there's a scope block which I don't
think adds any value. There is one local defined within the scope,
the local is currently an 'int' but should be a 'bool', either way
there's no destructor being triggered when we exit the scope.
This commit changes the local to a 'bool', removes the unnecessary
scope, and re-indents the code.
Within the (now removed) scope was a `for' loop. Inside the loop I
have converted this:
for (....)
{
if (CONDITION)
{
/* Body */
}
}
to this:
for (....)
{
if (!CONDITION)
continue;
/* Body */
}
which means that the body doesn't need to be indented as much, making
things easier to read.
There should be no functional change after this commit.
Reviewed-By: Klaus Gerlicher <klaus.gerlicher@intel.com>
|
||
|
|
2778a124e3 |
gdb: remove bp_location::objfile
The bp_location::objfile member variable is never used, so lets delete it. There should be no user visible changes after this commit. |
||
|
|
86bb38cee9 |
gdb: Make tagged pointer support configurable.
The gdbarch function gdbarch_remove_non_address_bits adjusts addresses to enable debugging of programs with tagged pointers on Linux, for instance for ARM's feature top byte ignore (TBI). Once the function is implemented for an architecture, it adjusts addresses for memory access, breakpoints and watchpoints. Linear address masking (LAM) is Intel's (R) implementation of tagged pointer support. It requires certain adaptions to GDB's tagged pointer support due to the following: - LAM supports address tagging for data accesses only. Thus, specifying breakpoints on tagged addresses is not a valid use case. - In contrast to the implementation for ARM's TBI, the Linux kernel supports tagged pointers for memory access. This patch makes GDB's tagged pointer support configurable such that it is possible to enable the address adjustment for a specific feature only (e.g memory access, breakpoints or watchpoints). This way, one can make sure that addresses are only adjusted when necessary. In case of LAM, this avoids unnecessary parsing of the /proc/<pid>/status file to get the untag mask. Reviewed-By: Felix Willgerodt <felix.willgerodt@intel.com> (AArch64) Tested-By: Luis Machado <luis.machado@arm.com> Approved-By: Luis Machado <luis.machado@arm.com> |
||
|
|
40ae603e6e |
Use std::make_unique in more places
I searched for spots using ".reset (new ...)" and replaced most of these with std::make_unique. I think this is a bit cleaner and more idiomatic. Regression tested on x86-64 Fedora 40. Reviewed-By: Klaus Gerlicher<klaus.gerlicher@intel.com> |
||
|
|
f04b2702fa |
[gdb/breakpoints] Fix gdb.base/scope-hw-watch-disable.exp on arm-linux
On arm-linux, with test-case gdb.base/scope-hw-watch-disable.exp I run into: ... (gdb) awatch a^M Can't set read/access watchpoint when hardware watchpoints are disabled.^M (gdb) PASS: $exp: unsuccessful attempt to create an access watchpoint rwatch b^M Can't set read/access watchpoint when hardware watchpoints are disabled.^M (gdb) PASS: $exp: unsuccessful attempt to create a read watchpoint continue^M Continuing.^M ^M Program received signal SIGSEGV, Segmentation fault.^M 0xf7ec82c8 in ?? () from /lib/arm-linux-gnueabihf/libc.so.6^M (gdb) FAIL: $exp: continue until exit ... Using "maint info break", we can see that the two failed attempts to set a watchpoint each left behind a stale "watchpoint scope" breakpoint: ... -5 watchpoint scope del y 0xf7ec569a inf 1 -5.1 y 0xf7ec569a inf 1 stop only in stack frame at 0xfffef4f8 -6 watchpoint scope del y 0xf7ec569a inf 1 -6.1 y 0xf7ec569a inf 1 stop only in stack frame at 0xfffef4f8 ... The SIGSEGV is a consequence of the stale "watchpoint scope" breakpoint: the same happens if we: - have can-use-hw-watchpoints == 1, - set one of the watchpoints, and - continue to exit. The problem is missing symbol info on libc which is supposed to tell which code is thumb. After doing "set arm fallback-mode thumb" the SIGSEGV disappears. Extend the test-case to check the "maint info break" command before and after the two failed attempts, to make sure that we catch the stale "watchpoint scope" breakpoints also on x86_64-linux. Fix this in watch_command_1 by moving creation of the "watchpoint scope" breakpoint after the call to update_watchpoint. Tested on x86_64-linux. PR breakpoints/31860 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31860 |
||
|
|
16a6f7d2ee |
gdb: avoid breakpoint::clear_locations calls in update_breakpoint_locations
The commit:
commit
|
||
|
|
8f6606b6e3 |
[gdb] Fix common misspellings
Fix the following common misspellings: ... accidently -> accidentally additonal -> additional addresing -> addressing adress -> address agaisnt -> against albiet -> albeit arbitary -> arbitrary artifical -> artificial auxillary -> auxiliary auxilliary -> auxiliary bcak -> back begining -> beginning cannonical -> canonical compatiblity -> compatibility completetion -> completion diferent -> different emited -> emitted emiting -> emitting emmitted -> emitted everytime -> every time excercise -> exercise existance -> existence fucntion -> function funtion -> function guarentee -> guarantee htis -> this immediatly -> immediately layed -> laid noone -> no one occurances -> occurrences occured -> occurred originaly -> originally preceeded -> preceded preceeds -> precedes propogate -> propagate publically -> publicly refering -> referring substract -> subtract substracting -> subtracting substraction -> subtraction taht -> that targetting -> targeting teh -> the thier -> their thru -> through transfered -> transferred transfering -> transferring upto -> up to vincinity -> vicinity whcih -> which whereever -> wherever wierd -> weird withing -> within writen -> written wtih -> with doesnt -> doesn't ... Tested on x86_64-linux. |
||
|
|
887ae0cf2b |
Add line-number styling
This patch adds separate styling for line numbers. That is, whenever gdb prints a source line number, it uses this style. v2 includes a change to ensure that %ps works in query. Reviewed-By: Eli Zaretskii <eliz@gnu.org> Reviewed-by: Keith Seitz <keiths@redhat.com> |
||
|
|
43a1fffa62 |
gdb: update comment in code_breakpoint::re_set_default
Spotted a comment in code_breakpoint::re_set_default that was added in
commit:
commit
|
||
|
|
6cce025114 |
gdb: only insert thread-specific breakpoints in the relevant inferior
This commit updates GDB so that thread or inferior specific breakpoints are only inserted into the program space in which the specific thread or inferior is running. In terms of implementation, getting this basically working is easy enough, now that a breakpoint's thread or inferior field is setup prior to GDB looking for locations, we can easily use this information to find a suitable program_space and pass this to as a filter when creating the sals. Or we could if breakpoint_ops::create_sals_from_location_spec allowed us to pass in a filter program_space. So, this commit extends breakpoint_ops::create_sals_from_location_spec to take a program_space argument, and uses this to filter the set of returned sals. This accounts for about half the change in this patch. The second set of changes starts from breakpoint_set_thread and breakpoint_set_inferior, this is called when the thread or inferior for a breakpoint changes, e.g. from the Python API. Previously this call would never result in the locations of a breakpoint changing, after all, locations were inserted in every program space, and we just use the thread or inferior variable to decide when we should stop. Now though, changing a breakpoint's thread or inferior can mean we need to figure out a new set of breakpoint locations. To support this I've added a new breakpoint_re_set_one function, which is like breakpoint_re_set, but takes a single breakpoint, and just updates the locations for that one breakpoint. We only need to call this function if the program_space in which a breakpoint's thread (or inferior) is running actually changes. If the program_space does change then we call the new breakpoint_re_set_one function passing in the program_space which should be used to filter the new locations (or nullptr to indicate we should set locations in all program spaces). This filter program_space needs to propagate down to all the re_set methods, this accounts for the remaining half of the changes in this patch. There were a couple of existing tests that created thread or inferior specific breakpoints and then checked the 'info breakpoints' output, these needed updating. These were: gdb.mi/user-selected-context-sync.exp gdb.multi/bp-thread-specific.exp gdb.multi/multi-target-continue.exp gdb.multi/multi-target-ping-pong-next.exp gdb.multi/tids.exp gdb.mi/new-ui-bp-deleted.exp gdb.multi/inferior-specific-bp.exp gdb.multi/pending-bp-del-inferior.exp I've also added some additional tests to: gdb.multi/pending-bp.exp I've updated the documentation and added a NEWS entry. Reviewed-By: Eli Zaretskii <eliz@gnu.org> |
||
|
|
85eb08c5f0 |
gdb: don't set breakpoint::pspace in create_breakpoint
I spotted this code within create_breakpoint:
if ((type_wanted != bp_breakpoint
&& type_wanted != bp_hardware_breakpoint) || thread != -1)
b->pspace = current_program_space;
this code is only executed when creating a pending breakpoint, and
sets the breakpoint::pspace member variable.
The above code gained the 'thread != -1' clause with this commit:
commit
|
||
|
|
c6b486755e |
gdb: parse pending breakpoint thread/task immediately
The initial motivation for this commit was to allow thread or inferior
specific breakpoints to only be inserted within the appropriate
inferior's program-space. The benefit of this is that inferiors for
which the breakpoint does not apply will no longer need to stop, and
then resume, for such breakpoints. This commit does not make this
change, but is a refactor to allow this to happen in a later commit.
The problem we currently have is that when a thread-specific (or
inferior-specific) breakpoint is created, the thread (or inferior)
number is only parsed by calling find_condition_and_thread_for_sals.
This function is only called for non-pending breakpoints, and requires
that we know the locations at which the breakpoint will be placed (for
expression checking in case the breakpoint is also conditional).
A consequence of this is that by the time we figure out the breakpoint
is thread-specific we have already looked up locations in all program
spaces. This feels wasteful -- if we knew the thread-id earlier then
we could reduce the work GDB does by only looking up locations within
the program space for which the breakpoint applies.
Another consequence of how find_condition_and_thread_for_sals is
called is that pending breakpoints don't currently know they are
thread-specific, nor even that they are conditional! Additionally, by
delaying parsing the thread-id, pending breakpoints can be created for
non-existent threads, this is different to how non-pending
breakpoints are handled, so I can do this:
$ gdb -q ./gdb/testsuite/outputs/gdb.multi/pending-bp/pending-bp
Reading symbols from ./gdb/testsuite/outputs/gdb.multi/pending-bp/pending-bp...
(gdb) break foo thread 99
Function "foo" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (foo thread 99) pending.
(gdb) r
Starting program: /tmp/gdb/testsuite/outputs/gdb.multi/pending-bp/pending-bp
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Error in re-setting breakpoint 1: Unknown thread 99.
[Inferior 1 (process 3329749) exited normally]
(gdb)
GDB only checked the validity of 'thread 99' at the point the 'foo'
location became non-pending. In contrast, if I try this:
$ gdb -q ./gdb/testsuite/outputs/gdb.multi/pending-bp/pending-bp
Reading symbols from ./gdb/testsuite/outputs/gdb.multi/pending-bp/pending-bp...
(gdb) break main thread 99
Unknown thread 99.
(gdb)
GDB immediately checks if 'thread 99' exists. I think inconsistencies
like this are confusing, and should be fixed if possible.
In this commit the create_breakpoint function is updated so that the
extra_string, which contains the thread, inferior, task, and/or
condition information, is parsed immediately, even for pending
breakpoints.
Obviously, the condition still can't be validated until the breakpoint
becomes non-pending, but the thread, inferior, and task information
can be pulled from the extra-string, and can be validated early on,
even for pending breakpoints. The -force-condition flag is also
parsed as part of this early parsing change.
There are a couple of benefits to doing this:
1. Printing of breakpoints is more consistent now. Consider creating
a conditional breakpoint before this commit:
(gdb) set breakpoint pending on
(gdb) break pendingfunc if (0)
Function "pendingfunc" not defined.
Breakpoint 1 (pendingfunc if (0)) pending.
(gdb) break main if (0)
Breakpoint 2 at 0x401198: file /tmp/hello.c, line 18.
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y <PENDING> pendingfunc if (0)
2 breakpoint keep y 0x0000000000401198 in main at /tmp/hello.c:18
stop only if (0)
(gdb)
And after this commit:
(gdb) set breakpoint pending on
(gdb) break pendingfunc if (0)
Function "pendingfunc" not defined.
Breakpoint 1 (pendingfunc) pending.
(gdb) break main if (0)
Breakpoint 2 at 0x401198: file /home/andrew/tmp/hello.c, line 18.
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y <PENDING> pendingfunc
stop only if (0)
2 breakpoint keep y 0x0000000000401198 in main at /home/andrew/tmp/hello.c:18
stop only if (0)
(gdb)
Notice that the display of the condition is now the same for the
pending and non-pending breakpoints.
The same is true for the thread, inferior, or task information in
thread, inferior, or task specific breakpoints; this information is
displayed on its own line rather than being part of the 'What'
field.
2. We can check that the thread exists as soon as the pending
breakpoint is created. Currently there is a weird difference
between pending and non-pending breakpoints when creating a
thread-specific breakpoint.
A pending thread-specific breakpoint only checks its thread when it
becomes non-pending, at which point the thread the breakpoint was
intended for might have exited. Here's the behaviour before this
commit:
(gdb) set breakpoint pending on
(gdb) break foo thread 2
Function "foo" not defined.
Breakpoint 2 (foo thread 2) pending.
(gdb) c
Continuing.
[Thread 0x7ffff7c56700 (LWP 2948835) exited]
Error in re-setting breakpoint 2: Unknown thread 2.
[Inferior 1 (process 2948832) exited normally]
(gdb)
Notice the 'Error in re-setting breakpoint 2: Unknown thread 2.'
line, this was triggered when GDB tried to make the breakpoint
non-pending, and GDB discovers that the thread no longer exists.
Compare that to the behaviour after this commit:
(gdb) set breakpoint pending on
(gdb) break foo thread 2
Function "foo" not defined.
Breakpoint 2 (foo) pending.
(gdb) c
Continuing.
[Thread 0x7ffff7c56700 (LWP 2949243) exited]
Thread-specific breakpoint 2 deleted - thread 2 no longer in the thread list.
[Inferior 1 (process 2949240) exited normally]
(gdb)
Now the behaviour for pending breakpoints is identical to
non-pending breakpoints, the thread specific breakpoint is removed
as soon as the thread the breakpoint is associated with exits.
There is an additional change; when the pending breakpoint is
created prior to this patch we see this line:
Breakpoint 2 (foo thread 2) pending.
While after this patch we get this line:
Breakpoint 2 (foo) pending.
Notice that 'thread 2' has disappeared. This might look like a
regression, but I don't think it is. That we said 'thread 2'
before was just a consequence of the lazy parsing of the breakpoint
specification, while with this patch GDB understands, and has
parsed away the 'thread 2' bit of the spec. If folk think the old
information was useful then this would be trivial to add back in
code_breakpoint::say_where.
As a result of this commit the breakpoints 'extra_string' field is now
only used by bp_dprintf type breakpoints to hold the printf format and
arguments. This string should always be empty for other breakpoint
types. This allows some cleanup in print_breakpoint_location.
In code_breakpoint::code_breakpoint I've changed an error case into an
assert. This is because the error is now handled earlier in
create_breakpoint. As a result we know that by this point, the
extra_string will always be nullptr for anything other than a
bp_dprintf style breakpoint.
The find_condition_and_thread_for_sals function is now no longer
needed, this was previously doing the delayed splitting of the extra
string into thread, task, and condition, but this is now all done in
create_breakpoint, so find_condition_and_thread_for_sals can be
deleted, and the code that calls this in
code_breakpoint::location_spec_to_sals can be removed. With this
update this code would only ever be reached for bp_dprintf style
breakpoints, and in these cases the extra_string should not contain
anything other than format and args.
The most interesting changes are all in create_breakpoint and in the
new file break-cond-parse.c. We have a new block of code early on in
create_breakpoint that is responsible for splitting the extra_string
into its component parts by calling create_breakpoint_parse_arg_string
a function in the new break-cond-parse.c file. This means that some
of the later code can be simplified a little.
The new break-cond-parse.c file implements the splitting up the
extra_string and finding all the parts, as well as some self-tests for
the new function.
Finally, now we know all the breakpoint details, these can be stored
within the breakpoint object if we end up creating a deferred
breakpoint. Additionally, if we are creating a deferred bp_dprintf we
can parse the extra_string to build the printf command.
The implementation here aims to maintain backwards compatibility as
much as possible, this means that:
1. We support abbreviations of 'thread', 'task', and 'inferior' in
some places on the breakpoint line. The handling of abbreviations
has (before this patch) been a little weird, so this works:
(gdb) break *main th 1
And creates a breakpoint at '*main' for thread 1 only, while this
does not work:
(gdb) break main th 1
In this case GDB will try to find the symbol 'main th 1'. This
weirdness exists before and after this patch.
2. The handling of '-force-condition' is odd, if this flag appears
immediately after a condition then it will be treated as part of the
condition, e.g.:
(gdb) break main if 0 -force-condition
No symbol "force" in current context.
But we are fine with these alternatives:
(gdb) break main if 0 thread 1 -force-condition
(gdb) break main -force-condition if 0
Again, this is just a quirk of how the breakpoint line used to be
parsed, but I've maintained this for backward compatibility. During
review it was suggested that -force-condition should become an
actual breakpoint flag (i.e. only valid after the 'break' command
but before the function name), and I don't think that would be a
terrible idea, however, that's not currently a trivial change, and I
think should be done as a separate piece of work. For now, this
patch just maintains the current behaviour.
The implementation works by first splitting the breakpoint condition
string (everything after the location specification) into a list of
tokens, each token has a type and a value. (e.g. we have a THREAD
token where the value is the thread-id string). The list of tokens is
validated, and in some cases, tokens are merged. Then the values are
extracted from the remaining token list.
Consider this breakpoint command:
(gdb) break main thread 1 if argc == 2
The condition string passed to create_breakpoint_parse_arg_string is
going to be 'thread 1 if argc == 2', which is then split into the
tokens:
{ THREAD: "1" } { CONDITION: "argc == 2" }
The thread-id (1) and the condition string 'argc == 2' are extracted
from these tokens and returns back to create_breakpoint.
Now consider this breakpoint command:
(gdb) break some_function if ( some_var == thread )
Here the user wants a breakpoint if 'some_var' is equal to the
variable 'thread'. However, when this is initially parsed we will
find these tokens:
{ CONDITION: "( some_var == " } { THREAD: ")" }
This is a consequence of how we have to try and figure out the
contents of the 'if' condition without actually parsing the
expression; parsing the expression requires that we know the location
in order to lookup the variables by name, and this can't be done for
pending breakpoints (their location isn't known yet), and one of the
points of this work is that we extract things like thread-id for
pending breakpoints.
And so, it is in this case that token merging takes place. We check
if the value of a token appearing immediately after the CONDITION
token looks valid. In this case, does ')' look like a valid
thread-id. Clearly, in this case ')' does not, and so me merge the
THREAD token into the condition token, giving:
{ CONDITION: "( some_var == thread )" }
Which is what we want.
I'm sure that we might still be able to come up with some edge cases
where the parser makes the wrong choice. I think long term the best
way to work around these would be to move the thread, inferior, task,
and -force-condition flags to be "real" command options for the break
command. I am looking into doing this, but can't guarantee if/when
that work would be completed, so this patch should be reviewed assume
that the work will never arrive (though I hope it will).
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
|
||
|
|
4764e22161 |
gdb: make breakpoint_debug_printf global
This commit makes breakpoint_debug_printf available outside of breakpoint.c. In a later commit I'll want to use this macro from another file. This is just a refactor, there should be no user visible changes after this commit. |
||
|
|
dc22ab49e9 |
gdb: deprecated filename_completer and associated functions
Following on from the previous commit, this commit marks the old
unquoted filename completion related functions as deprecated.
The aim of doing this is to make it more obvious to someone adding a
new command that they should not be using the older unquoted style
filename argument handling.
I split this change from the previous to make for an easier review.
This commit touches more files, but is _just_ function renaming.
Check out gdb/completer.{c,h} for what has been renamed. All the
other files have just been updated to use the new names.
There should be no user visible changes after this commit.
|
||
|
|
a92e943014 |
gdb: implement ::re_set method for catchpoint class
It is possible to attach a condition to a catchpoint. This can't be
done when the catchpoint is created, but can be done with the
'condition' command, this is documented in the GDB manual:
You can also use the 'if' keyword with the 'watch' command. The
'catch' command does not recognize the 'if' keyword; 'condition' is the
only way to impose a further condition on a catchpoint.
A GDB crash was reported against Fedora GDB where a user had attached
a condition to a catchpoint and then restarted the inferior. When the
catchpoint was hit GDB would immediately segfault. I was able to
reproduce the failure on upstream GDB:
(gdb) file ./some/binary
(gdb) catch syscall write
(gdb) run
...
Catchpoint 1 (returned from syscall write), 0x00007ffff7b594a7 in write () from /lib64/libc.so.6
(gdb) condition 1 $_streq((char *) $rsi, "foobar") == 0
(gdb) run
...
Fatal signal: Segmentation fault
...
What happened here is that on the system in question we had debug
information available for both the main application and also for
libc.
When the condition was attached GDB was stopped inside libc and as the
debug information was available GDB found a reference to the 'char'
type (for the cast) inside libc's debug information.
When the inferior is restarted GDB discards all of the objfiles
associated with shared libraries, and this includes libc. As such the
'char' type, which is objfile owned, is discarded and the reference to
it from the catchpoint's condition expression becomes invalid.
Now, if it were a breakpoint instead of a catchpoint, what would
happen is that after the shared library objfiles had been discarded
we'd call the virtual breakpoint::re_set method on the breakpoint, and
this would update the breakpoint's condition expression. This is
because user breakpoints are actually instances of the code_breakpoint
class and the code_breakpoint::re_set method contains the code to
recompute the breakpoint's condition expression.
However, catchpoints are instances of the catchpoint class which
inherits from the base breakpoint class. The catchpoint class does
not override breakpoint::re_set, and breakpoint::re_set is empty!
The consequence of this is that catchpoint condition expressions are
never recomputed, and the dangling pointer to the now deleted, objfile
owned type 'char' is left around, and, when the catchpoint is hit, the
invalid pointer is used when GDB tries to evaluate the condition
expression.
In this commit I have implemented catchpoint::re_set. This is pretty
simple and just recomputes the condition expression as you'd expect.
If the condition doesn't evaluate then the catchpoint is marked as
disabled_by_cond.
I have also made breakpoint::re_set pure virtual. With the addition
of catchpoint::re_set every sub-class of breakpoint now implements the
::re_set method, and if new sub-classes are added in the future I
think that they _must_ implement ::re_set in order to avoid this
problem. As such falling back to an empty breakpoint::re_set doesn't
seem helpful.
For testing I have not relied on stopping in libc and having libc
debug information available, this doesn't seem like a good idea for
the GDB testsuite. Instead I create a (rather pointless) condition
check that uses a type defined only within a shared library. When the
inferior is restarted the catchpoint will temporarily be marked as
disabled_by_cond (due to the type not being available), but once the
shared library is loaded again the catchpoint will be re-enabled.
Without the fixes above then the same crashing behaviour can be
observed.
One point of note: the dangling pointer of course exposes undefined
behaviour, with no guarantee of a crash. Though a crash is what I
usually see I have see GDB throw random errors from the expression
evaluation code, and once, I saw no problem at all! If you recompile
GDB with the address sanitizer, or run under valgrind, then the bug
will be exposed every time.
After fixing this bug I checked bugzilla and found PR gdb/29960 which
is the same bug. I was able to reproduce the bug before this commit,
and after this commit GDB is no longer crashing.
Before:
(gdb) file /tmp/hello.x
Reading symbols from /tmp/hello.x...
(gdb) run
Starting program: /tmp/hello.x
Hello World
[Inferior 1 (process 1101855) exited normally]
(gdb) catch syscall 1
Catchpoint 1 (syscall 'write' [1])
(gdb) condition 1 write.fd == 1
(gdb) run
Starting program: /tmp/hello.x
Fatal signal: Segmentation fault
...
And after:
(gdb) file /tmp/hello.x
Reading symbols from /tmp/hello.x...
(gdb) run
Starting program: /tmp/hello.x
Hello World
Args: ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 )
[Inferior 1 (process 1102373) exited normally]
(gdb) catch syscall 1
Catchpoint 1 (syscall 'write' [1])
(gdb) condition 1 write.fd == 1
(gdb) r
Starting program: /tmp/hello.x
Error in testing condition for breakpoint 1:
Attempt to extract a component of a value that is not a structure.
Catchpoint 1 (call to syscall write), 0x00007ffff7eb94a7 in write ()
from /lib64/libc.so.6
(gdb) ptype write
type = <unknown return type> ()
(gdb)
Notice we get the error now when the condition fails to evaluate.
This seems reasonable given that 'write' will be a function, and
indeed the final 'ptype' shows that it's a function, not a struct.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29960
Reviewed-By: Tom de Vries <tdevries@suse.de>
|
||
|
|
c201bc6e93 |
gdb: remove duplicate check in disable_breakpoints_in_freed_objfile
I spotted that we have a duplicate condition check in the function disable_breakpoints_in_freed_objfile. Lets remove it. There should be no user visible changes after this commit. Approved-By: Tom Tromey <tom@tromey.com> |
||
|
|
71e0850800 |
Minor formatting fix in breakpoint.c
I noticed a spot in breakpoint.c that doesn't follow gdb's formatting rules: the return type is on the same line as the method name. |
||
|
|
358ada8bc5 |
gdb/doc: fix typo in 'watch' command
* gdb/breakpoint.c (watch_option_defs): Fix typo. Copyright-paperwork-exempt: yes. |
||
|
|
d47600c85d |
Add another constructor to scoped_restore_current_language
While working on something else, I noticed that this is relatively common: scoped_restore_current_language save; set_language (something); This patch adds a second constructor to scoped_restore_current_language to simplify this idiom. Reviewed-By: Tom de Vries <tdevries@suse.de> |
||
|
|
d1b72c2649 |
Notify Python when breakpoint symbol changes
A DAP user noticed that breakpoints set by address were never updated to show their location after the DAP launch request. It turns out that gdb does not emit the breakpoint-modified event when this sort of breakpoint is updated. This patch changes gdb to notify the breakpoint-modified observer when a breakpoint location's symbol changes. This in turn causes the DAP event to be emitted. Reviewed-by: Keith Seitz <keiths@redhat.com> |