aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
authorYao Qi <yao@codesourcery.com>2011-11-14 15:18:54 +0000
committerYao Qi <yao@codesourcery.com>2011-11-14 15:18:54 +0000
commit1e4d17643d49f247df304245675551ee71995a37 (patch)
treecfc5abd91467ef7a0270e37de1512e806cf4a1c0 /gdb/gdbserver
parent5c73ff4ec2c54aa1788d012003e59bfbd14a896b (diff)
downloadgdb-1e4d17643d49f247df304245675551ee71995a37.zip
gdb-1e4d17643d49f247df304245675551ee71995a37.tar.gz
gdb-1e4d17643d49f247df304245675551ee71995a37.tar.bz2
gdb/
* remote.c (struct remote_state): <install_in_trace> new field. (PACKET_InstallInTrace): New enum value. (remote_install_in_trace_feature): Support InstallInTrace. (remote_supports_install_in_trace): Likewise. (remote_protocol_features): Likewise. (_initialize_remote): Likewise. (remote_can_download_tracepoint): New. * target.h (struct target): New field `to_can_download_tracepoint'. (target_can_download_tracepoint): New macro. * target.c (update_current_target): Update. * breakpoint.h (struct bp_location): Add comment on field `duplicate'. (should_be_inserted): Don't differentiate breakpoint and tracepoint. (remove_breakpoints): Don't remove tracepoints. (tracepoint_locations_match ): New. (breakpoint_locations_match): Call it. (disable_breakpoints_in_unloaded_shlib): Handle tracepoint. (download_tracepoint_locations): New. (update_global_location_list): Call it. * tracepoint.c (find_matching_tracepoint): Delete. (find_matching_tracepoint_location): Renamed from find_matching_tracepoint. Return bp_location rather than tracepoint. (merge_uploaded_tracepoints): Set `inserted' field to 1 if tracepoint is found. gdb/doc/ * gdb.texinfo (Create and Delete Tracepoints): Describe changed behavior of tracepoint. (General Query Packets): New feature InstallInTrace. (Remote Configuration): Document "set remote install-in-trace-packet". gdb/gdbserver/ * server.c (handle_query): Handle InstallInTrace for qSupported. * tracepoint.c (add_tracepoint): Sort list. (install_tracepoint, download_tracepoint): New. (cmd_qtdp): Call them to install and download tracepoints. (sort_tracepoints): Removed. (cmd_qtstart): Update. gdb/testsuite/ * gdb.trace/change-loc-1.c: New. * gdb.trace/change-loc-2.c: New. * gdb.trace/change-loc.c: New. * gdb.trace/change-loc.exp: New. * gdb.trace/change-loc.h: New. * gdb.trace/trace-break.c (marker): Define new symbol. * gdb.trace/trace-break.exp (break_trace_same_addr_5): New. (break_trace_same_addr_6): New.
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/ChangeLog9
-rw-r--r--gdb/gdbserver/server.c1
-rw-r--r--gdb/gdbserver/tracepoint.c248
3 files changed, 194 insertions, 64 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 4b2ca28..2a5aae9 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,5 +1,14 @@
2011-11-14 Yao Qi <yao@codesourcery.com>
+ * server.c (handle_query): Handle InstallInTrace for qSupported.
+ * tracepoint.c (add_tracepoint): Sort list.
+ (install_tracepoint, download_tracepoint): New.
+ (cmd_qtdp): Call them to install and download tracepoints.
+ (sort_tracepoints): Removed.
+ (cmd_qtstart): Update.
+
+2011-11-14 Yao Qi <yao@codesourcery.com>
+
* mem-break.c (inc_ref_fast_tracepoint_jump): New.
* mem-break.h: Declare.
* tracepoint.c (cmd_qtstart): Move some code to ...
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 4612457..0f963e8 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1584,6 +1584,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (gdb_supports_qRelocInsn && target_supports_fast_tracepoints ())
strcat (own_buf, ";FastTracepoints+");
strcat (own_buf, ";StaticTracepoints+");
+ strcat (own_buf, ";InstallInTrace+");
strcat (own_buf, ";qXfer:statictrace:read+");
strcat (own_buf, ";qXfer:traceframe-info:read+");
strcat (own_buf, ";EnableDisableTracepoints+");
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 3a6a0f3..f000f63 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -1245,6 +1245,9 @@ static void do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
#ifndef IN_PROCESS_AGENT
static struct tracepoint *fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR);
+
+static void install_tracepoint (struct tracepoint *, char *own_buf);
+static void download_tracepoint (struct tracepoint *);
static int install_fast_tracepoint (struct tracepoint *);
#endif
@@ -1641,12 +1644,13 @@ free_space (void)
static int seen_step_action_flag;
-/* Create a tracepoint (location) with given number and address. */
+/* Create a tracepoint (location) with given number and address. Add this
+ new tracepoint to list and sort this list. */
static struct tracepoint *
add_tracepoint (int num, CORE_ADDR addr)
{
- struct tracepoint *tpoint;
+ struct tracepoint *tpoint, **tp_next;
tpoint = xmalloc (sizeof (struct tracepoint));
tpoint->number = num;
@@ -1666,10 +1670,31 @@ add_tracepoint (int num, CORE_ADDR addr)
tpoint->handle = NULL;
tpoint->next = NULL;
- if (!last_tracepoint)
- tracepoints = tpoint;
- else
- last_tracepoint->next = tpoint;
+ /* Find a place to insert this tracepoint into list in order to keep
+ the tracepoint list still in the ascending order. There may be
+ multiple tracepoints at the same address as TPOINT's, and this
+ guarantees TPOINT is inserted after all the tracepoints which are
+ set at the same address. For example, fast tracepoints A, B, C are
+ set at the same address, and D is to be insert at the same place as
+ well,
+
+ -->| A |--> | B |-->| C |->...
+
+ One jump pad was created for tracepoint A, B, and C, and the target
+ address of A is referenced/used in jump pad. So jump pad will let
+ inferior jump to A. If D is inserted in front of A, like this,
+
+ -->| D |-->| A |--> | B |-->| C |->...
+
+ without updating jump pad, D is not reachable during collect, which
+ is wrong. As we can see, the order of B, C and D doesn't matter, but
+ A should always be the `first' one. */
+ for (tp_next = &tracepoints;
+ (*tp_next) != NULL && (*tp_next)->address <= tpoint->address;
+ tp_next = &(*tp_next)->next)
+ ;
+ tpoint->next = *tp_next;
+ *tp_next = tpoint;
last_tracepoint = tpoint;
seen_step_action_flag = 0;
@@ -2269,6 +2294,8 @@ static void
cmd_qtdp (char *own_buf)
{
int tppacket;
+ /* Whether there is a trailing hyphen at the end of the QTDP packet. */
+ int trail_hyphen = 0;
ULONGEST num;
ULONGEST addr;
ULONGEST count;
@@ -2346,7 +2373,10 @@ cmd_qtdp (char *own_buf)
trace_debug ("Unknown optional tracepoint field");
}
if (*packet == '-')
- trace_debug ("Also has actions\n");
+ {
+ trail_hyphen = 1;
+ trace_debug ("Also has actions\n");
+ }
trace_debug ("Defined %stracepoint %d at 0x%s, "
"enabled %d step %ld pass %ld",
@@ -2365,6 +2395,29 @@ cmd_qtdp (char *own_buf)
return;
}
+ /* Install tracepoint during tracing only once for each tracepoint location.
+ For each tracepoint loc, GDB may send multiple QTDP packets, and we can
+ determine the last QTDP packet for one tracepoint location by checking
+ trailing hyphen in QTDP packet. */
+ if (tracing && !trail_hyphen)
+ {
+ /* Pause all threads temporarily while we patch tracepoints. */
+ pause_all (0);
+
+ /* download_tracepoint will update global `tracepoints'
+ list, so it is unsafe to leave threads in jump pad. */
+ stabilize_threads ();
+
+ /* Freeze threads. */
+ pause_all (1);
+
+ download_tracepoint (tpoint);
+ install_tracepoint (tpoint, own_buf);
+
+ unpause_all (1);
+ return;
+ }
+
write_ok (own_buf);
}
@@ -2658,59 +2711,6 @@ claim_jump_space (ULONGEST used)
gdb_jump_pad_head += used;
}
-/* Sort tracepoints by PC, using a bubble sort. */
-
-static void
-sort_tracepoints (void)
-{
- struct tracepoint *lst, *tmp, *prev = NULL;
- int i, j, n = 0;
-
- if (tracepoints == NULL)
- return;
-
- /* Count nodes. */
- for (tmp = tracepoints; tmp->next; tmp = tmp->next)
- n++;
-
- for (i = 0; i < n - 1; i++)
- for (j = 0, lst = tracepoints;
- lst && lst->next && (j <= n - 1 - i);
- j++)
- {
- /* If we're at beginning, the start node is the prev
- node. */
- if (j == 0)
- prev = lst;
-
- /* Compare neighbors. */
- if (lst->next->address < lst->address)
- {
- struct tracepoint *p;
-
- /* Swap'em. */
- tmp = (lst->next ? lst->next->next : NULL);
-
- if (j == 0 && prev == tracepoints)
- tracepoints = lst->next;
-
- p = lst->next;
- prev->next = lst->next;
- lst->next->next = lst;
- lst->next = tmp;
- prev = p;
- }
- else
- {
- lst = lst->next;
- /* Keep track of the previous node. We need it if we need
- to swap nodes. */
- if (j != 0)
- prev = prev->next;
- }
- }
-}
-
/* Ask the IPA to probe the marker at ADDRESS. Returns -1 if running
the command fails, or 0 otherwise. If the command ran
successfully, but probing the marker failed, ERROUT will be filled
@@ -2798,6 +2798,83 @@ install_fast_tracepoint (struct tracepoint *tpoint)
return 0;
}
+
+/* Install tracepoint TPOINT, and write reply message in OWN_BUF. */
+
+static void
+install_tracepoint (struct tracepoint *tpoint, char *own_buf)
+{
+ tpoint->handle = NULL;
+ *own_buf = '\0';
+
+ if (tpoint->type == trap_tracepoint)
+ {
+ /* Tracepoints are installed as memory breakpoints. Just go
+ ahead and install the trap. The breakpoints module
+ handles duplicated breakpoints, and the memory read
+ routine handles un-patching traps from memory reads. */
+ tpoint->handle = set_breakpoint_at (tpoint->address,
+ tracepoint_handler);
+ }
+ else if (tpoint->type == fast_tracepoint || tpoint->type == static_tracepoint)
+ {
+ struct tracepoint *tp;
+
+ if (!in_process_agent_loaded ())
+ {
+ trace_debug ("Requested a %s tracepoint, but fast "
+ "tracepoints aren't supported.",
+ tpoint->type == static_tracepoint ? "static" : "fast");
+ write_e_ipa_not_loaded (own_buf);
+ return;
+ }
+ if (tpoint->type == static_tracepoint && !in_process_agent_loaded_ust ())
+ {
+ trace_debug ("Requested a static tracepoint, but static "
+ "tracepoints are not supported.");
+ write_e_ust_not_loaded (own_buf);
+ return;
+ }
+
+ /* Find another fast or static tracepoint at the same address. */
+ for (tp = tracepoints; tp; tp = tp->next)
+ {
+ if (tp->address == tpoint->address && tp->type == tpoint->type
+ && tp->number != tpoint->number)
+ break;
+ }
+
+ if (tpoint->type == fast_tracepoint)
+ {
+ if (tp) /* TPOINT is installed at the same address as TP. */
+ clone_fast_tracepoint (tpoint, tp);
+ else
+ install_fast_tracepoint (tpoint);
+ }
+ else
+ {
+ if (tp)
+ tpoint->handle = (void *) -1;
+ else
+ {
+ if (probe_marker_at (tpoint->address, own_buf) == 0)
+ tpoint->handle = (void *) -1;
+ }
+ }
+
+ }
+ else
+ internal_error (__FILE__, __LINE__, "Unknown tracepoint type");
+
+ if (tpoint->handle == NULL)
+ {
+ if (*own_buf == '\0')
+ write_enn (own_buf);
+ }
+ else
+ write_ok (own_buf);
+}
+
static void
cmd_qtstart (char *packet)
{
@@ -2805,10 +2882,6 @@ cmd_qtstart (char *packet)
trace_debug ("Starting the trace");
- /* Sort tracepoints by ascending address. This makes installing
- fast tracepoints at the same address easier to handle. */
- sort_tracepoints ();
-
/* Pause all threads temporarily while we patch tracepoints. */
pause_all (0);
@@ -6462,6 +6535,53 @@ download_tracepoint_1 (struct tracepoint *tpoint)
}
static void
+download_tracepoint (struct tracepoint *tpoint)
+{
+ struct tracepoint *tp, *tp_prev;
+
+ if (tpoint->type != fast_tracepoint
+ && tpoint->type != static_tracepoint)
+ return;
+
+ download_tracepoint_1 (tpoint);
+
+ /* Find the previous entry of TPOINT, which is fast tracepoint or
+ static tracepoint. */
+ tp_prev = NULL;
+ for (tp = tracepoints; tp != tpoint; tp = tp->next)
+ {
+ if (tp->type == fast_tracepoint || tp->type == static_tracepoint)
+ tp_prev = tp;
+ }
+
+ if (tp_prev)
+ {
+ CORE_ADDR tp_prev_target_next_addr;
+
+ /* Insert TPOINT after TP_PREV in IPA. */
+ if (read_inferior_data_pointer (tp_prev->obj_addr_on_target
+ + offsetof (struct tracepoint, next),
+ &tp_prev_target_next_addr))
+ fatal ("error reading `tp_prev->next'");
+
+ /* tpoint->next = tp_prev->next */
+ write_inferior_data_ptr (tpoint->obj_addr_on_target
+ + offsetof (struct tracepoint, next),
+ tp_prev_target_next_addr);
+ /* tp_prev->next = tpoint */
+ write_inferior_data_ptr (tp_prev->obj_addr_on_target
+ + offsetof (struct tracepoint, next),
+ tpoint->obj_addr_on_target);
+ }
+ else
+ /* First object in list, set the head pointer in the
+ inferior. */
+ write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints,
+ tpoint->obj_addr_on_target);
+
+}
+
+static void
download_tracepoints (void)
{
CORE_ADDR tpptr = 0, prev_tpptr = 0;