gdb/
authorYao Qi <yao@codesourcery.com>
Mon, 14 Nov 2011 15:18:54 +0000 (15:18 +0000)
committerYao Qi <yao@codesourcery.com>
Mon, 14 Nov 2011 15:18:54 +0000 (15:18 +0000)
* 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.

20 files changed:
gdb/ChangeLog
gdb/breakpoint.c
gdb/breakpoint.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/gdbserver/ChangeLog
gdb/gdbserver/server.c
gdb/gdbserver/tracepoint.c
gdb/remote.c
gdb/target.c
gdb/target.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.trace/change-loc-1.c [new file with mode: 0644]
gdb/testsuite/gdb.trace/change-loc-2.c [new file with mode: 0644]
gdb/testsuite/gdb.trace/change-loc.c [new file with mode: 0644]
gdb/testsuite/gdb.trace/change-loc.exp [new file with mode: 0644]
gdb/testsuite/gdb.trace/change-loc.h [new file with mode: 0644]
gdb/testsuite/gdb.trace/trace-break.c
gdb/testsuite/gdb.trace/trace-break.exp
gdb/tracepoint.c

index 2a7d43a5cfc5ee3580dca457afb10c32a07db05e..3cbf7ea277004c21a7b61511467270598180eb1a 100644 (file)
@@ -1,3 +1,32 @@
+2011-11-14  Yao Qi  <yao@codesourcery.com>
+
+       * remote.c (struct remote_state): <install_in_trace> new field.
+       (PACKET_InstallInTrace): New enum value.
+       (remote_install_in_trace_feature): Support InstallInTrace.
+       (remote_supports_install_in_trace): Likewise.
+       (remote_protocol_features): Likewise.
+       (_initialize_remote): Likewise.
+       (remote_can_download_tracepoint): New.
+       * target.h (struct target): New field
+       `to_can_download_tracepoint'.
+       (target_can_download_tracepoint): New macro.
+       * target.c (update_current_target): Update.
+       * breakpoint.h (struct bp_location): Add comment on field
+       `duplicate'.
+       (should_be_inserted): Don't differentiate breakpoint and tracepoint.
+       (remove_breakpoints): Don't remove tracepoints.
+       (tracepoint_locations_match ): New.
+       (breakpoint_locations_match): Call it.
+       (disable_breakpoints_in_unloaded_shlib): Handle tracepoint.
+       (download_tracepoint_locations): New.
+       (update_global_location_list): Call it.
+       * tracepoint.c (find_matching_tracepoint): Delete.
+       (find_matching_tracepoint_location): Renamed from
+       find_matching_tracepoint.  Return bp_location rather than
+       tracepoint.
+       (merge_uploaded_tracepoints): Set `inserted' field to 1 if
+       tracepoint is found.
+
 2011-11-14  Yao Qi  <yao@codesourcery.com>
 
        * target.h (struct target): <to_download_tracepoint> Change type
index 931f433cf1b1ba0c85044d39de7aa0cf0de69a88..8f0929619bf8df1df9b28cc38fb38bde6b9a2b7e 100644 (file)
@@ -1558,7 +1558,10 @@ in which its expression is valid.\n"),
 
 
 /* Returns 1 iff breakpoint location should be
-   inserted in the inferior.  */
+   inserted in the inferior.  We don't differentiate the type of BL's owner
+   (breakpoint vs. tracepoint), although insert_location in tracepoint's
+   breakpoint_ops is not defined, because in insert_bp_location,
+   tracepoint's insert_location will not be called.  */
 static int
 should_be_inserted (struct bp_location *bl)
 {
@@ -1582,11 +1585,6 @@ should_be_inserted (struct bp_location *bl)
   if (bl->pspace->breakpoints_not_allowed)
     return 0;
 
-  /* Tracepoints are inserted by the target at a time of its choosing,
-     not by us.  */
-  if (is_tracepoint (bl->owner))
-    return 0;
-
   return 1;
 }
 
@@ -2052,7 +2050,7 @@ remove_breakpoints (void)
 
   ALL_BP_LOCATIONS (bl, blp_tmp)
   {
-    if (bl->inserted)
+    if (bl->inserted && !is_tracepoint (bl->owner))
       val |= remove_breakpoint (bl, mark_uninserted);
   }
   return val;
@@ -5446,6 +5444,23 @@ breakpoint_location_address_match (struct bp_location *bl,
                                                 aspace, addr)));
 }
 
+/* If LOC1 and LOC2's owners are not tracepoints, returns false directly.
+   Then, if LOC1 and LOC2 represent the same tracepoint location, returns
+   true, otherwise returns false.  */
+
+static int
+tracepoint_locations_match (struct bp_location *loc1,
+                           struct bp_location *loc2)
+{
+  if (is_tracepoint (loc1->owner) && is_tracepoint (loc2->owner))
+    /* Since tracepoint locations are never duplicated with others', tracepoint
+       locations at the same address of different tracepoints are regarded as
+       different locations.  */
+    return (loc1->address == loc2->address && loc1->owner == loc2->owner);
+  else
+    return 0;
+}
+
 /* Assuming LOC1 and LOC2's types' have meaningful target addresses
    (breakpoint_address_is_meaningful), returns true if LOC1 and LOC2
    represent the same location.  */
@@ -5467,6 +5482,8 @@ breakpoint_locations_match (struct bp_location *loc1,
     return 0;
   else if (hw_point1)
     return watchpoint_locations_match (loc1, loc2);
+  else if (is_tracepoint (loc1->owner) || is_tracepoint (loc2->owner))
+    return tracepoint_locations_match (loc1, loc2);
   else
     /* We compare bp_location.length in order to cover ranged breakpoints.  */
     return (breakpoint_address_match (loc1->pspace->aspace, loc1->address,
@@ -6050,8 +6067,8 @@ disable_breakpoints_in_shlibs (void)
   }
 }
 
-/* Disable any breakpoints that are in an unloaded shared library.
-   Only apply to enabled breakpoints, disabled ones can just stay
+/* Disable any breakpoints and tracepoints that are in an unloaded shared
+   library.  Only apply to enabled breakpoints, disabled ones can just stay
    disabled.  */
 
 static void
@@ -6073,13 +6090,14 @@ disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
     /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always non-NULL.  */
     struct breakpoint *b = loc->owner;
 
-    if ((loc->loc_type == bp_loc_hardware_breakpoint
-        || loc->loc_type == bp_loc_software_breakpoint)
-       && solib->pspace == loc->pspace
+    if (solib->pspace == loc->pspace
        && !loc->shlib_disabled
-       && (b->type == bp_breakpoint
-           || b->type == bp_jit_event
-           || b->type == bp_hardware_breakpoint)
+       && (((b->type == bp_breakpoint
+             || b->type == bp_jit_event
+             || b->type == bp_hardware_breakpoint)
+            && (loc->loc_type == bp_loc_hardware_breakpoint
+                || loc->loc_type == bp_loc_software_breakpoint))
+           || is_tracepoint (b))
        && solib_contains_address_p (solib, loc->address))
       {
        loc->shlib_disabled = 1;
@@ -10315,6 +10333,49 @@ bp_location_target_extensions_update (void)
     }
 }
 
+/* Download tracepoint locations if they haven't been.  */
+
+static void
+download_tracepoint_locations (void)
+{
+  struct bp_location *bl, **blp_tmp;
+  struct cleanup *old_chain;
+
+  if (!target_can_download_tracepoint ())
+    return;
+
+  old_chain = save_current_space_and_thread ();
+
+  ALL_BP_LOCATIONS (bl, blp_tmp)
+    {
+      struct tracepoint *t;
+
+      if (!is_tracepoint (bl->owner))
+       continue;
+
+      if ((bl->owner->type == bp_fast_tracepoint
+          ? !may_insert_fast_tracepoints
+          : !may_insert_tracepoints))
+       continue;
+
+      /* In tracepoint, locations are _never_ duplicated, so
+        should_be_inserted is equivalent to
+        unduplicated_should_be_inserted.  */
+      if (!should_be_inserted (bl) || bl->inserted)
+       continue;
+
+      switch_to_program_space_and_thread (bl->pspace);
+
+      target_download_tracepoint (bl);
+
+      bl->inserted = 1;
+      t = (struct tracepoint *) bl->owner;
+      t->number_on_target = bl->owner->number;
+    }
+
+  do_cleanups (old_chain);
+}
+
 /* Swap the insertion/duplication state between two locations.  */
 
 static void
@@ -10324,6 +10385,12 @@ swap_insertion (struct bp_location *left, struct bp_location *right)
   const int left_duplicate = left->duplicate;
   const struct bp_target_info left_target_info = left->target_info;
 
+  /* Locations of tracepoints can never be duplicated.  */
+  if (is_tracepoint (left->owner))
+    gdb_assert (!left->duplicate);
+  if (is_tracepoint (right->owner))
+    gdb_assert (!right->duplicate);
+
   left->inserted = right->inserted;
   left->duplicate = right->duplicate;
   left->target_info = right->target_info;
@@ -10603,6 +10670,9 @@ update_global_location_list (int should_insert)
          || !loc->enabled
          || loc->shlib_disabled
          || !breakpoint_address_is_meaningful (b)
+         /* Don't detect duplicate for tracepoint locations because they are
+          never duplicated.  See the comments in field `duplicate' of
+          `struct bp_location'.  */
          || is_tracepoint (b))
        continue;
 
@@ -10650,6 +10720,9 @@ update_global_location_list (int should_insert)
          || (gdbarch_has_global_breakpoints (target_gdbarch))))
     insert_breakpoint_locations ();
 
+  if (should_insert)
+    download_tracepoint_locations ();
+
   do_cleanups (cleanups);
 }
 
index fe381df11d13e1fd50ad76ed2cfd431fb5210daa..506ae80721776b49152b0138daf24f44ce7af954 100644 (file)
@@ -335,7 +335,11 @@ struct bp_location
   char inserted;
 
   /* Nonzero if this is not the first breakpoint in the list
-     for the given address.  */
+     for the given address.  location of tracepoint can _never_
+     be duplicated with other locations of tracepoints and other
+     kinds of breakpoints, because two locations at the same
+     address may have different actions, so both of these locations
+     should be downloaded and so that `tfind N' always works.  */
   char duplicate;
 
   /* If we someday support real thread-specific breakpoints, then
index 9d8da57c509202cbaae7dafc149fcc540f08a53c..ac38897619bebdb96d92e5fa47f91372dae16ca1 100644 (file)
@@ -1,3 +1,11 @@
+2011-11-14  Yao Qi  <yao@codesourcery.com>
+
+       * gdb.texinfo (Create and Delete Tracepoints): Describe changed
+       behavior of tracepoint.
+       (General Query Packets): New feature InstallInTrace.
+       (Remote Configuration): Document "set remote
+       install-in-trace-packet".
+
 2011-11-12  Matt Rice  <ratmice@gmail.com>
 
        * gdb.texinfo (C Preprocessor Macros): Remove info definitions.
index 65f1924d18670e4dda44e80dec7b53f85953e083..f17c80061d51e2f9cbd1484a8efa8c074bba2da7 100644 (file)
@@ -10331,7 +10331,11 @@ an address in the target program.  @xref{Specify Location}.  The
 @code{trace} command defines a tracepoint, which is a point in the
 target program where the debugger will briefly stop, collect some
 data, and then allow the program to continue.  Setting a tracepoint or
-changing its actions doesn't take effect until the next @code{tstart}
+changing its actions takes effect immediately if the remote stub
+supports the @samp{InstallInTrace} feature (@pxref{install tracepoint
+in tracing}).
+If remote stub doesn't support the @samp{InstallInTrace} feature, all
+these changes don't take effect until the next @code{tstart}
 command, and once a trace experiment is running, further changes will
 not have any effect until the next trace experiment starts.
 
@@ -17317,6 +17321,10 @@ are:
 @tab @code{qXfer:traceframe-info:read}
 @tab Traceframe info
 
+@item @code{install-in-trace}
+@tab @code{InstallInTrace}
+@tab Install tracepoint in tracing
+
 @item @code{disable-randomization}
 @tab @code{QDisableRandomization}
 @tab @code{set disable-randomization}
@@ -34845,6 +34853,10 @@ The remote stub understands the @samp{QDisableRandomization} packet.
 @cindex static tracepoints, in remote protocol
 The remote stub supports static tracepoints.
 
+@item InstallInTrace
+@anchor{install tracepoint in tracing}
+The remote stub supports installing tracepoint in tracing.
+
 @item EnableDisableTracepoints
 The remote stub supports the @samp{QTEnable} (@pxref{QTEnable}) and
 @samp{QTDisable} (@pxref{QTDisable}) packets that allow tracepoints
index 4b2ca28d8da2e02a004025c8d3b4a53189d80054..2a5aae92c59e09231ba9c8562764d535a06c1579 100644 (file)
@@ -1,3 +1,12 @@
+2011-11-14  Yao Qi  <yao@codesourcery.com>
+
+       * server.c (handle_query): Handle InstallInTrace for qSupported.
+       * tracepoint.c (add_tracepoint): Sort list.
+       (install_tracepoint, download_tracepoint): New.
+       (cmd_qtdp): Call them to install and download tracepoints.
+       (sort_tracepoints): Removed.
+       (cmd_qtstart): Update.
+
 2011-11-14  Yao Qi  <yao@codesourcery.com>
 
        * mem-break.c (inc_ref_fast_tracepoint_jump): New.
index 4612457ed7ef02763450adf47004a1e1659e706e..0f963e8bb144026c7c277de19d1f6b6b96633d4c 100644 (file)
@@ -1584,6 +1584,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
          if (gdb_supports_qRelocInsn && target_supports_fast_tracepoints ())
            strcat (own_buf, ";FastTracepoints+");
          strcat (own_buf, ";StaticTracepoints+");
+         strcat (own_buf, ";InstallInTrace+");
          strcat (own_buf, ";qXfer:statictrace:read+");
          strcat (own_buf, ";qXfer:traceframe-info:read+");
          strcat (own_buf, ";EnableDisableTracepoints+");
index 3a6a0f3cb630c99d0e7de89dccccfaee20be6ca1..f000f63777554a22e9c7365f498a5ebfaf490d5a 100644 (file)
@@ -1245,6 +1245,9 @@ static void do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
 
 #ifndef IN_PROCESS_AGENT
 static struct tracepoint *fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR);
+
+static void install_tracepoint (struct tracepoint *, char *own_buf);
+static void download_tracepoint (struct tracepoint *);
 static int install_fast_tracepoint (struct tracepoint *);
 #endif
 
@@ -1641,12 +1644,13 @@ free_space (void)
 
 static int seen_step_action_flag;
 
-/* Create a tracepoint (location) with given number and address.  */
+/* Create a tracepoint (location) with given number and address.  Add this
+   new tracepoint to list and sort this list.  */
 
 static struct tracepoint *
 add_tracepoint (int num, CORE_ADDR addr)
 {
-  struct tracepoint *tpoint;
+  struct tracepoint *tpoint, **tp_next;
 
   tpoint = xmalloc (sizeof (struct tracepoint));
   tpoint->number = num;
@@ -1666,10 +1670,31 @@ add_tracepoint (int num, CORE_ADDR addr)
   tpoint->handle = NULL;
   tpoint->next = NULL;
 
-  if (!last_tracepoint)
-    tracepoints = tpoint;
-  else
-    last_tracepoint->next = tpoint;
+  /* Find a place to insert this tracepoint into list in order to keep
+     the tracepoint list still in the ascending order.  There may be
+     multiple tracepoints at the same address as TPOINT's, and this
+     guarantees TPOINT is inserted after all the tracepoints which are
+     set at the same address.  For example, fast tracepoints A, B, C are
+     set at the same address, and D is to be insert at the same place as
+     well,
+
+     -->| A |--> | B |-->| C |->...
+
+     One jump pad was created for tracepoint A, B, and C, and the target
+     address of A is referenced/used in jump pad.  So jump pad will let
+     inferior jump to A.  If D is inserted in front of A, like this,
+
+     -->| D |-->| A |--> | B |-->| C |->...
+
+     without updating jump pad, D is not reachable during collect, which
+     is wrong.  As we can see, the order of B, C and D doesn't matter, but
+     A should always be the `first' one.  */
+  for (tp_next = &tracepoints;
+       (*tp_next) != NULL && (*tp_next)->address <= tpoint->address;
+       tp_next = &(*tp_next)->next)
+    ;
+  tpoint->next = *tp_next;
+  *tp_next = tpoint;
   last_tracepoint = tpoint;
 
   seen_step_action_flag = 0;
@@ -2269,6 +2294,8 @@ static void
 cmd_qtdp (char *own_buf)
 {
   int tppacket;
+  /* Whether there is a trailing hyphen at the end of the QTDP packet.  */
+  int trail_hyphen = 0;
   ULONGEST num;
   ULONGEST addr;
   ULONGEST count;
@@ -2346,7 +2373,10 @@ cmd_qtdp (char *own_buf)
            trace_debug ("Unknown optional tracepoint field");
        }
       if (*packet == '-')
-       trace_debug ("Also has actions\n");
+       {
+         trail_hyphen = 1;
+         trace_debug ("Also has actions\n");
+       }
 
       trace_debug ("Defined %stracepoint %d at 0x%s, "
                   "enabled %d step %ld pass %ld",
@@ -2365,6 +2395,29 @@ cmd_qtdp (char *own_buf)
       return;
     }
 
+  /* Install tracepoint during tracing only once for each tracepoint location.
+     For each tracepoint loc, GDB may send multiple QTDP packets, and we can
+     determine the last QTDP packet for one tracepoint location by checking
+     trailing hyphen in QTDP packet.  */
+  if (tracing && !trail_hyphen)
+    {
+      /* Pause all threads temporarily while we patch tracepoints.  */
+      pause_all (0);
+
+      /* download_tracepoint will update global `tracepoints'
+        list, so it is unsafe to leave threads in jump pad.  */
+      stabilize_threads ();
+
+      /* Freeze threads.  */
+      pause_all (1);
+
+      download_tracepoint (tpoint);
+      install_tracepoint (tpoint, own_buf);
+
+      unpause_all (1);
+      return;
+    }
+
   write_ok (own_buf);
 }
 
