2010-04-21 Stan Shebs <stan@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / tracepoint.c
index 447682a86868c1b376e9fa8903d917e0fa61960f..e50a1e0f990d4320d09c2975ba067b8e19a0b9a8 100644 (file)
@@ -44,6 +44,8 @@
 #include "objfiles.h"
 #include "filenames.h"
 #include "gdbthread.h"
+#include "stack.h"
+#include "gdbcore.h"
 
 #include "ax.h"
 #include "ax-gdb.h"
@@ -202,9 +204,6 @@ char *stop_reason_names[] = {
 struct trace_status *
 current_trace_status ()
 {
-  /* Ensure this is never NULL.  */
-  if (!trace_status.error_desc)
-    trace_status.error_desc = "";
   return &trace_status;
 }
 
@@ -366,6 +365,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;
     }
 
@@ -482,6 +482,23 @@ tvariables_info (char *args, int from_tty)
   tvariables_info_1 ();
 }
 
+/* Stash definitions of tsvs into the given file.  */
+
+void
+save_trace_state_variables (struct ui_file *fp)
+{
+  struct trace_state_variable *tsv;
+  int ix;
+
+  for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
+    {
+      fprintf_unfiltered (fp, "tvariable $%s", tsv->name);
+      if (tsv->initial_value)
+       fprintf_unfiltered (fp, " = %s", plongest (tsv->initial_value));
+      fprintf_unfiltered (fp, "\n");
+    }
+}
+
 /* ACTIONS functions: */
 
 /* The three functions:
@@ -539,8 +556,35 @@ trace_actions_command (char *args, int from_tty)
   /* else just return */
 }
 
+/* Report the results of checking the agent expression, as errors or
+   internal errors.  */
+
+static void
+report_agent_reqs_errors (struct agent_expr *aexpr, struct agent_reqs *areqs)
+{
+  /* All of the "flaws" are serious bytecode generation issues that
+     should never occur.  */
+  if (areqs->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)
+    internal_error (__FILE__, __LINE__,
+                   _("expression has min height < 0"));
+
+  /* Issue this error if the stack is predicted to get too deep.  The
+     limit is rather arbitrary; a better scheme might be for the
+     target to report how much stack it will have available.  The
+     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)
+    error (_("Expression is too complicated."));
+}
+
 /* worker function */
-enum actionline_type
+void
 validate_actionline (char **line, struct breakpoint *t)
 {
   struct cmd_list_element *c;
@@ -548,34 +592,29 @@ validate_actionline (char **line, struct breakpoint *t)
   struct cleanup *old_chain = NULL;
   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)
-    return END;
+    return;
 
   for (p = *line; isspace ((int) *p);)
     p++;
 
   /* Symbol lookup etc.  */
   if (*p == '\0')      /* empty line: just prompt for another line.  */
-    return BADLINE;
+    return;
 
   if (*p == '#')               /* comment line */
-    return GENERIC;
+    return;
 
   c = lookup_cmd (&p, cmdlist, "", -1, 1);
   if (c == 0)
-    {
-      warning (_("'%s' is not an action that I know, or is ambiguous."), 
-              p);
-      return BADLINE;
-    }
+    error (_("`%s' is not a tracepoint action, or is ambiguous."), p);
 
   if (cmd_cfunc_eq (c, collect_pseudocommand))
     {
-      struct agent_expr *aexpr;
-      struct agent_reqs areqs;
-
       do
        {                       /* repeat over a comma-separated list */
          QUIT;                 /* allow user to bail out with ^C */
@@ -604,16 +643,14 @@ validate_actionline (char **line, struct breakpoint *t)
                {
                  if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
                    {
-                     warning (_("constant %s (value %ld) will not be collected."),
-                              SYMBOL_PRINT_NAME (exp->elts[2].symbol),
-                              SYMBOL_VALUE (exp->elts[2].symbol));
-                     return BADLINE;
+                     error (_("constant `%s' (value %ld) will not be collected."),
+                            SYMBOL_PRINT_NAME (exp->elts[2].symbol),
+                            SYMBOL_VALUE (exp->elts[2].symbol));
                    }
                  else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT)
                    {
-                     warning (_("%s is optimized away and cannot be collected."),
-                              SYMBOL_PRINT_NAME (exp->elts[2].symbol));
-                     return BADLINE;
+                     error (_("`%s' is optimized away and cannot be collected."),
+                            SYMBOL_PRINT_NAME (exp->elts[2].symbol));
                    }
                }
 
@@ -624,30 +661,21 @@ validate_actionline (char **line, struct breakpoint *t)
              make_cleanup_free_agent_expr (aexpr);
 
              if (aexpr->len > MAX_AGENT_EXPR_LEN)
-               error (_("expression too complicated, try simplifying"));
+               error (_("Expression is too complicated."));
 
              ax_reqs (aexpr, &areqs);
              (void) make_cleanup (xfree, areqs.reg_mask);
 
-             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"));
+             report_agent_reqs_errors (aexpr, &areqs);
 
              do_cleanups (old_chain);
            }
        }
       while (p && *p++ == ',');
