X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Ftracepoint.c;h=3484d7ad3b61aea01dbeccaac4f479910fc15920;hb=3c853d931322f71b01a217f05bb8302f32a263d2;hp=c25be707259c8334fa53b144d1519dcebad337ed;hpb=3149d8c1150e24222c6c41e2c0fdde42f202d750;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index c25be70725..3484d7ad3b 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -46,7 +46,8 @@ #include "gdbthread.h" #include "stack.h" #include "gdbcore.h" - +#include "remote.h" +#include "source.h" #include "ax.h" #include "ax-gdb.h" @@ -365,6 +366,7 @@ trace_variable_command (char *args, int from_tty) tsv->initial_value = initval; printf_filtered (_("Trace state variable $%s now has initial value %s.\n"), tsv->name, plongest (tsv->initial_value)); + do_cleanups (old_chain); return; } @@ -381,10 +383,9 @@ trace_variable_command (char *args, int from_tty) void delete_trace_variable_command (char *args, int from_tty) { - int i, ix; + int ix; char **argv; struct cleanup *back_to; - struct trace_state_variable *tsv; if (args == NULL) { @@ -397,12 +398,12 @@ delete_trace_variable_command (char *args, int from_tty) argv = gdb_buildargv (args); back_to = make_cleanup_freeargv (argv); - for (i = 0; argv[i] != NULL; i++) + for (ix = 0; argv[ix] != NULL; ix++) { - if (*argv[i] == '$') - delete_trace_state_variable (argv[i] + 1); + if (*argv[ix] == '$') + delete_trace_state_variable (argv[ix] + 1); else - warning (_("Name \"%s\" not prefixed with '$', ignoring"), argv[i]); + warning (_("Name \"%s\" not prefixed with '$', ignoring"), argv[ix]); } do_cleanups (back_to); @@ -445,7 +446,7 @@ tvariables_info_1 (void) back_to2 = make_cleanup_ui_out_tuple_begin_end (uiout, "variable"); - name = concat ("$", tsv->name, NULL); + name = concat ("$", tsv->name, (char *) NULL); make_cleanup (xfree, name); ui_out_field_string (uiout, "name", name); ui_out_field_string (uiout, "initial", plongest (tsv->initial_value)); @@ -559,16 +560,16 @@ trace_actions_command (char *args, int from_tty) internal errors. */ static void -report_agent_reqs_errors (struct agent_expr *aexpr, struct agent_reqs *areqs) +report_agent_reqs_errors (struct agent_expr *aexpr) { /* All of the "flaws" are serious bytecode generation issues that should never occur. */ - if (areqs->flaw != agent_flaw_none) + if (aexpr->flaw != agent_flaw_none) internal_error (__FILE__, __LINE__, _("expression is malformed")); /* If analysis shows a stack underflow, GDB must have done something badly wrong in its bytecode generation. */ - if (areqs->min_height < 0) + if (aexpr->min_height < 0) internal_error (__FILE__, __LINE__, _("expression has min height < 0")); @@ -578,7 +579,7 @@ report_agent_reqs_errors (struct agent_expr *aexpr, struct agent_reqs *areqs) depth roughly corresponds to parenthesization, so a limit of 20 amounts to 20 levels of expression nesting, which is actually a pretty big hairy expression. */ - if (areqs->max_height > 20) + if (aexpr->max_height > 20) error (_("Expression is too complicated.")); } @@ -592,7 +593,6 @@ validate_actionline (char **line, struct breakpoint *t) char *p, *tmp_p; struct bp_location *loc; struct agent_expr *aexpr; - struct agent_reqs areqs; /* if EOF is typed, *line is NULL */ if (*line == NULL) @@ -622,9 +622,10 @@ validate_actionline (char **line, struct breakpoint *t) if (*p == '$') /* look for special pseudo-symbols */ { - if ((0 == strncasecmp ("reg", p + 1, 3)) || - (0 == strncasecmp ("arg", p + 1, 3)) || - (0 == strncasecmp ("loc", p + 1, 3))) + if (0 == strncasecmp ("reg", p + 1, 3) + || 0 == strncasecmp ("arg", p + 1, 3) + || 0 == strncasecmp ("loc", p + 1, 3) + || 0 == strncasecmp ("_sdata", p + 1, 6)) { p = strchr (p, ','); continue; @@ -662,10 +663,9 @@ validate_actionline (char **line, struct breakpoint *t) if (aexpr->len > MAX_AGENT_EXPR_LEN) error (_("Expression is too complicated.")); - ax_reqs (aexpr, &areqs); - (void) make_cleanup (xfree, areqs.reg_mask); + ax_reqs (aexpr); - report_agent_reqs_errors (aexpr, &areqs); + report_agent_reqs_errors (aexpr); do_cleanups (old_chain); } @@ -698,10 +698,8 @@ validate_actionline (char **line, struct breakpoint *t) if (aexpr->len > MAX_AGENT_EXPR_LEN) error (_("Expression is too complicated.")); - ax_reqs (aexpr, &areqs); - (void) make_cleanup (xfree, areqs.reg_mask); - - report_agent_reqs_errors (aexpr, &areqs); + ax_reqs (aexpr); + report_agent_reqs_errors (aexpr); do_cleanups (old_chain); } @@ -750,6 +748,9 @@ struct collection_list long next_aexpr_elt; struct agent_expr **aexpr_list; + /* True is the user requested a collection of "$_sdata", "static + tracepoint data". */ + int strace_data; } tracepoint_list, stepping_list; @@ -973,7 +974,6 @@ collect_symbol (struct collection_list *collect, { struct agent_expr *aexpr; struct cleanup *old_chain1 = NULL; - struct agent_reqs areqs; aexpr = gen_trace_for_var (scope, gdbarch, sym); @@ -989,26 +989,26 @@ collect_symbol (struct collection_list *collect, old_chain1 = make_cleanup_free_agent_expr (aexpr); - ax_reqs (aexpr, &areqs); + ax_reqs (aexpr); - report_agent_reqs_errors (aexpr, &areqs); + report_agent_reqs_errors (aexpr); discard_cleanups (old_chain1); add_aexpr (collect, aexpr); /* take care of the registers */ - if (areqs.reg_mask_len > 0) + if (aexpr->reg_mask_len > 0) { int ndx1, ndx2; - for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++) + for (ndx1 = 0; ndx1 < aexpr->reg_mask_len; ndx1++) { QUIT; /* allow user to bail out with ^C */ - if (areqs.reg_mask[ndx1] != 0) + if (aexpr->reg_mask[ndx1] != 0) { /* assume chars have 8 bits */ for (ndx2 = 0; ndx2 < 8; ndx2++) - if (areqs.reg_mask[ndx1] & (1 << ndx2)) + if (aexpr->reg_mask[ndx1] & (1 << ndx2)) /* it's used -- record it */ add_register (collect, ndx1 * 8 + ndx2); } @@ -1090,6 +1090,14 @@ add_local_symbols (struct collection_list *collect, } } +static void +add_static_trace_data (struct collection_list *collection) +{ + if (info_verbose) + printf_filtered ("collect static trace data\n"); + collection->strace_data = 1; +} + /* worker function */ static void clear_collection_list (struct collection_list *list) @@ -1104,6 +1112,7 @@ clear_collection_list (struct collection_list *list) } list->next_aexpr_elt = 0; memset (list->regs_mask, 0, sizeof (list->regs_mask)); + list->strace_data = 0; } /* reduce a collection list to string form (for gdb protocol) */ @@ -1118,9 +1127,19 @@ stringify_collection_list (struct collection_list *list, char *string) char *end; long i; - count = 1 + list->next_memrange + list->next_aexpr_elt + 1; + count = 1 + 1 + list->next_memrange + list->next_aexpr_elt + 1; str_list = (char *(*)[]) xmalloc (count * sizeof (char *)); + if (list->strace_data) + { + if (info_verbose) + printf_filtered ("\nCollecting static trace data\n"); + end = temp_buf; + *end++ = 'L'; + (*str_list)[ndx] = savestring (temp_buf, end - temp_buf); + ndx++; + } + for (i = sizeof (list->regs_mask) - 1; i > 0; i--) if (list->regs_mask[i] != 0) /* skip leading zeroes in regs_mask */ break; @@ -1230,7 +1249,6 @@ encode_actions_1 (struct command_line *action, { char *action_exp; struct expression *exp = NULL; - struct command_line *actions; int i; struct value *tempval; struct cmd_list_element *cmd; @@ -1281,12 +1299,16 @@ encode_actions_1 (struct command_line *action, 'L'); action_exp = strchr (action_exp, ','); /* more? */ } + else if (0 == strncasecmp ("$_sdata", action_exp, 7)) + { + add_static_trace_data (collect); + action_exp = strchr (action_exp, ','); /* more? */ + } else { unsigned long addr, len; struct cleanup *old_chain = NULL; struct cleanup *old_chain1 = NULL; - struct agent_reqs areqs; exp = parse_exp_1 (&action_exp, block_for_pc (tloc->address), 1); @@ -1332,27 +1354,27 @@ encode_actions_1 (struct command_line *action, old_chain1 = make_cleanup_free_agent_expr (aexpr); - ax_reqs (aexpr, &areqs); + ax_reqs (aexpr); - report_agent_reqs_errors (aexpr, &areqs); + report_agent_reqs_errors (aexpr); discard_cleanups (old_chain1); add_aexpr (collect, aexpr); /* take care of the registers */ - if (areqs.reg_mask_len > 0) + if (aexpr->reg_mask_len > 0) { int ndx1; int ndx2; - for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++) + for (ndx1 = 0; ndx1 < aexpr->reg_mask_len; ndx1++) { QUIT; /* allow user to bail out with ^C */ - if (areqs.reg_mask[ndx1] != 0) + if (aexpr->reg_mask[ndx1] != 0) { /* assume chars have 8 bits */ for (ndx2 = 0; ndx2 < 8; ndx2++) - if (areqs.reg_mask[ndx1] & (1 << ndx2)) + if (aexpr->reg_mask[ndx1] & (1 << ndx2)) /* it's used -- record it */ add_register (collect, ndx1 * 8 + ndx2); @@ -1375,10 +1397,8 @@ encode_actions_1 (struct command_line *action, action_exp++; { - unsigned long addr, len; struct cleanup *old_chain = NULL; struct cleanup *old_chain1 = NULL; - struct agent_reqs areqs; exp = parse_exp_1 (&action_exp, block_for_pc (tloc->address), 1); @@ -1387,9 +1407,8 @@ encode_actions_1 (struct command_line *action, aexpr = gen_eval_for_expr (tloc->address, exp); old_chain1 = make_cleanup_free_agent_expr (aexpr); - ax_reqs (aexpr, &areqs); - - report_agent_reqs_errors (aexpr, &areqs); + ax_reqs (aexpr); + report_agent_reqs_errors (aexpr); discard_cleanups (old_chain1); /* Even though we're not officially collecting, add @@ -1408,8 +1427,8 @@ encode_actions_1 (struct command_line *action, here. */ gdb_assert (stepping_list); - encode_actions_1 (action->body_list[0], t, tloc, frame_reg, frame_offset, - stepping_list, NULL); + encode_actions_1 (action->body_list[0], t, tloc, frame_reg, + frame_offset, stepping_list, NULL); } else error (_("Invalid tracepoint command '%s'"), action->line); @@ -1484,7 +1503,7 @@ add_aexpr (struct collection_list *collect, struct agent_expr *aexpr) { collect->aexpr_list = xrealloc (collect->aexpr_list, - 2 * collect->aexpr_listsize * sizeof (struct agent_expr *)); + 2 * collect->aexpr_listsize * sizeof (struct agent_expr *)); collect->aexpr_listsize *= 2; } collect->aexpr_list[collect->next_aexpr_elt] = aexpr; @@ -1495,12 +1514,11 @@ add_aexpr (struct collection_list *collect, struct agent_expr *aexpr) void start_tracing (void) { - char buf[2048]; VEC(breakpoint_p) *tp_vec = NULL; int ix; struct breakpoint *t; struct trace_state_variable *tsv; - int any_enabled = 0; + int any_enabled = 0, num_to_download = 0; tp_vec = all_tracepoints (); @@ -1514,10 +1532,15 @@ start_tracing (void) for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++) { if (t->enable_state == bp_enabled) - { - any_enabled = 1; - break; - } + any_enabled = 1; + + if ((t->type == bp_fast_tracepoint + ? may_insert_fast_tracepoints + : may_insert_tracepoints)) + ++num_to_download; + else + warning (_("May not insert %stracepoints, skipping tracepoint %d"), + (t->type == bp_fast_tracepoint ? "fast " : ""), t->number); } /* No point in tracing with only disabled tracepoints. */ @@ -1527,10 +1550,21 @@ start_tracing (void) error (_("No tracepoints enabled, not starting trace")); } + if (num_to_download <= 0) + { + VEC_free (breakpoint_p, tp_vec); + error (_("No tracepoints that may be downloaded, not starting trace")); + } + target_trace_init (); for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++) { + if ((t->type == bp_fast_tracepoint + ? !may_insert_fast_tracepoints + : !may_insert_tracepoints)) + continue; + t->number_on_target = 0; target_download_tracepoint (t); t->number_on_target = t->number; @@ -1626,10 +1660,6 @@ trace_status_command (char *args, int from_tty) else if (ts->running) { printf_filtered (_("Trace is running on the target.\n")); - if (disconnected_tracing) - printf_filtered (_("Trace will continue if GDB disconnects.\n")); - else - printf_filtered (_("Trace will stop if GDB disconnects.\n")); } else { @@ -1699,6 +1729,14 @@ trace_status_command (char *args, int from_tty) ts->buffer_free); } + if (ts->disconnected_tracing) + printf_filtered (_("Trace will continue if GDB disconnects.\n")); + else + printf_filtered (_("Trace will stop if GDB disconnects.\n")); + + if (ts->circular_buffer) + printf_filtered (_("Trace buffer is circular.\n")); + /* Now report on what we're doing with tfind. */ if (traceframe_number >= 0) printf_filtered (_("Looking at trace frame %d, tracepoint %d.\n"), @@ -1718,7 +1756,6 @@ trace_status_mi (int on_stop) { struct trace_status *ts = current_trace_status (); int status; - char *string_status; status = target_get_trace_status (ts); @@ -1792,18 +1829,24 @@ trace_status_mi (int on_stop) } } - - if ((int) ts->traceframe_count != -1) + if (ts->traceframe_count != -1) ui_out_field_int (uiout, "frames", ts->traceframe_count); - if ((int) ts->buffer_size != -1) - ui_out_field_int (uiout, "buffer-size", (int) ts->buffer_size); - if ((int) ts->buffer_free != -1) - ui_out_field_int (uiout, "buffer-free", (int) ts->buffer_free); + if (ts->traceframes_created != -1) + ui_out_field_int (uiout, "frames-created", ts->traceframes_created); + if (ts->buffer_size != -1) + ui_out_field_int (uiout, "buffer-size", ts->buffer_size); + if (ts->buffer_free != -1) + ui_out_field_int (uiout, "buffer-free", ts->buffer_free); + + ui_out_field_int (uiout, "disconnected", ts->disconnected_tracing); + ui_out_field_int (uiout, "circular", ts->circular_buffer); } - +/* This function handles the details of what to do about an ongoing + tracing run if the user has asked to detach or otherwise disconnect + from the target. */ void -disconnect_or_stop_tracing (int from_tty) +disconnect_tracing (int from_tty) { /* It can happen that the target that was tracing went away on its own, and we didn't notice. Get a status update, and if the @@ -1812,18 +1855,23 @@ disconnect_or_stop_tracing (int from_tty) if (target_get_trace_status (current_trace_status ()) < 0) current_trace_status ()->running = 0; + /* If running interactively, give the user the option to cancel and + then decide what to do differently with the run. Scripts are + just going to disconnect and let the target deal with it, + according to how it's been instructed previously via + disconnected-tracing. */ if (current_trace_status ()->running && from_tty) { - int cont = query (_("Trace is running. Continue tracing after detach? ")); - /* Note that we send the query result without affecting the - user's setting of disconnected_tracing, so that the answer is - a one-time-only. */ - send_disconnected_tracing_value (cont); - - /* Also ensure that we do the equivalent of a tstop command if - tracing is not to continue after the detach. */ - if (!cont) - stop_tracing (); + if (current_trace_status ()->disconnected_tracing) + { + if (!query (_("Trace is running and will continue after detach; detach anyway? "))) + error (_("Not confirmed.")); + } + else + { + if (!query (_("Trace is running but will stop on detach; detach anyway? "))) + error (_("Not confirmed.")); + } } /* Also we want to be out of tfind mode, otherwise things can get @@ -1841,11 +1889,18 @@ tfind_1 (enum trace_find_type type, int num, int from_tty) { int target_frameno = -1, target_tracept = -1; - struct frame_id old_frame_id; - char *reply; + struct frame_id old_frame_id = null_frame_id; struct breakpoint *tp; - old_frame_id = get_frame_id (get_current_frame ()); + /* Only try to get the current stack frame if we have a chance of + succeeding. In particular, if we're trying to get a first trace + frame while all threads are running, it's not going to succeed, + so leave it with a default value and let the frame comparison + below (correctly) decide to print out the source location of the + trace frame. */ + if (!(type == tfind_number && num == -1) + && (has_stack_frames () || traceframe_number >= 0)) + old_frame_id = get_frame_id (get_current_frame ()); target_frameno = target_trace_find (type, num, addr1, addr2, &target_tracept); @@ -1858,7 +1913,7 @@ tfind_1 (enum trace_find_type type, int num, } else if (target_frameno == -1) { - /* A request for a non-existant trace frame has failed. + /* A request for a non-existent trace frame has failed. Our response will be different, depending on FROM_TTY: If FROM_TTY is true, meaning that this command was @@ -1925,8 +1980,10 @@ tfind_1 (enum trace_find_type type, int num, { if (ui_out_is_mi_like_p (uiout)) ui_out_field_string (uiout, "found", "0"); - else - printf_unfiltered (_("No trace frame found")); + else if (type == tfind_number && num == -1) + printf_unfiltered (_("No longer looking at any trace frame\n")); + else /* this case may never occur, check */ + printf_unfiltered (_("No trace frame found\n")); } /* If we're in nonstop mode and getting out of looking at trace @@ -1937,7 +1994,7 @@ tfind_1 (enum trace_find_type type, int num, { enum print_what print_what; - /* NOTE: in immitation of the step command, try to determine + /* NOTE: in imitation of the step command, try to determine whether we have made a transition from one function to another. If so, we'll print the "stack frame" (ie. the new function and it's arguments) -- otherwise we'll just show the @@ -2031,7 +2088,6 @@ static void trace_find_pc_command (char *args, int from_tty) { CORE_ADDR pc; - char tmp[40]; if (current_trace_status ()->running && !current_trace_status ()->from_file) error ("May not look at trace frames while trace is running."); @@ -2089,7 +2145,6 @@ trace_find_line_command (char *args, int from_tty) struct symtabs_and_lines sals; struct symtab_and_line sal; struct cleanup *old_chain; - char startpc_str[40], endpc_str[40]; if (current_trace_status ()->running && !current_trace_status ()->from_file) error ("May not look at trace frames while trace is running."); @@ -2153,7 +2208,6 @@ static void trace_find_range_command (char *args, int from_tty) { static CORE_ADDR start, stop; - char start_str[40], stop_str[40]; char *tmp; if (current_trace_status ()->running && !current_trace_status ()->from_file) @@ -2187,7 +2241,6 @@ static void trace_find_outside_command (char *args, int from_tty) { CORE_ADDR start, stop; - char start_str[40], stop_str[40]; char *tmp; if (current_trace_status ()->running && !current_trace_status ()->from_file) @@ -2346,7 +2399,9 @@ scope_info (char *args, int from_tty) printf_filtered ("optimized out.\n"); continue; case LOC_COMPUTED: - SYMBOL_COMPUTED_OPS (sym)->describe_location (sym, gdb_stdout); + SYMBOL_COMPUTED_OPS (sym)->describe_location (sym, + BLOCK_START (block), + gdb_stdout); break; } if (SYMBOL_TYPE (sym)) @@ -2468,6 +2523,9 @@ trace_dump_command (char *args, int from_tty) struct breakpoint *t; int stepping_frame = 0; struct bp_location *loc; + char *line, *default_collect_line = NULL; + struct command_line *actions, *default_collect_action = NULL; + struct cleanup *old_chain = NULL; if (tracepoint_number == -1) { @@ -2499,7 +2557,29 @@ trace_dump_command (char *args, int from_tty) if (loc->address == regcache_read_pc (regcache)) stepping_frame = 0; - trace_dump_actions (breakpoint_commands (t), 0, stepping_frame, from_tty); + actions = breakpoint_commands (t); + + /* If there is a default-collect list, make up a collect command, + prepend to the tracepoint's commands, and pass the whole mess to + the trace dump scanner. We need to validate because + default-collect might have been junked since the trace run. */ + if (*default_collect) + { + default_collect_line = xstrprintf ("collect %s", default_collect); + old_chain = make_cleanup (xfree, default_collect_line); + line = default_collect_line; + validate_actionline (&line, t); + default_collect_action = xmalloc (sizeof (struct command_line)); + make_cleanup (xfree, default_collect_action); + default_collect_action->next = actions; + default_collect_action->line = line; + actions = default_collect_action; + } + + trace_dump_actions (actions, 0, stepping_frame, from_tty); + + if (*default_collect) + do_cleanups (old_chain); } /* Encode a piece of a tracepoint's source-level definition in a form @@ -2563,7 +2643,7 @@ trace_save (const char *filename, int target_does_save) pathname = tilde_expand (filename); cleanup = make_cleanup (xfree, pathname); - fp = fopen (pathname, "w"); + fp = fopen (pathname, "wb"); if (!fp) error (_("Unable to open file '%s' for saving trace data (%s)"), filename, safe_strerror (errno)); @@ -2587,6 +2667,7 @@ trace_save (const char *filename, int target_does_save) if (ts->stop_reason == tracepoint_error) { char *buf = (char *) alloca (strlen (ts->error_desc) * 2 + 1); + bin2hex ((gdb_byte *) ts->error_desc, buf, 0); fprintf (fp, ":%s", buf); } @@ -2599,6 +2680,10 @@ trace_save (const char *filename, int target_does_save) fprintf (fp, ";tfree:%x", ts->buffer_free); if (ts->buffer_size >= 0) fprintf (fp, ";tsize:%x", ts->buffer_size); + if (ts->disconnected_tracing) + fprintf (fp, ";disconn:%x", ts->disconnected_tracing); + if (ts->circular_buffer) + fprintf (fp, ";circular:%x", ts->circular_buffer); fprintf (fp, "\n"); /* Note that we want to upload tracepoints and save those, rather @@ -2649,7 +2734,7 @@ trace_save (const char *filename, int target_does_save) for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a) fprintf (fp, "tp A%x:%s:%s\n", utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act); - for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a) + for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a) fprintf (fp, "tp S%x:%s:%s\n", utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act); if (utp->at_string) @@ -3054,13 +3139,17 @@ merge_uploaded_trace_state_variables (struct uploaded_tsv **uploaded_tsvs) { tsv = find_matching_tsv (utsv); if (tsv) - printf_filtered (_("Assuming trace state variable $%s is same as target's variable %d.\n"), - tsv->name, utsv->number); + { + if (info_verbose) + printf_filtered (_("Assuming trace state variable $%s is same as target's variable %d.\n"), + tsv->name, utsv->number); + } else { tsv = create_tsv_from_upload (utsv); - printf_filtered (_("Created trace state variable $%s for target's variable %d.\n"), - tsv->name, utsv->number); + if (info_verbose) + printf_filtered (_("Created trace state variable $%s for target's variable %d.\n"), + tsv->name, utsv->number); } /* Give precedence to numberings that come from the target. */ if (tsv) @@ -3122,7 +3211,7 @@ tfile_open (char *filename, int from_tty) filename = tilde_expand (filename); if (!IS_ABSOLUTE_PATH(filename)) { - temp = concat (current_directory, "/", filename, (char *)NULL); + temp = concat (current_directory, "/", filename, (char *) NULL); xfree (filename); filename = temp; } @@ -3167,6 +3256,8 @@ tfile_open (char *filename, int from_tty) ts->stop_reason = trace_stop_reason_unknown; ts->traceframe_count = -1; ts->buffer_free = 0; + ts->disconnected_tracing = 0; + ts->circular_buffer = 0; /* Read through a section of newline-terminated lines that define things like tracepoints. */ @@ -3265,8 +3356,6 @@ tfile_interp_line (char *line, /* Parse the part of trace status syntax that is shared between the remote protocol and the trace file reader. */ -extern char *unpack_varlen_hex (char *buff, ULONGEST *result); - void parse_trace_status (char *line, struct trace_status *ts) { @@ -3282,6 +3371,8 @@ parse_trace_status (char *line, struct trace_status *ts) ts->traceframes_created = -1; ts->buffer_free = -1; ts->buffer_size = -1; + ts->disconnected_tracing = 0; + ts->circular_buffer = 0; while (*p++) { @@ -3310,6 +3401,11 @@ Status line: '%s'\n"), p, line); p = unpack_varlen_hex (++p1, &val); ts->stop_reason = tstop_command; } + else if (strncmp (p, stop_reason_names[trace_disconnected], p1 - p) == 0) + { + p = unpack_varlen_hex (++p1, &val); + ts->stop_reason = trace_disconnected; + } else if (strncmp (p, stop_reason_names[tracepoint_error], p1 - p) == 0) { p2 = strchr (++p1, ':'); @@ -3348,6 +3444,16 @@ Status line: '%s'\n"), p, line); p = unpack_varlen_hex (++p1, &val); ts->buffer_size = val; } + else if (strncmp (p, "disconn", p1 - p) == 0) + { + p = unpack_varlen_hex (++p1, &val); + ts->disconnected_tracing = val; + } + else if (strncmp (p, "circular", p1 - p) == 0) + { + p = unpack_varlen_hex (++p1, &val); + ts->circular_buffer = val; + } else { /* Silently skip unknown optional info. */ @@ -3370,9 +3476,9 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp) char *p; char piece; ULONGEST num, addr, step, pass, orig_size, xlen, start; - int enabled, i, end; + int enabled, end; enum bptype type; - char *cond, *srctype, *src, *buf; + char *cond, *srctype, *buf; struct uploaded_tp *utp = NULL; p = line; @@ -3402,6 +3508,11 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp) p++; p = unpack_varlen_hex (p, &orig_size); } + else if (*p == 'S') + { + type = bp_static_tracepoint; + p++; + } else if (*p == 'X') { p++; @@ -3554,6 +3665,9 @@ tfile_get_traceframe_address (off_t tframe_offset) perror_with_name (trace_filename); else if (gotten < 2) error (_("Premature end of file while reading trace file")); + tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2, + gdbarch_byte_order + (target_gdbarch)); tp = get_tracepoint_by_number_on_target (tpnum); /* FIXME this is a poor heuristic if multiple locations */ @@ -3577,7 +3691,7 @@ tfile_trace_find (enum trace_find_type type, int num, { short tpnum; int tfnum = 0, found = 0, gotten; - int data_size; + unsigned int data_size; struct breakpoint *tp; off_t offset, tframe_offset; ULONGEST tfaddr; @@ -3592,6 +3706,9 @@ tfile_trace_find (enum trace_find_type type, int num, perror_with_name (trace_filename); else if (gotten < 2) error (_("Premature end of file while reading trace file")); + tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2, + gdbarch_byte_order + (target_gdbarch)); offset += 2; if (tpnum == 0) break; @@ -3600,6 +3717,9 @@ tfile_trace_find (enum trace_find_type type, int num, perror_with_name (trace_filename); else if (gotten < 4) error (_("Premature end of file while reading trace file")); + data_size = (unsigned int) extract_unsigned_integer + ((gdb_byte *) &data_size, 4, + gdbarch_byte_order (target_gdbarch)); offset += 4; switch (type) { @@ -3659,7 +3779,7 @@ tfile_fetch_registers (struct target_ops *ops, { struct gdbarch *gdbarch = get_regcache_arch (regcache); char block_type; - int i, pos, offset, regn, regsize, gotten, pc_regno; + int pos, offset, regn, regsize, gotten, pc_regno; unsigned short mlen; char *regs; @@ -3721,6 +3841,10 @@ tfile_fetch_registers (struct target_ops *ops, perror_with_name (trace_filename); else if (gotten < 2) error (_("Premature end of file while reading trace file")); + mlen = (unsigned short) + extract_unsigned_integer ((gdb_byte *) &mlen, 2, + gdbarch_byte_order + (target_gdbarch)); lseek (trace_fd, mlen, SEEK_CUR); pos += (8 + 2 + mlen); break; @@ -3813,12 +3937,18 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, perror_with_name (trace_filename); else if (gotten < 8) error (_("Premature end of file while reading trace file")); - + maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8, + gdbarch_byte_order + (target_gdbarch)); gotten = read (trace_fd, &mlen, 2); if (gotten < 0) perror_with_name (trace_filename); else if (gotten < 2) error (_("Premature end of file while reading trace file")); + mlen = (unsigned short) + extract_unsigned_integer ((gdb_byte *) &mlen, 2, + gdbarch_byte_order + (target_gdbarch)); /* If the block includes the first part of the desired range, return as much it has; GDB will re-request the remainder, which might be in a different block of this @@ -3829,7 +3959,14 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, if (amt > len) amt = len; - read (trace_fd, readbuf, amt); + gotten = read (trace_fd, readbuf, amt); + if (gotten < 0) + perror_with_name (trace_filename); + /* While it's acceptable to return less than was + originally asked for, it's not acceptable to return + less than what this block claims to contain. */ + else if (gotten < amt) + error (_("Premature end of file while reading trace file")); return amt; } lseek (trace_fd, mlen, SEEK_CUR); @@ -3854,7 +3991,7 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, { asection *s; bfd_size_type size; - bfd_vma lma; + bfd_vma vma; for (s = exec_bfd->sections; s; s = s->next) { @@ -3862,16 +3999,16 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, (s->flags & SEC_READONLY) == 0) continue; - lma = s->lma; + vma = s->vma; size = bfd_get_section_size (s); - if (lma <= offset && offset < (lma + size)) + if (vma <= offset && offset < (vma + size)) { - amt = (lma + size) - offset; + amt = (vma + size) - offset; if (amt > len) amt = len; amt = bfd_get_section_contents (exec_bfd, s, - readbuf, offset - lma, amt); + readbuf, offset - vma, amt); return amt; } } @@ -3914,6 +4051,10 @@ tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val) perror_with_name (trace_filename); else if (gotten < 2) error (_("Premature end of file while reading trace file")); + mlen = (unsigned short) + extract_unsigned_integer ((gdb_byte *) &mlen, 2, + gdbarch_byte_order + (target_gdbarch)); lseek (trace_fd, mlen, SEEK_CUR); pos += (8 + 2 + mlen); break; @@ -3923,6 +4064,9 @@ tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val) perror_with_name (trace_filename); else if (gotten < 4) error (_("Premature end of file while reading trace file")); + vnum = (int) extract_signed_integer ((gdb_byte *) &vnum, 4, + gdbarch_byte_order + (target_gdbarch)); if (tsvnum == vnum) { gotten = read (trace_fd, val, 8); @@ -3930,6 +4074,9 @@ tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val) perror_with_name (trace_filename); else if (gotten < 8) error (_("Premature end of file while reading trace file")); + *val = extract_signed_integer ((gdb_byte *)val, 8, + gdbarch_byte_order + (target_gdbarch)); return 1; } lseek (trace_fd, 8, SEEK_CUR); @@ -3984,8 +4131,6 @@ init_tfile_ops (void) tfile_ops.to_get_trace_status = tfile_get_trace_status; tfile_ops.to_trace_find = tfile_trace_find; tfile_ops.to_get_trace_state_variable_value = tfile_get_trace_state_variable_value; - /* core_stratum might seem more logical, but GDB doesn't like having - more than one core_stratum vector. */ tfile_ops.to_stratum = process_stratum; tfile_ops.to_has_all_memory = tfile_has_all_memory; tfile_ops.to_has_memory = tfile_has_memory; @@ -3994,12 +4139,266 @@ init_tfile_ops (void) tfile_ops.to_magic = OPS_MAGIC; } +/* Given a line of text defining a static tracepoint marker, parse it + into a "static tracepoint marker" object. Throws an error is + parsing fails. If PP is non-null, it points to one past the end of + the parsed marker definition. */ + +void +parse_static_tracepoint_marker_definition (char *line, char **pp, + struct static_tracepoint_marker *marker) +{ + char *p, *endp; + ULONGEST addr; + int end; + + p = line; + p = unpack_varlen_hex (p, &addr); + p++; /* skip a colon */ + + marker->gdbarch = target_gdbarch; + marker->address = (CORE_ADDR) addr; + + endp = strchr (p, ':'); + if (endp == NULL) + error (_("bad marker definition: %s"), line); + + marker->str_id = xmalloc (endp - p + 1); + end = hex2bin (p, (gdb_byte *) marker->str_id, (endp - p + 1) / 2); + marker->str_id[end] = '\0'; + + p += 2 * end; + p++; /* skip a colon */ + + marker->extra = xmalloc (strlen (p) + 1); + end = hex2bin (p, (gdb_byte *) marker->extra, strlen (p) / 2); + marker->extra[end] = '\0'; + + if (pp) + *pp = p; +} + +/* Release a static tracepoint marker's contents. Note that the + object itself isn't released here. There objects are usually on + the stack. */ + +void +release_static_tracepoint_marker (struct static_tracepoint_marker *marker) +{ + xfree (marker->str_id); + marker->str_id = NULL; +} + +/* Print MARKER to gdb_stdout. */ + +static void +print_one_static_tracepoint_marker (int count, + struct static_tracepoint_marker *marker) +{ + struct command_line *l; + struct symbol *sym; + + char wrap_indent[80]; + char extra_field_indent[80]; + struct ui_stream *stb = ui_out_stream_new (uiout); + struct cleanup *old_chain = make_cleanup_ui_out_stream_delete (stb); + struct cleanup *bkpt_chain; + VEC(breakpoint_p) *tracepoints; + + struct symtab_and_line sal; + + init_sal (&sal); + + sal.pc = marker->address; + + tracepoints = static_tracepoints_here (marker->address); + + bkpt_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "marker"); + + /* A counter field to help readability. This is not a stable + identifier! */ + ui_out_field_int (uiout, "count", count); + + ui_out_field_string (uiout, "marker-id", marker->str_id); + + ui_out_field_fmt (uiout, "enabled", "%c", + !VEC_empty (breakpoint_p, tracepoints) ? 'y' : 'n'); + ui_out_spaces (uiout, 2); + + strcpy (wrap_indent, " "); + + if (gdbarch_addr_bit (marker->gdbarch) <= 32) + strcat (wrap_indent, " "); + else + strcat (wrap_indent, " "); + + strcpy (extra_field_indent, " "); + + ui_out_field_core_addr (uiout, "addr", marker->gdbarch, marker->address); + + sal = find_pc_line (marker->address, 0); + sym = find_pc_sect_function (marker->address, NULL); + if (sym) + { + ui_out_text (uiout, "in "); + ui_out_field_string (uiout, "func", + SYMBOL_PRINT_NAME (sym)); + ui_out_wrap_hint (uiout, wrap_indent); + ui_out_text (uiout, " at "); + } + else + ui_out_field_skip (uiout, "func"); + + if (sal.symtab != NULL) + { + ui_out_field_string (uiout, "file", sal.symtab->filename); + ui_out_text (uiout, ":"); + + if (ui_out_is_mi_like_p (uiout)) + { + char *fullname = symtab_to_fullname (sal.symtab); + + if (fullname) + ui_out_field_string (uiout, "fullname", fullname); + } + else + ui_out_field_skip (uiout, "fullname"); + + ui_out_field_int (uiout, "line", sal.line); + } + else + { + ui_out_field_skip (uiout, "fullname"); + ui_out_field_skip (uiout, "line"); + } + + ui_out_text (uiout, "\n"); + ui_out_text (uiout, extra_field_indent); + ui_out_text (uiout, _("Data: \"")); + ui_out_field_string (uiout, "extra-data", marker->extra); + ui_out_text (uiout, "\"\n"); + + if (!VEC_empty (breakpoint_p, tracepoints)) + { + struct cleanup *cleanup_chain; + int ix; + struct breakpoint *b; + + cleanup_chain = make_cleanup_ui_out_tuple_begin_end (uiout, + "tracepoints-at"); + + ui_out_text (uiout, extra_field_indent); + ui_out_text (uiout, _("Probed by static tracepoints: ")); + for (ix = 0; VEC_iterate(breakpoint_p, tracepoints, ix, b); ix++) + { + if (ix > 0) + ui_out_text (uiout, ", "); + ui_out_text (uiout, "#"); + ui_out_field_int (uiout, "tracepoint-id", b->number); + } + + do_cleanups (cleanup_chain); + + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_int (uiout, "number-of-tracepoints", + VEC_length(breakpoint_p, tracepoints)); + else + ui_out_text (uiout, "\n"); + } + VEC_free (breakpoint_p, tracepoints); + + do_cleanups (bkpt_chain); + do_cleanups (old_chain); +} + +static void +info_static_tracepoint_markers_command (char *arg, int from_tty) +{ + VEC(static_tracepoint_marker_p) *markers; + struct cleanup *old_chain; + struct static_tracepoint_marker *marker; + int i; + + old_chain + = make_cleanup_ui_out_table_begin_end (uiout, 5, -1, + "StaticTracepointMarkersTable"); + + ui_out_table_header (uiout, 7, ui_left, "counter", "Cnt"); + + ui_out_table_header (uiout, 40, ui_left, "marker-id", "ID"); + + ui_out_table_header (uiout, 3, ui_left, "enabled", "Enb"); + if (gdbarch_addr_bit (target_gdbarch) <= 32) + ui_out_table_header (uiout, 10, ui_left, "addr", "Address"); + else + ui_out_table_header (uiout, 18, ui_left, "addr", "Address"); + ui_out_table_header (uiout, 40, ui_noalign, "what", "What"); + + ui_out_table_body (uiout); + + markers = target_static_tracepoint_markers_by_strid (NULL); + make_cleanup (VEC_cleanup (static_tracepoint_marker_p), &markers); + + for (i = 0; + VEC_iterate (static_tracepoint_marker_p, + markers, i, marker); + i++) + { + print_one_static_tracepoint_marker (i + 1, marker); + release_static_tracepoint_marker (marker); + } + + do_cleanups (old_chain); +} + +/* The $_sdata convenience variable is a bit special. We don't know + for sure type of the value until we actually have a chance to fetch + the data --- the size of the object depends on what has been + collected. We solve this by making $_sdata be an internalvar that + creates a new value on access. */ + +/* Return a new value with the correct type for the sdata object of + the current trace frame. Return a void value if there's no object + available. */ + +static struct value * +sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var) +{ + LONGEST size; + gdb_byte *buf; + + /* We need to read the whole object before we know its size. */ + size = target_read_alloc (¤t_target, + TARGET_OBJECT_STATIC_TRACE_DATA, + NULL, &buf); + if (size >= 0) + { + struct value *v; + struct type *type; + + type = init_vector_type (builtin_type (gdbarch)->builtin_true_char, + size); + v = allocate_value (type); + memcpy (value_contents_raw (v), buf, size); + xfree (buf); + return v; + } + else + return allocate_value (builtin_type (gdbarch)->builtin_void); +} + /* module initialization */ void _initialize_tracepoint (void) { struct cmd_list_element *c; + /* Explicitly create without lookup, since that tries to create a + value with a void typed value, and when we get here, gdbarch + isn't initialized yet. At this point, we're quite sure there + isn't another convenience variable of the same name. */ + create_internalvar_type_lazy ("_sdata", sdata_make_value); + traceframe_number = -1; tracepoint_number = -1; @@ -4060,6 +4459,11 @@ If no arguments are supplied, delete all variables."), &deletelist); add_info ("tvariables", tvariables_info, _("\ Status of trace state variables and their values.\n\ +")); + + add_info ("static-tracepoint-markers", + info_static_tracepoint_markers_command, _("\ +List target static tracepoints markers.\n\ ")); add_prefix_cmd ("tfind", class_trace, trace_find_command, _("\ @@ -4079,7 +4483,7 @@ Usage: tfind range addr1,addr2"), add_cmd ("line", class_trace, trace_find_line_command, _("\ Select a trace frame by source line.\n\ -Argument can be a line number (with optional source file), \n\ +Argument can be a line number (with optional source file),\n\ a function name, or '*' followed by an address.\n\ Default argument is 'the next source line that was traced'."), &tfindlist); @@ -4142,6 +4546,7 @@ Also accepts the following special arguments:\n\ $regs -- all registers.\n\ $args -- all function arguments.\n\ $locals -- all variables local to the block/function scope.\n\ + $_sdata -- static tracepoint data (ignored for non-static tracepoints).\n\ Note: this command can only be used in a tracepoint \"actions\" list.")); add_com ("teval", class_trace, teval_pseudocommand, _("\ @@ -4152,8 +4557,8 @@ Note: this command can only be used in a tracepoint \"actions\" list.")); add_com ("actions", class_trace, trace_actions_command, _("\ Specify the actions to be taken at a tracepoint.\n\ -Tracepoint actions may include collecting of specified data, \n\ -single-stepping, or enabling/disabling other tracepoints, \n\ +Tracepoint actions may include collecting of specified data,\n\ +single-stepping, or enabling/disabling other tracepoints,\n\ depending on target's capabilities.")); default_collect = xstrdup ("");