@@ -2658,59 +2711,6 @@ claim_jump_space (ULONGEST used)
   gdb_jump_pad_head += used;
 }
 
-/* Sort tracepoints by PC, using a bubble sort.  */
-
-static void
-sort_tracepoints (void)
-{
-  struct tracepoint *lst, *tmp, *prev = NULL;
-  int i, j, n = 0;
-
-  if (tracepoints == NULL)
-    return;
-
-  /* Count nodes.  */
-  for (tmp = tracepoints; tmp->next; tmp = tmp->next)
-    n++;
-
-  for (i = 0; i < n - 1; i++)
-    for (j = 0, lst = tracepoints;
-        lst && lst->next && (j <= n - 1 - i);
-        j++)
-      {
-       /* If we're at beginning, the start node is the prev
-          node.  */
-       if (j == 0)
-         prev = lst;
-
-       /* Compare neighbors.  */
-       if (lst->next->address < lst->address)
-         {
-           struct tracepoint *p;
-
-           /* Swap'em.  */
-           tmp = (lst->next ? lst->next->next : NULL);
-
-           if (j == 0 && prev == tracepoints)
-             tracepoints = lst->next;
-
-           p = lst->next;
-           prev->next = lst->next;
-           lst->next->next = lst;
-           lst->next = tmp;
-           prev = p;
-         }
-       else
-         {
-           lst = lst->next;
-           /* Keep track of the previous node.  We need it if we need
-              to swap nodes.  */
-           if (j != 0)
-             prev = prev->next;
-         }
-      }
-}
-
 /* Ask the IPA to probe the marker at ADDRESS.  Returns -1 if running
    the command fails, or 0 otherwise.  If the command ran
    successfully, but probing the marker failed, ERROUT will be filled
@@ -2798,6 +2798,83 @@ install_fast_tracepoint (struct tracepoint *tpoint)
   return 0;
 }
 
+
+/* Install tracepoint TPOINT, and write reply message in OWN_BUF.  */
+
+static void
+install_tracepoint (struct tracepoint *tpoint, char *own_buf)
+{
+  tpoint->handle = NULL;
+  *own_buf = '\0';
+
+  if (tpoint->type == trap_tracepoint)
+    {
+      /* Tracepoints are installed as memory breakpoints.  Just go
+        ahead and install the trap.  The breakpoints module
+        handles duplicated breakpoints, and the memory read
+        routine handles un-patching traps from memory reads.  */
+      tpoint->handle = set_breakpoint_at (tpoint->address,
+                                         tracepoint_handler);
+    }
+  else if (tpoint->type == fast_tracepoint || tpoint->type == static_tracepoint)
+    {
+      struct tracepoint *tp;
+
+      if (!in_process_agent_loaded ())
+       {
+         trace_debug ("Requested a %s tracepoint, but fast "
+                      "tracepoints aren't supported.",
+                      tpoint->type == static_tracepoint ? "static" : "fast");
+         write_e_ipa_not_loaded (own_buf);
+         return;
+       }
+      if (tpoint->type == static_tracepoint && !in_process_agent_loaded_ust ())
+       {
+         trace_debug ("Requested a static tracepoint, but static "
+                      "tracepoints are not supported.");
+         write_e_ust_not_loaded (own_buf);
+         return;
+       }
+
+      /* Find another fast or static tracepoint at the same address.  */
+      for (tp = tracepoints; tp; tp = tp->next)
+       {
+         if (tp->address == tpoint->address && tp->type == tpoint->type
+             && tp->number != tpoint->number)
+           break;
+       }
+
+      if (tpoint->type == fast_tracepoint)
+       {
+         if (tp) /* TPOINT is installed at the same address as TP.  */
+           clone_fast_tracepoint (tpoint, tp);
+         else
+           install_fast_tracepoint (tpoint);
+       }
+      else
+       {
+         if (tp)
+           tpoint->handle = (void *) -1;
+         else
+           {
+             if (probe_marker_at (tpoint->address, own_buf) == 0)
+               tpoint->handle = (void *) -1;
+           }
+       }
+
+    }
+  else
+    internal_error (__FILE__, __LINE__, "Unknown tracepoint type");
+
+  if (tpoint->handle == NULL)
+    {
+      if (*own_buf == '\0')
+       write_enn (own_buf);
+    }
+  else
+    write_ok (own_buf);
+}
+
 static void
 cmd_qtstart (char *packet)
 {
@@ -2805,10 +2882,6 @@ cmd_qtstart (char *packet)
 
   trace_debug ("Starting the trace");
 
-  /* Sort tracepoints by ascending address.  This makes installing
-     fast tracepoints at the same address easier to handle. */
-  sort_tracepoints ();
-
   /* Pause all threads temporarily while we patch tracepoints.  */
   pause_all (0);
 
@@ -6461,6 +6534,53 @@ download_tracepoint_1 (struct tracepoint *tpoint)
     }
 }
 