-      return GENERIC;
     }
+
   else if (cmd_cfunc_eq (c, teval_pseudocommand))
     {
-      struct agent_expr *aexpr;
-
       do
        {                       /* repeat over a comma-separated list */
          QUIT;                 /* allow user to bail out with ^C */
@@ -669,14 +697,19 @@ validate_actionline (char **line, struct breakpoint *t)
              make_cleanup_free_agent_expr (aexpr);
 
              if (aexpr->len > MAX_AGENT_EXPR_LEN)
-               error (_("expression too complicated, try simplifying"));
+               error (_("Expression is too complicated."));
+
+             ax_reqs (aexpr, &areqs);
+             (void) make_cleanup (xfree, areqs.reg_mask);
+
+             report_agent_reqs_errors (aexpr, &areqs);
 
              do_cleanups (old_chain);
            }
        }
       while (p && *p++ == ',');
-      return GENERIC;
     }
+
   else if (cmd_cfunc_eq (c, while_stepping_pseudocommand))
     {
       char *steparg;           /* in case warning is necessary */
@@ -685,19 +718,15 @@ validate_actionline (char **line, struct breakpoint *t)
        p++;
       steparg = p;
 
-      if (*p == '\0' ||
-         (t->step_count = strtol (p, &p, 0)) == 0)
-       {
-         error (_("'%s': bad step-count."), *line);
-       }
-      return STEPPING;
+      if (*p == '\0' || (t->step_count = strtol (p, &p, 0)) == 0)
+       error (_("while-stepping step count `%s' is malformed."), *line);
     }
+
   else if (cmd_cfunc_eq (c, end_actions_pseudocommand))
-    return END;
+    ;
+
   else
