Add fast tracepoints.
authorStan Shebs <shebs@codesourcery.com>
Wed, 6 Jan 2010 04:20:27 +0000 (04:20 +0000)
committerStan Shebs <shebs@codesourcery.com>
Wed, 6 Jan 2010 04:20:27 +0000 (04:20 +0000)
* arch-utils.h (default_fast_tracepoint_valid_at): Declare.
* arch-utils.c (default_fast_tracepoint_valid_at): New function.
* breakpoint.h (enum bptype): Add bp_fast_tracepoint.
* breakpoint.c (tracepoint_type): New function.
(ALL_TRACEPOINTS): Use it.
(should_be_inserted): Ditto.
(bpstat_check_location): Ditto.
(print_one_breakpoint_location): Ditto.
(user_settable_breakpoint): Ditto.
(set_breakpoint_location_function): Ditto.
(disable_breakpoints_in_shlibs): Ditto.
(delete_trace_command): Ditto.
(print_it_typical): Add bp_fast_tracepoint case.
(bpstat_what): Ditto.
(print_one_breakpoint_location): Ditto.
(allocate_bp_location): Ditto.
(mention): Ditto.
(breakpoint_re_set_one): Ditto.
(disable_command): Ditto.
(enable_command): Ditto.
(check_fast_tracepoint_sals): New function.
(break_command_really): Call it.
(ftrace_command): New function.
(_initialize_breakpoint): Add ftrace command.
* gdbarch.sh (fast_tracepoint_valid_at): New.
* gdbarch.h, gdbarch.c: Regenerate.
* i386-tdep.c (i386_fast_tracepoint_valid_at): New function.
(i386_gdbarch_init): Use it.
* remote.c (struct remote_state): New field fast_tracepoints.
(PACKET_FastTracepoints): New packet config type.
(remote_fast_tracepoint_feature): New function.
(remote_protocol_features): Add FastTracepoints.
(remote_supports_fast_tracepoints): New function.
(_initialize_remote): Add FastTracepoints.
* tracepoint.c (download_tracepoint): Add fast tracepoint option.
* NEWS: Mention fast tracepoints.

* gdb.texinfo (Create and Delete Tracepoints): Describe fast
tracepoints.
(Tracepoint Packets): Describe remote protocol for fast
tracepoints.

* gdb.trace/tracecmd.exp: Test ftrace.

16 files changed:
gdb/ChangeLog
gdb/NEWS
gdb/arch-utils.c
gdb/arch-utils.h
gdb/breakpoint.c
gdb/breakpoint.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/i386-tdep.c
gdb/remote.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.trace/tracecmd.exp
gdb/tracepoint.c

index 4ba426e8ddad198a984a2ce43d35104b95dfa2cc..74aba43077c0a6c150665ec5d7b522babfe9f729 100644 (file)
@@ -1,3 +1,43 @@
+2010-01-05  Stan Shebs  <stan@codesourcery.com>
+
+       Add fast tracepoints.
+       * arch-utils.h (default_fast_tracepoint_valid_at): Declare.
+       * arch-utils.c (default_fast_tracepoint_valid_at): New function.
+       * breakpoint.h (enum bptype): Add bp_fast_tracepoint.
+       * breakpoint.c (tracepoint_type): New function.
+       (ALL_TRACEPOINTS): Use it.
+       (should_be_inserted): Ditto.
+       (bpstat_check_location): Ditto.
+       (print_one_breakpoint_location): Ditto.
+       (user_settable_breakpoint): Ditto.
+       (set_breakpoint_location_function): Ditto.
+       (disable_breakpoints_in_shlibs): Ditto.
+       (delete_trace_command): Ditto.
+       (print_it_typical): Add bp_fast_tracepoint case.
+       (bpstat_what): Ditto.
+       (print_one_breakpoint_location): Ditto.
+       (allocate_bp_location): Ditto.
+       (mention): Ditto.
+       (breakpoint_re_set_one): Ditto.
+       (disable_command): Ditto.
+       (enable_command): Ditto.
+       (check_fast_tracepoint_sals): New function.
+       (break_command_really): Call it.
+       (ftrace_command): New function.
+       (_initialize_breakpoint): Add ftrace command.
+       * gdbarch.sh (fast_tracepoint_valid_at): New.
+       * gdbarch.h, gdbarch.c: Regenerate.
+       * i386-tdep.c (i386_fast_tracepoint_valid_at): New function.
+       (i386_gdbarch_init): Use it.
+       * remote.c (struct remote_state): New field fast_tracepoints.
+       (PACKET_FastTracepoints): New packet config type.
+       (remote_fast_tracepoint_feature): New function.
+       (remote_protocol_features): Add FastTracepoints.
+       (remote_supports_fast_tracepoints): New function.
+       (_initialize_remote): Add FastTracepoints.
+       * tracepoint.c (download_tracepoint): Add fast tracepoint option.
+       * NEWS: Mention fast tracepoints.
+
 2010-01-06  Joel Brobecker  <brobecker@adacore.com>
 
        * gdb-gdb.py: New file.
