gdb: testsuite: Test whether PC register is expedited in gdb.server/server-run.exp

One thing GDB always does when the inferior stops is finding out where
it's stopped at, by way of querying the value of the program counter
register.

To save a packet round trip, the remote target can send the PC
value (often alongside other frequently consulted registers such as the
stack pointer) in the stop reply packet as an "expedited register".

Test that this is actually done for the targets where gdbserver is
supposed to.

Extend the "maintenance print remote-registers" command output with an
"Expedited" column which says "yes" if the register was seen by GDB in
the last stop reply packet it received, and is left blank otherwise.

Tested for regressions on aarch64-linux-gnu native-extended-remote.

The testcase was tested on aarch64-linux-gnu, i686-linux-gnu and
x86_64-linux-gnu native-remote and native-extended-remote targets.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Approved-By: Tom Tromey <tom@tromey.com>
This commit is contained in:
Thiago Jung Bauermann
2024-09-05 01:42:02 -03:00
parent 89320f8658
commit 94aedcf7ea
6 changed files with 87 additions and 8 deletions

View File

@@ -90,6 +90,11 @@ save gdb-index
it contains white space or quote characters. If the argument
contains no such special characters then quoting is not required.
maintenance print remote-registers
Add an "Expedited" column to the output of the command. It indicates
which registers were included in the last stop reply packet received by
GDB.
* New remote packets
vFile:stat

View File

@@ -42082,7 +42082,11 @@ including registers which aren't available on the target nor visible
to user; the command @code{maint print register-groups} includes the
groups that each register is a member of; and the command @code{maint
print remote-registers} includes the remote target's register numbers
and offsets in the `G' packets.
and offsets in the `G' packets, as well as an indication of which
registers were included in the last stop reply packet received by
@value{GDBN} (@pxref{Stop Reply Packets}). Please note that the list
of registers included in a stop reply can change from one stop to the
next.
These commands take an optional parameter, a file name to which to
write the information.

View File

@@ -162,7 +162,7 @@ protected:
{
if (regnum < 0)
{
gdb_printf (file, "Rmt Nr g/G Offset");
gdb_printf (file, "Rmt Nr g/G Offset Expedited");
}
else if (regnum < gdbarch_num_regs (m_gdbarch))
{
@@ -170,7 +170,12 @@ protected:
if (remote_register_number_and_offset (m_gdbarch, regnum,
&pnum, &poffset))
gdb_printf (file, "%7d %11d", pnum, poffset);
{
if (remote_register_is_expedited (regnum))
gdb_printf (file, "%7d %11d yes", pnum, poffset);
else
gdb_printf (file, "%7d %11d", pnum, poffset);
}
}
}
};
@@ -324,9 +329,11 @@ _initialize_regcache_dump ()
"Takes an optional file parameter."),
&maintenanceprintlist);
add_cmd ("remote-registers", class_maintenance,
maintenance_print_remote_registers, _("\
Print the internal register configuration including remote register number "
"and g/G packets offset.\n\
Takes an optional file parameter."),
maintenance_print_remote_registers,
_("Print the internal register configuration including remote "
"register number and g/G packets offset.\n"
"Also prints which registers were sent in the last stop reply "
"packet (i.e. expedited).\n"
"Takes an optional file parameter."),
&maintenanceprintlist);
}

View File

@@ -696,6 +696,10 @@ public: /* data */
qSupported. */
gdb_thread_options supported_thread_options = 0;
/* Contains the regnums of the expedited registers in the last stop
reply packet. */
std::set<int> last_seen_expedited_registers;
private:
/* Asynchronous signal handle registered as event loop source for
when we have pending events ready to be passed to the core. */
@@ -1493,6 +1497,20 @@ is_remote_target (process_stratum_target *target)
return as_remote_target (target) != nullptr;
}
/* See remote.h. */
bool
remote_register_is_expedited (int regnum)
{
remote_target *rt = as_remote_target (current_inferior ()->process_target ());
if (rt == nullptr)
return false;
remote_state *rs = rt->get_remote_state ();
return rs->last_seen_expedited_registers.count (regnum) > 0;
}
/* Per-program-space data key. */
static const registry<program_space>::key<char, gdb::xfree_deleter<char>>
remote_pspace_data;
@@ -8523,6 +8541,10 @@ remote_target::process_stop_reply (stop_reply_up stop_reply,
{
*status = stop_reply->ws;
ptid_t ptid = stop_reply->ptid;
struct remote_state *rs = get_remote_state ();
/* Forget about last reply's expedited registers. */
rs->last_seen_expedited_registers.clear ();
/* If no thread/process was reported by the stub then select a suitable
thread/process. */
@@ -8549,7 +8571,10 @@ remote_target::process_stop_reply (stop_reply_up stop_reply,
stop_reply->arch);
for (cached_reg_t &reg : stop_reply->regcache)
regcache->raw_supply (reg.num, reg.data.get ());
{
regcache->raw_supply (reg.num, reg.data.get ());
rs->last_seen_expedited_registers.insert (reg.num);
}
}
remote_thread_info *remote_thr = get_remote_thread_info (this, ptid);

View File

@@ -121,4 +121,9 @@ extern void send_remote_packet (gdb::array_view<const char> &buf,
extern bool is_remote_target (process_stratum_target *target);
/* Return true if REGNUM was returned as an expedited register in the last
stop reply we received. */
extern bool remote_register_is_expedited (int regnum);
#endif

View File

@@ -52,3 +52,36 @@ if { [istarget *-*-linux*] } {
gdb_breakpoint main
gdb_test "continue" "Breakpoint.* main .*" "continue to main"
if { [istarget "aarch64*-*-*"]
|| [istarget "arm*-*-*"]
|| [istarget "csky*-*-*"]
|| [istarget "loongarch*-*-*"]
|| [istarget "riscv*-*-*"] } {
set pc_regname "pc"
} elseif { [is_amd64_regs_target] } {
set pc_regname "rip"
} elseif { [is_x86_like_target] } {
set pc_regname "eip"
} elseif { [istarget "tic6x-*-*"] } {
set pc_regname "PC"
}
# Sending the PC register in advance is good practice. Test that this is
# actually done for the targets where gdbserver is supposed to.
set expedited_pc_test_name "send PC as expedited register in stop reply"
if { [info exists pc_regname] } {
set seen_line false
gdb_test_multiple "maintenance print remote-registers" \
$expedited_pc_test_name -lbl {
-re " ${pc_regname}\[\[:space:\]\]+${decimal}.*${decimal} yes" {
set seen_line true
exp_continue
}
-re "\r\n$gdb_prompt $" {
gdb_assert { $seen_line } $gdb_test_name
}
}
} else {
untested $expedited_pc_test_name
}