gdb/
* remote.c (struct remote_state): <install_in_trace> new field. (PACKET_InstallInTrace): New enum value. (remote_install_in_trace_feature): Support InstallInTrace. (remote_supports_install_in_trace): Likewise. (remote_protocol_features): Likewise. (_initialize_remote): Likewise. (remote_can_download_tracepoint): New. * target.h (struct target): New field `to_can_download_tracepoint'. (target_can_download_tracepoint): New macro. * target.c (update_current_target): Update. * breakpoint.h (struct bp_location): Add comment on field `duplicate'. (should_be_inserted): Don't differentiate breakpoint and tracepoint. (remove_breakpoints): Don't remove tracepoints. (tracepoint_locations_match ): New. (breakpoint_locations_match): Call it. (disable_breakpoints_in_unloaded_shlib): Handle tracepoint. (download_tracepoint_locations): New. (update_global_location_list): Call it. * tracepoint.c (find_matching_tracepoint): Delete. (find_matching_tracepoint_location): Renamed from find_matching_tracepoint. Return bp_location rather than tracepoint. (merge_uploaded_tracepoints): Set `inserted' field to 1 if tracepoint is found. gdb/doc/ * gdb.texinfo (Create and Delete Tracepoints): Describe changed behavior of tracepoint. (General Query Packets): New feature InstallInTrace. (Remote Configuration): Document "set remote install-in-trace-packet". gdb/gdbserver/ * server.c (handle_query): Handle InstallInTrace for qSupported. * tracepoint.c (add_tracepoint): Sort list. (install_tracepoint, download_tracepoint): New. (cmd_qtdp): Call them to install and download tracepoints. (sort_tracepoints): Removed. (cmd_qtstart): Update. gdb/testsuite/ * gdb.trace/change-loc-1.c: New. * gdb.trace/change-loc-2.c: New. * gdb.trace/change-loc.c: New. * gdb.trace/change-loc.exp: New. * gdb.trace/change-loc.h: New. * gdb.trace/trace-break.c (marker): Define new symbol. * gdb.trace/trace-break.exp (break_trace_same_addr_5): New. (break_trace_same_addr_6): New.
This commit is contained in:
parent
5c73ff4ec2
commit
1e4d17643d
@ -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
|
||||
|
103
gdb/breakpoint.c
103
gdb/breakpoint.c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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+");
|
||||
|
@ -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)
|
||||
{
|
||||
|
47
gdb/remote.c
47
gdb/remote.c
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
29
gdb/testsuite/gdb.trace/change-loc-1.c
Normal file
29
gdb/testsuite/gdb.trace/change-loc-1.c
Normal 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);
|
||||
}
|
24
gdb/testsuite/gdb.trace/change-loc-2.c
Normal file
24
gdb/testsuite/gdb.trace/change-loc-2.c
Normal 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 ();
|
||||
}
|
53
gdb/testsuite/gdb.trace/change-loc.c
Normal file
53
gdb/testsuite/gdb.trace/change-loc.c
Normal 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;
|
||||
}
|
153
gdb/testsuite/gdb.trace/change-loc.exp
Normal file
153
gdb/testsuite/gdb.trace/change-loc.exp
Normal 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"
|
42
gdb/testsuite/gdb.trace/change-loc.h
Normal file
42
gdb/testsuite/gdb.trace/change-loc.h
Normal 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
|
||||
);
|
||||
|
||||
}
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user