+static void
+download_tracepoint (struct tracepoint *tpoint)
+{
+  struct tracepoint *tp, *tp_prev;
+
+  if (tpoint->type != fast_tracepoint
+      && tpoint->type != static_tracepoint)
+    return;
+
+  download_tracepoint_1 (tpoint);
+
+  /* Find the previous entry of TPOINT, which is fast tracepoint or
+     static tracepoint.  */
+  tp_prev = NULL;
+  for (tp = tracepoints; tp != tpoint; tp = tp->next)
+    {
+      if (tp->type == fast_tracepoint || tp->type == static_tracepoint)
+       tp_prev = tp;
+    }
+
+  if (tp_prev)
+    {
+      CORE_ADDR tp_prev_target_next_addr;
+
+      /* Insert TPOINT after TP_PREV in IPA.  */
+      if (read_inferior_data_pointer (tp_prev->obj_addr_on_target
+                                     + offsetof (struct tracepoint, next),
+                                     &tp_prev_target_next_addr))
+       fatal ("error reading `tp_prev->next'");
+
+      /* tpoint->next = tp_prev->next */
+      write_inferior_data_ptr (tpoint->obj_addr_on_target
+                              + offsetof (struct tracepoint, next),
+                              tp_prev_target_next_addr);
+      /* tp_prev->next = tpoint */
+      write_inferior_data_ptr (tp_prev->obj_addr_on_target
+                              + offsetof (struct tracepoint, next),
+                              tpoint->obj_addr_on_target);
+    }
+  else
+    /* First object in list, set the head pointer in the
+       inferior.  */
+    write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints,
+                            tpoint->obj_addr_on_target);
+
+}
+
 static void
 download_tracepoints (void)
 {
index 9271875d9cb08359f9ee13d1cc2b1b34542c8d94..a6d5e5f72ac0dae302f5a529d6fbc17741412f8e 100644 (file)
@@ -323,6 +323,10 @@ struct remote_state
   /* True if the stub reports support for static tracepoints.  */
   int static_tracepoints;
 
+  /* True if the stub reports support for installing tracepoint while
+     tracing.  */
+  int install_in_trace;
+
   /* True if the stub can continue running a trace while GDB is
      disconnected.  */
   int disconnected_tracing;
@@ -1261,6 +1265,7 @@ enum {
   PACKET_ConditionalTracepoints,
   PACKET_FastTracepoints,
   PACKET_StaticTracepoints,
+  PACKET_InstallInTrace,
   PACKET_bc,
   PACKET_bs,
   PACKET_TracepointSource,
@@ -3695,6 +3700,16 @@ remote_static_tracepoint_feature (const struct protocol_feature *feature,
   rs->static_tracepoints = (support == PACKET_ENABLE);
 }
 
+static void
+remote_install_in_trace_feature (const struct protocol_feature *feature,
+                                enum packet_support support,
+                                const char *value)
+{
+  struct remote_state *rs = get_remote_state ();
+
+  rs->install_in_trace = (support == PACKET_ENABLE);
+}
+
 static void
 remote_disconnected_tracing_feature (const struct protocol_feature *feature,
                                     enum packet_support support,
@@ -3761,6 +3776,8 @@ static struct protocol_feature remote_protocol_features[] = {
     PACKET_FastTracepoints },
   { "StaticTracepoints", PACKET_DISABLE, remote_static_tracepoint_feature,
     PACKET_StaticTracepoints },
+  {"InstallInTrace", PACKET_DISABLE, remote_install_in_trace_feature,
+   PACKET_InstallInTrace},
   { "DisconnectedTracing", PACKET_DISABLE, remote_disconnected_tracing_feature,
     -1 },
   { "ReverseContinue", PACKET_DISABLE, remote_supported_packet,
@@ -9747,6 +9764,14 @@ remote_supports_static_tracepoints (void)
   return rs->static_tracepoints;
 }
 
+static int
+remote_supports_install_in_trace (void)
+{
+  struct remote_state *rs = get_remote_state ();
+
+  return rs->install_in_trace;
+}
+
 static int
 remote_supports_enable_disable_tracepoint (void)
 {
@@ -10008,6 +10033,24 @@ remote_download_tracepoint (struct bp_location *loc)
   do_cleanups (old_chain);
 }
 
+static int
+remote_can_download_tracepoint (void)
+{
+  struct trace_status *ts = current_trace_status ();
+  int status = remote_get_trace_status (ts);
+
+  if (status == -1 || !ts->running_known || !ts->running)
+    return 0;
+
+  /* If we are in a tracing experiment, but remote stub doesn't support
+     installing tracepoint in trace, we have to return.  */
+  if (!remote_supports_install_in_trace ())
+    return 0;
+
+  return 1;
+}
+
+
 static void
 remote_download_trace_state_variable (struct trace_state_variable *tsv)
 {
@@ -10480,6 +10523,7 @@ Specify the serial device it is connected to\n\
   remote_ops.to_supports_string_tracing = remote_supports_string_tracing;
   remote_ops.to_trace_init = remote_trace_init;
   remote_ops.to_download_tracepoint = remote_download_tracepoint;
+  remote_ops.to_can_download_tracepoint = remote_can_download_tracepoint;
   remote_ops.to_download_trace_state_variable
     = remote_download_trace_state_variable;
   remote_ops.to_enable_tracepoint = remote_enable_tracepoint;
@@ -10997,6 +11041,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_StaticTracepoints],
                         "StaticTracepoints", "static-tracepoints", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_InstallInTrace],
+                        "InstallInTrace", "install-in-trace", 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_statictrace_read],
                          "qXfer:statictrace:read", "read-sdata-object", 0);
 
