aboutsummaryrefslogtreecommitdiff
path: root/gdb/remote.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2015-03-04 20:41:16 +0000
committerPedro Alves <palves@redhat.com>2015-03-04 20:41:16 +0000
commitf7e6eed5283bb5c8a3598dd986dc922b9a794f58 (patch)
treea7343d12474798fc7be6fdc479527d52190bbedc /gdb/remote.c
parent9e8915c6cee5c37637521b424d723e990e06d597 (diff)
downloadgdb-f7e6eed5283bb5c8a3598dd986dc922b9a794f58.zip
gdb-f7e6eed5283bb5c8a3598dd986dc922b9a794f58.tar.gz
gdb-f7e6eed5283bb5c8a3598dd986dc922b9a794f58.tar.bz2
remote+docs: software/hardware breakpoint traps
This adjusts target remote to tell the core whether a trap was caused by a breakpoint. To that end, the patch teaches GDB about new RSP stop reasons "T05 swbreak" and "T05 hwbreak", that remote targets report back to GDB, similarly to how "T05 watch" indicates a stop caused by a watchpoint. Because targets that can report these events are expected to themselves adjust the PC after a software breakpoint, these new stop reasons must only be reported if the stub is talking to a GDB that understands them. Because of that, the use of the new stop reasons needs to be handshaked on initial connection, using the qSupported mechanism. GDB simply sends "swbreak+" in its qSupports query, and the stub reports back "swbreak+" too. Because these new stop reasons are required to fix a fundamental non-stop mode problem, this commit extends the remote non-stop intro section in the manual, documenting the events as required. To be clear, GDB will still cope with remote targets that don't support these new stop reasons; it will behave just like today. Tested on x86-64 Fedora 20, native and gdbserver. gdb/ChangeLog: 2015-03-04 Pedro Alves <palves@redhat.com> * NEWS: Mention the new "swbreak" and "hwbreak" stop reasons. * remote.c (struct remote_state) <remote_stopped_by_watchpoint_p>: Delete field. <stop_reason>: New field. (PACKET_swbreak_feature, PACKET_hwbreak_feature): New enum values. (packet_set_cmd_state): New function. (remote_protocol_features): Register the "swbreak" and "hwbreak" features. (remote_query_supported): If not disabled with the corresponding "set remote foo-packet" command, report support for the swbreak and hwbreak features. (struct stop_reply) <remote_stopped_by_watchpoint_p>: Delete field. <stop_reason>: New field. (remote_parse_stop_reply): Handle "swbreak" and "hwbreak". (remote_wait_as): Adjust. (remote_stopped_by_sw_breakpoint) (remote_supports_stopped_by_sw_breakpoint) (remote_stopped_by_hw_breakpoint) (remote_supports_stopped_by_hw_breakpoint): New functions. (remote_stopped_by_watchpoint): New function. (init_remote_ops): Install them. (_initialize_remote): Register new "set/show remote swbreak-feature-packet" and "set/show remote swbreak-feature-packet" commands. gdb/doc/ChangeLog: 2015-03-04 Pedro Alves <palves@redhat.com> * gdb.texinfo (Remote Configuration): Document the "set/show remote swbreak-feature-packet" and "set/show remote hwbreak-feature-packet" commands. (Packets) <Z0>: Add cross link to the "swbreak" stop reason's decription. (Stop Reply Packets): Document the swbreak and hwbreak stop reasons. (General Query Packets): Document the swbreak and hwbreak qSupported features. (Remote Non-Stop): Explain that swbreak and hwbreak are required.
Diffstat (limited to 'gdb/remote.c')
-rw-r--r--gdb/remote.c119
1 files changed, 110 insertions, 9 deletions
diff --git a/gdb/remote.c b/gdb/remote.c
index 2a823eb..8f783a4 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -364,8 +364,8 @@ struct remote_state
to stop for a watchpoint. */
CORE_ADDR remote_watch_data_address;
- /* This is non-zero if target stopped for a watchpoint. */
- int remote_stopped_by_watchpoint_p;
+ /* Whether the target stopped for a breakpoint/watchpoint. */
+ enum target_stop_reason stop_reason;
threadref echo_nextthread;
threadref nextthread;
@@ -1338,11 +1338,26 @@ enum {
/* Support for the Qbtrace-conf:bts:size packet. */
PACKET_Qbtrace_conf_bts_size,
+ /* Support for swbreak+ feature. */
+ PACKET_swbreak_feature,
+
+ /* Support for hwbreak+ feature. */
+ PACKET_hwbreak_feature,
+
PACKET_MAX
};
static struct packet_config remote_protocol_packets[PACKET_MAX];
+/* Returns the packet's corresponding "set remote foo-packet" command
+ state. See struct packet_config for more details. */
+
+static enum auto_boolean
+packet_set_cmd_state (int packet)
+{
+ return remote_protocol_packets[packet].detect;
+}
+
/* Returns whether a given packet or feature is supported. This takes
into account the state of the corresponding "set remote foo-packet"
command, which may be used to bypass auto-detection. */
@@ -4025,7 +4040,9 @@ static const struct protocol_feature remote_protocol_features[] = {
{ "qXfer:btrace-conf:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_btrace_conf },
{ "Qbtrace-conf:bts:size", PACKET_DISABLE, remote_supported_packet,
- PACKET_Qbtrace_conf_bts_size }
+ PACKET_Qbtrace_conf_bts_size },
+ { "swbreak", PACKET_DISABLE, remote_supported_packet, PACKET_swbreak_feature },
+ { "hwbreak", PACKET_DISABLE, remote_supported_packet, PACKET_hwbreak_feature }
};
static char *remote_support_xml;
@@ -4094,6 +4111,11 @@ remote_query_supported (void)
q = remote_query_supported_append (q, "multiprocess+");
+ if (packet_set_cmd_state (PACKET_swbreak_feature) != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "swbreak+");
+ if (packet_set_cmd_state (PACKET_hwbreak_feature) != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "hwbreak+");
+
if (remote_support_xml)
q = remote_query_supported_append (q, remote_support_xml);
@@ -5202,7 +5224,8 @@ typedef struct stop_reply
fetch them is avoided). */
VEC(cached_reg_t) *regcache;
- int stopped_by_watchpoint_p;
+ enum target_stop_reason stop_reason;
+
CORE_ADDR watch_data_address;
int core;
@@ -5513,7 +5536,7 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event)
event->rs = get_remote_state ();
event->ws.kind = TARGET_WAITKIND_IGNORE;
event->ws.value.integer = 0;
- event->stopped_by_watchpoint_p = 0;
+ event->stop_reason = TARGET_STOPPED_BY_NO_REASON;
event->regcache = NULL;
event->core = -1;
@@ -5556,10 +5579,36 @@ Packet: '%s'\n"),
|| (strncmp (p, "rwatch", p1 - p) == 0)
|| (strncmp (p, "awatch", p1 - p) == 0))
{
- event->stopped_by_watchpoint_p = 1;
+ event->stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
p = unpack_varlen_hex (++p1, &addr);
event->watch_data_address = (CORE_ADDR) addr;
}
+ else if (strncmp (p, "swbreak", p1 - p) == 0)
+ {
+ event->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
+
+ /* Make sure the stub doesn't forget to indicate support
+ with qSupported. */
+ if (packet_support (PACKET_swbreak_feature) != PACKET_ENABLE)
+ error (_("Unexpected swbreak stop reason"));
+
+ /* The value part is documented as "must be empty",
+ though we ignore it, in case we ever decide to make
+ use of it in a backward compatible way. */
+ p = skip_to_semicolon (p1 + 1);
+ }
+ else if (strncmp (p, "hwbreak", p1 - p) == 0)
+ {
+ event->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
+
+ /* Make sure the stub doesn't forget to indicate support
+ with qSupported. */
+ if (packet_support (PACKET_hwbreak_feature) != PACKET_ENABLE)
+ error (_("Unexpected hwbreak stop reason"));
+
+ /* See above. */
+ p = skip_to_semicolon (p1 + 1);
+ }
else if (strncmp (p, "library", p1 - p) == 0)
{
event->ws.kind = TARGET_WAITKIND_LOADED;
@@ -5817,7 +5866,7 @@ process_stop_reply (struct stop_reply *stop_reply,
VEC_free (cached_reg_t, stop_reply->regcache);
}
- rs->remote_stopped_by_watchpoint_p = stop_reply->stopped_by_watchpoint_p;
+ rs->stop_reason = stop_reply->stop_reason;
rs->remote_watch_data_address = stop_reply->watch_data_address;
remote_notice_new_inferior (ptid, 0);
@@ -5944,7 +5993,7 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status, int options)
buf = rs->buf;
- rs->remote_stopped_by_watchpoint_p = 0;
+ rs->stop_reason = TARGET_STOPPED_BY_NO_REASON;
/* We got something. */
rs->waiting_for_stop_reply = 0;
@@ -8421,12 +8470,54 @@ remote_check_watch_resources (struct target_ops *self,
return -1;
}
+/* The to_stopped_by_sw_breakpoint method of target remote. */
+
+static int
+remote_stopped_by_sw_breakpoint (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return rs->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
+}
+
+/* The to_supports_stopped_by_sw_breakpoint method of target
+ remote. */
+
+static int
+remote_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return (packet_support (PACKET_swbreak_feature) == PACKET_ENABLE);
+}
+
+/* The to_stopped_by_hw_breakpoint method of target remote. */
+
+static int
+remote_stopped_by_hw_breakpoint (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return rs->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
+}
+
+/* The to_supports_stopped_by_hw_breakpoint method of target
+ remote. */
+
+static int
+remote_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return (packet_support (PACKET_hwbreak_feature) == PACKET_ENABLE);
+}
+
static int
remote_stopped_by_watchpoint (struct target_ops *ops)
{
struct remote_state *rs = get_remote_state ();
- return rs->remote_stopped_by_watchpoint_p;
+ return rs->stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
}
static int
@@ -11617,6 +11708,10 @@ Specify the serial device it is connected to\n\
remote_ops.to_files_info = remote_files_info;
remote_ops.to_insert_breakpoint = remote_insert_breakpoint;
remote_ops.to_remove_breakpoint = remote_remove_breakpoint;
+ remote_ops.to_stopped_by_sw_breakpoint = remote_stopped_by_sw_breakpoint;
+ remote_ops.to_supports_stopped_by_sw_breakpoint = remote_supports_stopped_by_sw_breakpoint;
+ remote_ops.to_stopped_by_hw_breakpoint = remote_stopped_by_hw_breakpoint;
+ remote_ops.to_supports_stopped_by_hw_breakpoint = remote_supports_stopped_by_hw_breakpoint;
remote_ops.to_stopped_by_watchpoint = remote_stopped_by_watchpoint;
remote_ops.to_stopped_data_address = remote_stopped_data_address;
remote_ops.to_watchpoint_addr_within_range =
@@ -12322,6 +12417,12 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_bts_size],
"Qbtrace-conf:bts:size", "btrace-conf-bts-size", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_swbreak_feature],
+ "swbreak-feature", "swbreak-feature", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_hwbreak_feature],
+ "hwbreak-feature", "hwbreak-feature", 0);
+
/* Assert that we've registered commands for all packet configs. */
{
int i;