index 184c4e64c29629585e57a970f1d6da4f0172dca5..544a1aa510d07123efb1a2f122647806cc9ecab0 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -36,7 +36,19 @@ Renesas RX                   rx
   tracepoint actions and condition expressions.  Use the "tvariable"
   command to create, and "info tvariables" to view; see "Trace State
   Variables" in the manual for more detail.
-  
+
+* Fast tracepoints
+
+  GDB now includes an option for defining fast tracepoints, which
+  targets may implement more efficiently, such as by installing a jump
+  into the target agent rather than a trap instruction.  The resulting
+  speedup can be by two orders of magnitude or more, although the
+  tradeoff is that some program locations on some target architectures
+  might not allow fast tracepoint installation, for instance if the
+  instruction to be replaced is shorter than the jump.  To request a
+  fast tracepoint, use the "ftrace" command, with syntax identical to
+  the regular trace command.
+
 * Changed commands
 
 disassemble
@@ -101,6 +113,9 @@ teval EXPR, ...
   Evaluate the given expressions without collecting anything into the
   trace buffer. (Valid in tracepoint actions only.)
 
+ftrace FN / FILE:LINE / *ADDR
+  Define a fast tracepoint at the given function, line, or address.
+
 * New options
 
 set follow-exec-mode new|same
index 9a64a8c79a1cab81ec4e6a392c89c9a42174c491..55011754bcd9cc39139749bb79dfb37603a6e6f7 100644 (file)
@@ -765,6 +765,17 @@ default_has_shared_address_space (struct gdbarch *gdbarch)
   return 0;
 }
 
+int
+default_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
+                                 CORE_ADDR addr, int *isize, char **msg)
+{
+  /* We don't know if maybe the target has some way to do fast
+     tracepoints that doesn't need gdbarch, so always say yes.  */
+  if (msg)
+    *msg = NULL;
+  return 1;
+}
+
 /* */
 
 extern initialize_file_ftype _initialize_gdbarch_utils; /* -Wmissing-prototypes */
index 0cae9f87af6b098cf4f5c5666c3a5d3ac8421c6d..6fee1e57faa0418bbc9c996e09fed04552b49300 100644 (file)
@@ -155,4 +155,8 @@ extern struct gdbarch *get_current_arch (void);
 
 extern int default_has_shared_address_space (struct gdbarch *);
 
+extern int default_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
+                                            CORE_ADDR addr,
+                                            int *isize, char **msg);
+
 #endif
index 58102ec1e177c9f98e544ddafdf34eab866cc936..813080a7097eb18f8b3de4445f6edb4ff355dea0 100644 (file)
@@ -353,7 +353,7 @@ static int overlay_events_enabled;
 
 #define ALL_TRACEPOINTS(B)  \
   for (B = breakpoint_chain; B; B = B->next)  \
-    if ((B)->type == bp_tracepoint)
+    if (tracepoint_type (B))
 
 /* Chains of all breakpoints defined.  */
 
@@ -422,6 +422,14 @@ clear_breakpoint_hit_counts (void)
     b->hit_count = 0;
 }
 
+/* Encapsulate tests for different types of tracepoints.  */
+
+static int
+tracepoint_type (const struct breakpoint *b)
+{
+  return (b->type == bp_tracepoint || b->type == bp_fast_tracepoint);
+}
+  
 /* Default address, symtab and line to put a breakpoint at
    for "break" command with no arg.
    if default_breakpoint_valid is zero, the other three are
@@ -1282,7 +1290,7 @@ should_be_inserted (struct bp_location *bpt)
 
   /* Tracepoints are inserted by the target at a time of its choosing,
      not by us.  */
-  if (bpt->owner->type == bp_tracepoint)
+  if (tracepoint_type (bpt->owner))
     return 0;
 
   return 1;
@@ -2977,6 +2985,7 @@ print_it_typical (bpstat bs)
     case bp_watchpoint_scope:
     case bp_call_dummy:
     case bp_tracepoint:
+    case bp_fast_tracepoint:
     case bp_jit_event:
     default:
       result = PRINT_UNKNOWN;
