* 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.
This commit is contained in:
Yao Qi 2011-11-14 15:18:54 +00:00
parent 5c73ff4ec2
commit 1e4d17643d
20 changed files with 944 additions and 93 deletions

View File

@ -1,3 +1,32 @@
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

View File

@ -1558,7 +1558,10 @@ in which its expression is valid.\n"),
/* 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)
{
@ -1582,11 +1585,6 @@ 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;
}
@ -2052,7 +2050,7 @@ remove_breakpoints (void)
ALL_BP_LOCATIONS (bl, blp_tmp)
{
if (bl->inserted)
if (bl->inserted && !is_tracepoint (bl->owner))
val |= remove_breakpoint (bl, mark_uninserted);
}
return val;
@ -5446,6 +5444,23 @@ breakpoint_location_address_match (struct bp_location *bl,
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. */
@ -5467,6 +5482,8 @@ breakpoint_locations_match (struct bp_location *loc1,
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,
@ -6050,8 +6067,8 @@ disable_breakpoints_in_shlibs (void)
}
}
/* 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
@ -6073,13 +6090,14 @@ disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
/* 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;
@ -10315,6 +10333,49 @@ bp_location_target_extensions_update (void)
}
}
/* 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
@ -10324,6 +10385,12 @@ swap_insertion (struct bp_location *left, struct bp_location *right)
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;
@ -10603,6 +10670,9 @@ update_global_location_list (int should_insert)
|| !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;
@ -10650,6 +10720,9 @@ update_global_location_list (int should_insert)
|| (gdbarch_has_global_breakpoints (target_gdbarch))))
insert_breakpoint_locations ();
if (should_insert)
download_tracepoint_locations ();
do_cleanups (cleanups);
}

View File

@ -335,7 +335,11 @@ struct bp_location
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

View File

@ -1,3 +1,11 @@
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.

View File

@ -10331,7 +10331,11 @@ an address in the target program. @xref{Specify Location}. The
@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.
@ -17317,6 +17321,10 @@ are:
@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}
@ -34845,6 +34853,10 @@ The remote stub understands the @samp{QDisableRandomization} packet.
@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

View File

@ -1,3 +1,12 @@
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.

View File

@ -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+");

View File

@ -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);
@ -6461,6 +6534,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)
{

View File

@ -323,6 +323,10 @@ struct remote_state
/* 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;
@ -1261,6 +1265,7 @@ enum {
PACKET_ConditionalTracepoints,
PACKET_FastTracepoints,
PACKET_StaticTracepoints,
PACKET_InstallInTrace,
PACKET_bc,
PACKET_bs,
PACKET_TracepointSource,
@ -3695,6 +3700,16 @@ remote_static_tracepoint_feature (const struct protocol_feature *feature,
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,
@ -3761,6 +3776,8 @@ static struct protocol_feature remote_protocol_features[] = {
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,
@ -9747,6 +9764,14 @@ remote_supports_static_tracepoints (void)
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)
{
@ -10008,6 +10033,24 @@ remote_download_tracepoint (struct bp_location *loc)
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)
{
@ -10480,6 +10523,7 @@ Specify the serial device it is connected to\n\
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;
@ -10997,6 +11041,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
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);

View File

@ -675,6 +675,7 @@ update_current_target (void)
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);
@ -850,6 +851,9 @@ update_current_target (void)
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);

View File

@ -689,6 +689,10 @@ struct target_ops
/* 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);
@ -1477,6 +1481,9 @@ extern int target_search_memory (CORE_ADDR start_addr,
#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)

View File

@ -1,3 +1,15 @@
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

View File

@ -0,0 +1,29 @@
/* 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);
}

View File

@ -0,0 +1,24 @@
/* 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 ();
}

View File

@ -0,0 +1,53 @@
/* 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;
}

View File

@ -0,0 +1,153 @@
# 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"

View File

@ -0,0 +1,42 @@
/* 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
);
}

View File

@ -41,6 +41,13 @@ marker (void)
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
);
}

View File

@ -39,6 +39,20 @@ if ![gdb_target_supports_trace] {
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 } {
@ -200,6 +214,159 @@ proc break_trace_same_addr_4 { 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}
@ -207,6 +374,13 @@ foreach break_always_inserted { "on" "off" } {
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
@ -238,4 +412,32 @@ if { [gdb_test "info sharedlibrary" ".*libinproctrace\.so.*" "IPA loaded"] != 0
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"
}
}
}

View File

@ -1711,7 +1711,15 @@ start_tracing (void)
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;
}
@ -3203,10 +3211,10 @@ cond_string_is_same (char *str1, char *str2)
/* 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;
@ -3228,7 +3236,7 @@ find_matching_tracepoint (struct uploaded_tp *utp)
for (loc = b->loc; loc; loc = loc->next)
{
if (loc->address == utp->addr)
return t;
return loc;
}
}
}
@ -3243,17 +3251,24 @@ void
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);