-    {
-      error (_("'%s' is not a supported tracepoint action."), *line);
-    }
+    error (_("`%s' is not a supported tracepoint action."), *line);
 }
 
 enum {
@@ -925,10 +954,11 @@ collect_symbol (struct collection_list *collect,
        }
       add_memrange (collect, reg, offset, len);
       break;
+
     case LOC_UNRESOLVED:
-      printf_filtered ("Don't know LOC_UNRESOLVED %s\n", 
-                      SYMBOL_PRINT_NAME (sym));
+      treat_as_expr = 1;
       break;
+
     case LOC_OPTIMIZED_OUT:
       printf_filtered ("%s has been optimized out of existence.\n",
                       SYMBOL_PRINT_NAME (sym));
@@ -961,13 +991,8 @@ collect_symbol (struct collection_list *collect,
       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"));
+
+      report_agent_reqs_errors (aexpr, &areqs);
 
       discard_cleanups (old_chain1);
       add_aexpr (collect, aexpr);
@@ -993,40 +1018,77 @@ collect_symbol (struct collection_list *collect,
     }
 }
 
+/* Data to be passed around in the calls to the locals and args
+   iterators.  */
+
+struct add_local_symbols_data
+{
+  struct collection_list *collect;
+  struct gdbarch *gdbarch;
+  CORE_ADDR pc;
+  long frame_regno;
+  long frame_offset;
+  int count;
+};
+
+/* The callback for the locals and args iterators  */
+
+static void
+do_collect_symbol (const char *print_name,
+                  struct symbol *sym,
+                  void *cb_data)
+{
+  struct add_local_symbols_data *p = cb_data;
+
+  collect_symbol (p->collect, sym, p->gdbarch, p->frame_regno,
+                 p->frame_offset, p->pc);
+  p->count++;
+}
+
 /* Add all locals (or args) symbols to collection list */
 static void
 add_local_symbols (struct collection_list *collect,
                   struct gdbarch *gdbarch, CORE_ADDR pc,
                   long frame_regno, long frame_offset, int type)
 {
-  struct symbol *sym;
   struct block *block;
-  struct dict_iterator iter;
-  int count = 0;
+  struct add_local_symbols_data cb_data;
 
-  block = block_for_pc (pc);
-  while (block != 0)
+  cb_data.collect = collect;
+  cb_data.gdbarch = gdbarch;
+  cb_data.pc = pc;
+  cb_data.frame_regno = frame_regno;
+  cb_data.frame_offset = frame_offset;
+  cb_data.count = 0;
+
+  if (type == 'L')
     {
-      QUIT;                    /* allow user to bail out with ^C */
-      ALL_BLOCK_SYMBOLS (block, iter, sym)
+      block = block_for_pc (pc);
+      if (block == NULL)
        {
-         if (SYMBOL_IS_ARGUMENT (sym)
-             ? type == 'A'     /* collecting Arguments */
-             : type == 'L')    /* collecting Locals */
-           {
-             count++;
-             collect_symbol (collect, sym, gdbarch,
-                             frame_regno, frame_offset, pc);
-           }
+         warning (_("Can't collect locals; "
+                    "no symbol table info available.\n"));
+         return;
        }
-      if (BLOCK_FUNCTION (block))
-       break;
-      else
-       block = BLOCK_SUPERBLOCK (block);
+
+      iterate_over_block_local_vars (block, do_collect_symbol, &cb_data);
+      if (cb_data.count == 0)
+       warning (_("No locals found in scope."));
+    }
+  else
+    {
+      pc = get_pc_function_start (pc);
+      block = block_for_pc (pc);
+      if (block == NULL)
+       {
+         warning (_("Can't collect args; no symbol table info available.\n"));
+         return;
+       }
+
+      iterate_over_block_arg_vars (block, do_collect_symbol, &cb_data);
+      if (cb_data.count == 0)
+       warning (_("No args found in scope."));
     }
-  if (count == 0)
-    warning (_("No %s found in scope."), 
-            type == 'L' ? "locals" : "args");
 }
 
 /* worker function */
@@ -1272,13 +1334,8 @@ encode_actions_1 (struct command_line *action,
                      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"));
+                     report_agent_reqs_errors (aexpr, &areqs);
 
                      discard_cleanups (old_chain1);
                      add_aexpr (collect, aexpr);
@@ -1332,13 +1389,8 @@ encode_actions_1 (struct command_line *action,
                  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"));
+                 report_agent_reqs_errors (aexpr, &areqs);
 
                  discard_cleanups (old_chain1);
                  /* Even though we're not officially collecting, add
@@ -1389,7 +1441,7 @@ encode_actions (struct breakpoint *t, struct bp_location *tloc,
   gdbarch_virtual_frame_pointer (t->gdbarch,
                                 t->loc->address, &frame_reg, &frame_offset);
 
-  actions = t->commands->commands;
+  actions = breakpoint_commands (t);
 
   /* If there are default expressions to collect, make up a collect
      action and prepend to the action list to encode.  Note that since
@@ -1399,21 +1451,18 @@ encode_actions (struct breakpoint *t, struct bp_location *tloc,
   if (*default_collect)
     {
       char *line;
-      enum actionline_type linetype;
 
       default_collect_line =  xstrprintf ("collect %s", default_collect);
       make_cleanup (xfree, default_collect_line);
 
       line = default_collect_line;
-      linetype = validate_actionline (&line, t);
-      if (linetype != BADLINE)
-       {
-         default_collect_action = xmalloc (sizeof (struct command_line));
-         make_cleanup (xfree, default_collect_action);
-         default_collect_action->next = t->commands->commands;
-         default_collect_action->line = line;
-         actions = default_collect_action;
-       }
+      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;
     }
   encode_actions_1 (actions, t, tloc, frame_reg, frame_offset,
                    &tracepoint_list, &stepping_list);
@@ -1452,24 +1501,43 @@ start_tracing (void)
   int ix;
   struct breakpoint *t;
   struct trace_state_variable *tsv;
-  int any_downloaded = 0;
-
-  target_trace_init ();
+  int any_enabled = 0;
   
   tp_vec = all_tracepoints ();
+
+  /* No point in tracing without any tracepoints... */
+  if (VEC_length (breakpoint_p, tp_vec) == 0)
+    {
+      VEC_free (breakpoint_p, tp_vec);
+      error (_("No tracepoints defined, not starting trace"));
+    }
+
+  for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
+    {
+      if (t->enable_state == bp_enabled)
+       {
+         any_enabled = 1;
+         break;
+       }
+    }
+
+  /* No point in tracing with only disabled tracepoints.  */
+  if (!any_enabled)
+    {
+      VEC_free (breakpoint_p, tp_vec);
+      error (_("No tracepoints enabled, not starting trace"));
+    }
+
+  target_trace_init ();
+
   for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
     {
       t->number_on_target = 0;
       target_download_tracepoint (t);
       t->number_on_target = t->number;
-      any_downloaded = 1;
     }
   VEC_free (breakpoint_p, tp_vec);
-  
-  /* No point in tracing without any tracepoints... */
-  if (!any_downloaded)
-    error ("No tracepoints downloaded, not starting trace");
-  
+
   /* Send down all the trace state variables too.  */
   for (ix = 0; VEC_iterate (tsv_s, tvariables, ix, tsv); ++ix)
     {
@@ -1504,6 +1572,13 @@ trace_start_command (char *args, int from_tty)
 {
   dont_repeat ();      /* Like "run", dangerous to repeat accidentally.  */
 
+  if (current_trace_status ()->running)
+    {
+      if (from_tty
+         && !query (_("A trace is running already.  Start a new run? ")))
+       error (_("New trace run not started."));
+    }
+
   start_tracing ();
 }
 
@@ -1511,6 +1586,9 @@ trace_start_command (char *args, int from_tty)
 static void
 trace_stop_command (char *args, int from_tty)
 {
+  if (!current_trace_status ()->running)
+    error (_("Trace is not running."));
+
   stop_tracing ();
 }
 
@@ -1549,10 +1627,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
     {
@@ -1622,6 +1696,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"),
@@ -1715,18 +1797,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
@@ -1735,19 +1823,31 @@ 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
+     confusing upon reconnection.  Just use these calls instead of
+     full tfind_1 behavior because we're in the middle of detaching,
+     and there's no point to updating current stack frame etc.  */
+  set_traceframe_number (-1);
+  set_traceframe_context (NULL);
 }
 
 /* Worker function for the various flavors of the tfind command.  */
@@ -1757,11 +1857,19 @@ 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;
+  struct frame_id old_frame_id = null_frame_id;
   char *reply;
   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);
@@ -1774,7 +1882,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 
@@ -1841,8 +1949,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
@@ -1853,7 +1963,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
@@ -2019,33 +2129,16 @@ trace_find_line_command (char *args, int from_tty)
       sals.sals[0] = sal;
     }
   else
-      {
+    {
       sals = decode_line_spec (args, 1);
       sal = sals.sals[0];
     }
   
   old_chain = make_cleanup (xfree, sals.sals);
   if (sal.symtab == 0)
-    {
-      printf_filtered ("TFIND: No line number information available");
-      if (sal.pc != 0)
-       {
-         /* This is useful for "info line *0x7f34".  If we can't
-            tell the user about a source line, at least let them
-            have the symbolic address.  */
-         printf_filtered (" for address ");
-         wrap_here ("  ");
-         print_address (get_current_arch (), sal.pc, gdb_stdout);
-         printf_filtered (";\n -- will attempt to find by PC. \n");
-       }
-        else
-       {
-         printf_filtered (".\n");
-         return;               /* No line, no PC; what can we do?  */
-       }
-    }
-  else if (sal.line > 0
-          && find_line_pc_range (sal, &start_pc, &end_pc))
+    error (_("No line number information available."));
+
+  if (sal.line > 0 && find_line_pc_range (sal, &start_pc, &end_pc))
     {
       if (start_pc == end_pc)
        {
@@ -2279,7 +2372,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))
@@ -2304,54 +2399,21 @@ replace_comma (void *data)
   *comma = ',';
 }
 
-/* tdump command */
+
+/* Helper for trace_dump_command.  Dump the action list starting at
+   ACTION.  STEPPING_ACTIONS is true if we're iterating over the
+   actions of the body of a while-stepping action.  STEPPING_FRAME is
+   set if the current traceframe was determined to be a while-stepping
+   traceframe.  */
+
 static void
-trace_dump_command (char *args, int from_tty)
+trace_dump_actions (struct command_line *action,
+                   int stepping_actions, int stepping_frame,
+                   int from_tty)
 {
-  struct regcache *regcache;
-  struct gdbarch *gdbarch;
-  struct breakpoint *t;
-  struct command_line *action;
   char *action_exp, *next_comma;
-  struct cleanup *old_cleanups;
-  int stepping_actions = 0;
-  int stepping_frame = 0;
-  struct bp_location *loc;
 
-  if (tracepoint_number == -1)
-    {
-      warning (_("No current trace frame."));
-      return;
-    }
-
-  t = get_tracepoint (tracepoint_number);
-
-  if (t == NULL)
-    error (_("No known tracepoint matches 'current' tracepoint #%d."),
-          tracepoint_number);
-
-  old_cleanups = make_cleanup (null_cleanup, NULL);
-
-  printf_filtered ("Data collected at tracepoint %d, trace frame %d:\n",
-                  tracepoint_number, traceframe_number);
-
-  /* The current frame is a trap frame if the frame PC is equal
-     to the tracepoint PC.  If not, then the current frame was
-     collected during single-stepping.  */
-
-  regcache = get_current_regcache ();
-  gdbarch = get_regcache_arch (regcache);
-
-  /* If the traceframe's address matches any of the tracepoint's
-     locations, assume it is a direct hit rather than a while-stepping
-     frame.  (FIXME this is not reliable, should record each frame's
-     type.)  */
-  stepping_frame = 1;
-  for (loc = t->loc; loc; loc = loc->next)
-    if (loc->address == regcache_read_pc (regcache))
-      stepping_frame = 0;
-
-  for (action = t->commands->commands; action; action = action->next)
+  for (; action != NULL; action = action->next)
     {
       struct cmd_list_element *cmd;
 
@@ -2371,9 +2433,13 @@ trace_dump_command (char *args, int from_tty)
        error (_("Bad action list item: %s"), action_exp);
 
       if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
-       stepping_actions = 1;
-      else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
-       stepping_actions = 0;
+       {
+         int i;
+
+         for (i = 0; i < action->body_count; ++i)
+           trace_dump_actions (action->body_list[i],
+                               1, stepping_frame, from_tty);
+       }
       else if (cmd_cfunc_eq (cmd, collect_pseudocommand))
        {
          /* Display the collected data.
@@ -2419,7 +2485,93 @@ trace_dump_command (char *args, int from_tty)
            }
        }
     }
-  discard_cleanups (old_cleanups);
+}
+
+/* The tdump command.  */
+
+static void
+trace_dump_command (char *args, int from_tty)
+{
+  struct regcache *regcache;
+  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)
+    {
+      warning (_("No current trace frame."));
+      return;
+    }
+
+  t = get_tracepoint (tracepoint_number);
+
+  if (t == NULL)
+    error (_("No known tracepoint matches 'current' tracepoint #%d."),
+          tracepoint_number);
+
+  printf_filtered ("Data collected at tracepoint %d, trace frame %d:\n",
+                  tracepoint_number, traceframe_number);
+
+  /* The current frame is a trap frame if the frame PC is equal
+     to the tracepoint PC.  If not, then the current frame was
+     collected during single-stepping.  */
+
+  regcache = get_current_regcache ();
+
+  /* If the traceframe's address matches any of the tracepoint's
+     locations, assume it is a direct hit rather than a while-stepping
+     frame.  (FIXME this is not reliable, should record each frame's
+     type.)  */
+  stepping_frame = 1;
+  for (loc = t->loc; loc; loc = loc->next)
+    if (loc->address == regcache_read_pc (regcache))
+      stepping_frame = 0;
+
+  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
+   that is suitable for both protocol and saving in files.  */
+/* This version does not do multiple encodes for long strings; it should
+   return an offset to the next piece to encode.  FIXME  */
+
+extern int
+encode_source_string (int tpnum, ULONGEST addr,
+                     char *srctype, char *src, char *buf, int buf_size)
+{
+  if (80 + strlen (srctype) > buf_size)
+    error (_("Buffer too small for source encoding"));
+  sprintf (buf, "%x:%s:%s:%x:%x:",
+          tpnum, phex_nz (addr, sizeof (addr)), srctype, 0, (int) strlen (src));
+  if (strlen (buf) + strlen (src) * 2 >= buf_size)
+    error (_("Source string too long for buffer"));
+  bin2hex (src, buf + strlen (buf), 0);
+  return -1;
 }
 
 extern int trace_regblock_size;
@@ -2439,6 +2591,7 @@ trace_save (const char *filename, int target_does_save)
   struct uploaded_tp *uploaded_tps = NULL, *utp;
   struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
   int a;
+  char *act;
   LONGEST gotten = 0;
   ULONGEST offset = 0;
 #define MAX_TRACE_UPLOAD 2000
@@ -2473,7 +2626,7 @@ trace_save (const char *filename, int target_does_save)
      binary file, plus a hint as what this file is, and a version
      number in case of future needs.  */
   written = fwrite ("\x7fTRACE0\n", 8, 1, fp);
-  if (written < 8)
+  if (written < 1)
     perror_with_name (pathname);
 
   /* Write descriptive info.  */
@@ -2484,12 +2637,11 @@ trace_save (const char *filename, int target_does_save)
   /* Write out status of the tracing run (aka "tstatus" info).  */
   fprintf (fp, "status %c;%s",
           (ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
-  /* Encode the error message in hex, might have weird chars.  */
   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, ":X%s", buf);
+      fprintf (fp, ":%s", buf);
     }
   fprintf (fp, ":%x", ts->stopping_tracepoint);
   if (ts->traceframe_count >= 0)
@@ -2500,6 +2652,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
@@ -2547,14 +2703,30 @@ trace_save (const char *filename, int target_does_save)
        fprintf (fp, ":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
                 utp->cond);
       fprintf (fp, "\n");
-      for (a = 0; a < utp->numactions; ++a)
+      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)),
-                utp->actions[a]);
-      for (a = 0; a < utp->num_step_actions; ++a)
+                utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+      for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
        fprintf (fp, "tp S%x:%s:%s\n",
-                utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
-                utp->step_actions[a]);
+                utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+      if (utp->at_string)
+       {
+         encode_source_string (utp->number, utp->addr,
+                               "at", utp->at_string, buf, MAX_TRACE_UPLOAD);
+         fprintf (fp, "tp Z%s\n", buf);
+       }
+      if (utp->cond_string)
+       {
+         encode_source_string (utp->number, utp->addr,
+                               "cond", utp->cond_string, buf, MAX_TRACE_UPLOAD);
+         fprintf (fp, "tp Z%s\n", buf);
+       }
+      for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
+       {
+         encode_source_string (utp->number, utp->addr, "cmd", act,
+                               buf, MAX_TRACE_UPLOAD);
+         fprintf (fp, "tp Z%s\n", buf);
+       }
     }
 
   free_uploaded_tps (&uploaded_tps);
@@ -2574,14 +2746,14 @@ trace_save (const char *filename, int target_does_save)
       if (gotten == 0)
        break;
       written = fwrite (buf, gotten, 1, fp);
-      if (written < gotten)
+      if (written < 1)
        perror_with_name (pathname);
       offset += gotten;
     }
 
