Thu May 21 13:14:25 1998 John Metzler <jmetzler@cygnus.com>
[deliverable/binutils-gdb.git] / gdb / tracepoint.c
index 4de163a7b0ecd90cf6888fb9c052639347ce248a..2916944897373ee298f6caff920bd1123fd796c8 100644 (file)
@@ -44,6 +44,7 @@ extern int info_verbose;
 extern void (*readline_begin_hook) PARAMS ((char *, ...));
 extern char * (*readline_hook) PARAMS ((char *));
 extern void (*readline_end_hook) PARAMS ((void));
+extern void x_command PARAMS ((char *, int));
 
 /* If this definition isn't overridden by the header files, assume
    that isatty and fileno exist on this system.  */
@@ -327,10 +328,11 @@ set_raw_tracepoint (sal)
   t->language = current_language->la_language;
   t->input_radix = input_radix;
   t->line_number = sal.line;
-  t->enabled = enabled;
-  t->next = 0;
-  t->step_count = 0;
-  t->pass_count = 0;
+  t->enabled     = enabled;
+  t->next        = 0;
+  t->step_count  = 0;
+  t->pass_count  = 0;
+  t->addr_string = NULL;
 
   /* Add this tracepoint to the end of the chain
      so that a list of tracepoints will come out in order
@@ -359,7 +361,7 @@ trace_command (arg, from_tty)
   struct symtabs_and_lines sals;
   struct symtab_and_line sal;
   struct tracepoint *t;
-  char *addr_start = 0, *addr_end = 0, *cond_start = 0, *cond_end = 0;
+  char *addr_start = 0, *addr_end = 0;
   int i;
 
   if (!arg || !*arg)
@@ -398,8 +400,6 @@ trace_command (arg, from_tty)
        t->addr_string = canonical[i];
       else if (addr_start)
        t->addr_string = savestring (addr_start, addr_end - addr_start);
-      if (cond_start)
-       t->cond_string = savestring (cond_start, cond_end - cond_start);
 
       /* Let the UI know of any additions */
       if (create_tracepoint_hook)
