[patch 6/8] gdbserver - Install tracepoint when tracing is running

Yao Qi
2011-11-08T06:40:37Z

[-- Attachment #1: Type: text/plain, Size: 362 bytes --]

This patch is the major part of gdbserver side in this patch set.
gdbserver will receive tracepoint locations details, and install them to
inferior. The order of tracepoint list in IPA is kept when adding new
tracepoints, to make sure new added fast tracepoint works correctly with
existing fast tracepoints which are already installed.

--
Yao (é½å°§)

[-- Attachment #2: 0006-gdbserver-install-tp-if-in-tracing.patch --]
[-- Type: text/x-patch, Size: 9397 bytes --]

* tracepoint.c (install_tracepoint, download_tracepoint): New.
(cmd_qtdp): Call them.
(add_tracepoint): Add one parameter to sort list conditionally.
* server.c (handle_query): Handle InstallInTrace for qSupported.
---
gdb/gdbserver/server.c | 1 +
gdb/gdbserver/tracepoint.c | 213 ++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 207 insertions(+), 7 deletions(-)

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..6a5e111 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,10 +1644,11 @@ 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. If SORT is
+ non-zero, the list of tracepoint will be sorted. */

static struct tracepoint *
-add_tracepoint (int num, CORE_ADDR addr)
+add_tracepoint (int num, CORE_ADDR addr, int sort)
{
struct tracepoint *tpoint;

@@ -1666,10 +1670,48 @@ add_tracepoint (int num, CORE_ADDR addr)
tpoint->handle = NULL;
tpoint->next = NULL;

- if (!last_tracepoint)
- tracepoints = tpoint;
+ if (sort)
+ {
+ struct tracepoint *tp, *tp_prev;
+
+ /* Find a place to insert this tracepoint into list in order to keep
+ the tracepoint list still in an ascending order. There may be
+ multiple tracepoints at the same address as TPOINT's, and this
+ guarantee that TP_PREV is the last tracepoint entry of them, so that
+ TPOINT is inserted at the last of them. For example, fast tracepoint
+ 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_prev = tp = tracepoints; tp && tp->address <= tpoint->address;
+ tp = tp->next)
+ tp_prev = tp;
+
+ if (tp_prev)
+ {
+ tpoint->next = tp_prev->next;
+ tp_prev->next = tpoint;
+ }
+ else
+ tracepoints = tpoint;
+ }
else
- last_tracepoint->next = tpoint;
+ {
+ if (!last_tracepoint)
+ tracepoints = tpoint;
+ else
+ last_tracepoint->next = tpoint;
+ }
last_tracepoint = tpoint;

seen_step_action_flag = 0;
@@ -2269,6 +2311,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;
@@ -2306,7 +2350,11 @@ cmd_qtdp (char *own_buf)
return;
}

- tpoint = add_tracepoint (num, addr);
+ /* When it is not tracing, we don't have to sort tracepoints, because
+ they will be sorted in cmd_qtstart later. When it is tracing, the
+ list has been sorted, and we should still keep ascending order of
+ list after adding new entry. */
+ tpoint = add_tracepoint (num, addr, tracing);

tpoint->enabled = (*packet == 'E');
++packet; /* skip 'E' */
@@ -2346,7 +2394,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 +2416,29 @@ cmd_qtdp (char *own_buf)
return;
}

+ /* Install tracepoint during tracing only once of 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);
}

@@ -2798,6 +2872,84 @@ 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;
+
+ 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);
+ unpause_all (1);
+ 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);
+ unpause_all (1);
+ 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 (tpoint->type == fast_tracepoint)
+ write_enn (own_buf);
+ }
+ else
+ write_ok (own_buf);
+}
+
static void
cmd_qtstart (char *packet)
{
@@ -6462,6 +6614,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
+ 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;
--
1.7.0.4