-  /* Mark the end of trace data.  */
+  /* Mark the end of trace data.  (We know that gotten is 0 at this point.)  */
   written = fwrite (&gotten, 4, 1, fp);
-  if (written < 4)
+  if (written < 1)
     perror_with_name (pathname);
 
   do_cleanups (cleanup);
@@ -2753,6 +2925,9 @@ get_uploaded_tp (int num, ULONGEST addr, struct uploaded_tp **utpp)
   memset (utp, 0, sizeof (struct uploaded_tp));
   utp->number = num;
   utp->addr = addr;
+  utp->actions = NULL;
+  utp->step_actions = NULL;
+  utp->cmd_strings = NULL;
   utp->next = *utpp;
   *utpp = utp;
   return utp;
@@ -3049,6 +3224,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.  */
@@ -3158,11 +3335,14 @@ parse_trace_status (char *line, struct trace_status *ts)
   ts->running_known = 1;
   ts->running = (*p++ == '1');
   ts->stop_reason = trace_stop_reason_unknown;
-  ts->error_desc = "";
+  xfree (ts->error_desc);
+  ts->error_desc = NULL;
   ts->traceframe_count = -1;
   ts->traceframes_created = -1;
   ts->buffer_free = -1;
   ts->buffer_size = -1;
+  ts->disconnected_tracing = 0;
+  ts->circular_buffer = 0;
 
   while (*p++)
     {
@@ -3191,26 +3371,25 @@ 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, ':');
          if (p2 != p1)
            {
              int end;
-             ts->error_desc = (char *) xmalloc (p2 - p1 + 1);
-             /* See if we're doing plain text or hex encoding.  */
-             if (*p1 == 'X')
-               {
-                 ++p1;
-                 end = hex2bin (p1, ts->error_desc, (p2 - p1) / 2);
-               }
-             else
-               {
-                 memcpy (ts->error_desc, p1, p2 - p1);
-                 end = p2 - p1;
-               }
+
+             ts->error_desc = xmalloc ((p2 - p1) / 2 + 1);
+             end = hex2bin (p1, ts->error_desc, (p2 - p1) / 2);
              ts->error_desc[end] = '\0';
            }
