Commit graph

1543 commits

Author SHA1 Message Date
Tom Tromey
1f9e9ea5b7 Remove some frame invalidation code
I stumbled across a few spots that mention that a function
"invalidates frame" and also assignments of NULL to a frame_info_ptr.
This code isn't harmful, but is also unnecessary since the
introduction of frame_info_ptr -- nowadays frame invalidations are
handled automatically.

Regression tested on x86-64 Fedora 38.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-10-30 21:47:36 -06:00
Simon Marchi
3fe0dfd160 gdb: rename struct so_list to shobj
Now that so_list lists are implemented using intrusive_list, it doesn't
really make sense for the element type to be named "_list".  Rename to
just `struct shobj` (`struct so` was deemed to be not greppable enough).

Change-Id: I1063061901298bb40fee73bf0cce44cd12154c0e
Approved-By: Pedro Alves <pedro@palves.net>
Reviewed-By: Reviewed-By: Lancelot Six <lancelot.six@amd.com>
2023-10-19 11:14:26 -04:00
Simon Marchi
98107b0b17 gdb: make so_list::{so_original_name,so_name} std::strings
Change these two fields, simplifying memory management and copying.

Change-Id: If2559284c515721e71e1ef56ada8b64667eebe55
Approved-By: Pedro Alves <pedro@palves.net>
Reviewed-By: Reviewed-By: Lancelot Six <lancelot.six@amd.com>
2023-10-19 10:57:51 -04:00
Simon Marchi
bb86ab837e gdb: replace some so_list parameters to use references
A subsequent patch changes so_list to be linked using
intrusive_list.  Iterating an intrusive_list yields some references to
the list elements.  Convert some functions accepting so_list objects to
take references, to make things easier and more natural.  Add const
where possible and convenient.

Change-Id: Id5ab5339c3eb6432e809ad14782952d6a45806f3
Approved-By: Pedro Alves <pedro@palves.net>
Reviewed-By: Reviewed-By: Lancelot Six <lancelot.six@amd.com>
2023-10-19 10:57:51 -04:00
Simon Marchi
99d9c3b92c gdb: remove target_gdbarch
This function is just a wrapper around the current inferior's gdbarch.
I find that having that wrapper just obscures where the arch is coming
from, and that it's often used as "I don't know which arch to use so
I'll use this magical target_gdbarch function that gets me an arch" when
the arch should in fact come from something in the context (a thread,
objfile, symbol, etc).  I think that removing it and inlining
`current_inferior ()->arch ()` everywhere will make it a bit clearer
where that arch comes from and will trigger people into reflecting
whether this is the right place to get the arch or not.

Change-Id: I79f14b4e4934c88f91ca3a3155f5fc3ea2fadf6b
Reviewed-By: John Baldwin <jhb@FreeBSD.org>
Approved-By: Andrew Burgess <aburgess@redhat.com>
2023-10-10 10:44:35 -04:00
Simon Marchi
e0322c6a7b gdb: remove unnecessary nullptr check in free_objfile observers
The free_objfile observable is never called with a nullptr objfile.

Change-Id: I1e990edeb45bc38009ccb129c623911097ab65fe
Approved-By: Tom Tromey <tom@tromey.com>
2023-10-05 13:20:50 -04:00
Simon Marchi
bd93891c9a gdb: remove solib::pspace field
This backlink is not necessary, we always know the program space from
the context.  Pass it down the solib_unloaded observer.

Change-Id: I45a503472dc791f517558b8141901472634e0556
Approved-By: Tom Tromey <tom@tromey.com>
2023-10-02 11:53:21 -04:00
Tom Tromey
0128542673 Use string_file::release in some places
I found a few spots like:

    string_file f;
    std::string x = f.string ();

However, string_file::string returns a 'const std::string &'...  so it
seems to me that this must be copying the string (? I find it hard to
reason about this in C++).

This patch changes these spots to use release() instead, which moves
the string.

Reviewed-by: Keith Seitz <keiths@redhat.com>
Reviewed-by: Lancelot Six <lancelot.six@amd.com>
2023-09-26 06:56:27 -06:00
Tom Tromey
6a9196a65f Use gdb::checked_static_cast for code_breakpoint
This replaces some casts to 'code_breakpoint *' with
checked_static_cast.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-09-19 08:14:01 -06:00
Tom Tromey
01bccc56af Use gdb::checked_static_cast for tracepoints
This replaces some casts to 'tracepoint *' with checked_static_cast.
Some functions are changed to accept a 'tracepoint *' now, for better
type safety.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-09-19 08:14:00 -06:00
Tom Tromey
bcafd1c19e Use gdb::checked_static_cast for watchpoints
This replaces some casts to 'watchpoint *' with checked_static_cast.
In one spot, an unnecessary block is also removed.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2023-09-19 08:14:00 -06:00
Mohamed Bouhaouel
093da43d2a gdb, breakpoint: add a destructor to the watchpoint struct
Make sure to unlink the related breakpoint when the watchpoint instance
is deleted.  This prevents having a wp-related breakpoint that is
linked to a NULL watchpoint (e.g.  the watchpoint instance is being
deleted when the 'watch' command fails).  With the below scenario,
having such a left out breakpoint will lead to a GDB hang, and this
is due to an infinite loop when deleting all inferior breakpoints.

Scenario:
	(gdb) set can-use-hw-watchpoints 0
	(gdb) awatch <SCOPE VAR>
	Can't set read/access watchpoint when hardware watchpoints are disabled.
	(gdb) rwatch <SCOPE VAR>
	Can't set read/access watchpoint when hardware watchpoints are disabled.
	(gdb) <continue the program until the end>
	>> HANG <<

Signed-off-by: Mohamed Bouhaouel <mohamed.bouhaouel@intel.com>
Reviewed-by: Bruno Larsen <blarsen@redhat.com>
2023-09-19 06:56:53 -06:00
Pedro Alves
9d7d58e726 gdb: centralize "[Thread ...exited]" notifications
Currently, each target backend is responsible for printing "[Thread
...exited]" before deleting a thread.  This leads to unnecessary
differences between targets, like e.g. with the remote target, we
never print such messages, even though we do print "[New Thread ...]".

E.g., debugging the gdb.threads/attach-many-short-lived-threads.exp
with gdbserver, letting it run for a bit, and then pressing Ctrl-C, we
currently see:

 (gdb) c
 Continuing.
 ^C[New Thread 3850398.3887449]
 [New Thread 3850398.3887500]
 [New Thread 3850398.3887551]
 [New Thread 3850398.3887602]
 [New Thread 3850398.3887653]
 ...

 Thread 1 "attach-many-sho" received signal SIGINT, Interrupt.
 0x00007ffff7e6a23f in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7fffffffda80, rem=rem@entry=0x7fffffffda80)
     at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
 78      in ../sysdeps/unix/sysv/linux/clock_nanosleep.c
 (gdb)

Above, we only see "New Thread" notifications, even though threads
were deleted.

After this patch, we'll see:

 (gdb) c
 Continuing.
 ^C[Thread 3558643.3577053 exited]
 [Thread 3558643.3577104 exited]
 [Thread 3558643.3577155 exited]
 [Thread 3558643.3579603 exited]
 ...
 [New Thread 3558643.3597415]
 [New Thread 3558643.3600015]
 [New Thread 3558643.3599965]
 ...

 Thread 1 "attach-many-sho" received signal SIGINT, Interrupt.
 0x00007ffff7e6a23f in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7fffffffda80, rem=rem@entry=0x7fffffffda80)
     at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
 78      in ../sysdeps/unix/sysv/linux/clock_nanosleep.c
 (gdb) q

This commit fixes this by moving the thread exit printing to common
code instead, triggered from within delete_thread (or rather,
set_thread_exited).

There's one wrinkle, though.  While most targest want to print:

 [Thread ... exited]

the Windows target wants to print:

 [Thread ... exited with code <exit_code>]

... and sometimes wants to suppress the notification for the main
thread.  To address that, this commits adds a delete_thread_with_code
function, only used by that target (so far).

This fix was originally posted as part of a larger series:

  https://inbox.sourceware.org/gdb-patches/20221212203101.1034916-1-pedro@palves.net/

But didn't really need to be part of that series.  In order to get
this fix merged sooner, I (Andrew Burgess) have rebased this commit
outside of the original series.  Any bugs introduced while splitting
this patch out and rebasing, are entirely my own.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30129
Co-Authored-By: Andrew Burgess <aburgess@redhat.com>
2023-08-23 09:57:38 +01:00
Andrew Burgess
f29ab2e0e3 gdb: add missing notify_breakpoint_modified call
The commit:

  commit b080fe54fb
  Date:   Tue Nov 8 12:32:51 2022 +0000

      gdb: add inferior-specific breakpoints

