gdb/gdbserver/
[deliverable/binutils-gdb.git] / gdb / tracepoint.c
index 14fcbc58fef5b6537f3f3e8febb2a5162e9bffe9..41fcc97bf65095e1e54c200d59d653dddd572210 100644 (file)
@@ -45,6 +45,7 @@
 #include "filenames.h"
 #include "gdbthread.h"
 #include "stack.h"
+#include "gdbcore.h"
 
 #include "ax.h"
 #include "ax-gdb.h"
@@ -554,8 +555,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;
@@ -563,34 +591,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 */
@@ -619,16 +642,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));
                    }
                }
 
@@ -639,30 +660,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 */
@@ -684,14 +696,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 */
@@ -700,19 +717,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 {
@@ -977,13 +990,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);
@@ -1325,13 +1333,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);
@@ -1385,13 +1388,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
@@ -1442,7 +1440,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
@@ -1452,21 +1450,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);
@@ -1631,10 +1626,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
     {
@@ -1704,6 +1695,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"),
@@ -1806,9 +1805,11 @@ trace_status_mi (int on_stop)
     ui_out_field_int (uiout, "buffer-free",  (int) ts->buffer_free);
 }
 
-
+/* 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
@@ -1817,18 +1818,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
@@ -2376,54 +2382,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;
 
@@ -2443,9 +2416,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.
@@ -2491,7 +2468,49 @@ 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;
+
+  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;
+
+  trace_dump_actions (breakpoint_commands (t), 0, stepping_frame, from_tty);
 }
 
 /* Encode a piece of a tracepoint's source-level definition in a form
@@ -2530,7 +2549,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;
-  struct uploaded_string *cmd;
+  char *act;
   LONGEST gotten = 0;
   ULONGEST offset = 0;
 #define MAX_TRACE_UPLOAD 2000
@@ -2591,6 +2610,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
@@ -2638,14 +2661,12 @@ 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,
@@ -2658,9 +2679,9 @@ trace_save (const char *filename, int target_does_save)
                                "cond", utp->cond_string, buf, MAX_TRACE_UPLOAD);
          fprintf (fp, "tp Z%s\n", buf);
        }
-      for (cmd = utp->cmd_strings; cmd; cmd = cmd->next)
+      for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
        {
-         encode_source_string (utp->number, utp->addr, "cmd", cmd->str,
+         encode_source_string (utp->number, utp->addr, "cmd", act,
                                buf, MAX_TRACE_UPLOAD);
          fprintf (fp, "tp Z%s\n", buf);
        }
@@ -2862,6 +2883,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;
@@ -3158,6 +3182,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.  */
@@ -3273,6 +3299,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++)
     {
@@ -3301,6 +3329,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, ':');
@@ -3339,6 +3372,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.  */
@@ -3416,12 +3459,12 @@ 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')
     {
@@ -3445,21 +3488,7 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp)
       else if (strncmp (srctype, "cond:", strlen ("cond:")) == 0)
        utp->cond_string = xstrdup (buf);
       else if (strncmp (srctype, "cmd:", strlen ("cmd:")) == 0)
-       {
-         /* FIXME consider using a vector? */
-         struct uploaded_string *last, *newlast;
-         newlast = (struct uploaded_string *) xmalloc (sizeof (struct uploaded_string));
-         newlast->str = xstrdup (buf);
-         newlast->next = NULL;
-         if (utp->cmd_strings)
-           {
-             for (last = utp->cmd_strings; last->next; last = last->next)
-               ;
-             last->next = newlast;
-           }
-         else
-           utp->cmd_strings = newlast;
-       }
+       VEC_safe_push (char_ptr, utp->cmd_strings, xstrdup (buf));
     }
   else
     {
@@ -3664,7 +3693,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;
 
@@ -3739,6 +3768,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
@@ -3748,7 +3815,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.  */
@@ -3786,16 +3853,19 @@ 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 (gotten < 0)
-               perror_with_name (trace_filename);
-             else if (gotten < mlen)
-               error (_("Premature end of file qwhile reading trace file"));
-
-             return 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;
+
+             read (trace_fd, readbuf, amt);
+             return amt;
+           }
          lseek (trace_fd, mlen, SEEK_CUR);
          pos += (8 + 2 + mlen);
          break;
@@ -3809,6 +3879,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;
 }
@@ -3877,6 +3979,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)
 {
@@ -3913,6 +4021,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.042652 seconds and 4 git commands to generate.