+         else
+           ts->error_desc = xstrdup ("");
+
          p = unpack_varlen_hex (++p2, &val);
          ts->stopping_tracepoint = val;
          ts->stop_reason = tracepoint_error;
@@ -3235,6 +3414,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.  */
@@ -3248,18 +3437,18 @@ Status line: '%s'\n"), p, line);
     }
 }
 
-/* Given a line of text defining a tracepoint or tracepoint action, parse
-   it into an "uploaded tracepoint".  */
+/* Given a line of text defining a part of a tracepoint, parse it into
+   an "uploaded tracepoint".  */
 
 void
 parse_tracepoint_definition (char *line, struct uploaded_tp **utpp)
 {
   char *p;
   char piece;
-  ULONGEST num, addr, step, pass, orig_size, xlen;
-  int enabled, i;
+  ULONGEST num, addr, step, pass, orig_size, xlen, start;
+  int enabled, i, end;
   enum bptype type;
-  char *cond;
+  char *cond, *srctype, *src, *buf;
   struct uploaded_tp *utp = NULL;
 
   p = line;
@@ -3300,7 +3489,7 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp)
              p += 2 * xlen;
            }
          else
-           warning ("Unrecognized char '%c' in tracepoint definition, skipping rest", *p);
+           warning (_("Unrecognized char '%c' in tracepoint definition, skipping rest"), *p);
        }
       utp = get_uploaded_tp (num, addr, utpp);
       utp->type = type;