introduced a bug in the function breakpoint_set_inferior. The above
commit includes this line:

  gdb::observers::breakpoint_modified.notify (b);

when it should have instead used this line:

  notify_breakpoint_modified (b);

The change to use notify_breakpoint_modified was introduced to GDB
after commit b080fe54fb was written, but before it was merged, and I
failed to update this part of the code during the rebase.

The consequence of this error is that the MI interpreter will not emit
breakpoint-modified notifications when breakpoint_set_inferior is
called.

In this commit I update the code to call notify_breakpoint_modified,
and add a test that checks the MI events are being emitted correctly
in this case.
2023-08-23 09:04:45 +01:00
Andrew Burgess
b080fe54fb gdb: add inferior-specific breakpoints
This commit extends the breakpoint mechanism to allow for inferior
specific breakpoints (but not watchpoints in this commit).

As GDB gains better support for multiple connections, and so for
running multiple (possibly unrelated) inferiors, then it is not hard
to imagine that a user might wish to create breakpoints that apply to
any thread in a single inferior.  To achieve this currently, the user
would need to create a condition possibly making use of the $_inferior
convenience variable, which, though functional, isn't the most user
friendly.

This commit adds a new 'inferior' keyword that allows for the creation
of inferior specific breakpoints.

Inferior specific breakpoints are automatically deleted when the
associated inferior is removed from GDB, this is similar to how
thread-specific breakpoints are deleted when the associated thread is
deleted.

Watchpoints are already per-program-space, which in most cases mean
watchpoints are already inferior specific.  There is a small window
where inferior-specific watchpoints might make sense, which is after a
vfork, when two processes are sharing the same address space.
However, I'm leaving that as an exercise for another day.  For now,
attempting to use the inferior keyword with a watchpoint will give an
error, like this:

  (gdb) watch a8 inferior 1
  Cannot use 'inferior' keyword with watchpoints

A final note on the implementation: currently, inferior specific
breakpoints, like thread-specific breakpoints, are inserted into every
inferior, GDB then checks once the inferior stops if we are in the
correct thread or inferior, and resumes automatically if we stopped in
the wrong thread/inferior.

An obvious optimisation here is to only insert breakpoint locations
into the specific program space (which mostly means inferior) that
contains either the inferior or thread we are interested in.  This
would reduce the number times GDB has to stop and then resume again in
a multi-inferior setup.

I have a series on the mailing list[1] that implements this
optimisation for thread-specific breakpoints.  Once this series has
landed I'll update that series to also handle inferior specific
breakpoints in the same way.  For now, inferior specific breakpoints
are just slightly less optimal, but this is no different to
thread-specific breakpoints in a multi-inferior debug session, so I
don't see this as a huge problem.

[1] https://inbox.sourceware.org/gdb-patches/cover.1685479504.git.aburgess@redhat.com/
2023-08-17 16:42:39 +01:00
Mihails Strasuns
3cdc2d7e66 gdb, breakpoint: add breakpoint location debugging logs
Add new commands:

  set debug breakpoint on|off
  show debug breakpoint

This patch introduces new debugging information that prints
breakpoint location insertion and removal flow.

The debug output looks like:
~~~
(gdb) set debug breakpoint on
(gdb) disassemble main
Dump of assembler code for function main:
   0x0000555555555129 <+0>:	endbr64
   0x000055555555512d <+4>:	push   %rbp
   0x000055555555512e <+5>:	mov    %rsp,%rbp
=> 0x0000555555555131 <+8>:	mov    $0x0,%eax
   0x0000555555555136 <+13>:	pop    %rbp
   0x0000555555555137 <+14>:	ret
End of assembler dump.
(gdb) break *0x0000555555555137
Breakpoint 2 at 0x555555555137: file main.c, line 4.
[breakpoint] update_global_location_list: insert_mode = UGLL_MAY_INSERT
(gdb) c
Continuing.
[breakpoint] update_global_location_list: insert_mode = UGLL_INSERT
[breakpoint] insert_bp_location: Breakpoint 2 (0x5565daddb1e0) at address 0x555555555137 in main at main.c:4
[breakpoint] insert_bp_location: Breakpoint -2 (0x5565dab51c10) at address 0x7ffff7fd37b5
[breakpoint] insert_bp_location: Breakpoint -5 (0x5565dab68f30) at address 0x7ffff7fe509e
[breakpoint] insert_bp_location: Breakpoint -7 (0x5565dab694f0) at address 0x7ffff7fe63f4
[breakpoint] remove_breakpoint_1: Breakpoint 2 (0x5565daddb1e0) at address 0x555555555137 in main at main.c:4 due to regular remove
[breakpoint] remove_breakpoint_1: Breakpoint -2 (0x5565dab51c10) at address 0x7ffff7fd37b5 due to regular remove
[breakpoint] remove_breakpoint_1: Breakpoint -5 (0x5565dab68f30) at address 0x7ffff7fe509e due to regular remove
[breakpoint] remove_breakpoint_1: Breakpoint -7 (0x5565dab694f0) at address 0x7ffff7fe63f4 due to regular remove

Breakpoint 2, 0x0000555555555137 in main () at main.c:4
4	}
~~~

Co-Authored-By: Christina Schimpe <christina.schimpe@intel.com>
2023-08-09 07:38:57 +00:00
Andrew Burgess
b1c0ab2080 gdb: avoid double stop after failed breakpoint condition check
This commit replaces this earlier commit:

  commit 2e411b8c68
  Date:   Fri Oct 14 14:53:15 2022 +0100

      gdb: don't always print breakpoint location after failed condition check

and is a result of feedback received here[1].

The original commit addressed a problem where, if a breakpoint
condition included an inferior function call, and if the inferior
function call failed, then GDB would announce the stop twice.  Here's
an example of GDB's output before the above commit that shows the
problem being addressed:

  (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)

The original commit addressed this issue in breakpoint.c, by spotting
that the $pc had changed while evaluating the breakpoint condition,
and inferring from this that GDB must have stopped elsewhere.

