summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Shebs <shebs@codesourcery.com>2010-01-06 04:20:27 +0000
committerStan Shebs <shebs@codesourcery.com>2010-01-06 04:20:27 +0000
commit7a697b8dd7ac3c14e35ae3026d955aeae3ecc054 (patch)
tree62009f9b707ae6f18c12be8956f7b1e5fc586a7a
parent737a160ed9bb7bbe1ac8ebea1cdc27438213c247 (diff)
downloadbinutils-gdb-7a697b8dd7ac3c14e35ae3026d955aeae3ecc054.tar.gz
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. * gdb.texinfo (Create and Delete Tracepoints): Describe fast tracepoints. (Tracepoint Packets): Describe remote protocol for fast tracepoints. * gdb.trace/tracecmd.exp: Test ftrace.
-rw-r--r--gdb/ChangeLog40
-rw-r--r--gdb/NEWS17
-rw-r--r--gdb/arch-utils.c11
-rw-r--r--gdb/arch-utils.h4
-rw-r--r--gdb/breakpoint.c105
-rw-r--r--gdb/breakpoint.h1
-rw-r--r--gdb/doc/ChangeLog7
-rw-r--r--gdb/doc/gdb.texinfo36
-rw-r--r--gdb/gdbarch.c24
-rw-r--r--gdb/gdbarch.h6
-rwxr-xr-xgdb/gdbarch.sh3
-rw-r--r--gdb/i386-tdep.c47
-rw-r--r--gdb/remote.c24
-rw-r--r--gdb/testsuite/ChangeLog4
-rw-r--r--gdb/testsuite/gdb.trace/tracecmd.exp12
-rw-r--r--gdb/tracepoint.c31
16 files changed, 353 insertions, 19 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4ba426e8dda..74aba43077c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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.
diff --git a/gdb/NEWS b/gdb/NEWS
index 184c4e64c29..544a1aa510d 100644
--- 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
diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index 9a64a8c79a1..55011754bcd 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -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 */
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index 0cae9f87af6..6fee1e57faa 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -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
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 58102ec1e17..813080a7097 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -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\
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index b4ea3391111..01fc0e96691 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -121,6 +121,7 @@ enum bptype
bp_catchpoint,
bp_tracepoint,
+ bp_fast_tracepoint,
/* Event for JIT compiled code generation or deletion. */
bp_jit_event,
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index deb3a14725b..48d187bb021 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -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".
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index d0997b3525a..d23c67519c6 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 3680dc441b4..9d7702758f4 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -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)
@@ -826,6 +830,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *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));
fprintf_unfiltered (file,
@@ -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. */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index d392ece7446..18267c9c5fe 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -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)
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 426a7de5f4c..9474addc5c5 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -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
}
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index f4d037c3494..eea4ff4dd97 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -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;
+}
+
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;
}
diff --git a/gdb/remote.c b/gdb/remote.c
index 7af67e54bd3..cba9f5b81e7 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 2d1b83429e5..6e4870ec8fa 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -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.
diff --git a/gdb/testsuite/gdb.trace/tracecmd.exp b/gdb/testsuite/gdb.trace/tracecmd.exp
index 0fd89680c67..5ce31badcba 100644
--- a/gdb/testsuite/gdb.trace/tracecmd.exp
+++ b/gdb/testsuite/gdb.trace/tracecmd.exp
@@ -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" }
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index b61362f4bdd..8ec81a3a1d2 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -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)