@@ -3312,16 +3501,42 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp)
   else if (piece == 'A')
     {
       utp = get_uploaded_tp (num, addr, utpp);
-      utp->actions[utp->numactions++] = xstrdup (p);
+      VEC_safe_push (char_ptr, utp->actions, xstrdup (p));
     }
   else if (piece == 'S')
     {
       utp = get_uploaded_tp (num, addr, utpp);
-      utp->step_actions[utp->num_step_actions++] = xstrdup (p);
+      VEC_safe_push (char_ptr, utp->step_actions, xstrdup (p));
+    }
+  else if (piece == 'Z')
+    {
+      /* Parse a chunk of source form definition.  */
+      utp = get_uploaded_tp (num, addr, utpp);
+      srctype = p;
+      p = strchr (p, ':');
+      p++;  /* skip a colon */
+      p = unpack_varlen_hex (p, &start);
+      p++;  /* skip a colon */
+      p = unpack_varlen_hex (p, &xlen);
+      p++;  /* skip a colon */
+
+      buf = alloca (strlen (line));
+
+      end = hex2bin (p, (gdb_byte *) buf, strlen (p) / 2);
+      buf[end] = '\0';
+
+      if (strncmp (srctype, "at:", strlen ("at:")) == 0)
+       utp->at_string = xstrdup (buf);
+      else if (strncmp (srctype, "cond:", strlen ("cond:")) == 0)
+       utp->cond_string = xstrdup (buf);
+      else if (strncmp (srctype, "cmd:", strlen ("cmd:")) == 0)
+       VEC_safe_push (char_ptr, utp->cmd_strings, xstrdup (buf));
     }
   else
     {
-      error ("Invalid tracepoint piece");
+      /* Don't error out, the target might be sending us optional
+        info that we don't care about.  */
+      warning (_("Unrecognized tracepoint piece '%c', ignoring"), piece);
     }
 }
 