index fc7b7c63f316c2eb4d1ec1cbeb54a2d580851e6e..16b2128e9e0659af8fe2bb6dd9869075d789cb81 100644 (file)
@@ -675,6 +675,7 @@ update_current_target (void)
       INHERIT (to_supports_string_tracing, t);
       INHERIT (to_trace_init, t);
       INHERIT (to_download_tracepoint, t);
+      INHERIT (to_can_download_tracepoint, t);
       INHERIT (to_download_trace_state_variable, t);
       INHERIT (to_enable_tracepoint, t);
       INHERIT (to_disable_tracepoint, t);
@@ -850,6 +851,9 @@ update_current_target (void)
   de_fault (to_download_tracepoint,
            (void (*) (struct bp_location *))
            tcomplain);
+  de_fault (to_can_download_tracepoint,
+           (int (*) (void))
+           return_zero);
   de_fault (to_download_trace_state_variable,
            (void (*) (struct trace_state_variable *))
            tcomplain);
index ec7937a53b7cb5545a5a06fc3657862b8db666d9..c8941a4058123b6569e9040594b2ff426b48e51c 100644 (file)
@@ -689,6 +689,10 @@ struct target_ops
     /* Send full details of a tracepoint location to the target.  */
     void (*to_download_tracepoint) (struct bp_location *location);
 
