From 7a697b8dd7ac3c14e35ae3026d955aeae3ecc054 Mon Sep 17 00:00:00 2001 From: Stan Shebs Date: Wed, 6 Jan 2010 04:20:27 +0000 Subject: [PATCH] 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. --- gdb/ChangeLog | 40 ++++++++++ gdb/NEWS | 17 ++++- gdb/arch-utils.c | 11 +++ gdb/arch-utils.h | 4 + gdb/breakpoint.c | 105 ++++++++++++++++++++++++--- gdb/breakpoint.h | 1 + gdb/doc/ChangeLog | 7 ++ gdb/doc/gdb.texinfo | 36 +++++++-- gdb/gdbarch.c | 24 ++++++ gdb/gdbarch.h | 6 ++ gdb/gdbarch.sh | 3 + gdb/i386-tdep.c | 47 ++++++++++++ gdb/remote.c | 24 ++++++ gdb/testsuite/ChangeLog | 4 + gdb/testsuite/gdb.trace/tracecmd.exp | 12 +++ gdb/tracepoint.c | 31 +++++++- 16 files changed, 353 insertions(+), 19 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4ba426e8dd..74aba43077 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,43 @@ +2010-01-05 Stan Shebs + + 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 * gdb-gdb.py: New file. diff --git a/gdb/NEWS b/gdb/NEWS index 184c4e64c2..544a1aa510 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 9a64a8c79a..55011754bc 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 0cae9f87af..6fee1e57fa 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 58102ec1e1..813080a709 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 b4ea339111..01fc0e9669 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 deb3a14725..48d187bb02 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,10 @@ +2010-01-05 Stan Shebs + + * gdb.texinfo (Create and Delete Tracepoints): Describe fast + tracepoints. + (Tracepoint Packets): Describe remote protocol for fast + tracepoints. + 2010-01-01 Joel Brobecker Update the "Start of New Year Procedure". diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index d0997b3525..d23c67519c 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 3680dc441b..9d7702758f 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) @@ -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. */ diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index d392ece744..18267c9c5f 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 426a7de5f4..9474addc5c 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 f4d037c349..eea4ff4dd9 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 7af67e54bd..cba9f5b81e 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 2d1b83429e..6e4870ec8f 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2010-01-05 Stan Shebs + + * gdb.trace/tracecmd.exp: Test ftrace. + 2010-01-04 Ulrich Weigand * 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 0fd89680c6..5ce31badcb 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 b61362f4bd..8ec81a3a1d 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) -- 2.34.1