@@ -3520,7 +3735,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;
+  int i, pos, offset, regn, regsize, gotten, pc_regno;
   unsigned short mlen;
   char *regs;
 
@@ -3595,6 +3810,44 @@ tfile_fetch_registers (struct target_ops *ops,
          break;
        }
     }
+
+  /* We get here if no register data has been found.  Although we
+     don't like making up numbers, GDB has all manner of troubles when
+     the target says some register is not available.  Filling in with
+     zeroes is a reasonable fallback.  */
+  for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+    regcache_raw_supply (regcache, regn, NULL);
+
+  /* We can often usefully guess that the PC is going to be the same
+     as the address of the tracepoint.  */
+  pc_regno = gdbarch_pc_regnum (gdbarch);
+  if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
+    {
+      struct breakpoint *tp = get_tracepoint (tracepoint_number);
+
+      if (tp && tp->loc)
+       {
+         /* But don't try to guess if tracepoint is multi-location...  */
+         if (tp->loc->next)
+           {
+             warning ("Tracepoint %d has multiple locations, cannot infer $pc",
+                      tp->number);
+             return;
+           }
+         /* ... or does while-stepping.  */
+         if (tp->step_count > 0)
+           {
+             warning ("Tracepoint %d does while-stepping, cannot infer $pc",
+                      tp->number);
+             return;
+           }
+
+         store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+                                 gdbarch_byte_order (gdbarch),
+                                 tp->loc->address);
+         regcache_raw_supply (regcache, pc_regno, regs);
+       }
+    }
 }
 
 static LONGEST
