X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Ftracepoint.c;h=702d348badf34661c736d66cd5867c3f61fcef07;hb=f61e138d9a5c10da22c01ef377034e66e6978fe6;hp=fb686e145e1939c9bd493087fd06b89cc254b2d8;hpb=4fa62494657f9b422edd7049c7207bd6c6849c3f;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index fb686e145e..702d348bad 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -19,6 +19,7 @@ along with this program. If not, see . */ #include "defs.h" +#include "arch-utils.h" #include "symtab.h" #include "frame.h" #include "gdbtypes.h" @@ -32,6 +33,8 @@ #include "breakpoint.h" #include "tracepoint.h" #include "remote.h" +extern int remote_supports_cond_tracepoints (void); +extern char *unpack_varlen_hex (char *buff, ULONGEST *result); #include "linespec.h" #include "regcache.h" #include "completer.h" @@ -41,6 +44,7 @@ #include "user-regs.h" #include "valprint.h" #include "gdbcore.h" +#include "objfiles.h" #include "ax.h" #include "ax-gdb.h" @@ -66,6 +70,10 @@ large. (400 - 31)/2 == 184 */ #define MAX_AGENT_EXPR_LEN 184 +/* A hook used to notify the UI of tracepoint operations. */ + +void (*deprecated_trace_find_hook) (char *arg, int from_tty); +void (*deprecated_trace_start_stop_hook) (int start, int from_tty); extern void (*deprecated_readline_begin_hook) (char *, ...); extern char *(*deprecated_readline_hook) (char *); @@ -104,6 +112,19 @@ extern void output_command (char *, int); /* ======= Important global variables: ======= */ +/* The list of all trace state variables. We don't retain pointers to + any of these for any reason - API is by name or number only - so it + works to have a vector of objects. */ + +typedef struct trace_state_variable tsv_s; +DEF_VEC_O(tsv_s); + +static VEC(tsv_s) *tvariables; + +/* The next integer to assign to a variable. */ + +static int next_tsv_number = 1; + /* Number of last traceframe collected. */ static int traceframe_number; @@ -119,6 +140,9 @@ static struct symtab_and_line traceframe_sal; /* Tracing command lists */ static struct cmd_list_element *tfindlist; +static char *target_buf; +static long target_buf_size; + /* ======= Important command functions: ======= */ static void trace_actions_command (char *, int); static void trace_start_command (char *, int); @@ -227,12 +251,6 @@ set_traceframe_context (struct frame_info *trace_frame) { CORE_ADDR trace_pc; - static struct type *func_string, *file_string; - static struct type *func_range, *file_range; - struct value *func_val; - struct value *file_val; - int len; - if (trace_frame == NULL) /* Cease debugging any trace buffers. */ { traceframe_fun = 0; @@ -260,20 +278,8 @@ set_traceframe_context (struct frame_info *trace_frame) || SYMBOL_LINKAGE_NAME (traceframe_fun) == NULL) clear_internalvar (lookup_internalvar ("trace_func")); else - { - len = strlen (SYMBOL_LINKAGE_NAME (traceframe_fun)); - func_range = create_range_type (func_range, - builtin_type_int32, 0, len - 1); - func_string = create_array_type (func_string, - builtin_type_true_char, func_range); - func_val = allocate_value (func_string); - deprecated_set_value_type (func_val, func_string); - memcpy (value_contents_raw (func_val), - SYMBOL_LINKAGE_NAME (traceframe_fun), - len); - deprecated_set_value_modifiable (func_val, 0); - set_internalvar (lookup_internalvar ("trace_func"), func_val); - } + set_internalvar_string (lookup_internalvar ("trace_func"), + SYMBOL_LINKAGE_NAME (traceframe_fun)); /* Save file name as "$trace_file", a debugger variable visible to users. */ @@ -281,19 +287,206 @@ set_traceframe_context (struct frame_info *trace_frame) || traceframe_sal.symtab->filename == NULL) clear_internalvar (lookup_internalvar ("trace_file")); else + set_internalvar_string (lookup_internalvar ("trace_file"), + traceframe_sal.symtab->filename); +} + +/* Create a new trace state variable with the given name. */ + +struct trace_state_variable * +create_trace_state_variable (const char *name) +{ + struct trace_state_variable tsv; + + memset (&tsv, 0, sizeof (tsv)); + tsv.name = name; + tsv.number = next_tsv_number++; + return VEC_safe_push (tsv_s, tvariables, &tsv); +} + +/* Look for a trace state variable of the given name. */ + +struct trace_state_variable * +find_trace_state_variable (const char *name) +{ + struct trace_state_variable *tsv; + int ix; + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + if (strcmp (name, tsv->name) == 0) + return tsv; + + return NULL; +} + +void +delete_trace_state_variable (const char *name) +{ + struct trace_state_variable *tsv; + int ix; + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + if (strcmp (name, tsv->name) == 0) + { + VEC_unordered_remove (tsv_s, tvariables, ix); + return; + } + + warning (_("No trace variable named \"$%s\", not deleting"), name); +} + +/* The 'tvariable' command collects a name and optional expression to + evaluate into an initial value. */ + +void +trace_variable_command (char *args, int from_tty) +{ + struct expression *expr; + struct cleanup *old_chain; + struct internalvar *intvar = NULL; + LONGEST initval = 0; + struct trace_state_variable *tsv; + + if (!args || !*args) + error_no_arg (_("trace state variable name")); + + /* All the possible valid arguments are expressions. */ + expr = parse_expression (args); + old_chain = make_cleanup (free_current_contents, &expr); + + if (expr->nelts == 0) + error (_("No expression?")); + + /* Only allow two syntaxes; "$name" and "$name=value". */ + if (expr->elts[0].opcode == OP_INTERNALVAR) + { + intvar = expr->elts[1].internalvar; + } + else if (expr->elts[0].opcode == BINOP_ASSIGN + && expr->elts[1].opcode == OP_INTERNALVAR) + { + intvar = expr->elts[2].internalvar; + initval = value_as_long (evaluate_subexpression_type (expr, 4)); + } + else + error (_("Syntax must be $NAME [ = EXPR ]")); + + if (!intvar) + error (_("No name given")); + + if (strlen (internalvar_name (intvar)) <= 0) + error (_("Must supply a non-empty variable name")); + + /* If the variable already exists, just change its initial value. */ + tsv = find_trace_state_variable (internalvar_name (intvar)); + if (tsv) { - len = strlen (traceframe_sal.symtab->filename); - file_range = create_range_type (file_range, - builtin_type_int32, 0, len - 1); - file_string = create_array_type (file_string, - builtin_type_true_char, file_range); - file_val = allocate_value (file_string); - deprecated_set_value_type (file_val, file_string); - memcpy (value_contents_raw (file_val), - traceframe_sal.symtab->filename, - len); - deprecated_set_value_modifiable (file_val, 0); - set_internalvar (lookup_internalvar ("trace_file"), file_val); + tsv->initial_value = initval; + printf_filtered (_("Trace state variable $%s now has initial value %s.\n"), + tsv->name, plongest (tsv->initial_value)); + return; + } + + /* Create a new variable. */ + tsv = create_trace_state_variable (internalvar_name (intvar)); + tsv->initial_value = initval; + + printf_filtered (_("Trace state variable $%s created, with initial value %s.\n"), + tsv->name, plongest (tsv->initial_value)); + + do_cleanups (old_chain); +} + +void +delete_trace_variable_command (char *args, int from_tty) +{ + int i, ix; + char **argv; + struct cleanup *back_to; + struct trace_state_variable *tsv; + + if (args == NULL) + { + if (query (_("Delete all trace state variables? "))) + VEC_free (tsv_s, tvariables); + dont_repeat (); + return; + } + + argv = gdb_buildargv (args); + back_to = make_cleanup_freeargv (argv); + + for (i = 0; argv[i] != NULL; i++) + { + if (*argv[i] == '$') + delete_trace_state_variable (argv[i] + 1); + else + warning (_("Name \"%s\" not prefixed with '$', ignoring"), argv[i]); + } + + do_cleanups (back_to); + + dont_repeat (); +} + +/* List all the trace state variables. */ + +static void +tvariables_info (char *args, int from_tty) +{ + struct trace_state_variable *tsv; + int ix; + char *reply; + ULONGEST tval; + + if (target_is_remote ()) + { + char buf[20]; + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + { + /* We don't know anything about the value until we get a + valid packet. */ + tsv->value_known = 0; + sprintf (buf, "qTV:%x", tsv->number); + putpkt (buf); + reply = remote_get_noisy_reply (&target_buf, &target_buf_size); + if (reply && *reply) + { + if (*reply == 'V') + { + unpack_varlen_hex (reply + 1, &tval); + tsv->value = (LONGEST) tval; + tsv->value_known = 1; + } + /* FIXME say anything about oddball replies? */ + } + } + } + + if (VEC_length (tsv_s, tvariables) == 0) + { + printf_filtered (_("No trace state variables.\n")); + return; + } + + printf_filtered (_("Name\t\t Initial\tCurrent\n")); + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + { + printf_filtered ("$%s", tsv->name); + print_spaces_filtered (17 - strlen (tsv->name), gdb_stdout); + printf_filtered ("%s ", plongest (tsv->initial_value)); + print_spaces_filtered (11 - strlen (plongest (tsv->initial_value)), gdb_stdout); + if (tsv->value_known) + printf_filtered (" %s", plongest (tsv->value)); + else if (trace_running_p || traceframe_number >= 0) + /* The value is/was defined, but we don't have it. */ + printf_filtered (_(" ")); + else + /* It is not meaningful to ask about the value. */ + printf_filtered (_(" ")); + printf_filtered ("\n"); } } @@ -751,7 +944,9 @@ add_memrange (struct collection_list *memranges, static void collect_symbol (struct collection_list *collect, struct symbol *sym, - long frame_regno, long frame_offset) + struct gdbarch *gdbarch, + long frame_regno, long frame_offset, + CORE_ADDR scope) { unsigned long len; unsigned int reg; @@ -783,7 +978,7 @@ collect_symbol (struct collection_list *collect, add_memrange (collect, memrange_absolute, offset, len); break; case LOC_REGISTER: - reg = SYMBOL_VALUE (sym); + reg = SYMBOL_REGISTER_OPS (sym)->register_number (sym, gdbarch); if (info_verbose) printf_filtered ("LOC_REG[parm] %s: ", SYMBOL_PRINT_NAME (sym)); @@ -791,7 +986,7 @@ collect_symbol (struct collection_list *collect, /* Check for doubles stored in two registers. */ /* FIXME: how about larger types stored in 3 or more regs? */ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FLT && - len > register_size (current_gdbarch, reg)) + len > register_size (gdbarch, reg)) add_register (collect, reg + 1); break; case LOC_REF_ARG: @@ -843,12 +1038,57 @@ collect_symbol (struct collection_list *collect, printf_filtered ("%s has been optimized out of existence.\n", SYMBOL_PRINT_NAME (sym)); break; + + case LOC_COMPUTED: + { + struct agent_expr *aexpr; + struct cleanup *old_chain1 = NULL; + struct agent_reqs areqs; + + aexpr = gen_trace_for_var (scope, sym); + + old_chain1 = make_cleanup_free_agent_expr (aexpr); + + ax_reqs (aexpr, &areqs); + if (areqs.flaw != agent_flaw_none) + error (_("malformed expression")); + + if (areqs.min_height < 0) + error (_("gdb: Internal error: expression has min height < 0")); + if (areqs.max_height > 20) + error (_("expression too complicated, try simplifying")); + + discard_cleanups (old_chain1); + add_aexpr (collect, aexpr); + + /* take care of the registers */ + if (areqs.reg_mask_len > 0) + { + int ndx1, ndx2; + + for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++) + { + QUIT; /* allow user to bail out with ^C */ + if (areqs.reg_mask[ndx1] != 0) + { + /* assume chars have 8 bits */ + for (ndx2 = 0; ndx2 < 8; ndx2++) + if (areqs.reg_mask[ndx1] & (1 << ndx2)) + /* it's used -- record it */ + add_register (collect, + ndx1 * 8 + ndx2); + } + } + } + } + break; } } /* Add all locals (or args) symbols to collection list */ static void -add_local_symbols (struct collection_list *collect, CORE_ADDR pc, +add_local_symbols (struct collection_list *collect, + struct gdbarch *gdbarch, CORE_ADDR pc, long frame_regno, long frame_offset, int type) { struct symbol *sym; @@ -867,8 +1107,8 @@ add_local_symbols (struct collection_list *collect, CORE_ADDR pc, : type == 'L') /* collecting Locals */ { count++; - collect_symbol (collect, sym, frame_regno, - frame_offset); + collect_symbol (collect, sym, gdbarch, + frame_regno, frame_offset, pc); } } if (BLOCK_FUNCTION (block)) @@ -1054,7 +1294,7 @@ encode_actions (struct breakpoint *t, char ***tdp_actions, *tdp_actions = NULL; *stepping_actions = NULL; - gdbarch_virtual_frame_pointer (current_gdbarch, + gdbarch_virtual_frame_pointer (t->gdbarch, t->loc->address, &frame_reg, &frame_offset); for (action = t->actions; action; action = action->next) @@ -1081,13 +1321,14 @@ encode_actions (struct breakpoint *t, char ***tdp_actions, if (0 == strncasecmp ("$reg", action_exp, 4)) { - for (i = 0; i < gdbarch_num_regs (current_gdbarch); i++) + for (i = 0; i < gdbarch_num_regs (t->gdbarch); i++) add_register (collect, i); action_exp = strchr (action_exp, ','); /* more? */ } else if (0 == strncasecmp ("$arg", action_exp, 4)) { add_local_symbols (collect, + t->gdbarch, t->loc->address, frame_reg, frame_offset, @@ -1097,6 +1338,7 @@ encode_actions (struct breakpoint *t, char ***tdp_actions, else if (0 == strncasecmp ("$loc", action_exp, 4)) { add_local_symbols (collect, + t->gdbarch, t->loc->address, frame_reg, frame_offset, @@ -1120,7 +1362,7 @@ encode_actions (struct breakpoint *t, char ***tdp_actions, { const char *name = &exp->elts[2].string; - i = user_reg_map_name_to_regnum (current_gdbarch, + i = user_reg_map_name_to_regnum (t->gdbarch, name, strlen (name)); if (i == -1) internal_error (__FILE__, __LINE__, @@ -1143,8 +1385,10 @@ encode_actions (struct breakpoint *t, char ***tdp_actions, case OP_VAR_VALUE: collect_symbol (collect, exp->elts[2].symbol, + t->gdbarch, frame_reg, - frame_offset); + frame_offset, + t->loc->address); break; default: /* full-fledged expression */ @@ -1226,9 +1470,6 @@ add_aexpr (struct collection_list *collect, struct agent_expr *aexpr) collect->next_aexpr_elt++; } -static char *target_buf; -static long target_buf_size; - /* Set "transparent" memory ranges Allow trace mechanism to treat text-like sections @@ -1284,9 +1525,11 @@ void download_tracepoint (struct breakpoint *t); static void trace_start_command (char *args, int from_tty) { + char buf[2048]; VEC(breakpoint_p) *tp_vec = NULL; int ix; struct breakpoint *t; + struct trace_state_variable *tsv; dont_repeat (); /* Like "run", dangerous to repeat accidentally. */ @@ -1304,6 +1547,19 @@ trace_start_command (char *args, int from_tty) } VEC_free (breakpoint_p, tp_vec); + /* Init any trace state variables that start with nonzero values. */ + + for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix) + { + if (tsv->initial_value != 0) + { + sprintf (buf, "QTDV:%x:%s", + tsv->number, phex ((ULONGEST) tsv->initial_value, 8)); + putpkt (buf); + remote_get_noisy_reply (&target_buf, &target_buf_size); + } + } + /* Tell target to treat text-like sections as transparent. */ remote_set_transparent_ranges (); /* Now insert traps and begin collecting data. */ @@ -1334,12 +1590,31 @@ download_tracepoint (struct breakpoint *t) char **stepping_actions; int ndx; struct cleanup *old_chain = NULL; + struct agent_expr *aexpr; + struct cleanup *aexpr_chain = NULL; sprintf_vma (tmp, (t->loc ? t->loc->address : 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); + /* If the tracepoint has a conditional, make it into an agent + expression and append to the definition. */ + if (t->loc->cond) + { + /* Only test support at download time, we may not know target + capabilities at definition time. */ + if (remote_supports_cond_tracepoints ()) + { + aexpr = gen_eval_for_expr (t->loc->address, t->loc->cond); + aexpr_chain = make_cleanup_free_agent_expr (aexpr); + sprintf (buf + strlen (buf), ":X%x,", aexpr->len); + mem2hex (aexpr->buf, buf + strlen (buf), aexpr->len); + do_cleanups (aexpr_chain); + } + else + warning (_("Target does not support conditional tracepoints, ignoring tp %d cond"), t->number); + } if (t->actions) strcat (buf, "-"); @@ -1692,6 +1967,8 @@ trace_find_line_command (char *args, int from_tty) old_chain = make_cleanup (xfree, sals.sals); if (sal.symtab == 0) { + struct gdbarch *gdbarch = get_current_arch (); + printf_filtered ("TFIND: No line number information available"); if (sal.pc != 0) { @@ -1700,7 +1977,7 @@ trace_find_line_command (char *args, int from_tty) have the symbolic address. */ printf_filtered (" for address "); wrap_here (" "); - print_address (sal.pc, gdb_stdout); + print_address (gdbarch, sal.pc, gdb_stdout); printf_filtered (";\n -- will attempt to find by PC. \n"); } else @@ -1712,13 +1989,15 @@ trace_find_line_command (char *args, int from_tty) else if (sal.line > 0 && find_line_pc_range (sal, &start_pc, &end_pc)) { + struct gdbarch *gdbarch = get_objfile_arch (sal.symtab->objfile); + if (start_pc == end_pc) { printf_filtered ("Line %d of \"%s\"", sal.line, sal.symtab->filename); wrap_here (" "); printf_filtered (" is at address "); - print_address (start_pc, gdb_stdout); + print_address (gdbarch, start_pc, gdb_stdout); wrap_here (" "); printf_filtered (" but contains no code.\n"); sal = find_pc_line (start_pc, 0); @@ -1845,6 +2124,8 @@ scope_info (char *args, int from_tty) char **canonical, *symname, *save_args = args; struct dict_iterator iter; int j, count = 0; + struct gdbarch *gdbarch; + int regno; if (args == 0 || *args == 0) error (_("requires an argument (function, line or *addr) to define a scope")); @@ -1871,6 +2152,8 @@ scope_info (char *args, int from_tty) if (symname == NULL || *symname == '\0') continue; /* probably botched, certainly useless */ + gdbarch = get_objfile_arch (SYMBOL_SYMTAB (sym)->objfile); + printf_filtered ("Symbol %s is ", symname); switch (SYMBOL_CLASS (sym)) { @@ -1893,17 +2176,25 @@ scope_info (char *args, int from_tty) break; case LOC_STATIC: printf_filtered ("in static storage at address "); - printf_filtered ("%s", paddress (SYMBOL_VALUE_ADDRESS (sym))); + printf_filtered ("%s", paddress (gdbarch, + SYMBOL_VALUE_ADDRESS (sym))); break; case LOC_REGISTER: + /* GDBARCH is the architecture associated with the objfile + the symbol is defined in; the target architecture may be + different, and may provide additional registers. However, + we do not know the target architecture at this point. + We assume the objfile architecture will contain all the + standard registers that occur in debug info in that + objfile. */ + regno = SYMBOL_REGISTER_OPS (sym)->register_number (sym, gdbarch); + if (SYMBOL_IS_ARGUMENT (sym)) printf_filtered ("an argument in register $%s", - gdbarch_register_name - (current_gdbarch, SYMBOL_VALUE (sym))); + gdbarch_register_name (gdbarch, regno)); else printf_filtered ("a local variable in register $%s", - gdbarch_register_name - (current_gdbarch, SYMBOL_VALUE (sym))); + gdbarch_register_name (gdbarch, regno)); break; case LOC_ARG: printf_filtered ("an argument at stack/frame offset %ld", @@ -1918,20 +2209,23 @@ scope_info (char *args, int from_tty) SYMBOL_VALUE (sym)); break; case LOC_REGPARM_ADDR: + /* Note comment at LOC_REGISTER. */ + regno = SYMBOL_REGISTER_OPS (sym)->register_number (sym, gdbarch); printf_filtered ("the address of an argument, in register $%s", - gdbarch_register_name - (current_gdbarch, SYMBOL_VALUE (sym))); + gdbarch_register_name (gdbarch, regno)); break; case LOC_TYPEDEF: printf_filtered ("a typedef.\n"); continue; case LOC_LABEL: printf_filtered ("a label at address "); - printf_filtered ("%s", paddress (SYMBOL_VALUE_ADDRESS (sym))); + printf_filtered ("%s", paddress (gdbarch, + SYMBOL_VALUE_ADDRESS (sym))); break; case LOC_BLOCK: printf_filtered ("a function at address "); - printf_filtered ("%s", paddress (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)))); + printf_filtered ("%s", + paddress (gdbarch, BLOCK_START (SYMBOL_BLOCK_VALUE (sym)))); break; case LOC_UNRESOLVED: msym = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (sym), @@ -1941,14 +2235,15 @@ scope_info (char *args, int from_tty) else { printf_filtered ("static storage at address "); - printf_filtered ("%s", paddress (SYMBOL_VALUE_ADDRESS (msym))); + printf_filtered ("%s", + paddress (gdbarch, SYMBOL_VALUE_ADDRESS (msym))); } break; case LOC_OPTIMIZED_OUT: printf_filtered ("optimized out.\n"); continue; case LOC_COMPUTED: - SYMBOL_OPS (sym)->describe_location (sym, gdb_stdout); + SYMBOL_COMPUTED_OPS (sym)->describe_location (sym, gdb_stdout); break; } if (SYMBOL_TYPE (sym)) @@ -2168,6 +2463,23 @@ _initialize_tracepoint (void) add_com ("tdump", class_trace, trace_dump_command, _("Print everything collected at the current tracepoint.")); + c = add_com ("tvariable", class_trace, trace_variable_command,_("\ +Define a trace state variable.\n\ +Argument is a $-prefixed name, optionally followed\n\ +by '=' and an expression that sets the initial value\n\ +at the start of tracing.")); + set_cmd_completer (c, expression_completer); + + add_cmd ("tvariable", class_trace, delete_trace_variable_command, _("\ +Delete one or more trace state variables.\n\ +Arguments are the names of the variables to delete.\n\ +If no arguments are supplied, delete all variables."), &deletelist); + /* FIXME add a trace variable completer */ + + add_info ("tvariables", tvariables_info, _("\ +Status of trace state variables and their values.\n\ +")); + add_prefix_cmd ("tfind", class_trace, trace_find_command, _("\ Select a trace frame;\n\ No argument means forward by one frame; '-' means backward by one frame."),