@@ -525,14 +525,17 @@ tracepoint_operation (t, from_tty, opcode)
      enum tracepoint_opcode opcode;
 {
   struct tracepoint *t2;
-  struct action_line *action, *next;
 
   switch (opcode) {
   case enable:
     t->enabled = enabled;
+    if (modify_tracepoint_hook)
+      modify_tracepoint_hook (t);
     break;
   case disable:
     t->enabled = disabled;
+    if (modify_tracepoint_hook)
+      modify_tracepoint_hook (t);
     break;
   case delete:
     if (tracepoint_chain == t)
@@ -549,19 +552,13 @@ tracepoint_operation (t, from_tty, opcode)
     if (delete_tracepoint_hook)
       delete_tracepoint_hook (t);
 
-    if (t->cond_string)
-      free (t->cond_string);
     if (t->addr_string)
       free (t->addr_string);
     if (t->source_file)
       free (t->source_file);
-    for (action = t->actions; action; action = next)
-      {
-       next = action->next;
-       if (action->action) 
-         free (action->action);
-       free (action);
-      }
+    if (t->actions)
+      free_actions (t);
+
     free (t);
     break;
   }
@@ -619,12 +616,12 @@ map_args_over_tracepoints (args, from_tty, opcode)
      int from_tty;
      enum tracepoint_opcode opcode;
 {
-  struct tracepoint *t;
+  struct tracepoint *t, *tmp;
   int tpnum;
   char *cp;
 
   if (args == 0 || *args == 0) /* do them all */
-    ALL_TRACEPOINTS (t)
+    ALL_TRACEPOINTS_SAFE (t, tmp)
       tracepoint_operation (t, from_tty, opcode);
   else
     while (*args)
@@ -704,6 +701,8 @@ trace_pass_command (args, from_tty)
     if (t1 == (struct tracepoint *) -1 || t1 == t2)
       {
        t2->pass_count = count;
+        if (modify_tracepoint_hook)
+          modify_tracepoint_hook (t2);
        if (from_tty)
          printf_filtered ("Setting tracepoint %d's passcount to %d\n", 
                           t2->number, count);
@@ -714,7 +713,6 @@ trace_pass_command (args, from_tty)
 
 /* Prototypes for action-parsing utility commands  */
 static void  read_actions PARAMS((struct tracepoint *));
-static void  free_actions PARAMS((struct tracepoint *));
 static char *parse_and_eval_memrange PARAMS ((char *,
                                              CORE_ADDR, 
                                              long *,
@@ -732,18 +730,24 @@ static char *parse_and_eval_memrange PARAMS ((char *,
 
 static void 
 end_actions_pseudocommand (args, from_tty)
+     char *args;
+     int from_tty;
 {
   error ("This command cannot be used at the top level.");
 }
 
 static void
 while_stepping_pseudocommand (args, from_tty)
+     char *args;
+     int from_tty;
 {
   error ("This command can only be used in a tracepoint actions list.");
 }
 
 static void
 collect_pseudocommand (args, from_tty)
+     char *args;
+     int from_tty;
 {
   error ("This command can only be used in a tracepoint actions list.");
 }
@@ -764,10 +768,13 @@ trace_actions_command (args, from_tty)
       sprintf (tmpbuf, "Enter actions for tracepoint %d, one per line.",
               t->number);
 
-      if (readline_begin_hook)
-       (*readline_begin_hook) ("%s  %s\n", tmpbuf, end_msg);
-      else if (from_tty && input_from_terminal_p ())
-       printf_filtered ("%s\n%s\n", tmpbuf, end_msg);
+      if (from_tty)
+       {
+         if (readline_begin_hook)
+           (*readline_begin_hook) ("%s  %s\n", tmpbuf, end_msg);
+         else if (input_from_terminal_p ())
+           printf_filtered ("%s\n%s\n", tmpbuf, end_msg);
+       }
 
       free_actions (t);
       read_actions (t);
@@ -788,7 +795,7 @@ enum actionline_type
   STEPPING =  2,
 };
 
-static enum actionline_type validate_actionline PARAMS((char *, 
+static enum actionline_type validate_actionline PARAMS((char **
                                                        struct tracepoint *));
 
 /* worker function */
@@ -823,15 +830,19 @@ read_actions (t)
       if (readline_hook && instream == NULL)
        line = (*readline_hook) (prompt);
       else if (instream == stdin && ISATTY (instream))
-       line = readline (prompt);
+       {
+         line = readline (prompt);
+         if (line && *line)            /* add it to command history */
+           add_history (line);
+       }
       else
        line = gdb_readline (0);
 
-      linetype = validate_actionline (line, t);
+      linetype = validate_actionline (&line, t);
       if (linetype == BADLINE)
        continue;       /* already warned -- collect another line */
 
-      temp = xmalloc (sizeof (struct action_line));
+      temp = (struct action_line *) xmalloc (sizeof (struct action_line));
       temp->next = NULL;
       temp->action = line;
 
@@ -868,7 +879,7 @@ read_actions (t)
 /* worker function */
 static enum actionline_type
 validate_actionline (line, t)
-     char *line;
+     char **line;
      struct tracepoint *t;
 {
   struct cmd_list_element *c;
@@ -876,13 +887,16 @@ validate_actionline (line, t)
   value_ptr temp, temp2;
   char *p;
 
-  for (p = line; isspace (*p); )
+  for (p = *line; isspace (*p); )
     p++;
 
   /* symbol lookup etc. */
   if (*p == '\0')      /* empty line: just prompt for another line. */
     return BADLINE;
 
+  if (*p == '#')       /* comment line */
+    return GENERIC;
+
   c = lookup_cmd (&p, cmdlist, "", -1, 1);
   if (c == 0)
     {
@@ -907,14 +921,38 @@ validate_actionline (line, t)
              p = strchr (p, ',');
 
            else if (p[1] == '(')       /* literal memrange */
-             p = parse_and_eval_memrange (p, t->address, 
-                                           &typecode, &offset, &size);
+             {
+               char *temp, *newline;
+
+               newline = malloc (strlen (*line) + 32);
+               strcpy (newline, *line);
+               newline[p - *line] = '\0';
+               /* newline is now a copy of line, up to "p" (the memrange) */
+               temp = parse_and_eval_memrange (p, t->address, 
+                                               &typecode, &offset, &size) + 1;
+               /* now compose the memrange as a literal value */
+               if (typecode == -1)
+                 sprintf (newline + strlen (newline), 
+                          "$(0x%x, %d)",
+                          offset, size);
+               else
+                 sprintf (newline + strlen (newline), 
+                          "$($%s, 0x%x, %d)", 
+                          reg_names[typecode], offset, size);
+               /* now add the remainder of the old line to the new one */
+               p = newline + strlen (newline);
+               if (temp && *temp)
+                 strcat (newline, temp);
+               free (*line);
+               *line = newline;
+             }
          }
        else
          {
            exp   = parse_exp_1 (&p, block_for_pc (t->address), 1);
 
            if (exp->elts[0].opcode != OP_VAR_VALUE &&
+               exp->elts[0].opcode != UNOP_MEMVAL  &&
              /*exp->elts[0].opcode != OP_LONG      && */
              /*exp->elts[0].opcode != UNOP_CAST    && */
                exp->elts[0].opcode != OP_REGISTER)
@@ -965,13 +1003,13 @@ validate_actionline (line, t)
     return END;
   else
     {
-      warning ("'%s' is not a supported tracepoint action.", line);
+      warning ("'%s' is not a supported tracepoint action.", *line);
       return BADLINE;
     }
 }
 
 /* worker function */
-static void 
+void 
 free_actions (t)
      struct tracepoint *t;
 {
@@ -980,6 +1018,8 @@ free_actions (t)
   for (line = t->actions; line; line = next)
     {
       next = line->next;
+      if (line->action) 
+       free (line->action);
       free (line);
     }
   t->actions = NULL;
@@ -1008,11 +1048,12 @@ parse_and_eval_memrange (arg, addr, typecode, offset, size)
      long *typecode, *size;
      bfd_signed_vma *offset;
 {
-  char *start = arg;
+  char *start      = arg;
   struct expression *exp;
+  value_ptr          val;
 
   if (*arg++ != '$' || *arg++ != '(')
-    error ("Internal: bad argument to validate_memrange: %s", start);
+    error ("Internal: bad argument to parse_and_eval_memrange: %s", start);
 
   if (*arg == '$')     /* register for relative memrange? */
     {
@@ -1024,67 +1065,18 @@ parse_and_eval_memrange (arg, addr, typecode, offset, size)
       *typecode = exp->elts[1].longconst;
     }
   else
-    *typecode = 0;
-
-#if 0
-  /* While attractive, this fails for a number of reasons:
-     1) parse_and_eval_address does not deal with trailing commas,
-        close-parens etc.
-     2) There is no safeguard against the user trying to use
-        an out-of-scope variable in an address expression (for instance).
-     2.5) If you are going to allow semi-arbitrary expressions, you 
-          would need to explain which expressions are allowed, and 
-         which are not (which would provoke endless questions).
-     3) If you are going to allow semi-arbitrary expressions in the
-        offset and size fields, then the leading "$" of a register
-       name no longer disambiguates the typecode field.
-  */
-
-  *offset = parse_and_eval_address (arg);
-  if ((arg = strchr (arg, ',')) == NULL)
-    error ("missing comma for memrange: %s", start);
-  else
-    arg++;
-
-  *size = parse_and_eval_address (arg);
-  if ((arg = strchr (arg, ')')) == NULL)
-    error ("missing close-parenthesis for memrange: %s", start);
-  else
-    arg++;
-#else
-#if 0
-  /* This, on the other hand, doesn't work because "-1" is an 
-     expression, not an OP_LONG!  Fall back to using strtol for now. */
+    *typecode = -1;    /* absolute memrange; */
 
-  exp = parse_exp_1 (&arg, block_for_pc (addr), 1);
-  if (exp->elts[0].opcode != OP_LONG)
-    error ("Bad offset operand for memrange: %s", start);
-  *offset = exp->elts[2].longconst;
+  exp = parse_exp_1 (&arg, 0, 1);
+  *offset = value_as_pointer (evaluate_expression (exp));
 
+  /* now parse the size */
   if (*arg++ != ',')
     error ("missing comma for memrange: %s", start);
 
-  exp = parse_exp_1 (&arg, block_for_pc (addr), 1);
-  if (exp->elts[0].opcode != OP_LONG)
-    error ("Bad size operand for memrange: %s", start);
-  *size = exp->elts[2].longconst;
-
-  if (*size <= 0)
-    error ("invalid size in memrange: %s", start);
+  exp = parse_exp_1 (&arg, 0, 0);
+  *size = value_as_long (evaluate_expression (exp));
 
-  if (*arg++ != ')')
-    error ("missing close-parenthesis for memrange: %s", start);
-#else
-  *offset = strtol (arg, &arg, 0);
-  if (*arg++ != ',')
-    error ("missing comma for memrange: %s", start);
-  *size   = strtol (arg, &arg, 0);
-  if (*size <= 0)
-    error ("invalid size in memrange: %s", start);
-  if (*arg++ != ')')
-    error ("missing close-parenthesis for memrange: %s", start);
-#endif
-#endif
   if (info_verbose)
     printf_filtered ("Collecting memrange: (0x%x,0x%x,0x%x)\n", 
                     *typecode, *offset, *size);
@@ -1094,9 +1086,14 @@ parse_and_eval_memrange (arg, addr, typecode, offset, size)
 
 /* compare memranges for qsort */
 static int
-memrange_cmp (a, b)
-     struct memrange *a, *b;
+memrange_cmp (voidpa, voidpb)
+     void *voidpa, *voidpb;
 {
+  struct memrange *a, *b;
+
+  a = (struct memrange *) voidpa;
+  b = (struct memrange *) voidpb;
+
   if (a->type < b->type) return -1;
   if (a->type > b->type) return  1;
   if (a->type == 0)
@@ -1129,7 +1126,9 @@ memrange_sortmerge (memranges)
              memranges->list[b].start - memranges->list[a].end <= 
              MAX_REGISTER_VIRTUAL_SIZE)
            {
-             memranges->list[a].end = memranges->list[b].end;
+             /* memrange b starts before memrange a ends; merge them.  */
+             if (memranges->list[b].end > memranges->list[a].end)
+               memranges->list[a].end = memranges->list[b].end;
              continue;         /* next b, same a */
            }
          a++;                  /* next a */
@@ -1175,11 +1174,11 @@ add_memrange (memranges, type, base, len)
   if (memranges->next_memrange >= memranges->listsize)
     {
       memranges->listsize *= 2;
-      memranges->list = xrealloc (memranges->list, 
+      memranges->list = (struct memrange *) xrealloc (memranges->list, 
                                  memranges->listsize);
     }
 
-  if (type != 0)       /* better collect the base register! */
+  if (type != -1)      /* better collect the base register! */
     add_register (memranges, type);
 }
 
@@ -1206,10 +1205,9 @@ collect_symbol (collect, sym)
   case LOC_STATIC:
     offset = SYMBOL_VALUE_ADDRESS (sym); 
     if (info_verbose)
-      printf_filtered ("LOC_STATIC %s: collect %d bytes "
-                      "at 0x%08x\n",
+      printf_filtered ("LOC_STATIC %s: collect %d bytes at 0x%08x\n",
                       SYMBOL_NAME (sym), len, offset);
-    add_memrange (collect, 0, offset, len);    /* 0 == memory */
+    add_memrange (collect, -1, offset, len);   /* 0 == memory */
     break;
   case LOC_REGISTER:
   case LOC_REGPARM:
@@ -1388,6 +1386,7 @@ encode_actions (t, tdp_actions, step_count, stepping_actions)
   struct action_line *action;
   bfd_signed_vma      offset;
   long                i;
+  value_ptr           tempval;
   struct collection_list  *collect;
   struct cmd_list_element *cmd;
 
@@ -1404,6 +1403,9 @@ encode_actions (t, tdp_actions, step_count, stepping_actions)
       while (isspace (*action_exp))
        action_exp++;
 
+      if (*action_exp == '#')  /* comment line */
+       return;
+
       cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
       if (cmd == 0)
        error ("Bad action list item: %s", action_exp);
@@ -1455,6 +1457,15 @@ encode_actions (t, tdp_actions, step_count, stepping_actions)
                    printf_filtered ("OP_REGISTER: ");
                  add_register (collect, i);
                  break;
+
+               case UNOP_MEMVAL:
+                 /* safe because we know it's a simple expression */
+                 tempval = evaluate_expression (exp);
+                 addr = VALUE_ADDRESS (tempval) + VALUE_OFFSET (tempval);
+                 len = TYPE_LENGTH (check_typedef (exp->elts[1].type));
+                 add_memrange (collect, -1, addr, len);
+                 break;
+
                case OP_VAR_VALUE:
                  collect_symbol (collect, exp->elts[2].symbol);
                  break;
@@ -1474,7 +1485,7 @@ encode_actions (t, tdp_actions, step_count, stepping_actions)
                  else 
                    len = 4;
 
-                 add_memrange (collect, 0, addr, len);
+                 add_memrange (collect, -1, addr, len);
                  break;
 #endif
                }
@@ -1496,8 +1507,8 @@ encode_actions (t, tdp_actions, step_count, stepping_actions)
   memrange_sortmerge (&tracepoint_list); 
   memrange_sortmerge (&stepping_list); 
 
-  *tdp_actions      = stringify_collection_list (&tracepoint_list, &tdp_buff);
-  *stepping_actions = stringify_collection_list (&stepping_list,   &step_buff);
+  *tdp_actions      = stringify_collection_list (&tracepoint_list, tdp_buff);
+  *stepping_actions = stringify_collection_list (&stepping_list,   step_buff);
 }
 
 static char target_buf[2048];
@@ -1545,16 +1556,16 @@ trace_start_command (args, from_tty)
              if (tdp_actions)
                {
                  if (strlen (buf) + strlen (tdp_actions) >= sizeof (buf))
-                   error ("Actions for tracepoint %d too complex; "
-                          "please simplify.", t->number);
+                   error ("Actions for tracepoint %d too complex; please simplify.",
+                          t->number);
                  strcat (buf, tdp_actions);
                }
              if (stepping_actions)
                {
                  strcat (buf, "S");
                  if (strlen (buf) + strlen (stepping_actions) >= sizeof (buf))
-                   error ("Actions for tracepoint %d too complex; "
-                          "please simplify.", t->number);
+                   error ("Actions for tracepoint %d too complex; please simplify.",
+                          t->number);
                  strcat (buf, stepping_actions);
                }
            }
@@ -1570,6 +1581,7 @@ trace_start_command (args, from_tty)
       set_traceframe_num (-1); /* all old traceframes invalidated */
       set_tracepoint_num (-1);
       set_traceframe_context(-1);
+      trace_running_p = 1;
     }
   else
     printf_filtered ("Trace can only be run on remote targets.\n");
@@ -1587,11 +1599,14 @@ trace_stop_command (args, from_tty)
       remote_get_noisy_reply (target_buf);
       if (strcmp (target_buf, "OK"))
        error ("Bogus reply from target: %s", target_buf);
+      trace_running_p = 0;
     }
   else
     error ("Trace can only be run on remote targets.");
 }
 
+unsigned long trace_running_p;
+
 /* tstatus command */
 static void
 trace_status_command (args, from_tty)
@@ -1602,8 +1617,13 @@ trace_status_command (args, from_tty)
     {
       putpkt ("qTStatus");
       remote_get_noisy_reply (target_buf);
-      if (strcmp (target_buf, "OK"))
-       error ("Bogus reply from target: %s", target_buf);
+
+      if (target_buf[0] != 'T' ||
+          (target_buf[1] != '0' && target_buf[1] != '1'))
+        error ("Bogus reply from target: %s", target_buf);
+      /* exported for use by the GUI */
+      trace_running_p = (target_buf[1] == '1');
     }
   else
     error ("Trace can only be run on remote targets.");
@@ -1693,8 +1713,20 @@ finish_tfind_command (msg, from_tty)
     {
       int source_only;
 
-      if (old_frame_addr == FRAME_FP (get_current_frame ()) &&
-         old_func       == find_pc_function (read_pc ()))
+      /* NOTE: in immitation 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 new source line.
+
+        This determination is made by checking (1) whether the current
+        function has changed, and (2) whether the current FP has changed.
+        Hack: if the FP wasn't collected, either at the current or the
+        previous frame, assume that the FP has NOT changed.  */
+
+      if (old_func       == find_pc_function (read_pc ()) &&
+        (old_frame_addr == 0 ||
+         FRAME_FP (get_current_frame ()) == 0 ||
+         old_frame_addr == FRAME_FP (get_current_frame ())))
        source_only = -1;
       else
        source_only =  1;
@@ -1742,7 +1774,7 @@ trace_find_command (args, from_tty)
        {
          if (traceframe_number == -1)
            error ("not debugging trace buffer");
-         else if (traceframe_number == 0)
+         else if (from_tty && traceframe_number == 0)
            error ("already at start of trace buffer");
 
          frameno = traceframe_number - 1;
@@ -2105,13 +2137,16 @@ tracepoint_save_command (args, from_tty)
                actionline++;
 
              fprintf (fp, "%s%s\n", indent, actionline);
-             cmd = lookup_cmd (&actionline, cmdlist, "", -1, 1);
-             if (cmd == 0)
-               error ("Bad action list item: %s", actionline);
-             if (cmd->function.cfunc == while_stepping_pseudocommand)
-               indent = i2;
-             else if (cmd->function.cfunc == end_actions_pseudocommand)
-               indent = i1;
+             if (*actionline != '#')   /* skip for comment lines */
+               {
+                 cmd = lookup_cmd (&actionline, cmdlist, "", -1, 1);
+                 if (cmd == 0)
+                   error ("Bad action list item: %s", actionline);
+                 if (cmd->function.cfunc == while_stepping_pseudocommand)
+                   indent = i2;
+                 else if (cmd->function.cfunc == end_actions_pseudocommand)
+                   indent = i1;
+               }
            }
        }
     }
@@ -2315,6 +2350,9 @@ trace_dump_command (args, from_tty)
       /* The collection actions to be done while stepping are
         bracketed by the commands "while-stepping" and "end".  */
 
+      if (*action_exp == '#')  /* comment line */
+       continue;
+
       cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
       if (cmd == 0)
        error ("Bad action list item: %s", action_exp);
@@ -2402,13 +2440,13 @@ _initialize_tracepoint ()
   if (tracepoint_list.list == NULL)
     {
       tracepoint_list.listsize = 128;
-      tracepoint_list.list = xmalloc 
+      tracepoint_list.list = (struct memrange *) xmalloc 
        (tracepoint_list.listsize * sizeof (struct memrange));
     }
   if (stepping_list.list == NULL)
     {
       stepping_list.listsize = 128;
-      stepping_list.list = xmalloc 
+      stepping_list.list = (struct memrange *) xmalloc 
        (stepping_list.listsize * sizeof (struct memrange));
     }
 
This page took 0.030653 seconds and 4 git commands to generate.