From 1e4d17643d49f247df304245675551ee71995a37 Mon Sep 17 00:00:00 2001 From: Yao Qi Date: Mon, 14 Nov 2011 15:18:54 +0000 Subject: [PATCH] gdb/ * remote.c (struct remote_state): 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. --- gdb/ChangeLog | 29 +++ gdb/breakpoint.c | 103 ++++++++-- gdb/breakpoint.h | 6 +- gdb/doc/ChangeLog | 8 + gdb/doc/gdb.texinfo | 14 +- gdb/gdbserver/ChangeLog | 9 + gdb/gdbserver/server.c | 1 + gdb/gdbserver/tracepoint.c | 248 ++++++++++++++++++------ gdb/remote.c | 47 +++++ gdb/target.c | 4 + gdb/target.h | 7 + gdb/testsuite/ChangeLog | 12 ++ gdb/testsuite/gdb.trace/change-loc-1.c | 29 +++ gdb/testsuite/gdb.trace/change-loc-2.c | 24 +++ gdb/testsuite/gdb.trace/change-loc.c | 53 +++++ gdb/testsuite/gdb.trace/change-loc.exp | 153 +++++++++++++++ gdb/testsuite/gdb.trace/change-loc.h | 42 ++++ gdb/testsuite/gdb.trace/trace-break.c | 7 + gdb/testsuite/gdb.trace/trace-break.exp | 202 +++++++++++++++++++ gdb/tracepoint.c | 39 ++-- 20 files changed, 944 insertions(+), 93 deletions(-) create mode 100644 gdb/testsuite/gdb.trace/change-loc-1.c create mode 100644 gdb/testsuite/gdb.trace/change-loc-2.c create mode 100644 gdb/testsuite/gdb.trace/change-loc.c create mode 100644 gdb/testsuite/gdb.trace/change-loc.exp create mode 100644 gdb/testsuite/gdb.trace/change-loc.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2a7d43a5cf..3cbf7ea277 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,32 @@ +2011-11-14 Yao Qi + + * remote.c (struct remote_state): 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 * target.h (struct target): Change type diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 931f433cf1..8f0929619b 100644 --- a/gdb/breakpoint.c +++ b/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); } diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index fe381df11d..506ae80721 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -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 diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 9d8da57c50..ac38897619 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,11 @@ +2011-11-14 Yao Qi + + * 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 * gdb.texinfo (C Preprocessor Macros): Remove info definitions. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 65f1924d18..f17c80061d 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -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 diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 4b2ca28d8d..2a5aae92c5 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,12 @@ +2011-11-14 Yao Qi + + * 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 * mem-break.c (inc_ref_fast_tracepoint_jump): New. diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 4612457ed7..0f963e8bb1 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -1584,6 +1584,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (gdb_supports_qRelocInsn && target_supports_fast_tracepoints ()) strcat (own_buf, ";FastTracepoints+"); strcat (own_buf, ";StaticTracepoints+"); + strcat (own_buf, ";InstallInTrace+"); strcat (own_buf, ";qXfer:statictrace:read+"); strcat (own_buf, ";qXfer:traceframe-info:read+"); strcat (own_buf, ";EnableDisableTracepoints+"); diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 3a6a0f3cb6..f000f63777 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -1245,6 +1245,9 @@ static void do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx, #ifndef IN_PROCESS_AGENT static struct tracepoint *fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR); + +static void install_tracepoint (struct tracepoint *, char *own_buf); +static void download_tracepoint (struct tracepoint *); static int install_fast_tracepoint (struct tracepoint *); #endif @@ -1641,12 +1644,13 @@ free_space (void) static int seen_step_action_flag; -/* Create a tracepoint (location) with given number and address. */ +/* Create a tracepoint (location) with given number and address. Add this + new tracepoint to list and sort this list. */ static struct tracepoint * add_tracepoint (int num, CORE_ADDR addr) { - struct tracepoint *tpoint; + struct tracepoint *tpoint, **tp_next; tpoint = xmalloc (sizeof (struct tracepoint)); tpoint->number = num; @@ -1666,10 +1670,31 @@ add_tracepoint (int num, CORE_ADDR addr) tpoint->handle = NULL; tpoint->next = NULL; - if (!last_tracepoint) - tracepoints = tpoint; - else - last_tracepoint->next = tpoint; + /* Find a place to insert this tracepoint into list in order to keep + the tracepoint list still in the ascending order. There may be + multiple tracepoints at the same address as TPOINT's, and this + guarantees TPOINT is inserted after all the tracepoints which are + set at the same address. For example, fast tracepoints A, B, C are + set at the same address, and D is to be insert at the same place as + well, + + -->| A |--> | B |-->| C |->... + + One jump pad was created for tracepoint A, B, and C, and the target + address of A is referenced/used in jump pad. So jump pad will let + inferior jump to A. If D is inserted in front of A, like this, + + -->| D |-->| A |--> | B |-->| C |->... + + without updating jump pad, D is not reachable during collect, which + is wrong. As we can see, the order of B, C and D doesn't matter, but + A should always be the `first' one. */ + for (tp_next = &tracepoints; + (*tp_next) != NULL && (*tp_next)->address <= tpoint->address; + tp_next = &(*tp_next)->next) + ; + tpoint->next = *tp_next; + *tp_next = tpoint; last_tracepoint = tpoint; seen_step_action_flag = 0; @@ -2269,6 +2294,8 @@ static void cmd_qtdp (char *own_buf) { int tppacket; + /* Whether there is a trailing hyphen at the end of the QTDP packet. */ + int trail_hyphen = 0; ULONGEST num; ULONGEST addr; ULONGEST count; @@ -2346,7 +2373,10 @@ cmd_qtdp (char *own_buf) trace_debug ("Unknown optional tracepoint field"); } if (*packet == '-') - trace_debug ("Also has actions\n"); + { + trail_hyphen = 1; + trace_debug ("Also has actions\n"); + } trace_debug ("Defined %stracepoint %d at 0x%s, " "enabled %d step %ld pass %ld", @@ -2365,6 +2395,29 @@ cmd_qtdp (char *own_buf) return; } + /* Install tracepoint during tracing only once for each tracepoint location. + For each tracepoint loc, GDB may send multiple QTDP packets, and we can + determine the last QTDP packet for one tracepoint location by checking + trailing hyphen in QTDP packet. */ + if (tracing && !trail_hyphen) + { + /* Pause all threads temporarily while we patch tracepoints. */ + pause_all (0); + + /* download_tracepoint will update global `tracepoints' + list, so it is unsafe to leave threads in jump pad. */ + stabilize_threads (); + + /* Freeze threads. */ + pause_all (1); + + download_tracepoint (tpoint); + install_tracepoint (tpoint, own_buf); + + unpause_all (1); + return; + } + write_ok (own_buf); } @@ -2658,59 +2711,6 @@ claim_jump_space (ULONGEST used) gdb_jump_pad_head += used; } -/* Sort tracepoints by PC, using a bubble sort. */ - -static void -sort_tracepoints (void) -{ - struct tracepoint *lst, *tmp, *prev = NULL; - int i, j, n = 0; - - if (tracepoints == NULL) - return; - - /* Count nodes. */ - for (tmp = tracepoints; tmp->next; tmp = tmp->next) - n++; - - for (i = 0; i < n - 1; i++) - for (j = 0, lst = tracepoints; - lst && lst->next && (j <= n - 1 - i); - j++) - { - /* If we're at beginning, the start node is the prev - node. */ - if (j == 0) - prev = lst; - - /* Compare neighbors. */ - if (lst->next->address < lst->address) - { - struct tracepoint *p; - - /* Swap'em. */ - tmp = (lst->next ? lst->next->next : NULL); - - if (j == 0 && prev == tracepoints) - tracepoints = lst->next; - - p = lst->next; - prev->next = lst->next; - lst->next->next = lst; - lst->next = tmp; - prev = p; - } - else - { - lst = lst->next; - /* Keep track of the previous node. We need it if we need - to swap nodes. */ - if (j != 0) - prev = prev->next; - } - } -} - /* Ask the IPA to probe the marker at ADDRESS. Returns -1 if running the command fails, or 0 otherwise. If the command ran successfully, but probing the marker failed, ERROUT will be filled @@ -2798,6 +2798,83 @@ install_fast_tracepoint (struct tracepoint *tpoint) return 0; } + +/* Install tracepoint TPOINT, and write reply message in OWN_BUF. */ + +static void +install_tracepoint (struct tracepoint *tpoint, char *own_buf) +{ + tpoint->handle = NULL; + *own_buf = '\0'; + + if (tpoint->type == trap_tracepoint) + { + /* Tracepoints are installed as memory breakpoints. Just go + ahead and install the trap. The breakpoints module + handles duplicated breakpoints, and the memory read + routine handles un-patching traps from memory reads. */ + tpoint->handle = set_breakpoint_at (tpoint->address, + tracepoint_handler); + } + else if (tpoint->type == fast_tracepoint || tpoint->type == static_tracepoint) + { + struct tracepoint *tp; + + if (!in_process_agent_loaded ()) + { + trace_debug ("Requested a %s tracepoint, but fast " + "tracepoints aren't supported.", + tpoint->type == static_tracepoint ? "static" : "fast"); + write_e_ipa_not_loaded (own_buf); + return; + } + if (tpoint->type == static_tracepoint && !in_process_agent_loaded_ust ()) + { + trace_debug ("Requested a static tracepoint, but static " + "tracepoints are not supported."); + write_e_ust_not_loaded (own_buf); + return; + } + + /* Find another fast or static tracepoint at the same address. */ + for (tp = tracepoints; tp; tp = tp->next) + { + if (tp->address == tpoint->address && tp->type == tpoint->type + && tp->number != tpoint->number) + break; + } + + if (tpoint->type == fast_tracepoint) + { + if (tp) /* TPOINT is installed at the same address as TP. */ + clone_fast_tracepoint (tpoint, tp); + else + install_fast_tracepoint (tpoint); + } + else + { + if (tp) + tpoint->handle = (void *) -1; + else + { + if (probe_marker_at (tpoint->address, own_buf) == 0) + tpoint->handle = (void *) -1; + } + } + + } + else + internal_error (__FILE__, __LINE__, "Unknown tracepoint type"); + + if (tpoint->handle == NULL) + { + if (*own_buf == '\0') + write_enn (own_buf); + } + else + write_ok (own_buf); +} + static void cmd_qtstart (char *packet) { @@ -2805,10 +2882,6 @@ cmd_qtstart (char *packet) trace_debug ("Starting the trace"); - /* Sort tracepoints by ascending address. This makes installing - fast tracepoints at the same address easier to handle. */ - sort_tracepoints (); - /* Pause all threads temporarily while we patch tracepoints. */ pause_all (0); @@ -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) { diff --git a/gdb/remote.c b/gdb/remote.c index 9271875d9c..a6d5e5f72a 100644 --- a/gdb/remote.c +++ b/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); diff --git a/gdb/target.c b/gdb/target.c index fc7b7c63f3..16b2128e9e 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -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); diff --git a/gdb/target.h b/gdb/target.h index ec7937a53b..c8941a4058 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -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) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 81dd708728..8a6825f3bc 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2011-11-14 Yao Qi + + * 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 * gdb.base/info-macros.exp: Make tests for info definitions diff --git a/gdb/testsuite/gdb.trace/change-loc-1.c b/gdb/testsuite/gdb.trace/change-loc-1.c new file mode 100644 index 0000000000..92d453c45c --- /dev/null +++ b/gdb/testsuite/gdb.trace/change-loc-1.c @@ -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 . */ + +#include "change-loc.h" + +void func1 (int x) +{ + int y = x + 4; + func4 (); +} + +void func (int x) +{ + func1 (x); +} diff --git a/gdb/testsuite/gdb.trace/change-loc-2.c b/gdb/testsuite/gdb.trace/change-loc-2.c new file mode 100644 index 0000000000..d479917acd --- /dev/null +++ b/gdb/testsuite/gdb.trace/change-loc-2.c @@ -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 . */ + +#include "change-loc.h" + +void +func2 (int x) +{ + func4 (); +} diff --git a/gdb/testsuite/gdb.trace/change-loc.c b/gdb/testsuite/gdb.trace/change-loc.c new file mode 100644 index 0000000000..d1e0a7fe02 --- /dev/null +++ b/gdb/testsuite/gdb.trace/change-loc.c @@ -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 . */ + +#include +#include +#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; +} diff --git a/gdb/testsuite/gdb.trace/change-loc.exp b/gdb/testsuite/gdb.trace/change-loc.exp new file mode 100644 index 0000000000..e1250249e2 --- /dev/null +++ b/gdb/testsuite/gdb.trace/change-loc.exp @@ -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 . + +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.*\.*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.*\.*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" diff --git a/gdb/testsuite/gdb.trace/change-loc.h b/gdb/testsuite/gdb.trace/change-loc.h new file mode 100644 index 0000000000..1b0e303950 --- /dev/null +++ b/gdb/testsuite/gdb.trace/change-loc.h @@ -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 . */ + +#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 + ); + +} diff --git a/gdb/testsuite/gdb.trace/trace-break.c b/gdb/testsuite/gdb.trace/trace-break.c index fd06142442..a327202424 100644 --- a/gdb/testsuite/gdb.trace/trace-break.c +++ b/gdb/testsuite/gdb.trace/trace-break.c @@ -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 ); } diff --git a/gdb/testsuite/gdb.trace/trace-break.exp b/gdb/testsuite/gdb.trace/trace-break.exp index c2d7b2ce4d..50344d2090 100644 --- a/gdb/testsuite/gdb.trace/trace-break.exp +++ b/gdb/testsuite/gdb.trace/trace-break.exp @@ -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" + } + } } diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index a7035d1635..82ca0b8ec9 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -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);