@@ -3322,7 +3331,7 @@ bpstat_check_location (const struct bp_location *bl,
 
   /* By definition, the inferior does not report stops at
      tracepoints.  */
-  if (b->type == bp_tracepoint)
+  if (tracepoint_type (b))
     return 0;
 
   if (b->type != bp_watchpoint
@@ -3914,11 +3923,12 @@ bpstat_what (bpstat bs)
          retval.call_dummy = 1;
          break;
        case bp_tracepoint:
+       case bp_fast_tracepoint:
          /* Tracepoint hits should not be reported back to GDB, and
             if one got through somehow, it should have been filtered
             out already.  */
          internal_error (__FILE__, __LINE__,
-                         _("bpstat_what: bp_tracepoint encountered"));
+                         _("bpstat_what: tracepoint encountered"));
          break;
        }
       current_action = table[(int) bs_class][(int) current_action];
@@ -4044,6 +4054,7 @@ print_one_breakpoint_location (struct breakpoint *b,
     {bp_longjmp_master, "longjmp master"},
     {bp_catchpoint, "catchpoint"},
     {bp_tracepoint, "tracepoint"},
+    {bp_fast_tracepoint, "fast tracepoint"},
     {bp_jit_event, "jit events"},
   };
   
@@ -4173,6 +4184,7 @@ print_one_breakpoint_location (struct breakpoint *b,
       case bp_overlay_event:
       case bp_longjmp_master:
       case bp_tracepoint:
+      case bp_fast_tracepoint:
       case bp_jit_event:
        if (opts.addressprint)
          {
@@ -4258,7 +4270,7 @@ print_one_breakpoint_location (struct breakpoint *b,
          because the condition is an internal implementation detail
          that we do not want to expose to the user.  */
       annotate_field (7);
-      if (b->type == bp_tracepoint)
+      if (tracepoint_type (b))
        ui_out_text (uiout, "\ttrace only if ");
       else
        ui_out_text (uiout, "\tstop only if ");
@@ -4451,7 +4463,7 @@ user_settable_breakpoint (const struct breakpoint *b)
   return (b->type == bp_breakpoint
          || b->type == bp_catchpoint
          || b->type == bp_hardware_breakpoint
-         || b->type == bp_tracepoint
+         || tracepoint_type (b)
          || b->type == bp_watchpoint
          || b->type == bp_read_watchpoint
          || b->type == bp_access_watchpoint
@@ -4804,6 +4816,7 @@ allocate_bp_location (struct breakpoint *bpt)
     {
     case bp_breakpoint:
     case bp_tracepoint:
+    case bp_fast_tracepoint:
     case bp_until:
     case bp_finish:
     case bp_longjmp:
@@ -4900,7 +4913,7 @@ set_breakpoint_location_function (struct bp_location *loc)
 {
   if (loc->owner->type == bp_breakpoint
       || loc->owner->type == bp_hardware_breakpoint
-      || loc->owner->type == bp_tracepoint)
+      || tracepoint_type (loc->owner))
     {
       find_pc_partial_function (loc->address, &(loc->function_name), 
                                NULL, NULL);
@@ -5159,7 +5172,7 @@ disable_breakpoints_in_shlibs (void)
        to insert those breakpoints and fail.  */
     if (((b->type == bp_breakpoint)
         || (b->type == bp_hardware_breakpoint)
-        || (b->type == bp_tracepoint))
+        || (tracepoint_type (b)))
        && loc->pspace == current_program_space
        && !loc->shlib_disabled
 #ifdef PC_SOLIB
@@ -6091,6 +6104,16 @@ mention (struct breakpoint *b)
        printf_filtered (_(" %d"), b->number);
        say_where = 1;
        break;
+      case bp_fast_tracepoint:
+       if (ui_out_is_mi_like_p (uiout))
+         {
+           say_where = 0;
+           break;
+         }
+       printf_filtered (_("Fast tracepoint"));
+       printf_filtered (_(" %d"), b->number);
+       say_where = 1;
+       break;
 
       case bp_until:
       case bp_finish:
@@ -6593,6 +6616,38 @@ breakpoint_sals_to_pc (struct symtabs_and_lines *sals,
     resolve_sal_pc (&sals->sals[i]);
 }
 
+/* Fast tracepoints may have restrictions on valid locations.  For
+   instance, a fast tracepoint using a jump instead of a trap will
+   likely have to overwrite more bytes than a trap would, and so can
+   only be placed where the instruction is longer than the jump, or a
+   multi-instruction sequence does not have a jump into the middle of
+   it, etc.  */
+
+static void
+check_fast_tracepoint_sals (struct gdbarch *gdbarch,
+                           struct symtabs_and_lines *sals)
+{
+  int i, rslt;
+  struct symtab_and_line *sal;
+  char *msg;
+  struct cleanup *old_chain;
+
+  for (i = 0; i < sals->nelts; i++)
+    {
+      sal = &sals->sals[i];
+
+      rslt = gdbarch_fast_tracepoint_valid_at (gdbarch, sal->pc,
+                                              NULL, &msg);
+      old_chain = make_cleanup (xfree, msg);
+
+      if (!rslt)
+       error (_("May not have a fast tracepoint at 0x%s%s"),
+              paddress (gdbarch, sal->pc), (msg ? msg : ""));
+
+      do_cleanups (old_chain);
+    }
+}
+
 static void
 do_captured_parse_breakpoint (struct ui_out *ui, void *data)
 {
@@ -6794,9 +6849,13 @@ break_command_really (struct gdbarch *gdbarch,
     breakpoint_sals_to_pc (&sals, addr_start);
 
   type_wanted = (traceflag
-                ? bp_tracepoint
+                ? (hardwareflag ? bp_fast_tracepoint : bp_tracepoint)
                 : (hardwareflag ? bp_hardware_breakpoint : bp_breakpoint));
 
+  /* Fast tracepoints may have additional restrictions on location.  */
+  if (type_wanted == bp_fast_tracepoint)
+    check_fast_tracepoint_sals (gdbarch, &sals);
+
   /* Verify that condition can be parsed, before setting any
      breakpoints.  Allocate a separate condition expression for each
      breakpoint. */
@@ -8970,6 +9029,7 @@ breakpoint_re_set_one (void *bint)
     case bp_breakpoint:
     case bp_hardware_breakpoint:
     case bp_tracepoint:
+    case bp_fast_tracepoint:
       /* Do not attempt to re-set breakpoints disabled during startup.  */
       if (b->enable_state == bp_startup_disabled)
        return 0;
@@ -9369,6 +9429,7 @@ disable_command (char *args, int from_tty)
        continue;
       case bp_breakpoint:
       case bp_tracepoint:
+      case bp_fast_tracepoint:
       case bp_catchpoint:
       case bp_hardware_breakpoint:
       case bp_watchpoint:
@@ -9462,6 +9523,7 @@ enable_command (char *args, int from_tty)
        continue;
       case bp_breakpoint:
       case bp_tracepoint:
+      case bp_fast_tracepoint:
       case bp_catchpoint:
       case bp_hardware_breakpoint:
       case bp_watchpoint:
@@ -9769,6 +9831,22 @@ trace_command (char *arg, int from_tty)
   set_tracepoint_count (breakpoint_count);
 }
 
+void
+ftrace_command (char *arg, int from_tty)
+{
+  break_command_really (get_current_arch (),
+                       arg, 
+                       NULL, 0, 1 /* parse arg */,
+                       0 /* tempflag */, 1 /* hardwareflag */,
+                       1 /* traceflag */,
+                       0 /* Ignore count */,
+                       pending_break_support, 
+                       NULL,
+                       from_tty,
+                       1 /* enabled */);
+  set_tracepoint_count (breakpoint_count);
+}
+
 /* Print information on tracepoint number TPNUM_EXP, or all if
    omitted.  */
 
@@ -9846,7 +9924,7 @@ delete_trace_command (char *arg, int from_tty)
        {
          ALL_BREAKPOINTS_SAFE (b, temp)
          {
-           if (b->type == bp_tracepoint
+           if (tracepoint_type (b)
                && b->number >= 0)
              delete_breakpoint (b);
          }
@@ -10501,6 +10579,13 @@ Do \"help tracepoints\" for info on other tracepoint commands."));
   add_com_alias ("tra", "trace", class_alias, 1);
   add_com_alias ("trac", "trace", class_alias, 1);
 
+  c = add_com ("ftrace", class_breakpoint, ftrace_command, _("\
+Set a fast tracepoint at specified line or function.\n\
+\n"
+BREAK_ARGS_HELP ("ftrace") "\n\
+Do \"help tracepoints\" for info on other tracepoint commands."));
+  set_cmd_completer (c, location_completer);
+
   add_info ("tracepoints", tracepoints_info, _("\
 Status of tracepoints, or tracepoint number NUMBER.\n\
 Convenience variable \"$tpnum\" contains the number of the\n\
index b4ea339111111746a17734e75f0c8b6b6d84e497..01fc0e96691fd013ec7b7c7ddae61cb6e6ecdf7b 100644 (file)
@@ -121,6 +121,7 @@ enum bptype
     bp_catchpoint,
 
     bp_tracepoint,
+    bp_fast_tracepoint,
 
     /* Event for JIT compiled code generation or deletion.  */
     bp_jit_event,
index deb3a14725b2e2499bae16a787d257e852be8f05..48d187bb02142f86371db9e8553fa9e09aeda2bb 100644 (file)
@@ -1,3 +1,10 @@
+2010-01-05  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.texinfo (Create and Delete Tracepoints): Describe fast
+       tracepoints.
+       (Tracepoint Packets): Describe remote protocol for fast
+       tracepoints.
+
 2010-01-01  Joel Brobecker  <brobecker@adacore.com>
 
        Update the "Start of New Year Procedure".
index d0997b3525a9e2a4c9505950f9bf4647951412a7..d23c67519c6cab8eeed8895e1d3e49b327ac92df 100644 (file)
@@ -9323,6 +9323,11 @@ expressions and ignore counts on tracepoints have no effect, and
 tracepoints cannot run @value{GDBN} commands when they are
 hit.  Tracepoints may not be thread-specific either.
 
+@cindex fast tracepoints
+Some targets may support @dfn{fast tracepoints}, which are inserted in
+a different way (such as with a jump instead of a trap), that is
+faster but possibly restricted in where they may be installed.
+
 This section describes commands to set tracepoints and associated
 conditions and actions.
 
@@ -9378,6 +9383,20 @@ if the value is nonzero---that is, if @var{cond} evaluates as true.
 @xref{Tracepoint Conditions, ,Tracepoint Conditions}, for more
 information on tracepoint conditions.
 
+@item ftrace @var{location} [ if @var{cond} ]
+@cindex set fast tracepoint
+@kindex ftrace
+The @code{ftrace} command sets a fast tracepoint.  For targets that
+support them, fast tracepoints will use a more efficient but possibly
+less general technique to trigger data collection, such as a jump
+instruction instead of a trap, or some sort of hardware support.  It
+may not be possible to create a fast tracepoint at the desired
+location, in which case the command will exit with an explanatory
+message.
+
+@value{GDBN} handles arguments to @code{ftrace} exactly as for
+@code{trace}.
+
 @vindex $tpnum
 @cindex last tracepoint number
 @cindex recent tracepoint number
@@ -29975,16 +29994,19 @@ tracepoints (@pxref{Tracepoints}).
 
 @table @samp
 
-@item QTDP:@var{n}:@var{addr}:@var{ena}:@var{step}:@var{pass}[:X@var{len},@var{bytes}]@r{[}-@r{]}
+@item QTDP:@var{n}:@var{addr}:@var{ena}:@var{step}:@var{pass}[:F@var{flen}][:X@var{len},@var{bytes}]@r{[}-@r{]}
 Create a new tracepoint, number @var{n}, at @var{addr}.  If @var{ena}
 is @samp{E}, then the tracepoint is enabled; if it is @samp{D}, then
 the tracepoint is disabled.  @var{step} is the tracepoint's step
-count, and @var{pass} is its pass count.  If an @samp{X} is present,
-it introduces a tracepoint condition, which consists of a hexadecimal
-length, followed by a comma and hex-encoded bytes, in a manner similar
-to action encodings as described below.  If the trailing @samp{-} is
-present, further @samp{QTDP} packets will follow to specify this
-tracepoint's actions.
+count, and @var{pass} is its pass count.  If an @samp{F} is present,
+then the tracepoint is to be a fast tracepoint, and the @var{flen} is
+the number of bytes that the target should copy elsewhere to make room
+for the tracepoint.  If an @samp{X} is present, it introduces a
+tracepoint condition, which consists of a hexadecimal length, followed
+by a comma and hex-encoded bytes, in a manner similar to action
+encodings as described below.  If the trailing @samp{-} is present,
+further @samp{QTDP} packets will follow to specify this tracepoint's
+actions.
 
 Replies:
 @table @samp
index 3680dc441b4de5a4536d2afdc93e4172ad72154f..9d7702758f4636451a8c3547e5101468cb8e5f5f 100644 (file)
@@ -250,6 +250,7 @@ struct gdbarch
   int has_global_solist;
   int has_global_breakpoints;
   gdbarch_has_shared_address_space_ftype *has_shared_address_space;
+  gdbarch_fast_tracepoint_valid_at_ftype *fast_tracepoint_valid_at;
 };
 
 
@@ -391,6 +392,7 @@ struct gdbarch startup_gdbarch =
   0,  /* has_global_solist */
   0,  /* has_global_breakpoints */
   default_has_shared_address_space,  /* has_shared_address_space */
+  default_fast_tracepoint_valid_at,  /* fast_tracepoint_valid_at */
   /* startup_gdbarch() */
 };
 
@@ -475,6 +477,7 @@ gdbarch_alloc (const struct gdbarch_info *info,
   gdbarch->target_signal_from_host = default_target_signal_from_host;
   gdbarch->target_signal_to_host = default_target_signal_to_host;
   gdbarch->has_shared_address_space = default_has_shared_address_space;
+  gdbarch->fast_tracepoint_valid_at = default_fast_tracepoint_valid_at;
   /* gdbarch_alloc() */
 
   return gdbarch;
@@ -653,6 +656,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of has_global_solist, invalid_p == 0 */
   /* Skip verify of has_global_breakpoints, invalid_p == 0 */
   /* Skip verify of has_shared_address_space, invalid_p == 0 */
+  /* Skip verify of fast_tracepoint_valid_at, invalid_p == 0 */
   buf = ui_file_xstrdup (log, &length);
   make_cleanup (xfree, buf);
   if (length > 0)
@@ -825,6 +829,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: elf_make_msymbol_special = <%s>\n",
                       host_address_to_string (gdbarch->elf_make_msymbol_special));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: fast_tracepoint_valid_at = <%s>\n",
+                      host_address_to_string (gdbarch->fast_tracepoint_valid_at));
   fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_fetch_pointer_argument_p() = %d\n",
                       gdbarch_fetch_pointer_argument_p (gdbarch));
@@ -3528,6 +3535,23 @@ set_gdbarch_has_shared_address_space (struct gdbarch *gdbarch,
   gdbarch->has_shared_address_space = has_shared_address_space;
 }
 
+int
+gdbarch_fast_tracepoint_valid_at (struct gdbarch *gdbarch, CORE_ADDR addr, int *isize, char **msg)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->fast_tracepoint_valid_at != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_fast_tracepoint_valid_at called\n");
+  return gdbarch->fast_tracepoint_valid_at (gdbarch, addr, isize, msg);
+}
+
+void
+set_gdbarch_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
+                                      gdbarch_fast_tracepoint_valid_at_ftype fast_tracepoint_valid_at)
+{
+  gdbarch->fast_tracepoint_valid_at = fast_tracepoint_valid_at;
+}
+
 
 /* Keep a registry of per-architecture data-pointers required by GDB
    modules. */
index d392ece74468e40ae8e21f942b295b8f2b020ce3..18267c9c5fe23b79116888331a38e0efb6cffeaf 100644 (file)
@@ -909,6 +909,12 @@ typedef int (gdbarch_has_shared_address_space_ftype) (struct gdbarch *gdbarch);
 extern int gdbarch_has_shared_address_space (struct gdbarch *gdbarch);
 extern void set_gdbarch_has_shared_address_space (struct gdbarch *gdbarch, gdbarch_has_shared_address_space_ftype *has_shared_address_space);
 
+/* True if a fast tracepoint can be set at an address. */
+
+typedef int (gdbarch_fast_tracepoint_valid_at_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr, int *isize, char **msg);
+extern int gdbarch_fast_tracepoint_valid_at (struct gdbarch *gdbarch, CORE_ADDR addr, int *isize, char **msg);
+extern void set_gdbarch_fast_tracepoint_valid_at (struct gdbarch *gdbarch, gdbarch_fast_tracepoint_valid_at_ftype *fast_tracepoint_valid_at);
+
 /* Definition for an unknown syscall, used basically in error-cases.  */
 #define UNKNOWN_SYSCALL (-1)
 
index 426a7de5f4cd4fed8b41ad4f09209e6fd37dc15c..9474addc5c5b76808df0f5e2e60f57a43e9fc55e 100755 (executable)
@@ -759,6 +759,9 @@ v:int:has_global_breakpoints:::0:0::0
 
 # True if inferiors share an address space (e.g., uClinux).
 m:int:has_shared_address_space:void:::default_has_shared_address_space::0
+
+# True if a fast tracepoint can be set at an address.
+m:int:fast_tracepoint_valid_at:CORE_ADDR addr, int *isize, char **msg:addr, isize, msg::default_fast_tracepoint_valid_at::0
 EOF
 }
 
index f4d037c3494fd18eb91ba989519e59355a71353d..eea4ff4dd97f6b255ac4df0536478cec951f7497 100644 (file)
@@ -43,6 +43,7 @@
 #include "target.h"
 #include "value.h"
 #include "dis-asm.h"
+#include "disasm.h"
 
 #include "gdb_assert.h"
 #include "gdb_string.h"
@@ -5567,6 +5568,49 @@ static const int i386_record_regmap[] =
   I386_DS_REGNUM, I386_ES_REGNUM, I386_FS_REGNUM, I386_GS_REGNUM
 };
 
+/* Check that the given address appears suitable for a fast
+   tracepoint, which on x86 means that we need an instruction of at
+   least 5 bytes, so that we can overwrite it with a 4-byte-offset
+   jump and not have to worry about program jumps to an address in the
+   middle of the tracepoint jump.  Returns 1 if OK, and writes a size
+   of instruction to replace, and 0 if not, plus an explanatory
+   string.  */
+
+static int
+i386_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
+                              CORE_ADDR addr, int *isize, char **msg)
+{
+  int len, jumplen;
+  static struct ui_file *gdb_null = NULL;
+
+  /* This is based on the target agent using a 4-byte relative jump.
+     Alternate future possibilities include 8-byte offset for x86-84,
+     or 3-byte jumps if the program has trampoline space close by.  */
+  jumplen = 5;
+
+  /* Dummy file descriptor for the disassembler.  */
+  if (!gdb_null)
+    gdb_null = ui_file_new ();
+
+  /* Check for fit.  */
+  len = gdb_print_insn (gdbarch, addr, gdb_null, NULL);
+  if (len < jumplen)
+    {
+      /* Return a bit of target-specific detail to add to the caller's
+        generic failure message.  */
+      if (msg)
+       *msg = xstrprintf (_("; instruction is only %d bytes long, need at least %d bytes for the jump"),
+                          len, jumplen);
+      return 0;
+    }
+
+  if (isize)
+    *isize = len;
+  if (msg)
+    *msg = NULL;
+  return 1;
+}
+
 \f
 static struct gdbarch *
 i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