+    /* Is the target able to download tracepoint locations in current
+       state?  */
+    int (*to_can_download_tracepoint) (void);
+
     /* Send full details of a trace state variable to the target.  */
     void (*to_download_trace_state_variable) (struct trace_state_variable *tsv);
 
@@ -1477,6 +1481,9 @@ extern int target_search_memory (CORE_ADDR start_addr,
 #define target_download_tracepoint(t) \
   (*current_target.to_download_tracepoint) (t)
 
+#define target_can_download_tracepoint() \
+  (*current_target.to_can_download_tracepoint) ()
+
 #define target_download_trace_state_variable(tsv) \
   (*current_target.to_download_trace_state_variable) (tsv)
 
index 81dd708728819fa21d7e95ef37a9f10013972753..8a6825f3bc15d8433732bdea284fd32de3ef86f6 100644 (file)
@@ -1,3 +1,15 @@
+2011-11-14  Yao Qi  <yao@codesourcery.com>
+
+       * gdb.trace/change-loc-1.c: New.
+       * gdb.trace/change-loc-2.c: New.
+       * gdb.trace/change-loc.c: New.
+       * gdb.trace/change-loc.exp:  New.
+       * gdb.trace/change-loc.h:  New.
+       * gdb.trace/trace-break.c (marker): Define new symbol.
+       * gdb.trace/trace-break.exp (break_trace_same_addr_5):
+        New.
+       (break_trace_same_addr_6): New.
+
 2011-11-12  Matt Rice  <ratmice@gmail.com>
 
        * gdb.base/info-macros.exp: Make tests for info definitions
diff --git a/gdb/testsuite/gdb.trace/change-loc-1.c b/gdb/testsuite/gdb.trace/change-loc-1.c
new file mode 100644 (file)
index 0000000..92d453c
--- /dev/null
@@ -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);
+}
diff --git a/gdb/testsuite/gdb.trace/change-loc-2.c b/gdb/testsuite/gdb.trace/change-loc-2.c
new file mode 100644 (file)
index 0000000..d479917
--- /dev/null
@@ -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 ();
+}
diff --git a/gdb/testsuite/gdb.trace/change-loc.c b/gdb/testsuite/gdb.trace/change-loc.c
new file mode 100644 (file)
index 0000000..d1e0a7f
--- /dev/null
@@ -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;
+}
diff --git a/gdb/testsuite/gdb.trace/change-loc.exp b/gdb/testsuite/gdb.trace/change-loc.exp
new file mode 100644 (file)
index 0000000..e125024
--- /dev/null
@@ -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"
diff --git a/gdb/testsuite/gdb.trace/change-loc.h b/gdb/testsuite/gdb.trace/change-loc.h
new file mode 100644 (file)
index 0000000..1b0e303
--- /dev/null
@@ -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
+       );
+
+}
index fd061424421d3b21745ef1b21086e451dc0e6852..a327202424258bfd3bd1f1ff6c2a20c86700b4fe 100644 (file)
@@ -41,6 +41,13 @@ marker (void)
        SYMBOL(set_point) ":\n"
 #if (defined __x86_64__ || defined __i386__)
        "    call " SYMBOL(func) "\n"
