* 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.
+2011-11-14 Yao Qi <yao@codesourcery.com>
+
+ * 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.
+
2011-11-14 Yao Qi <yao@codesourcery.com>
* target.h (struct target): <to_download_tracepoint> Change type
/* Returns 1 iff breakpoint location should be
- inserted in the inferior. */
+ inserted in the inferior. We don't differentiate the type of BL's owner
+ (breakpoint vs. tracepoint), although insert_location in tracepoint's
+ breakpoint_ops is not defined, because in insert_bp_location,
+ tracepoint's insert_location will not be called. */
static int
should_be_inserted (struct bp_location *bl)
{
if (bl->pspace->breakpoints_not_allowed)
return 0;
- /* Tracepoints are inserted by the target at a time of its choosing,
- not by us. */
- if (is_tracepoint (bl->owner))
- return 0;
-
return 1;
}
ALL_BP_LOCATIONS (bl, blp_tmp)
{
- if (bl->inserted)
+ if (bl->inserted && !is_tracepoint (bl->owner))
val |= remove_breakpoint (bl, mark_uninserted);
}
return val;
aspace, addr)));
}
+/* If LOC1 and LOC2's owners are not tracepoints, returns false directly.
+ Then, if LOC1 and LOC2 represent the same tracepoint location, returns
+ true, otherwise returns false. */
+
+static int
+tracepoint_locations_match (struct bp_location *loc1,
+ struct bp_location *loc2)
+{
+ if (is_tracepoint (loc1->owner) && is_tracepoint (loc2->owner))
+ /* Since tracepoint locations are never duplicated with others', tracepoint
+ locations at the same address of different tracepoints are regarded as
+ different locations. */
+ return (loc1->address == loc2->address && loc1->owner == loc2->owner);
+ else
+ return 0;
+}
+
/* Assuming LOC1 and LOC2's types' have meaningful target addresses
(breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
represent the same location. */
return 0;
else if (hw_point1)
return watchpoint_locations_match (loc1, loc2);
+ else if (is_tracepoint (loc1->owner) || is_tracepoint (loc2->owner))
+ return tracepoint_locations_match (loc1, loc2);
else
/* We compare bp_location.length in order to cover ranged breakpoints. */
return (breakpoint_address_match (loc1->pspace->aspace, loc1->address,
}
}
-/* Disable any breakpoints that are in an unloaded shared library.
- Only apply to enabled breakpoints, disabled ones can just stay
+/* Disable any breakpoints and tracepoints that are in an unloaded shared
+ library. Only apply to enabled breakpoints, disabled ones can just stay
disabled. */
static void
/* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL. */
struct breakpoint *b = loc->owner;
- if ((loc->loc_type == bp_loc_hardware_breakpoint
- || loc->loc_type == bp_loc_software_breakpoint)
- && solib->pspace == loc->pspace
+ if (solib->pspace == loc->pspace
&& !loc->shlib_disabled
- && (b->type == bp_breakpoint
- || b->type == bp_jit_event
- || b->type == bp_hardware_breakpoint)
+ && (((b->type == bp_breakpoint
+ || b->type == bp_jit_event
+ || b->type == bp_hardware_breakpoint)
+ && (loc->loc_type == bp_loc_hardware_breakpoint
+ || loc->loc_type == bp_loc_software_breakpoint))
+ || is_tracepoint (b))
&& solib_contains_address_p (solib, loc->address))
{
loc->shlib_disabled = 1;
}
}
+/* Download tracepoint locations if they haven't been. */
+
+static void
+download_tracepoint_locations (void)
+{
+ struct bp_location *bl, **blp_tmp;
+ struct cleanup *old_chain;
+
+ if (!target_can_download_tracepoint ())
+ return;
+
+ old_chain = save_current_space_and_thread ();
+
+ ALL_BP_LOCATIONS (bl, blp_tmp)
+ {
+ struct tracepoint *t;
+
+ if (!is_tracepoint (bl->owner))
+ continue;
+
+ if ((bl->owner->type == bp_fast_tracepoint
+ ? !may_insert_fast_tracepoints
+ : !may_insert_tracepoints))
+ continue;
+
+ /* In tracepoint, locations are _never_ duplicated, so
+ should_be_inserted is equivalent to
+ unduplicated_should_be_inserted. */
+ if (!should_be_inserted (bl) || bl->inserted)
+ continue;
+
+ switch_to_program_space_and_thread (bl->pspace);
+
+ target_download_tracepoint (bl);
+
+ bl->inserted = 1;
+ t = (struct tracepoint *) bl->owner;
+ t->number_on_target = bl->owner->number;
+ }
+
+ do_cleanups (old_chain);
+}
+
/* Swap the insertion/duplication state between two locations. */
static void
const int left_duplicate = left->duplicate;
const struct bp_target_info left_target_info = left->target_info;
+ /* Locations of tracepoints can never be duplicated. */
+ if (is_tracepoint (left->owner))
+ gdb_assert (!left->duplicate);
+ if (is_tracepoint (right->owner))
+ gdb_assert (!right->duplicate);
+
left->inserted = right->inserted;
left->duplicate = right->duplicate;
left->target_info = right->target_info;
|| !loc->enabled
|| loc->shlib_disabled
|| !breakpoint_address_is_meaningful (b)
+ /* Don't detect duplicate for tracepoint locations because they are
+ never duplicated. See the comments in field `duplicate' of
+ `struct bp_location'. */
|| is_tracepoint (b))
continue;
|| (gdbarch_has_global_breakpoints (target_gdbarch))))
insert_breakpoint_locations ();
+ if (should_insert)
+ download_tracepoint_locations ();
+
do_cleanups (cleanups);
}
char inserted;
/* Nonzero if this is not the first breakpoint in the list
- for the given address. */
+ for the given address. location of tracepoint can _never_
+ be duplicated with other locations of tracepoints and other
+ kinds of breakpoints, because two locations at the same
+ address may have different actions, so both of these locations
+ should be downloaded and so that `tfind N' always works. */
char duplicate;
/* If we someday support real thread-specific breakpoints, then
+2011-11-14 Yao Qi <yao@codesourcery.com>
+
+ * 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".
+
2011-11-12 Matt Rice <ratmice@gmail.com>
* gdb.texinfo (C Preprocessor Macros): Remove info definitions.
@code{trace} command defines a tracepoint, which is a point in the
target program where the debugger will briefly stop, collect some
data, and then allow the program to continue. Setting a tracepoint or
-changing its actions doesn't take effect until the next @code{tstart}
+changing its actions takes effect immediately if the remote stub
+supports the @samp{InstallInTrace} feature (@pxref{install tracepoint
+in tracing}).
+If remote stub doesn't support the @samp{InstallInTrace} feature, all
+these changes don't take effect until the next @code{tstart}
command, and once a trace experiment is running, further changes will
not have any effect until the next trace experiment starts.
@tab @code{qXfer:traceframe-info:read}
@tab Traceframe info
+@item @code{install-in-trace}
+@tab @code{InstallInTrace}
+@tab Install tracepoint in tracing
+
@item @code{disable-randomization}
@tab @code{QDisableRandomization}
@tab @code{set disable-randomization}
@cindex static tracepoints, in remote protocol
The remote stub supports static tracepoints.
+@item InstallInTrace
+@anchor{install tracepoint in tracing}
+The remote stub supports installing tracepoint in tracing.
+
@item EnableDisableTracepoints
The remote stub supports the @samp{QTEnable} (@pxref{QTEnable}) and
@samp{QTDisable} (@pxref{QTDisable}) packets that allow tracepoints
+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.
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+");
#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
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;
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;
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;
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",
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);
}
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
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)
{
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);
}
}
+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)
{
/* True if the stub reports support for static tracepoints. */
int static_tracepoints;
+ /* True if the stub reports support for installing tracepoint while
+ tracing. */
+ int install_in_trace;
+
/* True if the stub can continue running a trace while GDB is
disconnected. */
int disconnected_tracing;
PACKET_ConditionalTracepoints,
PACKET_FastTracepoints,
PACKET_StaticTracepoints,
+ PACKET_InstallInTrace,
PACKET_bc,
PACKET_bs,
PACKET_TracepointSource,
rs->static_tracepoints = (support == PACKET_ENABLE);
}
+static void
+remote_install_in_trace_feature (const struct protocol_feature *feature,
+ enum packet_support support,
+ const char *value)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ rs->install_in_trace = (support == PACKET_ENABLE);
+}
+
static void
remote_disconnected_tracing_feature (const struct protocol_feature *feature,
enum packet_support support,
PACKET_FastTracepoints },
{ "StaticTracepoints", PACKET_DISABLE, remote_static_tracepoint_feature,
PACKET_StaticTracepoints },
+ {"InstallInTrace", PACKET_DISABLE, remote_install_in_trace_feature,
+ PACKET_InstallInTrace},
{ "DisconnectedTracing", PACKET_DISABLE, remote_disconnected_tracing_feature,
-1 },
{ "ReverseContinue", PACKET_DISABLE, remote_supported_packet,
return rs->static_tracepoints;
}
+static int
+remote_supports_install_in_trace (void)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return rs->install_in_trace;
+}
+
static int
remote_supports_enable_disable_tracepoint (void)
{
do_cleanups (old_chain);
}
+static int
+remote_can_download_tracepoint (void)
+{
+ struct trace_status *ts = current_trace_status ();
+ int status = remote_get_trace_status (ts);
+
+ if (status == -1 || !ts->running_known || !ts->running)
+ return 0;
+
+ /* If we are in a tracing experiment, but remote stub doesn't support
+ installing tracepoint in trace, we have to return. */
+ if (!remote_supports_install_in_trace ())
+ return 0;
+
+ return 1;
+}
+
+
static void
remote_download_trace_state_variable (struct trace_state_variable *tsv)
{
remote_ops.to_supports_string_tracing = remote_supports_string_tracing;
remote_ops.to_trace_init = remote_trace_init;
remote_ops.to_download_tracepoint = remote_download_tracepoint;
+ remote_ops.to_can_download_tracepoint = remote_can_download_tracepoint;
remote_ops.to_download_trace_state_variable
= remote_download_trace_state_variable;
remote_ops.to_enable_tracepoint = remote_enable_tracepoint;
add_packet_config_cmd (&remote_protocol_packets[PACKET_StaticTracepoints],
"StaticTracepoints", "static-tracepoints", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_InstallInTrace],
+ "InstallInTrace", "install-in-trace", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_statictrace_read],
"qXfer:statictrace:read", "read-sdata-object", 0);
INHERIT (to_supports_string_tracing, t);
INHERIT (to_trace_init, t);
INHERIT (to_download_tracepoint, t);
+ INHERIT (to_can_download_tracepoint, t);
INHERIT (to_download_trace_state_variable, t);
INHERIT (to_enable_tracepoint, t);
INHERIT (to_disable_tracepoint, t);
de_fault (to_download_tracepoint,
(void (*) (struct bp_location *))
tcomplain);
+ de_fault (to_can_download_tracepoint,
+ (int (*) (void))
+ return_zero);
de_fault (to_download_trace_state_variable,
(void (*) (struct trace_state_variable *))
tcomplain);
/* Send full details of a tracepoint location to the target. */
void (*to_download_tracepoint) (struct bp_location *location);
+ /* Is the target able to download tracepoint locations in current
+ state? */
+ int (*to_can_download_tracepoint) (void);
+
/* Send full details of a trace state variable to the target. */
void (*to_download_trace_state_variable) (struct trace_state_variable *tsv);
#define target_download_tracepoint(t) \
(*current_target.to_download_tracepoint) (t)
+#define target_can_download_tracepoint() \
+ (*current_target.to_can_download_tracepoint) ()
+
#define target_download_trace_state_variable(tsv) \
(*current_target.to_download_trace_state_variable) (tsv)
+2011-11-14 Yao Qi <yao@codesourcery.com>
+
+ * 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.
+
2011-11-12 Matt Rice <ratmice@gmail.com>
* gdb.base/info-macros.exp: Make tests for info definitions
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "change-loc.h"
+
+void func1 (int x)
+{
+ int y = x + 4;
+ func4 ();
+}
+
+void func (int x)
+{
+ func1 (x);
+}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "change-loc.h"
+
+void
+func2 (int x)
+{
+ func4 ();
+}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include "change-loc.h"
+
+extern void func (int x);
+
+static void
+marker () {}
+
+int main()
+{
+ const char *libname = "change-loc-2.sl";
+ void *h;
+ int (*p_func) (int);
+
+ func (3);
+
+ func4 ();
+
+ marker ();
+
+ h = dlopen (libname, RTLD_LAZY);
+ if (h == NULL) return 1;
+
+ p_func = dlsym (h, "func2");
+ if (p_func == NULL) return 2;
+
+ (*p_func) (4);
+
+ marker ();
+
+ dlclose (h);
+
+ marker ();
+ return 0;
+}
--- /dev/null
+# Copyright 2011 Free Software Foundation, Inc.
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+load_lib "trace-support.exp";
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+if {[skip_shlib_tests]} {
+ return 0
+}
+
+set testfile "change-loc"
+set libfile1 "change-loc-1"
+set libfile2 "change-loc-2"
+set srcfile $testfile.c
+set executable $testfile
+set libsrc1 $srcdir/$subdir/$libfile1.c
+set libsrc2 $srcdir/$subdir/$libfile2.c
+set binfile $objdir/$subdir/$testfile
+set lib_sl1 $objdir/$subdir/$libfile1.sl
+set lib_sl2 $objdir/$subdir/$libfile2.sl
+
+set lib_opts debug
+
+if [get_compiler_info ${binfile}] {
+ return -1
+}
+
+# Some targets have leading underscores on assembly symbols.
+set additional_flags [list debug shlib=$lib_sl1 shlib_load [gdb_target_symbol_prefix_flags]]
+
+if { [gdb_compile_shlib $libsrc1 $lib_sl1 $lib_opts] != ""
+ || [gdb_compile_shlib $libsrc2 $lib_sl2 $lib_opts] != ""
+ || [gdb_compile $srcdir/$subdir/$srcfile $binfile executable $additional_flags] != ""} {
+ untested "Could not compile either $libsrc1 or $srcdir/$subdir/$srcfile."
+ return -1
+}
+
+clean_restart $executable
+
+gdb_load_shlibs $lib_sl1
+gdb_load_shlibs $lib_sl2
+
+if ![runto_main] {
+ fail "Can't run to main to check for trace support"
+ return -1
+}
+
+if { ![gdb_target_supports_trace] } then {
+ unsupported "Current target does not support trace"
+ return -1;
+}
+
+if [is_amd64_regs_target] {
+ set pcreg "rip"
+} elseif [is_x86_like_target] {
+ set pcreg "eip"
+} else {
+ set pcreg "pc"
+}
+
+
+# Set tracepoint during tracing experiment.
+
+proc tracepoint_change_loc_1 { trace_type } {
+ global testfile
+ global srcfile
+ global pcreg
+ global gdb_prompt
+ global pf_prefix
+
+ set old_pf_prefix $pf_prefix
+ set pf_prefix "$pf_prefix 1 $trace_type:"
+
+ clean_restart ${testfile}
+ if ![runto_main] {
+ fail "Can't run to main"
+ set pf_prefix $old_pf_prefix
+ return -1
+ }
+ gdb_test_no_output "delete break 1"
+
+ # Set a tracepoint we'll never meet. Just to avoid the complain after
+ # type `tstart' later.
+ gdb_test "next" ".*"
+ gdb_test "trace main" "Tracepoint \[0-9\] at.* file .*$srcfile, line.*" \
+ "set tracepoint on main"
+
+ gdb_test "break marker" "Breakpoint.*at.* file .*$srcfile, line.*" \
+ "breakpoint on marker"
+
+ gdb_test_no_output "tstart"
+
+ gdb_test "continue" ".*Breakpoint.*marker.*at.*$srcfile.*" \
+ "continue to marker 1"
+ # Set a tracepoint during tracing.
+ gdb_test "${trace_type} set_tracepoint" ".*" "set tracepoint on set_tracepoint"
+
+ gdb_trace_setactions "set action for tracepoint" "" \
+ "collect \$$pcreg" "^$"
+
+ # tracepoint has two locations after shlib change-loc-1 is loaded.
+ gdb_test "info trace" \
+ "Num Type\[ \]+Disp Enb Address\[ \]+What.*
+\[0-9\]+\[\t \]+\(|fast \)tracepoint\[ \]+keep y.*\<MULTIPLE\>.*4\.1.* in func4.*4\.2.* in func4.*" \
+ "tracepoint with two locations"
+
+ setup_kfail "gdb/13392" x86_64-*-*
+ gdb_test "continue" ".*Breakpoint.*marker.*at.*$srcfile.*" \
+ "continue to marker 2"
+
+ # tracepoint has three locations after shlib change-loc-2 is loaded.
+ gdb_test "info trace" \
+ "Num Type\[ \]+Disp Enb Address\[ \]+What.*
+\[0-9\]+\[\t \]+\(|fast \)tracepoint\[ \]+keep y.*\<MULTIPLE\>.*4\.1.* in func4.*4\.2.* in func4.*4\.3.* in func4 .*" \
+ "tracepoint with three locations"
+
+ gdb_test_no_output "tstop"
+
+ setup_kfail "gdb/13392" x86_64-*-*
+ gdb_test "tfind" "Found trace frame 0, tracepoint 4.*" "tfind frame 0"
+ gdb_test "tfind" "Target failed to find requested trace frame\\..*"
+
+ set pf_prefix $old_pf_prefix
+}
+
+
+tracepoint_change_loc_1 "trace"
+
+# Re-compile test case with IPA.
+set libipa $objdir/../gdbserver/libinproctrace.so
+gdb_load_shlibs $libipa
+
+if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile executable \
+ [list debug nowarnings shlib=$libipa shlib=$lib_sl1 shlib_load] ] != "" } {
+ untested change-loc.exp
+ return -1
+}
+
+tracepoint_change_loc_1 "ftrace"
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef SYMBOL_PREFIX
+#define SYMBOL(str) SYMBOL_PREFIX #str
+#else
+#define SYMBOL(str) #str
+#endif
+
+/* Called from asm. */
+static void __attribute__((used))
+func5 (void)
+{}
+
+static void
+func4 (void)
+{
+ /* `set_tracepoint' is the label where we'll set multiple tracepoints and
+ breakpoints at. The insn at the label must the large enough to
+ fit a fast tracepoint jump. */
+ asm (" .global " SYMBOL(set_tracepoint) "\n"
+ SYMBOL(set_tracepoint) ":\n"
+#if (defined __x86_64__ || defined __i386__)
+ " call " SYMBOL(func5) "\n"
+#endif
+ );
+
+}
SYMBOL(set_point) ":\n"
#if (defined __x86_64__ || defined __i386__)
" call " SYMBOL(func) "\n"
+#endif
+ );
+
+ asm (" .global " SYMBOL(after_set_point) "\n"
+ SYMBOL(after_set_point) ":\n"
+#if (defined __x86_64__ || defined __i386__)
+ " call " SYMBOL(func) "\n"
#endif
);
}
return -1;
}
+set fpreg "fp"
+set spreg "sp"
+set pcreg "pc"
+
+if [is_amd64_regs_target] {
+ set fpreg "rbp"
+ set spreg "rsp"
+ set pcreg "rip"
+} elseif [is_x86_like_target] {
+ set fpreg "ebp"
+ set spreg "esp"
+ set pcreg "eip"
+}
+
# Set breakpoint and tracepoint at the same address.
proc break_trace_same_addr_1 { trace_type option } {
set pf_prefix $old_pf_prefix
}
+# Set two tracepoints TRACE1 and TRACE2 at two locations, and start tracing.
+# Then, set tracepoint TRACE3 at either of these two locations.
+# TRACE3_AT_FIRST_LOC is a boolean variable to decide insert TRACE3 at which
+# of two locations. Verify these tracepoints work as expected.
+
+proc break_trace_same_addr_5 { trace1 trace2 trace3 trace3_at_first_loc } {
+ global executable
+ global pf_prefix
+ global hex
+ global fpreg
+ global spreg
+ global pcreg
+
+ set old_pf_prefix $pf_prefix
+ set pf_prefix "$pf_prefix 5 $trace1 $trace2 ${trace3}@${trace3_at_first_loc}:"
+
+ # Start with a fresh gdb.
+ clean_restart ${executable}
+ if ![runto_main] {
+ fail "Can't run to main"
+ set pf_prefix $old_pf_prefix
+ return -1
+ }
+
+ gdb_test "break marker" "Breakpoint \[0-9\] at $hex: file.*"
+ gdb_test "break end" "Breakpoint \[0-9\] at $hex: file.*"
+
+ gdb_test "${trace1} set_point" "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+ "${trace1} set_point 1"
+ gdb_trace_setactions "set action for tracepoint 1" "" \
+ "collect \$$pcreg" "^$"
+ gdb_test "${trace2} after_set_point" \
+ "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+ "${trace2} after_set_point 1"
+
+ gdb_trace_setactions "set action for tracepoint 2" "" \
+ "collect \$$spreg" "^$"
+
+ gdb_test_no_output "tstart"
+
+ gdb_test "continue" "Continuing\\.\[ \r\n\]+Breakpoint.*" "continue to marker"
+
+ if [string equal $trace3_at_first_loc "1"] {
+ gdb_test "${trace3} set_point" "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+ "${trace3} set_point 2"
+ } else {
+ gdb_test "${trace3} after_set_point" \
+ "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+ "${trace2} after_set_point 2"
+ }
+ gdb_trace_setactions "set action for tracepoint 3" "" \
+ "collect \$$fpreg" "^$"
+
+ gdb_test "continue" "Continuing\\.\[ \r\n\]+Breakpoint.*" "continue to end"
+ gdb_test_no_output "tstop"
+
+ gdb_test "tfind tracepoint 4" "Found trace frame \[0-9\], tracepoint .*" \
+ "tfind test frame of tracepoint 4"
+ gdb_test "tdump" \
+ "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${pcreg} = .*" \
+ "tdump 1"
+ gdb_test "tfind 0" "Found trace frame 0, tracepoint .*" \
+ "reset to frame 0 (1)"
+ gdb_test "tfind tracepoint 5" "Found trace frame \[0-9\], tracepoint .*" \
+ "tfind test frame of tracepoint 5"
+ gdb_test "tdump" \
+ "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${spreg} = .*" \
+ "tdump 2"
+ gdb_test "tfind 0" "Found trace frame 0, tracepoint .*" \
+ "reset to frame 0 (2)"
+ gdb_test "tfind tracepoint 6" "Found trace frame \[0-9\], tracepoint .*" \
+ "tfind test frame of tracepoint 6"
+ gdb_test "tdump" \
+ "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${fpreg} = .*" \
+ "tdump 3"
+
+ set pf_prefix $old_pf_prefix
+}
+
+# Set two tracepoints at the same address, and enable/disable them. Verify
+# tracepoints work as expect.
+
+proc break_trace_same_addr_6 { trace1 enable1 trace2 enable2 } {
+ global executable
+ global pf_prefix
+ global hex
+ global gdb_prompt
+ global spreg
+ global pcreg
+
+ set old_pf_prefix $pf_prefix
+ set pf_prefix "$pf_prefix 6 $trace1 $enable1 $trace2 $enable2:"
+
+ # Start with a fresh gdb.
+ clean_restart ${executable}
+ if ![runto_main] {
+ fail "Can't run to main"
+ set pf_prefix $old_pf_prefix
+ return -1
+ }
+
+ gdb_test "break marker" "Breakpoint \[0-9\] at $hex: file.*"
+ gdb_test "break end" "Breakpoint \[0-9\] at $hex: file.*"
+
+ gdb_test "continue" "Continuing\\.\[ \r\n\]+Breakpoint.*" "continue to marker"
+
+ gdb_test "${trace1} set_point" "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+ "${trace1} set_point 1"
+ gdb_trace_setactions "set action for tracepoint 1" "" \
+ "collect \$$pcreg" "^$"
+ gdb_test "${trace2} set_point" "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+ "${trace2} set_point 2"
+ gdb_trace_setactions "set action for tracepoint 2" "" \
+ "collect \$$spreg" "^$"
+
+ gdb_test_no_output "$enable1 4"
+ gdb_test_no_output "$enable2 5"
+
+ gdb_test_no_output "tstart"
+ gdb_test "continue" "Continuing\\.\[ \r\n\]+Breakpoint.*" "continue to end"
+ gdb_test_no_output "tstop"
+
+
+ if [string equal $enable1 "enable"] {
+ gdb_test "tfind tracepoint 4" "Found trace frame \[0-9\], tracepoint .*" \
+ "tfind test frame of tracepoint 4"
+ gdb_test "tdump" \
+ "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${pcreg} = .*" \
+ "tdump 1"
+ gdb_test "tfind 0" "Found trace frame 0, tracepoint .*" \
+ "reset to frame 0 (1)"
+ } else {
+ gdb_test "tfind tracepoint 4" "Target failed to find requested trace frame.*" \
+ "tfind test frame of tracepoint 4"
+ }
+
+ if [string equal $enable2 "enable"] {
+ gdb_test "tfind tracepoint 5" "Found trace frame \[0-9\], tracepoint .*" \
+ "tfind test frame of tracepoint 5"
+ gdb_test "tdump" \
+ "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${spreg} = .*" \
+ "tdump 2"
+ gdb_test "tfind 0" "Found trace frame 0, tracepoint .*" \
+ "reset to frame 0 (2)"
+ } else {
+ gdb_test "tfind tracepoint 5" "Target failed to find requested trace frame.*" \
+ "tfind test frame of tracepoint 5"
+ }
+
+ set pf_prefix $old_pf_prefix
+}
+
+
foreach break_always_inserted { "on" "off" } {
break_trace_same_addr_1 "trace" ${break_always_inserted}
break_trace_same_addr_2 "trace" "trace" ${break_always_inserted}
break_trace_same_addr_4 "trace" ${break_always_inserted}
}
+foreach at_first_loc { "1" "0" } {
+ break_trace_same_addr_5 "trace" "trace" "trace" ${at_first_loc}
+}
+
+break_trace_same_addr_6 "trace" "enable" "trace" "disable"
+break_trace_same_addr_6 "trace" "disable" "trace" "enable"
+
set libipa $objdir/../gdbserver/libinproctrace.so
gdb_load_shlibs $libipa
break_trace_same_addr_3 "ftrace" ${break_always_inserted}
break_trace_same_addr_4 "ftrace" ${break_always_inserted}
}
+
+ foreach trace1 { "trace" "ftrace" } {
+ foreach trace2 { "trace" "ftrace" } {
+ foreach trace3 { "trace" "ftrace" } {
+
+ if { [string equal $trace1 "trace"]
+ && [string equal $trace2 "trace"]
+ && [string equal $trace3 "trace"] } {
+ continue
+ }
+
+ foreach at_first_loc { "1" "0" } {
+ break_trace_same_addr_5 $trace1 $trace2 $trace3 $at_first_loc
+ }
+ }
+ }
+ }
+
+ foreach trace1 { "trace" "ftrace" } {
+ foreach trace2 { "trace" "ftrace" } {
+ if { [string equal $trace1 "trace"]
+ && [string equal $trace2 "trace"] } {
+ continue
+ }
+ break_trace_same_addr_6 $trace1 "enable" $trace2 "disable"
+ break_trace_same_addr_6 $trace1 "disable" $trace2 "enable"
+ }
+ }
}
t->number_on_target = 0;
for (loc = b->loc; loc; loc = loc->next)
- target_download_tracepoint (loc);
+ {
+ /* Since tracepoint locations are never duplicated, `inserted'
+ flag should be zero. */
+ gdb_assert (!loc->inserted);
+
+ target_download_tracepoint (loc);
+
+ loc->inserted = 1;
+ }
t->number_on_target = b->number;
}
/* Look for an existing tracepoint that seems similar enough to the
uploaded one. Enablement isn't compared, because the user can
toggle that freely, and may have done so in anticipation of the
- next trace run. */
+ next trace run. Return the location of matched tracepoint. */
-struct tracepoint *
-find_matching_tracepoint (struct uploaded_tp *utp)
+struct bp_location *
+find_matching_tracepoint_location (struct uploaded_tp *utp)
{
VEC(breakpoint_p) *tp_vec = all_tracepoints ();
int ix;
for (loc = b->loc; loc; loc = loc->next)
{
if (loc->address == utp->addr)
- return t;
+ return loc;
}
}
}
merge_uploaded_tracepoints (struct uploaded_tp **uploaded_tps)
{
struct uploaded_tp *utp;
- struct tracepoint *t;
/* Look for GDB tracepoints that match up with our uploaded versions. */
for (utp = *uploaded_tps; utp; utp = utp->next)
{
- t = find_matching_tracepoint (utp);
- if (t)
- printf_filtered (_("Assuming tracepoint %d is same "
- "as target's tracepoint %d at %s.\n"),
- t->base.number, utp->number,
- paddress (get_current_arch (), utp->addr));
+ struct bp_location *loc;
+ struct tracepoint *t;
+
+ loc = find_matching_tracepoint_location (utp);
+ if (loc)
+ {
+ /* Mark this location as already inserted. */
+ loc->inserted = 1;
+ t = (struct tracepoint *) loc->owner;
+ printf_filtered (_("Assuming tracepoint %d is same "
+ "as target's tracepoint %d at %s.\n"),
+ loc->owner->number, utp->number,
+ paddress (loc->gdbarch, utp->addr));
+ }
else
{
t = create_tracepoint_from_upload (utp);