@@ -5769,6 +5813,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_skip_permanent_breakpoint (gdbarch,
                                         i386_skip_permanent_breakpoint);
 
+  set_gdbarch_fast_tracepoint_valid_at (gdbarch,
+                                       i386_fast_tracepoint_valid_at);
+
   return gdbarch;
 }
 
index 7af67e54bd3481c1485667fc5959c73bd683f122..cba9f5b81e70269273e0c4be82dc272167360b51 100644 (file)
@@ -298,6 +298,9 @@ struct remote_state
   /* True if the stub reports support for conditional tracepoints.  */
   int cond_tracepoints;
 
+  /* True if the stub reports support for fast tracepoints.  */
+  int fast_tracepoints;
+
   /* Nonzero if the user has pressed Ctrl-C, but the target hasn't
      responded to that.  */
   int ctrlc_pending_p;
@@ -1066,6 +1069,7 @@ enum {
   PACKET_qXfer_siginfo_write,
   PACKET_qAttached,
   PACKET_ConditionalTracepoints,
+  PACKET_FastTracepoints,
   PACKET_bc,
   PACKET_bs,
   PACKET_MAX
@@ -3136,6 +3140,15 @@ remote_cond_tracepoint_feature (const struct protocol_feature *feature,
   rs->cond_tracepoints = (support == PACKET_ENABLE);
 }
 
+static void
+remote_fast_tracepoint_feature (const struct protocol_feature *feature,
+                               enum packet_support support,
+                               const char *value)
+{
+  struct remote_state *rs = get_remote_state ();
+  rs->fast_tracepoints = (support == PACKET_ENABLE);
+}
+
 static struct protocol_feature remote_protocol_features[] = {
   { "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
   { "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
@@ -3164,6 +3177,8 @@ static struct protocol_feature remote_protocol_features[] = {
     PACKET_qXfer_siginfo_write },
   { "ConditionalTracepoints", PACKET_DISABLE, remote_cond_tracepoint_feature,
     PACKET_ConditionalTracepoints },
+  { "FastTracepoints", PACKET_DISABLE, remote_fast_tracepoint_feature,
+    PACKET_FastTracepoints },
   { "ReverseContinue", PACKET_DISABLE, remote_supported_packet,
     PACKET_bc },
   { "ReverseStep", PACKET_DISABLE, remote_supported_packet,
@@ -8895,6 +8910,13 @@ remote_supports_cond_tracepoints (void)
   return rs->cond_tracepoints;
 }
 
+int
+remote_supports_fast_tracepoints (void)
+{
+  struct remote_state *rs = get_remote_state ();
+  return rs->fast_tracepoints;
+}
+
 static void
 init_remote_ops (void)
 {
@@ -9371,6 +9393,8 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
 
   add_packet_config_cmd (&remote_protocol_packets[PACKET_ConditionalTracepoints],
                         "ConditionalTracepoints", "conditional-tracepoints", 0);
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_FastTracepoints],
+                        "FastTracepoints", "fast-tracepoints", 0);
 
   /* Keep the old ``set remote Z-packet ...'' working.  Each individual
      Z sub-packet has its own set and show commands, but users may
index 2d1b83429e570f552f0556b66eb4f88ccabd6d9e..6e4870ec8fae7659af91b0e2bb87d656e1d791d4 100644 (file)
@@ -1,3 +1,7 @@
+2010-01-05  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.trace/tracecmd.exp: Test ftrace.
+
 2010-01-04  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
 
        * gdb.xml/tdesc-regs.exp: Support s390*-*-* targets.
index 0fd89680c676346b469733205d3f655db66f6995..5ce31badcba57f80a0e0155ddeb23430eae09dc2 100644 (file)
@@ -164,4 +164,16 @@ gdb_test "info trace" "in gdb_recursion_test.*$srcfile:$testline1.*trace only if
 # 1.14 help trace
 gdb_test "help trace" "Set a tracepoint at .*" "1.14: help trace"
 
+# 1.15 ftrace
 
+gdb_delete_tracepoints
+
+send_gdb "ftrace gdb_recursion_test\n"
+# Acceptance vs rejection of a location are target-specific, so allow both.
+gdb_expect {
+    -re "Fast tracepoint $decimal at $hex: file.*$srcfile, line $testline1.*$gdb_prompt $"
+    { pass "Set a fast tracepoint" }
+    -re ".*May not have a fast tracepoint at $hex.*$gdb_prompt $"
+    { pass "Declined to set a fast tracepoint" }
+    timeout { fail "Timeout while setting fast tracepoint" }
+}
index b61362f4bdd34c7cd19bb64444e814b74c038a28..8ec81a3a1d2289819c9b5b31da72788ff4a37ffe 100644 (file)
@@ -34,6 +34,7 @@
 #include "tracepoint.h"
 #include "remote.h"
 extern int remote_supports_cond_tracepoints (void);
+extern int remote_supports_fast_tracepoints (void);
 extern char *unpack_varlen_hex (char *buff, ULONGEST *result);
 #include "linespec.h"
 #include "regcache.h"
@@ -1690,6 +1691,7 @@ trace_start_command (char *args, int from_tty)
 void
 download_tracepoint (struct breakpoint *t)
 {
+  CORE_ADDR tpaddr;
   char tmp[40];
   char buf[2048];
   char **tdp_actions;
@@ -1699,11 +1701,38 @@ download_tracepoint (struct breakpoint *t)
   struct agent_expr *aexpr;
   struct cleanup *aexpr_chain = NULL;
 
-  sprintf_vma (tmp, (t->loc ? t->loc->address : 0));
+  tpaddr = t->loc->address;
+  sprintf_vma (tmp, (t->loc ? tpaddr : 0));
   sprintf (buf, "QTDP:%x:%s:%c:%lx:%x", t->number, 
           tmp, /* address */
           (t->enable_state == bp_enabled ? 'E' : 'D'),
           t->step_count, t->pass_count);
+  /* Fast tracepoints are mostly handled by the target, but we can
+     tell the target how big of an instruction block should be moved
+     around.  */
+  if (t->type == bp_fast_tracepoint)
+    {
+      /* Only test for support at download time; we may not know
+        target capabilities at definition time.  */
+      if (remote_supports_fast_tracepoints ())
+       {
+         int isize;
+
+         if (gdbarch_fast_tracepoint_valid_at (get_current_arch (),
+                                               tpaddr, &isize, NULL))
+           sprintf (buf + strlen (buf), ":F%x", isize);
+         else
+           /* If it passed validation at definition but fails now,
+              something is very wrong.  */
+           internal_error (__FILE__, __LINE__,
+                           "Fast tracepoint not valid during download");
+       }
+      else
+       /* Fast tracepoints are functionally identical to regular
+          tracepoints, so don't take lack of support as a reason to
+          give up on the trace run.  */
+       warning (_("Target does not support fast tracepoints, downloading %d as regular tracepoint"), t->number);
+    }
   /* If the tracepoint has a conditional, make it into an agent
      expression and append to the definition.  */
   if (t->loc->cond)