@@ -3604,7 +3857,7 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object,
 {
   char block_type;
   int pos, gotten;
-  ULONGEST maddr;
+  ULONGEST maddr, amt;
   unsigned short mlen;
 
   /* We're only doing regular memory for now.  */
@@ -3642,16 +3895,26 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object,
            perror_with_name (trace_filename);
          else if (gotten < 2)
            error (_("Premature end of file while reading trace file"));
-         if (maddr <= offset && (offset + len) <= (maddr + mlen))
-           {
-             gotten = read (trace_fd, readbuf, mlen);
+         /* 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
+            trace frame.  */
+         if (maddr <= offset && offset < (maddr + mlen))
+           {
+             amt = (maddr + mlen) - offset;
+             if (amt > len)
+               amt = len;
+
+             gotten = read (trace_fd, readbuf, amt);
              if (gotten < 0)
                perror_with_name (trace_filename);
-             else if (gotten < mlen)
-               error (_("Premature end of file qwhile reading trace file"));
-
-             return mlen;
-           }
+             /* 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);
          pos += (8 + 2 + mlen);
          break;
@@ -3665,6 +3928,38 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object,
          break;
        }
     }
+
+  /* It's unduly pedantic to refuse to look at the executable for
+     read-only pieces; so do the equivalent of readonly regions aka
+     QTro packet.  */
+  /* FIXME account for relocation at some point */
+  if (exec_bfd)
+    {
+      asection *s;
+      bfd_size_type size;
+      bfd_vma lma;
+
+      for (s = exec_bfd->sections; s; s = s->next)
+       {
+         if ((s->flags & SEC_LOAD) == 0 ||
+             (s->flags & SEC_READONLY) == 0)
+           continue;
+
+         lma = s->lma;
+         size = bfd_get_section_size (s);
+         if (lma <= offset && offset < (lma + size))
+           {
+             amt = (lma + size) - offset;
+             if (amt > len)
+               amt = len;
+
+             amt = bfd_get_section_contents (exec_bfd, s,
+                                             readbuf, offset - lma, amt);
+             return amt;
+           }
+       }
+    }
+
   /* Indicate failure to find the requested memory block.  */
   return -1;
 }
@@ -3733,6 +4028,12 @@ tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val)
   return 0;
 }
 
+static int
+tfile_has_all_memory (struct target_ops *ops)
+{
+  return 1;
+}
+
 static int
 tfile_has_memory (struct target_ops *ops)
 {
@@ -3769,6 +4070,7 @@ init_tfile_ops (void)
   /* 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;
   tfile_ops.to_has_stack = tfile_has_stack;
   tfile_ops.to_has_registers = tfile_has_registers;
This page took 0.037895 seconds and 4 git commands to generate.