Fix setting watchpoints when current thread is running

Currently, when the current thread is running, you can print global
variables.  However, if you try to set a watchpoint on the same
globals, GDB errors out, complaining that the selected thread is
running.  Like so:

 (gdb) c&
 Continuing.
 (gdb) p global
 $1 = 1098377287
 (gdb) watch global
 Selected thread is running.

This patch makes setting the watchpoint work.  You'll now get:

 (gdb) c&
 Continuing.
 (gdb) [New Thread 0x7ffff7d6e640 (LWP 434993)]
 [New Thread 0x7ffff756d640 (LWP 434994)]
 p global
 $1 = 88168
 (gdb) watch global
 Hardware watchpoint 2: global
 (gdb) [Switching to Thread 0x7ffff7d6e640 (LWP 434993)]

 Thread 2 "function0" hit Hardware watchpoint 2: global

 Old value = 185420
 New value = 185423
 int_return () at threads.c:39
 39      }

The problem is that update_watchpoint calls get_selected_frame
unconditionally.  We can skip it if the watchpoint expression is only
watching globals.

This adds a testcase that exercises both all-stop and non-stop, and
also software and hardware watchpoints.  It is kfailed for software
watchpoints, as those require another fix not handled by this patch
(the sw watchpoint doesn't fire because GDB doesn't force the
running-free thread to switch to single-stepping).

Change-Id: I68ca948541aea3edd4f70741f272f543187abe40
This commit is contained in:
Pedro Alves
2023-05-02 15:04:28 +01:00
parent ec48903170
commit c223d37388
3 changed files with 192 additions and 4 deletions

View File

@@ -2153,7 +2153,7 @@ update_watchpoint (struct watchpoint *b, bool reparse)
{
std::vector<value_ref_ptr> val_chain;
struct value *v, *result;
struct program_space *frame_pspace;
struct program_space *wp_pspace;
fetch_subexp_value (b->exp.get (), b->exp->op.get (), &v, &result,
&val_chain, false);
@@ -2172,7 +2172,10 @@ update_watchpoint (struct watchpoint *b, bool reparse)
b->val_valid = true;
}
frame_pspace = get_frame_program_space (get_selected_frame (NULL));
if (b->exp_valid_block == nullptr)
wp_pspace = current_program_space;
else
wp_pspace = get_frame_program_space (get_selected_frame (NULL));
/* Look at each value on the value chain. */
gdb_assert (!val_chain.empty ());
@@ -2232,7 +2235,7 @@ update_watchpoint (struct watchpoint *b, bool reparse)
bp_location *loc = b->allocate_location ();
loc->gdbarch = v->type ()->arch ();
loc->pspace = frame_pspace;
loc->pspace = wp_pspace;
loc->address
= gdbarch_remove_non_address_bits (loc->gdbarch, addr);
b->add_location (*loc);
@@ -2357,7 +2360,7 @@ update_watchpoint (struct watchpoint *b, bool reparse)
bpstat_stop_status requires a location to be able to report
stops, so make sure there's at least a dummy one. */
if (b->type == bp_watchpoint && !b->has_locations ())
add_dummy_location (b, frame_pspace);
add_dummy_location (b, wp_pspace);
}
else if (!within_current_scope)
{