However, the way in which the original commit suppressed the second
stop announcement was to set bpstat::print to true -- this tells GDB
not to print the frame during the stop announcement, and for the CLI
this is fine, however, it was pointed out that for the MI this still
isn't really enough.  Below is an example from an MI session after the
above commit was applied, this shows the problem with the above
commit:

  -break-insert -c "cond_fail()" foo
  ^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x000000000040111e",func="foo",file="/tmp/mi-condbreak-fail.c",line="30",thread-groups=["i1"],cond="cond_fail()",times="0",original-location="foo"}
  (gdb)
  -exec-run
  =thread-group-started,id="i1",pid="2636270"
  =thread-created,id="1",group-id="i1"
  =library-loaded,id="/lib64/ld-linux-x86-64.so.2",target-name="/lib64/ld-linux-x86-64.so.2",host-name="/lib64/ld-linux-x86-64.so.2",symbols-loaded="0",thread-group="i1",ranges=[{from="0x00007ffff7fd3110",to="0x00007ffff7ff2bb4"}]
  ^running
  *running,thread-id="all"
  (gdb)
  =library-loaded,id="/lib64/libm.so.6",target-name="/lib64/libm.so.6",host-name="/lib64/libm.so.6",symbols-loaded="0",thread-group="i1",ranges=[{from="0x00007ffff7e59390",to="0x00007ffff7ef4f98"}]
  =library-loaded,id="/lib64/libc.so.6",target-name="/lib64/libc.so.6",host-name="/lib64/libc.so.6",symbols-loaded="0",thread-group="i1",ranges=[{from="0x00007ffff7ca66b0",to="0x00007ffff7df3c5f"}]
  ~"\nProgram"
  ~" received signal SIGSEGV, Segmentation fault.\n"
  ~"0x0000000000401116 in cond_fail () at /tmp/mi-condbreak-fail.c:24\n"
  ~"24\t  return *p;\t\t\t/* Crash here.  */\n"
  *stopped,reason="signal-received",signal-name="SIGSEGV",signal-meaning="Segmentation fault",frame={addr="0x0000000000401116",func="cond_fail",args=[],file="/tmp/mi-condbreak-fail.c",fullname="/tmp/mi-condbreak-fail.c",line="24",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="9"
  &"Error in testing condition for breakpoint 1:\n"
  &"The program being debugged was signaled while in a function called from GDB.\n"
  &"GDB remains in the frame where the signal was received.\n"
  &"To change this behavior use \"set unwindonsignal on\".\n"
  &"Evaluation of the expression containing the function\n"
  &"(cond_fail) will be abandoned.\n"
  &"When the function is done executing, GDB will silently stop.\n"
  =breakpoint-modified,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x000000000040111e",func="foo",file="/tmp/mi-condbreak-fail.c",fullname="/tmp/mi-condbreak-fail.c",line="30",thread-groups=["i1"],cond="cond_fail()",times="1",original-location="foo"}
  *stopped
  (gdb)

Notice that we still see two '*stopped' lines, the first includes the
full frame information, while the second has no frame information,
this is a result of bpstat::print having been set.  Ideally, the
second '*stopped' line should not be present.

By setting bpstat::print I was addressing the problem too late, this
flag really only changes how interp::on_normal_stop prints the stop
event, and interp::on_normal_stop is called (indirectly) from the
normal_stop function in infrun.c.  A better solution is to avoid
calling normal_stop at all for the stops which should not be reported
to the user, and this is what I do in this commit.

This commit has 3 parts:

  1. In breakpoint.c, revert the above commit,

  2. In fetch_inferior_event (infrun.c), capture the stop-id before
  calling handle_inferior_event.  If, after calling
  handle_inferior_event, the stop-id has changed, then this indicates
  that somewhere within handle_inferior_event, a stop was announced to
  the user.  If this is the case then GDB should not call normal_stop,
  and we should rely on whoever announced the stop to ensure that we
  are in a PROMPT_NEEDED state, which means the prompt will be
  displayed once fetch_inferior_event returns.  And,

  3. In infcall.c, do two things:

     (a) In run_inferior_call, after making the inferior call, ensure
     that either async_disable_stdin or async_enable_stdin is called
     to put the prompt state, and stdin handling into the correct
     state based on whether the inferior call completed successfully
     or not, and

     (b) In call_thread_fsm::should_stop, call async_enable_stdin
     rather than changing the prompt state directly.  This isn't
     strictly necessary, but helped me understand this code more.
     This async_enable_stdin call is only reached if normal_stop is
     not going to be called, and replaces the async_enable_stdin call
     that exists in normal_stop.  Though we could just adjust the
     prompt state if felt (to me) much easier to understand when I
     could see this call and the corresponding call in normal_stop.

With these changes in place now, when the inferior call (from the
breakpoint condition) fails, infcall.c leaves the prompt state as
PROMPT_NEEDED, and leaves stdin registered with the event loop.

Back in fetch_inferior_event GDB notices that the stop-id has changed
and so avoids calling normal_stop.

And on return from fetch_inferior_event GDB will display the prompt
and handle input from stdin.

As normal_stop is not called the MI problem is solved, and the test
added in the earlier mentioned commit still passes just fine, so the
CLI has not regressed.

[1] https://inbox.sourceware.org/gdb-patches/6fd4aa13-6003-2563-5841-e80d5a55d59e@palves.net/
2023-08-03 14:55:31 +01:00
Andrew Burgess
3f3ffaca04 gdb: include location number in breakpoint error message
This commit improves the output of this previous commit:

  commit 2dc3457a45
  Date:   Fri Oct 14 13:22:55 2022 +0100

      gdb: include breakpoint number in testing condition error message

The earlier commit extended the error message:

  Error in testing breakpoint condition:

to include the breakpoint number, e.g.:

  Error in testing breakpoint condition 3:

This commit extends takes this further, and includes the location
number if the breakpoint has multiple locations, so we might now see:

  Error in testing breakpoint condition 3.2:

Just as with how GDB reports a normal breakpoint stop, if a breakpoint
only has a single location then the location number is not included,
this keeps things nice and consistent.

I've extended one of the tests to cover the new functionality.

Approved-By: Pedro Alves <pedro@palves.net>
2023-07-10 10:49:59 +01:00
Tom de Vries
3bfdcabbc2 [gdb] Fix more typos
Fix some more typos:
- distinquish -> distinguish
- actualy -> actually
- singe -> single
- frash -> frame
- chid -> child
- dissassembler -> disassembler
- uninitalized -> uninitialized
- precontidion -> precondition
- regsiters -> registers
- marge -> merge
- sate -> state
- garanteed -> guaranteed
- explictly -> explicitly
- prefices (nonstandard plural) -> prefixes
- bondary -> boundary
- formated -> formatted
- ithe -> the
- arrav -> array
- coresponding -> corresponding
- owend -> owned
- fials -> fails
- diasm -> disasm
- ture -> true
- tpye -> type

There's one code change, the name of macro SIG_CODE_BONDARY_FAULT changed to
SIG_CODE_BOUNDARY_FAULT.

Tested on x86_64-linux.
2023-06-05 12:53:15 +02:00
Tom de Vries
33b5899fc0 [gdb] Fix typos
Fix a few typos:
- implemention -> implementation
- convertion(s) -> conversion(s)
- backlashes -> backslashes
- signoring -> ignoring
- (un)ambigious -> (un)ambiguous
- occured -> occurred
- hidding -> hiding
- temporarilly -> temporarily
- immediatelly -> immediately
- sillyness -> silliness
- similiar -> similar
- porkuser -> pokeuser
- thats -> that
- alway -> always
- supercede -> supersede
- accomodate -> accommodate
- aquire -> acquire
- priveleged -> privileged
- priviliged -> privileged
- priviledges -> privileges
- privilige -> privilege
- recieve -> receive
- (p)refered -> (p)referred
- succesfully -> successfully
- successfuly -> successfully
- responsability -> responsibility
- wether -> whether
- wich -> which
- disasbleable -> disableable
- descriminant -> discriminant
- construcstor -> constructor
- underlaying -> underlying
- underyling -> underlying
- structureal -> structural
- appearences -> appearances
- terciarily -> tertiarily
- resgisters -> registers
- reacheable -> reachable
- likelyhood -> likelihood
- intepreter -> interpreter
- disassemly -> disassembly
- covnersion -> conversion
- conviently -> conveniently
- atttribute -> attribute
- struction -> struct
- resonable -> reasonable
- popupated -> populated
- namespaxe -> namespace
- intialize -> initialize
- identifer(s) -> identifier(s)
- expection -> exception
- exectuted -> executed
- dungerous -> dangerous
- dissapear -> disappear
- completly -> completely
- (inter)changable -> (inter)changeable
- beakpoint -> breakpoint
- automativ -> automatic
- alocating -> allocating
- agressive -> aggressive
- writting -> writing
- reguires -> requires
- registed -> registered
- recuding -> reducing
- opeartor -> operator
- ommitted -> omitted
- modifing -> modifying
- intances -> instances
- imbedded -> embedded
- gdbaarch -> gdbarch
- exection -> execution
- direcive -> directive
- demanged -> demangled
- decidely -> decidedly
- argments -> arguments
- agrument -> argument
- amespace -> namespace
- targtet -> target
- supress(ed) -> suppress(ed)
- startum -> stratum
- squence -> sequence
- prompty -> prompt
- overlow -> overflow
- memember -> member
- languge -> language
- geneate -> generate
- funcion -> function
- exising -> existing
- dinking -> syncing
- destroh -> destroy
- clenaed -> cleaned
- changep -> changedp (name of variable)
- arround -> around
- aproach -> approach
- whould -> would
- symobl -> symbol
- recuse -> recurse
- outter -> outer
- freeds -> frees
- contex -> context

Tested on x86_64-linux.

Reviewed-By: Tom Tromey <tom@tromey.com>
2023-06-03 22:43:57 +02:00
Simon Marchi
19081eb5f1 gdb: add interp::on_breakpoint_modified method
Same idea as previous patches, but for breakpoint_modified.

Change-Id: I4f0a9edea912de431e32451d74224b2022a7c328
2023-05-30 15:07:26 -04:00
Simon Marchi
e4239559f4 gdb: add interp::on_breakpoint_deleted method
Same idea as previous patches, but for breakpoint_deleted.

Change-Id: I59c231ce963491bb1eee1432ee1090138f09e19c
2023-05-30 15:07:26 -04:00
Simon Marchi
e7692320db gdb: add interp::on_breakpoint_created method
Same idea as previous patches, but for breakpoint_created.

Change-Id: I614113c924edc243590018b8fb3bf69cb62215ef
2023-05-30 15:07:26 -04:00
Simon Marchi
a1decfc1df gdb: remove breakpoint_pointer_iterator
Remove the breakpoint_pointer_iterator layer.  Adjust all users of
all_breakpoints and all_tracepoints to use references instead of
pointers.

Change-Id: I376826f812117cee1e6b199c384a10376973af5d
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
2023-05-25 09:52:22 -04:00
Simon Marchi
e2a1578868 gdb: link breakpoints with intrusive_list
Change-Id: I043d8d6f3dd864d80d5088f6ffc2c098337249ea
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
2023-05-25 09:41:16 -04:00
Simon Marchi
b00b30b298 gdb: remove bp_location_pointer_iterator
Remove the bp_location_pointer_iterator layer.  Adjust all users of
breakpoint::locations to use references instead of pointers.

Change-Id: Iceed34f5e0f5790a9cf44736aa658be6d1ba1afa
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
2023-05-25 09:40:58 -04:00
Simon Marchi
20afe380e8 gdb: use intrusive_list for breakpoint locations
Replace the hand-maintained linked lists of breakpoint locations with
and intrusive list.

 - Remove breakpoint::loc, add breakpoint::m_locations.

 - Add methods for the various manipulations that need to be done on the
   location list, while maintaining reasonably good encapsulation.

 - bp_location currently has a default constructor because of one use
   in hoist_existing_locations.  hoist_existing_locations now returns a
   bp_location_list, and doesn't need the default-constructor
   bp_location anymore, so remove the bp_location default constructor.

 - I needed to add a call to clear_locations in delete_breakpoint to
   avoid a use-after-free.

 - Add a breakpoint::last_loc method, for use in
   set_breakpoint_condition.

bp_location_range uses reference_to_pointer_iterator, so that all
existing callers of breakpoint::locations don't need to change right
now.  It will be removed in the next patch.

The rest of the changes are to adapt the call sites to use the new
methods, of breakpoint::locations, rather than breakpoint::loc directly.

Change-Id: I25f7ee3d66a4e914a0540589ac414b3b820b6e70
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
2023-05-25 08:47:12 -04:00
Simon Marchi
f5951b9ff8 gdb: add breakpoint::first_loc methods
Add convenience first_loc methods to struct breakpoint (const and
non-const overloads).  A subsequent patch changes the list of locations
to be an intrusive_list and makes the actual list private, so these
spots would need to change from:

    b->loc

to something ugly like:

    *b->locations ().begin ()

That would make the code much heavier and not readable.  There is a
surprisingly big number of places that access the first location of
breakpoints.  Whether this is correct, or these spots fail to consider
the possibility of multi-location breakpoints, I don't know.  But
anyhow, I think that using this instead:

 b->first_loc ()

conveys the intention better than the other two forms.

Change-Id: Ibbefe3e4ca6cdfe570351fe7e2725f2ce11d1e95
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
2023-05-25 08:47:00 -04:00
Simon Marchi
9dc1523b57 gdb: add breakpoint "has locations" methods
Add three convenience methods to struct breakpoint:

 - has_locations: returns true if the breakpoint has at least one
   location
 - has_single_location: returns true if the breakpoint has exactly one
   location
 - has_multiple_locations: returns true if the breakpoint has more than
   one location

A subsequent patch changes the list of breakpoints to be an
intrusive_list, so all these spots would need to change.  But in any
case, I think that this:

  if (b->has_multiple_locations ())

conveys the intention better than:

  if (b->loc != nullptr && b->loc->next != nullptr)

Change-Id: Ib18c3605fd35d425ef9df82cb7aacff1606c6747
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
2023-05-25 08:46:23 -04:00
Simon Marchi
5e632eca05 gdb: constify breakpoint::print_it parameter
The print_it method itself is const.  In a subsequent patch, the
locations that come out of a const breakpoint will be const as well.  It
will therefore be needed to make the last_loc output parameter const as
well.  Make that change now to reduce the size of the following patches.

Change-Id: I7ed962950bc9582646e31e2e42beca2a1c9c5105
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
2023-05-25 08:46:23 -04:00
Simon Marchi
dbaa3bf640 gdb: make some breakpoint methods use this
Some implementations of breakpoint::check_status and
breakpoint::print_it do this:

    struct breakpoint *b = bs->breakpoint_at;

bs->breakpoint_at is always the same as `this` (we can get convinced by
looking at the call sites of check_status and print_it), so it would
just be clearer to access fields through `this` instead.

Change-Id: Ic542a64fcd88e31ae2aad6feff1da278c7086891
Reviewed-By: Alexandra Petlanova Hajkova <ahajkova@redhat.com>
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
2023-05-25 08:46:23 -04:00
Tom Tromey
b8c03634d6 Introduce and use parser flags
This patch adds a new parser_flags type and changes the parser APIs to
use it rather than a collection of 'int' and 'bool'.  More flags will
be added in subsquent patches.
2023-05-23 13:57:54 -06:00
Andrew Burgess
a500c3d8e0 gdb/breakpoint: use warning function instead of gdb_printf
Noticed that in breakpoint.c, in one place, we do this:

  gdb_printf (_("warning: Error removing "
                "breakpoint %d\n"),
                old_loc->owner->number);

Instead of using the `warning` function.  There are a number of
differences between using gdb_printf like this and calling `warning`,
the main one is probably that real warnings are sent to gdb_stderr,
while the above gdb_printf call will go to gdb_stdout.

In this commit I:

  1. Change to call `warning`, we can drop the "warning: " prefix from
  the string in breakpoint.c,

  2. Update the warning text, I now start with a lower case 'e', which
  I believe is the GDB style for warnings,

  3. And I have included the address of the bp_location in the warning
  messsage,

  4. Finally, I update all the tests (2) that include this error
  message.

Reviewed-By: Tom Tromey <tom@tromey.com>
2023-05-19 10:15:01 +01:00
Johnson Sun
6e96d8a970 Disable out-of-scope watchpoints
Currently, when a local software watchpoint goes out of scope, GDB sets
the watchpoint's disposition to `delete at next stop' and then normal
stops (i.e., stop and wait for the next GDB command). When GDB normal
stops, it automatically deletes the breakpoints with their disposition
set to `delete at next stop'.

Suppose a Python script decides not to normal stop when a local
software watchpoint goes out of scope, the watchpoint will not be
automatically deleted even when its disposition is set to
`delete at next stop'.

Since GDB single-steps the program and tests the watched expression
after each instruction, not deleting the watchpoint causes the
watchpoint to be hit many more times than it should, as reported in
PR python/29603.

This was happening because the watchpoint is not deleted or disabled
when going out of scope.

This commit fixes this issue by disabling the watchpoint when going out
of scope. It also adds a test to ensure this feature isn't regressed in
the future.

Calling `breakpoint_auto_delete' on all kinds of stops (in
`fetch_inferior_event') seem to solve this issue, but is in fact
inappropriate, since `breakpoint_auto_delete' goes over all breakpoints
instead of just going through the bpstat chain (which only contains the
breakpoints that were hit right now).

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29603
Change-Id: Ia85e670b2bcba2799219abe4b6be3b582387e383
2023-05-11 12:09:10 -04:00
Simon Marchi
1fba7b3ac5 gdb: fix use-after-free in check_longjmp_breakpoint_for_call_dummy
Commit 7a8de0c330 ("Remove ALL_BREAKPOINTS_SAFE") introduced a
use-after-free in the breakpoints iterations (see below for full ASan
report).  This makes gdb.base/stale-infcall.exp fail when GDB is build
with ASan.

check_longjmp_breakpoint_for_call_dummy iterates on all breakpoints,
possibly deleting the current breakpoint as well as related breakpoints.
The problem arises when a breakpoint in the B->related_breakpoint chain
is also B->next.  In that case, deleting that related breakpoint frees
the breakpoint that all_breakpoints_safe has saved.

The old code worked around that by manually changing B_TMP, which was
the next breakpoint saved by the "safe iterator":

	while (b->related_breakpoint != b)
	  {
	    if (b_tmp == b->related_breakpoint)
	      b_tmp = b->related_breakpoint->next;
	    delete_breakpoint (b->related_breakpoint);
	  }

(Note that this seemed to assume that b->related_breakpoint->next was
the same as b->next->next, not sure this is guaranteed.)

The new code kept the B_TMP variable, but it's not useful in that
context.  We can't go change the next breakpoint as saved by the safe
iterator, like we did before.  I suggest fixing that by saving the
breakpoints to delete in a map and deleting them all at the end.

Here's the full ASan report:

    (gdb) PASS: gdb.base/stale-infcall.exp: continue to breakpoint: break-run1
    print infcall ()
    =================================================================
    ==47472==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000034980 at pc 0x563f7012c7bc bp 0x7ffdf3804d70 sp 0x7ffdf3804d60
    READ of size 8 at 0x611000034980 thread T0
        #0 0x563f7012c7bb in next_iterator<breakpoint>::operator++() /home/smarchi/src/binutils-gdb/gdb/../gdbsupport/next-iterator.h:66
        #1 0x563f702ce8c0 in basic_safe_iterator<next_iterator<breakpoint> >::operator++() /home/smarchi/src/binutils-gdb/gdb/../gdbsupport/safe-iterator.h:84
        #2 0x563f7021522a in check_longjmp_breakpoint_for_call_dummy(thread_info*) /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:7611
        #3 0x563f714567b1 in process_event_stop_test /home/smarchi/src/binutils-gdb/gdb/infrun.c:6881
        #4 0x563f71454e07 in handle_signal_stop /home/smarchi/src/binutils-gdb/gdb/infrun.c:6769
        #5 0x563f7144b680 in handle_inferior_event /home/smarchi/src/binutils-gdb/gdb/infrun.c:6023
        #6 0x563f71436165 in fetch_inferior_event() /home/smarchi/src/binutils-gdb/gdb/infrun.c:4387
        #7 0x563f7136ff51 in inferior_event_handler(inferior_event_type) /home/smarchi/src/binutils-gdb/gdb/inf-loop.c:42
        #8 0x563f7168038d in handle_target_event /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:4219
        #9 0x563f72fccb6d in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:573
        #10 0x563f72fcd503 in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:694
        #11 0x563f72fcaf2b in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:217
        #12 0x563f7262b9bb in wait_sync_command_done() /home/smarchi/src/binutils-gdb/gdb/top.c:426
        #13 0x563f7137a7c3 in run_inferior_call /home/smarchi/src/binutils-gdb/gdb/infcall.c:650
        #14 0x563f71381295 in call_function_by_hand_dummy(value*, type*, gdb::array_view<value*>, void (*)(void*, int), void*) /home/smarchi/src/binutils-gdb/gdb/infcall.c:1332
        #15 0x563f7137c0e2 in call_function_by_hand(value*, type*, gdb::array_view<value*>) /home/smarchi/src/binutils-gdb/gdb/infcall.c:780
        #16 0x563f70fe5960 in evaluate_subexp_do_call(expression*, noside, value*, gdb::array_view<value*>, char const*, type*) /home/smarchi/src/binutils-gdb/gdb/eval.c:649
        #17 0x563f70fe6617 in expr::operation::evaluate_funcall(type*, expression*, noside, char const*, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:677
        #18 0x563f6fd19668 in expr::operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/expression.h:136
        #19 0x563f70fe6bba in expr::var_value_operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:689
        #20 0x563f704b71dc in expr::funcall_operation::evaluate(type*, expression*, noside) /home/smarchi/src/binutils-gdb/gdb/expop.h:2219
        #21 0x563f70fe0f02 in expression::evaluate(type*, noside) /home/smarchi/src/binutils-gdb/gdb/eval.c:110
        #22 0x563f71b1373e in process_print_command_args /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1319
        #23 0x563f71b1391b in print_command_1 /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1332
        #24 0x563f71b147ec in print_command /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1465
        #25 0x563f706029b8 in do_simple_func /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:95
        #26 0x563f7061972a in cmd_func(cmd_list_element*, char const*, int) /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:2735
        #27 0x563f7262d0ef in execute_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/top.c:572
        #28 0x563f7100ed9c in command_handler(char const*) /home/smarchi/src/binutils-gdb/gdb/event-top.c:543
        #29 0x563f7101014b in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /home/smarchi/src/binutils-gdb/gdb/event-top.c:779
        #30 0x563f72777942 in tui_command_line_handler /home/smarchi/src/binutils-gdb/gdb/tui/tui-interp.c:104
        #31 0x563f7100d059 in gdb_rl_callback_handler /home/smarchi/src/binutils-gdb/gdb/event-top.c:250
        #32 0x7f5a80418246 in rl_callback_read_char (/usr/lib/libreadline.so.8+0x3b246) (BuildId: 092e91fc4361b0ef94561e3ae03a75f69398acbb)
        #33 0x563f7100ca06 in gdb_rl_callback_read_char_wrapper_noexcept /home/smarchi/src/binutils-gdb/gdb/event-top.c:192
        #34 0x563f7100cc5e in gdb_rl_callback_read_char_wrapper /home/smarchi/src/binutils-gdb/gdb/event-top.c:225
        #35 0x563f728c70db in stdin_event_handler /home/smarchi/src/binutils-gdb/gdb/ui.c:155
        #36 0x563f72fccb6d in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:573
        #37 0x563f72fcd503 in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:694
        #38 0x563f72fcb15c in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:264
        #39 0x563f7177ec1c in start_event_loop /home/smarchi/src/binutils-gdb/gdb/main.c:412
        #40 0x563f7177f12e in captured_command_loop /home/smarchi/src/binutils-gdb/gdb/main.c:476
        #41 0x563f717846e4 in captured_main /home/smarchi/src/binutils-gdb/gdb/main.c:1320
        #42 0x563f71784821 in gdb_main(captured_main_args*) /home/smarchi/src/binutils-gdb/gdb/main.c:1339
        #43 0x563f6fcedfbd in main /home/smarchi/src/binutils-gdb/gdb/gdb.c:32
        #44 0x7f5a7e43984f  (/usr/lib/libc.so.6+0x2384f) (BuildId: 2f005a79cd1a8e385972f5a102f16adba414d75e)
        #45 0x7f5a7e439909 in __libc_start_main (/usr/lib/libc.so.6+0x23909) (BuildId: 2f005a79cd1a8e385972f5a102f16adba414d75e)
        #46 0x563f6fcedd84 in _start (/home/smarchi/build/binutils-gdb/gdb/gdb+0xafb0d84) (BuildId: 50bd32e6e9d5e84543e9897b8faca34858ca3995)

    0x611000034980 is located 0 bytes inside of 208-byte region [0x611000034980,0x611000034a50)
    freed by thread T0 here:
        #0 0x7f5a7fce312a in operator delete(void*, unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:164
        #1 0x563f702bd1fa in momentary_breakpoint::~momentary_breakpoint() /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:304
        #2 0x563f702771c5 in delete_breakpoint(breakpoint*) /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:12404
        #3 0x563f702150a7 in check_longjmp_breakpoint_for_call_dummy(thread_info*) /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:7673
        #4 0x563f714567b1 in process_event_stop_test /home/smarchi/src/binutils-gdb/gdb/infrun.c:6881
        #5 0x563f71454e07 in handle_signal_stop /home/smarchi/src/binutils-gdb/gdb/infrun.c:6769
        #6 0x563f7144b680 in handle_inferior_event /home/smarchi/src/binutils-gdb/gdb/infrun.c:6023
        #7 0x563f71436165 in fetch_inferior_event() /home/smarchi/src/binutils-gdb/gdb/infrun.c:4387
        #8 0x563f7136ff51 in inferior_event_handler(inferior_event_type) /home/smarchi/src/binutils-gdb/gdb/inf-loop.c:42
        #9 0x563f7168038d in handle_target_event /home/smarchi/src/binutils-gdb/gdb/linux-nat.c:4219
        #10 0x563f72fccb6d in handle_file_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:573
        #11 0x563f72fcd503 in gdb_wait_for_event /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:694
        #12 0x563f72fcaf2b in gdb_do_one_event(int) /home/smarchi/src/binutils-gdb/gdbsupport/event-loop.cc:217
        #13 0x563f7262b9bb in wait_sync_command_done() /home/smarchi/src/binutils-gdb/gdb/top.c:426
        #14 0x563f7137a7c3 in run_inferior_call /home/smarchi/src/binutils-gdb/gdb/infcall.c:650
        #15 0x563f71381295 in call_function_by_hand_dummy(value*, type*, gdb::array_view<value*>, void (*)(void*, int), void*) /home/smarchi/src/binutils-gdb/gdb/infcall.c:1332
        #16 0x563f7137c0e2 in call_function_by_hand(value*, type*, gdb::array_view<value*>) /home/smarchi/src/binutils-gdb/gdb/infcall.c:780
        #17 0x563f70fe5960 in evaluate_subexp_do_call(expression*, noside, value*, gdb::array_view<value*>, char const*, type*) /home/smarchi/src/binutils-gdb/gdb/eval.c:649
        #18 0x563f70fe6617 in expr::operation::evaluate_funcall(type*, expression*, noside, char const*, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:677
        #19 0x563f6fd19668 in expr::operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/expression.h:136
        #20 0x563f70fe6bba in expr::var_value_operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:689
        #21 0x563f704b71dc in expr::funcall_operation::evaluate(type*, expression*, noside) /home/smarchi/src/binutils-gdb/gdb/expop.h:2219
        #22 0x563f70fe0f02 in expression::evaluate(type*, noside) /home/smarchi/src/binutils-gdb/gdb/eval.c:110
        #23 0x563f71b1373e in process_print_command_args /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1319
        #24 0x563f71b1391b in print_command_1 /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1332
        #25 0x563f71b147ec in print_command /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1465
        #26 0x563f706029b8 in do_simple_func /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:95
        #27 0x563f7061972a in cmd_func(cmd_list_element*, char const*, int) /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:2735
        #28 0x563f7262d0ef in execute_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/top.c:572
        #29 0x563f7100ed9c in command_handler(char const*) /home/smarchi/src/binutils-gdb/gdb/event-top.c:543

    previously allocated by thread T0 here:
        #0 0x7f5a7fce2012 in operator new(unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:95
        #1 0x563f7029a9a3 in new_momentary_breakpoint<program_space*&, frame_id&, int&> /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:8129
        #2 0x563f702212f6 in momentary_breakpoint_from_master /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:8169
        #3 0x563f70212db1 in set_longjmp_breakpoint_for_call_dummy() /home/smarchi/src/binutils-gdb/gdb/breakpoint.c:7582
        #4 0x563f713804db in call_function_by_hand_dummy(value*, type*, gdb::array_view<value*>, void (*)(void*, int), void*) /home/smarchi/src/binutils-gdb/gdb/infcall.c:1260
        #5 0x563f7137c0e2 in call_function_by_hand(value*, type*, gdb::array_view<value*>) /home/smarchi/src/binutils-gdb/gdb/infcall.c:780
        #6 0x563f70fe5960 in evaluate_subexp_do_call(expression*, noside, value*, gdb::array_view<value*>, char const*, type*) /home/smarchi/src/binutils-gdb/gdb/eval.c:649
        #7 0x563f70fe6617 in expr::operation::evaluate_funcall(type*, expression*, noside, char const*, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:677
        #8 0x563f6fd19668 in expr::operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/expression.h:136
        #9 0x563f70fe6bba in expr::var_value_operation::evaluate_funcall(type*, expression*, noside, std::__debug::vector<std::unique_ptr<expr::operation, std::default_delete<expr::operation> >, std::allocator<std::unique_ptr<expr::operation, std::default_delete<expr::operation> > > > const&) /home/smarchi/src/binutils-gdb/gdb/eval.c:689
        #10 0x563f704b71dc in expr::funcall_operation::evaluate(type*, expression*, noside) /home/smarchi/src/binutils-gdb/gdb/expop.h:2219
        #11 0x563f70fe0f02 in expression::evaluate(type*, noside) /home/smarchi/src/binutils-gdb/gdb/eval.c:110
        #12 0x563f71b1373e in process_print_command_args /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1319
        #13 0x563f71b1391b in print_command_1 /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1332
        #14 0x563f71b147ec in print_command /home/smarchi/src/binutils-gdb/gdb/printcmd.c:1465
        #15 0x563f706029b8 in do_simple_func /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:95
        #16 0x563f7061972a in cmd_func(cmd_list_element*, char const*, int) /home/smarchi/src/binutils-gdb/gdb/cli/cli-decode.c:2735
        #17 0x563f7262d0ef in execute_command(char const*, int) /home/smarchi/src/binutils-gdb/gdb/top.c:572
        #18 0x563f7100ed9c in command_handler(char const*) /home/smarchi/src/binutils-gdb/gdb/event-top.c:543
        #19 0x563f7101014b in command_line_handler(std::unique_ptr<char, gdb::xfree_deleter<char> >&&) /home/smarchi/src/binutils-gdb/gdb/event-top.c:779
        #20 0x563f72777942 in tui_command_line_handler /home/smarchi/src/binutils-gdb/gdb/tui/tui-interp.c:104
        #21 0x563f7100d059 in gdb_rl_callback_handler /home/smarchi/src/binutils-gdb/gdb/event-top.c:250
        #22 0x7f5a80418246 in rl_callback_read_char (/usr/lib/libreadline.so.8+0x3b246) (BuildId: 092e91fc4361b0ef94561e3ae03a75f69398acbb)

Change-Id: Id00c17ab677f847fbf4efdf0f4038373668d3d88
Approved-By: Tom Tromey <tom@tromey.com>
2023-05-09 13:48:14 -04:00
Tom Tromey
7a8de0c330 Remove ALL_BREAKPOINTS_SAFE
There's just a single remaining use of the ALL_BREAKPOINTS_SAFE macro;
this patch replaces it with a for-each and an explicit temporary
variable.
2023-05-07 12:44:17 -06:00
Tom Tromey
e29e63040d Remove error_stream
error_stream is trivial and only used in a couple of spots in
breakpoint.c.  This patch removes it in favor of just writing it out
at the spots where it was used.
2023-05-02 09:14:11 -06:00
Simon Marchi
13d03262f2 gdb: move struct ui and related things to ui.{c,h}
I'd like to move some things so they become methods on struct ui.  But
first, I think that struct ui and the related things are big enough to
deserve their own file, instead of being scattered through top.{c,h} and
event-top.c.

Change-Id: I15594269ace61fd76ef80a7b58f51ff3ab6979bc
2023-05-01 15:40:54 -04:00
Tom Tromey
43048e46db Remove evaluate_expression
evaluate_expression is just a little wrapper for a method on
expression.  Removing it also removes a lot of ugly (IMO) calls to
get().
2023-05-01 11:04:13 -06:00
Andrew Burgess
7594741ebc gdb: fix indentation within print_one_breakpoint_location
Spotted some code in print_one_breakpoint_location that was not
indented correctly, this commit just changes the indentation.

There should be no user visible changes after this commit.
2023-04-11 12:21:42 +01:00
Andrew Burgess
07c1c91de3 gdb: warn when converting h/w watchpoints to s/w
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>
2023-04-11 11:49:07 +01:00
Andrew Burgess
2e411b8c68 gdb: don't always print breakpoint location after failed condition check
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.
2023-04-03 14:46:32 +01:00
Andrew Burgess
2dc3457a45 gdb: include breakpoint number in testing condition error message
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.
2023-04-03 14:46:32 +01:00
Andrew Burgess
442716d400 gdb: don't use the global thread-id in the saved breakpoints file
I noticed that breakpoint::print_recreate_thread was printing the
global thread-id.  This function is used to implement the 'save
breakpoints' command, and should be writing out suitable CLI commands
for recreating the current breakpoints.  The CLI does not use global
thread-ids, but instead uses the inferior specific thread-ids,
e.g. "2.1".

After some discussion on the mailing list it was suggested that the
most consistent solution would be for the saved breakpoints file to
always contain the inferior-qualified thread-id, so the file would
include "thread 1.1" instead of just "thread 1", even when there is
only a single inferior.

So, this commit adds print_full_thread_id, which is just like the
existing print_thread_id, only it always prints the inferior-qualified
thread-id.

I then update the existing print_thread_id to make use of this new
function, and finally, I update  breakpoint::print_recreate_thread to
also use this new function.

There's a multi-inferior test that confirms the saved breakpoints file
correctly includes the fully-qualified thread-id, and I've also
updated the single inferior test gdb.base/save-bp.exp to have it
validate that the saved breakpoints file includes the
inferior-qualified thread-id, even for this single inferior case.
2023-03-20 10:37:15 +00:00
Simon Marchi
0b63c811ef gdb: introduce bp_loc_tracepoint
Since commit cb1e4e32c2 ("catch catch/throw/rethrow", breakpoint ->
catchpoint), this simple tracing scenario does not work:

    $ gdb/gdb -nx -q --data-directory=gdb/data-directory ./test
    Reading symbols from ./test...
    (gdb) tar rem :1234
    Remote debugging using :1234
    Reading symbols from /lib64/ld-linux-x86-64.so.2...
    (No debugging symbols found in /lib64/ld-linux-x86-64.so.2)
    0x00007ffff7fe5730 in ?? () from /lib64/ld-linux-x86-64.so.2
    (gdb) trace do_something
    Tracepoint 1 at 0x555555555144: file test.c, line 5.
    (gdb) tstart
    (gdb) continue
    Continuing.
    Target returns error code '01'.

The root cause is that the bp_location::nserted flag does not transfer
anymore from an old bp_location to the new matching one.  When a shared
library gets loaded, GDB computes new breakpoint locations for each
breakpoint in update_breakpoint_locations.  The new locations are in the
breakpoint::loc chain, while the old locations are still in the
bp_locations global vector.  Later, update_global_location_list is
called.  It tries to map old locations to new locations, and if
necessary transfer some properties, like the inserted flag.

Since commit cb1e4e32c2, the inserted flag isn't transferred for
locations of tracepoints.  This is because bl_address_is_meaningful used
to be implemented like this:

    static int
    breakpoint_address_is_meaningful (struct breakpoint *bpt)
    {
      enum bptype type = bpt->type;

      return (type != bp_watchpoint && type != bp_catchpoint);
    }

and was changed to this:

    static bool
    bl_address_is_meaningful (bp_location *loc)
    {
      return loc->loc_type != bp_loc_other;
    }

Because locations for tracepoints have the bp_loc_other type,
bl_address_is_meaningful started to return false for them, where it
returned true before.  This made update_global_location_list skip the
part where it calls swap_insertion.

I think this can be solved by introduced a new bp_loc_tracepoint
bp_loc_type.

I don't know if it's accurate, but my understanding is that bp_loc_type
describes roughly "how do we ask the target to insert that location".
bp_loc_software_breakpoint are inserted using
target_ops::insert_breakpoint_location.  bp_loc_hardware_breakpoint are
inserted using target_ops::insert_hw_breakpoint.
bp_loc_software_watchpoint and bp_loc_hardware_watchpoint are inserted
using target_ops::insert_watchpoint.  For all these, the address is
meaningful, as we ask the target to insert the point at a specific
address.  bp_loc_other is a catch-all for "the rest", in practice for
catchpoints that don't have a specific address (hence why
bl_address_is_meaningful returns false for them).  For instance,
inserting a signal catchpoint is done by asking the target to report
that specific signal.  GDB doesn't associate an address to that.

But tracepoints do have a meaningful address to thems, so they can't be
bp_loc_other, with that logic.  They also can't be
bp_loc_software_breakpoint, because we don't want GDB to insert
breakpoints for them (even though they might be implemented using
software breakpoints by the remote side).  So, the new bp_loc_tracepoint
type describes that the way to insert these locations is with
target_ops::download_tracepoint.  It makes bl_address_is_meaningful
return true for them.  And they'll be ignored by insert_bp_location and
GDB won't try to insert a memory breakpoint for them.

With this, I see a few instances of 'Target returns error code: 01'
disappearing from gdb.log, and the results of gdb.trace/*.exp improve a
little bit:

    -# of expected passes       3765
    +# of expected passes       3781
    -# of unexpected failures   518
    +# of unexpected failures   498

Things remain quite broken in that area though.

Change-Id: Ic40935c450410f4bfaba397c9ebc7faf97320dd3
2023-03-17 16:34:25 -04:00
Simon Marchi
287de65625 gdb, gdbserver, gdbsupport: fix whitespace issues
Replace spaces with tabs in a bunch of places.

Change-Id: If0f87180f1d13028dc178e5a8af7882a067868b0
2023-03-09 16:32:00 -05:00
Andrew Burgess
2968b79fca gdb: fix mi breakpoint-deleted notifications for thread-specific b/p
Background
----------

When a thread-specific breakpoint is deleted as a result of the
specific thread exiting the function remove_threaded_breakpoints is
called which sets the disposition of the breakpoint to
disp_del_at_next_stop and sets the breakpoint number to 0.  Setting
the breakpoint number to zero has the effect of hiding the breakpoint
from the user.  We also print a message indicating that the breakpoint
has been deleted.

It was brought to my attention during a review of another patch[1]
that setting a breakpoints number to zero will suppress the MI
breakpoint-deleted notification for that breakpoint, and indeed, this
can be seen to be true, in delete_breakpoint, if the breakpoint number
is zero, then GDB will not notify the breakpoint_deleted observer.

It seems wrong that a user created, thread-specific breakpoint, will
have a =breakpoint-created notification, but will not have a
=breakpoint-deleted notification.  I suspect that this is a bug.

[1] https://sourceware.org/pipermail/gdb-patches/2023-February/196560.html

The First Problem
-----------------

During my initial testing I wanted to see how GDB handled the
breakpoint after it's number was set to zero.  To do this I created
the testcase gdb.threads/thread-bp-deleted.exp.  This test creates a
worker thread, which immediately exits.  After the worker thread has
exited the main thread spins in a loop.

In GDB I break once the worker thread has been created and place a
thread-specific breakpoint, then use 'continue&' to resume the
inferior in non-stop mode.  The worker thread then exits, but the main
thread never stops - instead it sits in the spin.  I then tried to use
'maint info breakpoints' to see what GDB thought of the
thread-specific breakpoint.

Unfortunately, GDB crashed like this:

  (gdb) continue&
  Continuing.
  (gdb) [Thread 0x7ffff7c5d700 (LWP 1202458) exited]
  Thread-specific breakpoint 3 deleted - thread 2 no longer in the thread list.
  maint info breakpoints
  ... snip some output ...

  Fatal signal: Segmentation fault
  ----- Backtrace -----
  0x5ffb62 gdb_internal_backtrace_1
          ../../src/gdb/bt-utils.c:122
  0x5ffc05 _Z22gdb_internal_backtracev
          ../../src/gdb/bt-utils.c:168
  0x89965e handle_fatal_signal
          ../../src/gdb/event-top.c:964
  0x8997ca handle_sigsegv
          ../../src/gdb/event-top.c:1037
  0x7f96f5971b1f ???
          /usr/src/debug/glibc-2.30-2-gd74461fa34/nptl/../sysdeps/unix/sysv/linux/x86_64/sigaction.c:0
  0xe602b0 _Z15print_thread_idP11thread_info
          ../../src/gdb/thread.c:1439
  0x5b3d05 print_one_breakpoint_location
          ../../src/gdb/breakpoint.c:6542
  0x5b462e print_one_breakpoint
          ../../src/gdb/breakpoint.c:6702
  0x5b5354 breakpoint_1
          ../../src/gdb/breakpoint.c:6924
  0x5b58b8 maintenance_info_breakpoints
          ../../src/gdb/breakpoint.c:7009
  ... etc ...

As the thread-specific breakpoint is set to disp_del_at_next_stop, and
GDB hasn't stopped yet, then the breakpoint still exists in the global
breakpoint list.

The breakpoint will not show in 'info breakpoints' as its number is
zero, but it will show in 'maint info breakpoints'.

As GDB prints the breakpoint, the thread-id for the breakpoint is
printed as part of the 'stop only in thread ...' line.  Printing the
thread-id involves calling find_thread_global_id to convert the global
thread-id into a thread_info*.  Then calling print_thread_id to
convert the thread_info* into a string.

The problem is that find_thread_global_id returns nullptr as the
thread for the thread-specific breakpoint has exited.  The
print_thread_id assumes it will be passed a non-nullptr.  As a result
GDB crashes.

In this commit I've added an assert to print_thread_id (gdb/thread.c)
to check that the pointed passed in is not nullptr.  This assert would
have triggered in the above case before GDB crashed.

MI Notifications: The Dangers Of Changing A Breakpoint's Number
---------------------------------------------------------------

Currently the delete_breakpoint function doesn't trigger the
breakpoint_deleted observer for any breakpoint with the number zero.

There is a comment explaining why this is the case in the code; it's
something about watchpoints.  But I did consider just removing the 'is
the number zero' guard and always triggering the breakpoint_deleted
observer, figuring that I'd then fix the watchpoint issue some other
way.

But I realised this wasn't going to be good enough.  When the MI
notification was delivered the number would be zero, so any frontend
parsing the notifications would not be able to match
=breakpoint-deleted notification to the earlier =breakpoint-created
notification.

What this means is that, at the point the breakpoint_deleted observer
is called, the breakpoint's number must be correct.

MI Notifications: The Dangers Of Delaying Deletion
--------------------------------------------------

The test I used to expose the above crash also brought another problem
to my attention.  In the above test we used 'continue&' to resume,
after which a thread exited, but the inferior didn't stop.  Recreating
the same test in the MI looks like this:

  -break-insert -p 2 main
  ^done,bkpt={number="2",type="breakpoint",disp="keep",...<snip>...}
  (gdb)
  -exec-continue
  ^running
  *running,thread-id="all"
  (gdb)
  ~"[Thread 0x7ffff7c5d700 (LWP 987038) exited]\n"
  =thread-exited,id="2",group-id="i1"
  ~"Thread-specific breakpoint 2 deleted - thread 2 no longer in the thread list.\n"

At this point the we have a single thread left, which is still
running:

  -thread-info
  ^done,threads=[{id="1",target-id="Thread 0x7ffff7c5eb80 (LWP 987035)",name="thread-bp-delet",state="running",core="4"}],current-thread-id="1"
  (gdb)

Notice that we got the =thread-exited notification from GDB as soon as
the thread exited.  We also saw the CLI line from GDB, the line
explaining that breakpoint 2 was deleted.  But, as expected, we didn't
see the =breakpoint-deleted notification.

I say "as expected" because the number was set to zero.  But, even if
the number was not set to zero we still wouldn't see the
notification.  The MI notification is driven by the breakpoint_deleted
observer, which is only called when we actually delete the breakpoint,
which is only done the next time GDB stops.

Now, maybe this is fine.  The notification is delivered a little
late.  But remember, by setting the number to zero the breakpoint will
be hidden from the user, for example, the breakpoint is removed from
the MI's -break-info command output.

This means that GDB is in a position where the breakpoint doesn't show
up in the breakpoint table, but a =breakpoint-deleted notification has
not yet been sent out.  This doesn't seem right to me.

What this means is that, when the thread exits, we should immediately
be sending out the =breakpoint-deleted notification.  We should not
wait for GDB to next stop before sending the notification.

The Solution
------------

My proposed solution is this; in remove_threaded_breakpoints, instead
of setting the disposition to disp_del_at_next_stop and setting the
number to zero, we now just call delete_breakpoint directly.

The notification will now be sent out immediately; as soon as the
thread exits.

As the number has not changed when delete_breakpoint is called, the
notification will have the correct number.

And as the breakpoint is immediately removed from the breakpoint list,
we no longer need to worry about 'maint info breakpoints' trying to
print the thread-id for an exited thread.

My only concern is that calling delete_breakpoint directly seems so
obvious that I wonder why the original patch (that added
remove_threaded_breakpoints) didn't take this approach.  This code was
added in commit 49fa26b041, but the commit message offers no clues
to why this approach was taken, and the original email thread offers
no insights either[2].  There are no test regressions after making
this change, so I'm hopeful that this is going to be fine.

[2] https://sourceware.org/pipermail/gdb-patches/2013-September/106493.html

The Complication
----------------

Of course, it couldn't be that simple.

The script gdb.python/py-finish-breakpoint.exp had some regressions
during testing.

The problem was with the FinishBreakpoint.out_of_scope callback
implementation.  This callback is supposed to trigger whenever the
FinishBreakpoint goes out of scope; and this includes when the thread
for the breakpoint exits.

The problem I ran into is the Python FinishBreakpoint implementation.
Specifically, after this change I was loosing some of the out_of_scope
calls.

The problem is that the out_of_scope call (of which I'm interested) is
triggered from the inferior_exit observer.  Before my change the
observers were called in this order:

  thread_exit
  inferior_exit
  breakpoint_deleted

The inferior_exit would trigger the out_of_scope call.

After my change the breakpoint_deleted notification (for
thread-specific breakpoints) occurs earlier, as soon as the
thread-exits, so now the order is:

  thread_exit
  breakpoint_deleted
  inferior_exit

Currently, after the breakpoint_deleted call the Python object
associated with the breakpoint is released, so, when we get to the
inferior_exit observer, there's no longer a Python object to call the
out_of_scope method on.

My solution is to follow the model for how bpfinishpy_pre_stop_hook
and bpfinishpy_post_stop_hook are called, this is done from
gdbpy_breakpoint_cond_says_stop in py-breakpoint.c.

I've now added a new bpfinishpy_pre_delete_hook
gdbpy_breakpoint_deleted in py-breakpoint.c, and from this new hook
function I check and where needed call the out_of_scope method.

With this fix in place I now see the
gdb.python/py-finish-breakpoint.exp test fully passing again.

Testing
-------

Tested on x86-64/Linux with unix, native-gdbserver, and
native-extended-gdbserver boards.

New tests added to covers all the cases I've discussed above.

Approved-By: Pedro Alves <pedro@palves.net>
2023-02-28 10:56:28 +00:00
Andrew Burgess
2fd9a436c8 gdb: don't duplicate 'thread' field in MI breakpoint output
When creating a thread-specific breakpoint with a single location, the
'thread' field would be repeated in the MI output.  This can be seen
in two existing tests gdb.mi/mi-nsmoribund.exp and
gdb.mi/mi-pending.exp, e.g.:

  (gdb)
  -break-insert -p 1 bar
  ^done,bkpt={number="1",type="breakpoint",disp="keep",
	      enabled="y",
	      addr="0x000000000040110a",func="bar",
	      file="/tmp/mi-thread-specific-bp.c",
	      fullname="/tmp/mi-thread-specific-bp.c",
	      line="32",thread-groups=["i1"],
	      thread="1",thread="1",  <================ DUPLICATION!
	      times="0",original-location="bar"}

I know we need to be careful when adjusting MI output, but I'm hopeful
in this case, as the field is duplicated, and the field contents are
always identical, that we might get away with removing one of the
duplicates.

The change in GDB is a fairly trivial condition change.

We did have a couple of tests that contained the duplicate fields in
their expected output, but given there was no comment pointing out
this oddity either in the GDB code, or in the test, I suspect this was
more a case of copying whatever output GDB produced and using that as
the expected results.  I've updated these tests to remove the
duplication.

I've update lib/mi-support.exp to provide support for building
breakpoint patterns that contain the thread field, and I've made use
of this in a new test I've added that is just about creating
thread-specific breakpoints and checking the results.  The two tests I
mentioned above as being updated could also use the new
lib/mi-support.exp functionality, but I'm going to do that in a later
patch, this way it is clear what changes I'm actually proposing to
make to the expected output.

As I said, I hope that frontends will be able to handle this change,
but I still think its worth adding a NEWS entry, that way, if someone
runs into problems, there's a chance they can figure out what's going
on.

This should not impact CLI output at all.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Pedro Alves <pedro@palves.net>
2023-02-28 10:56:28 +00:00
Andrew Burgess
02aadca4fb gdb: remove an out of date comment about disp_del_at_next_stop
Delete an out of date comment about disp_del_at_next_stop, the comment
says:

  /* NOTE drow/2003-09-08: This state only exists for removing
     watchpoints.  It's not clear that it's necessary...  */

I'm sure this was true when the comment was added, but today the
disp_del_at_next_stop state is not just used for deleting watchpoints,
which leaves us with "It's not clear that it's necessary...", which
doesn't really help at all.

And then this comment is located on one random place where
disp_del_at_next_stop is used, rather than at its definition site.

Lets just delete the comment.

No user visible changes after this commit.

Reviewed-By: Pedro Alves <pedro@palves.net>
2023-02-28 10:56:28 +00:00
Kevin Buettner
b1ffd1124a Catch gdb_exception_error instead of gdb_exception (in many places)
As described in the previous commit for this series, I became
concerned that there might be instances in which a QUIT (due to either
a SIGINT or SIGTERM) might not cause execution to return to the top
level.  In some (though very few) instances, it is okay to not
propagate the exception for a Ctrl-C / SIGINT, but I don't think that
it is ever okay to swallow the exception caused by a SIGTERM.
Allowing that to happen would definitely be a deviation from the
current behavior in which GDB exits upon receipt of a SIGTERM.

I looked at all cases where an exception handler catches a
gdb_exception.  Handlers which did NOT need modification were those
which satisifed one or more of the following conditions:

  1) There is no call path to maybe_quit() in the try block.  I used a
     static analysis tool to help make this determination.  In
     instances where the tool didn't provide an answer of "yes, this
     call path can result in maybe_quit() being called", I reviewed it
     by hand.

  2) The catch block contains a throw for conditions that it
     doesn't want to handle; these "not handled" conditions
     must include the quit exception and the new "forced quit" exception.

  3) There was (also) a catch for gdb_exception_quit.

Any try/catch blocks not meeting the above conditions could
potentially swallow a QUIT exception.

My first thought was to add catch blocks for gdb_exception_quit and
then rethrow the exception.  But Pedro pointed out that this can be
handled without adding additional code by simply catching
gdb_exception_error instead.  That's what this patch series does.

There are some oddball cases which needed to be handled differently,
plus the extension languages, but those are handled in later patches.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=26761
Tested-by: Tom de Vries <tdevries@suse.de>
Approved-by: Pedro Alves <pedro@palves.net>
2023-02-27 16:20:39 -07:00