+#endif
+       );
+
+  asm ("    .global " SYMBOL(after_set_point) "\n"
+       SYMBOL(after_set_point) ":\n"
+#if (defined __x86_64__ || defined __i386__)
+       "    call " SYMBOL(func) "\n"
 #endif
        );
 }
index c2d7b2ce4dcede824fb410b13499fadc28e3421b..50344d2090d1fae572ec50d0ee1be09d51e7a0b3 100644 (file)
@@ -39,6 +39,20 @@ if ![gdb_target_supports_trace] {
     return -1;
 }
 
+set fpreg "fp"
+set spreg "sp"
+set pcreg "pc"
+
+if [is_amd64_regs_target] {
+    set fpreg "rbp"
+    set spreg "rsp"
+    set pcreg "rip"
+} elseif [is_x86_like_target] {
+    set fpreg "ebp"
+    set spreg "esp"
+    set pcreg "eip"
+}
+
 # Set breakpoint and tracepoint at the same address.
 
 proc break_trace_same_addr_1 { trace_type option } {
@@ -200,6 +214,159 @@ proc break_trace_same_addr_4 { trace_type option } {
     set pf_prefix $old_pf_prefix
 }
 
+# Set two tracepoints TRACE1 and TRACE2 at two locations, and start tracing.
+# Then, set tracepoint TRACE3 at either of these two locations.
+# TRACE3_AT_FIRST_LOC is a boolean variable to decide insert TRACE3 at which
+# of two locations.  Verify  these tracepoints work as expected.
+
+proc break_trace_same_addr_5 { trace1 trace2 trace3 trace3_at_first_loc } {
+    global executable
+    global pf_prefix
+    global hex
+    global fpreg
+    global spreg
+    global pcreg
+
+    set old_pf_prefix $pf_prefix
+    set pf_prefix "$pf_prefix 5 $trace1 $trace2 ${trace3}@${trace3_at_first_loc}:"
+
+    # Start with a fresh gdb.
+    clean_restart ${executable}
+    if ![runto_main] {
+       fail "Can't run to main"
+       set pf_prefix $old_pf_prefix
+       return -1
+    }
+
+    gdb_test "break marker" "Breakpoint \[0-9\] at $hex: file.*"
+    gdb_test "break end" "Breakpoint \[0-9\] at $hex: file.*"
+
+    gdb_test "${trace1} set_point" "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+       "${trace1} set_point 1"
+    gdb_trace_setactions "set action for tracepoint 1" "" \
+       "collect \$$pcreg" "^$"
+    gdb_test "${trace2} after_set_point" \
+       "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+       "${trace2} after_set_point 1"
+
+    gdb_trace_setactions "set action for tracepoint 2" "" \
+       "collect \$$spreg" "^$"
+
+    gdb_test_no_output "tstart"
+
+    gdb_test "continue" "Continuing\\.\[ \r\n\]+Breakpoint.*" "continue to marker"
+
+    if [string equal $trace3_at_first_loc "1"] {
+       gdb_test "${trace3} set_point" "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+           "${trace3} set_point 2"
+    } else {
+       gdb_test "${trace3} after_set_point" \
+           "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+           "${trace2} after_set_point 2"
+    }
+    gdb_trace_setactions "set action for tracepoint 3" "" \
+       "collect \$$fpreg" "^$"
+
+    gdb_test "continue" "Continuing\\.\[ \r\n\]+Breakpoint.*" "continue to end"
+    gdb_test_no_output "tstop"
+
+    gdb_test "tfind tracepoint 4" "Found trace frame \[0-9\], tracepoint .*" \
+       "tfind test frame of tracepoint 4"
+    gdb_test "tdump" \
+       "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${pcreg} = .*" \
+       "tdump 1"
+    gdb_test "tfind 0" "Found trace frame 0, tracepoint .*" \
+       "reset to frame 0 (1)"
+    gdb_test "tfind tracepoint 5" "Found trace frame \[0-9\], tracepoint .*" \
+       "tfind test frame of tracepoint 5"
+    gdb_test "tdump" \
+       "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${spreg} = .*" \
+       "tdump 2"
+    gdb_test "tfind 0" "Found trace frame 0, tracepoint .*" \
+       "reset to frame 0 (2)"
+    gdb_test "tfind tracepoint 6" "Found trace frame \[0-9\], tracepoint .*" \
+       "tfind test frame of tracepoint 6"
+    gdb_test "tdump" \
+       "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${fpreg} = .*" \
+       "tdump 3"
+
+    set pf_prefix $old_pf_prefix
+}
+
+# Set two tracepoints at the same address, and enable/disable them.  Verify
+# tracepoints work as expect.
+
+proc break_trace_same_addr_6 { trace1 enable1 trace2 enable2 } {
+    global executable
+    global pf_prefix
+    global hex
+    global gdb_prompt
+    global spreg
+    global pcreg
+
+    set old_pf_prefix $pf_prefix
+    set pf_prefix "$pf_prefix 6 $trace1 $enable1 $trace2 $enable2:"
+
+    # Start with a fresh gdb.
+    clean_restart ${executable}
+    if ![runto_main] {
+       fail "Can't run to main"
+       set pf_prefix $old_pf_prefix
+       return -1
+    }
+
+    gdb_test "break marker" "Breakpoint \[0-9\] at $hex: file.*"
+    gdb_test "break end" "Breakpoint \[0-9\] at $hex: file.*"
+
+    gdb_test "continue" "Continuing\\.\[ \r\n\]+Breakpoint.*" "continue to marker"
+
+    gdb_test "${trace1} set_point" "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+       "${trace1} set_point 1"
+    gdb_trace_setactions "set action for tracepoint 1" "" \
+       "collect \$$pcreg" "^$"
+    gdb_test "${trace2} set_point" "\(Fast t|T\)racepoint \[0-9\] at $hex: file.*" \
+       "${trace2} set_point 2"
+    gdb_trace_setactions "set action for tracepoint 2" "" \
+       "collect \$$spreg" "^$"
+
+    gdb_test_no_output "$enable1 4"
+    gdb_test_no_output "$enable2 5"
+
+    gdb_test_no_output "tstart"
+    gdb_test "continue" "Continuing\\.\[ \r\n\]+Breakpoint.*" "continue to end"
+    gdb_test_no_output "tstop"
+
+
+    if [string equal $enable1 "enable"] {
+       gdb_test "tfind tracepoint 4" "Found trace frame \[0-9\], tracepoint .*" \
+           "tfind test frame of tracepoint 4"
+       gdb_test "tdump" \
+           "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${pcreg} = .*" \
+           "tdump 1"
+       gdb_test "tfind 0" "Found trace frame 0, tracepoint .*" \
+           "reset to frame 0 (1)"
+    } else {
+       gdb_test "tfind tracepoint 4" "Target failed to find requested trace frame.*" \
+           "tfind test frame of tracepoint 4"
+    }
+
+    if [string equal $enable2 "enable"] {
+       gdb_test "tfind tracepoint 5" "Found trace frame \[0-9\], tracepoint .*" \
+           "tfind test frame of tracepoint 5"
+       gdb_test "tdump" \
+           "Data collected at tracepoint .*, trace frame \[0-9\]:.*\\$${spreg} = .*" \
+           "tdump 2"
+       gdb_test "tfind 0" "Found trace frame 0, tracepoint .*" \
+           "reset to frame 0 (2)"
+    } else {
+       gdb_test "tfind tracepoint 5" "Target failed to find requested trace frame.*" \
+           "tfind test frame of tracepoint 5"
+    }
+
+    set pf_prefix $old_pf_prefix
+}
+
+
 foreach break_always_inserted { "on" "off" } {
     break_trace_same_addr_1 "trace" ${break_always_inserted}
     break_trace_same_addr_2 "trace" "trace" ${break_always_inserted}
@@ -207,6 +374,13 @@ foreach break_always_inserted { "on" "off" } {
     break_trace_same_addr_4 "trace" ${break_always_inserted}
 }
 
+foreach at_first_loc { "1" "0" } {
+    break_trace_same_addr_5 "trace" "trace" "trace" ${at_first_loc}
+}
+
+break_trace_same_addr_6 "trace" "enable" "trace" "disable"
+break_trace_same_addr_6 "trace" "disable" "trace" "enable"
+
 set libipa $objdir/../gdbserver/libinproctrace.so
 gdb_load_shlibs $libipa
 
@@ -238,4 +412,32 @@ if { [gdb_test "info sharedlibrary" ".*libinproctrace\.so.*" "IPA loaded"] != 0
        break_trace_same_addr_3 "ftrace" ${break_always_inserted}
        break_trace_same_addr_4 "ftrace" ${break_always_inserted}
     }
+
+    foreach trace1 { "trace" "ftrace" } {
+       foreach trace2 { "trace" "ftrace" } {
+           foreach trace3 { "trace" "ftrace" } {
+
+               if { [string equal $trace1 "trace"]
+                    && [string equal $trace2 "trace"]
+                    && [string equal $trace3 "trace"] } {
+                   continue
+               }
+
+               foreach at_first_loc { "1" "0" } {
+                   break_trace_same_addr_5 $trace1 $trace2 $trace3 $at_first_loc
+               }
+           }
+       }
+    }
+
+    foreach trace1 { "trace" "ftrace" } {
+       foreach trace2 { "trace" "ftrace" } {
+           if { [string equal $trace1 "trace"]
+                && [string equal $trace2 "trace"] } {
+                   continue
+               }
+           break_trace_same_addr_6 $trace1 "enable" $trace2 "disable"
+           break_trace_same_addr_6 $trace1 "disable" $trace2 "enable"
+       }
+    }
 }
index a7035d1635772afc6bf8179a69efff9154cf6856..82ca0b8ec9785165fa01d0426d0ddc8b1d7ad365 100644 (file)
@@ -1711,7 +1711,15 @@ start_tracing (void)
       t->number_on_target = 0;
 
       for (loc = b->loc; loc; loc = loc->next)
-       target_download_tracepoint (loc);
+       {
+         /* Since tracepoint locations are never duplicated, `inserted'
+            flag should be zero.  */
+         gdb_assert (!loc->inserted);
+
+         target_download_tracepoint (loc);
+
+         loc->inserted = 1;
+       }
 
       t->number_on_target = b->number;
     }
@@ -3203,10 +3211,10 @@ cond_string_is_same (char *str1, char *str2)
 /* Look for an existing tracepoint that seems similar enough to the
    uploaded one.  Enablement isn't compared, because the user can
    toggle that freely, and may have done so in anticipation of the
-   next trace run.  */
+   next trace run.  Return the location of matched tracepoint.  */
 
-struct tracepoint *
-find_matching_tracepoint (struct uploaded_tp *utp)
+struct bp_location *
+find_matching_tracepoint_location (struct uploaded_tp *utp)
 {
   VEC(breakpoint_p) *tp_vec = all_tracepoints ();
   int ix;
@@ -3228,7 +3236,7 @@ find_matching_tracepoint (struct uploaded_tp *utp)
          for (loc = b->loc; loc; loc = loc->next)
            {
              if (loc->address == utp->addr)
-               return t;
+               return loc;
            }
        }
     }
@@ -3243,17 +3251,24 @@ void
 merge_uploaded_tracepoints (struct uploaded_tp **uploaded_tps)
 {
   struct uploaded_tp *utp;
-  struct tracepoint *t;
 
   /* Look for GDB tracepoints that match up with our uploaded versions.  */
   for (utp = *uploaded_tps; utp; utp = utp->next)
     {
-      t = find_matching_tracepoint (utp);
-      if (t)
-       printf_filtered (_("Assuming tracepoint %d is same "
-                          "as target's tracepoint %d at %s.\n"),
-                        t->base.number, utp->number,
-                        paddress (get_current_arch (), utp->addr));
+      struct bp_location *loc;
+      struct tracepoint *t;
+
+      loc = find_matching_tracepoint_location (utp);
+      if (loc)
+       {
+         /* Mark this location as already inserted.  */
+         loc->inserted = 1;
+         t = (struct tracepoint *) loc->owner;
+         printf_filtered (_("Assuming tracepoint %d is same "
+                            "as target's tracepoint %d at %s.\n"),
+                          loc->owner->number, utp->number,
+                          paddress (loc->gdbarch, utp->addr));
+       }
       else
        {
          t = create_tracepoint_from_upload (utp);
This page took 0.090056 seconds and 4 git commands to generate.