Fri Mar 13 15:37:02 1998 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
[platform/upstream/binutils.git] / gdb / tracepoint.c
1 /* Tracing functionality for remote targets in custom GDB protocol
2    Copyright 1997 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "defs.h"
21 #include "symtab.h"
22 #include "frame.h"
23 #include "tracepoint.h"
24 #include "gdbtypes.h"
25 #include "expression.h"
26 #include "gdbcmd.h"
27 #include "value.h"
28 #include "target.h"
29 #include "language.h"
30 #include "gdb_string.h"
31
32 /* readline include files */
33 #include "readline.h"
34 #include "history.h"
35
36 /* readline defines this.  */
37 #undef savestring
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 extern int info_verbose;
44 extern void (*readline_begin_hook) PARAMS ((char *, ...));
45 extern char * (*readline_hook) PARAMS ((char *));
46 extern void (*readline_end_hook) PARAMS ((void));
47 extern void x_command PARAMS ((char *, int));
48
49 /* If this definition isn't overridden by the header files, assume
50    that isatty and fileno exist on this system.  */
51 #ifndef ISATTY
52 #define ISATTY(FP)      (isatty (fileno (FP)))
53 #endif
54
55 /* 
56    Tracepoint.c:
57
58    This module defines the following debugger commands:
59    trace            : set a tracepoint on a function, line, or address.
60    info trace       : list all debugger-defined tracepoints.
61    delete trace     : delete one or more tracepoints.
62    enable trace     : enable one or more tracepoints.
63    disable trace    : disable one or more tracepoints.
64    actions          : specify actions to be taken at a tracepoint.
65    passcount        : specify a pass count for a tracepoint.
66    tstart           : start a trace experiment.
67    tstop            : stop a trace experiment.
68    tstatus          : query the status of a trace experiment.
69    tfind            : find a trace frame in the trace buffer.
70    tdump            : print everything collected at the current tracepoint.
71    save-tracepoints : write tracepoint setup into a file.
72
73    This module defines the following user-visible debugger variables:
74    $trace_frame : sequence number of trace frame currently being debugged.
75    $trace_line  : source line of trace frame currently being debugged.
76    $trace_file  : source file of trace frame currently being debugged.
77    $tracepoint  : tracepoint number of trace frame currently being debugged.
78    */
79
80
81 /* ======= Important global variables: ======= */
82
83 /* Chain of all tracepoints defined.  */
84 struct tracepoint *tracepoint_chain;
85
86 /* Number of last tracepoint made.  */
87 static int tracepoint_count;
88
89 /* Number of last traceframe collected.  */
90 static int traceframe_number;
91
92 /* Tracepoint for last traceframe collected.  */
93 static int tracepoint_number;
94
95 /* Symbol for function for last traceframe collected */
96 static struct symbol *traceframe_fun;
97
98 /* Symtab and line for last traceframe collected */
99 static struct symtab_and_line traceframe_sal;
100
101 /* Tracing command lists */
102 static struct cmd_list_element *tfindlist;
103
104 /* ======= Important command functions: ======= */
105 static void trace_command                 PARAMS ((char *, int));
106 static void tracepoints_info              PARAMS ((char *, int));
107 static void delete_trace_command          PARAMS ((char *, int));
108 static void enable_trace_command          PARAMS ((char *, int));
109 static void disable_trace_command         PARAMS ((char *, int));
110 static void trace_pass_command            PARAMS ((char *, int));
111 static void trace_actions_command         PARAMS ((char *, int));
112 static void trace_start_command           PARAMS ((char *, int));
113 static void trace_stop_command            PARAMS ((char *, int));
114 static void trace_status_command          PARAMS ((char *, int));
115 static void trace_find_command            PARAMS ((char *, int));
116 static void trace_find_pc_command         PARAMS ((char *, int));
117 static void trace_find_tracepoint_command PARAMS ((char *, int));
118 static void trace_find_line_command       PARAMS ((char *, int));
119 static void trace_find_range_command      PARAMS ((char *, int));
120 static void trace_find_outside_command    PARAMS ((char *, int));
121 static void tracepoint_save_command       PARAMS ((char *, int));
122 static void trace_dump_command            PARAMS ((char *, int));
123
124
125 /* Utility: returns true if "target remote" */
126 static int
127 target_is_remote ()
128 {
129   if (current_target.to_shortname &&
130       strcmp (current_target.to_shortname, "remote") == 0)
131     return 1;
132   else
133     return 0;
134 }
135
136 /* Utility: generate error from an incoming stub packet.  */
137 static void 
138 trace_error (buf)
139      char *buf;
140 {
141   if (*buf++ != 'E')
142     return;                     /* not an error msg */
143   switch (*buf) 
144     {
145     case '1':                   /* malformed packet error */
146       if (*++buf == '0')        /*   general case: */
147         error ("tracepoint.c: error in outgoing packet.");
148       else
149         error ("tracepoint.c: error in outgoing packet at field #%d.", 
150                strtol (buf, NULL, 16));
151     case '2':
152       error ("trace API error 0x%s.", ++buf);
153     default:
154       error ("Target returns error code '%s'.", buf);
155     }
156 }
157
158 /* Utility: wait for reply from stub, while accepting "O" packets */
159 static char *
160 remote_get_noisy_reply (buf)
161      char *buf;
162 {
163   do    /* loop on reply from remote stub */
164     {
165       getpkt (buf, 0);
166       if (buf[0] == 0)
167         error ("Target does not support this command.");
168       else if (buf[0] == 'E')
169         trace_error (buf);
170       else if (buf[0] == 'O' &&
171                buf[1] != 'K')
172         remote_console_output (buf + 1);        /* 'O' message from stub */
173       else
174         return buf;                             /* here's the actual reply */
175     } while (1);
176 }
177
178 /* Set tracepoint count to NUM.  */
179 static void
180 set_tracepoint_count (num)
181      int num;
182 {
183   tracepoint_count = num;
184   set_internalvar (lookup_internalvar ("tpnum"),
185                    value_from_longest (builtin_type_int, (LONGEST) num));
186 }
187
188 /* Set traceframe number to NUM.  */
189 static void
190 set_traceframe_num (num)
191      int num;
192 {
193   traceframe_number = num;
194   set_internalvar (lookup_internalvar ("trace_frame"),
195                    value_from_longest (builtin_type_int, (LONGEST) num));
196 }
197
198 /* Set tracepoint number to NUM.  */
199 static void
200 set_tracepoint_num (num)
201      int num;
202 {
203   tracepoint_number = num;
204   set_internalvar (lookup_internalvar ("tracepoint"),
205                    value_from_longest (builtin_type_int, (LONGEST) num));
206 }
207
208 /* Set externally visible debug variables for querying/printing
209    the traceframe context (line, function, file) */
210
211 static void
212 set_traceframe_context (trace_pc)
213      CORE_ADDR trace_pc;
214 {
215   static struct type *func_string, *file_string;
216   static struct type *func_range,  *file_range;
217   static value_ptr    func_val,     file_val;
218   static struct type *charstar;
219   int len;
220
221   if (charstar == (struct type *) NULL)
222     charstar = lookup_pointer_type (builtin_type_char);
223
224   if (trace_pc == -1)   /* cease debugging any trace buffers */
225     {
226       traceframe_fun = 0;
227       traceframe_sal.pc = traceframe_sal.line = 0;
228       traceframe_sal.symtab = NULL;
229       set_internalvar (lookup_internalvar ("trace_func"), 
230                        value_from_longest (charstar, (LONGEST) 0));
231       set_internalvar (lookup_internalvar ("trace_file"), 
232                        value_from_longest (charstar, (LONGEST) 0));
233       set_internalvar (lookup_internalvar ("trace_line"),
234                        value_from_longest (builtin_type_int, (LONGEST) -1));
235       return;
236     }
237
238   /* save as globals for internal use */
239   traceframe_sal = find_pc_line (trace_pc, 0);
240   traceframe_fun = find_pc_function (trace_pc);
241
242   /* save linenumber as "$trace_line", a debugger variable visible to users */
243   set_internalvar (lookup_internalvar ("trace_line"),
244                    value_from_longest (builtin_type_int, 
245                                        (LONGEST) traceframe_sal.line));
246
247   /* save func name as "$trace_func", a debugger variable visible to users */
248   if (traceframe_fun == NULL || 
249       SYMBOL_NAME (traceframe_fun) == NULL)
250     set_internalvar (lookup_internalvar ("trace_func"), 
251                      value_from_longest (charstar, (LONGEST) 0));
252   else
253     {
254       len = strlen (SYMBOL_NAME (traceframe_fun));
255       func_range  = create_range_type (func_range,  
256                                        builtin_type_int, 0, len - 1);
257       func_string = create_array_type (func_string, 
258                                        builtin_type_char, func_range);
259       func_val = allocate_value (func_string);
260       VALUE_TYPE (func_val) = func_string;
261       memcpy (VALUE_CONTENTS_RAW (func_val), 
262               SYMBOL_NAME (traceframe_fun), 
263               len);
264       func_val->modifiable = 0;
265       set_internalvar (lookup_internalvar ("trace_func"), func_val);
266     }
267
268   /* save file name as "$trace_file", a debugger variable visible to users */
269   if (traceframe_sal.symtab == NULL || 
270       traceframe_sal.symtab->filename == NULL)
271     set_internalvar (lookup_internalvar ("trace_file"), 
272                      value_from_longest (charstar, (LONGEST) 0));
273   else
274     {
275       len = strlen (traceframe_sal.symtab->filename);
276       file_range  = create_range_type (file_range,  
277                                        builtin_type_int, 0, len - 1);
278       file_string = create_array_type (file_string, 
279                                        builtin_type_char, file_range);
280       file_val = allocate_value (file_string);
281       VALUE_TYPE (file_val) = file_string;
282       memcpy (VALUE_CONTENTS_RAW (file_val), 
283               traceframe_sal.symtab->filename, 
284               len);
285       file_val->modifiable = 0;
286       set_internalvar (lookup_internalvar ("trace_file"), file_val);
287     }
288 }
289
290 /* Low level routine to set a tracepoint.
291    Returns the tracepoint object so caller can set other things.
292    Does not set the tracepoint number!
293    Does not print anything.
294
295    ==> This routine should not be called if there is a chance of later
296    error(); otherwise it leaves a bogus tracepoint on the chain.  Validate
297    your arguments BEFORE calling this routine!  */
298
299 static struct tracepoint *
300 set_raw_tracepoint (sal)
301      struct symtab_and_line sal;
302 {
303   register struct tracepoint *t, *tc;
304   struct cleanup *old_chain;
305
306   t = (struct tracepoint *) xmalloc (sizeof (struct tracepoint));
307   old_chain = make_cleanup (free, t);
308   memset (t, 0, sizeof (*t));
309   t->address = sal.pc;
310   if (sal.symtab == NULL)
311     t->source_file = NULL;
312   else
313     {
314       char *p;
315
316       t->source_file = (char *) xmalloc (strlen (sal.symtab->filename) +
317                                          strlen (sal.symtab->dirname) + 2);
318
319       strcpy (t->source_file, sal.symtab->dirname);
320       p = t->source_file;
321       while (*p)
322         p++;
323       if (*(--p) != '/')            /* Will this work on Windows? */
324         strcat (t->source_file, "/");
325       strcat (t->source_file, sal.symtab->filename);
326     }
327
328   t->language = current_language->la_language;
329   t->input_radix = input_radix;
330   t->line_number = sal.line;
331   t->enabled     = enabled;
332   t->next        = 0;
333   t->step_count  = 0;
334   t->pass_count  = 0;
335   t->addr_string = NULL;
336
337   /* Add this tracepoint to the end of the chain
338      so that a list of tracepoints will come out in order
339      of increasing numbers.  */
340
341   tc = tracepoint_chain;
342   if (tc == 0)
343     tracepoint_chain = t;
344   else
345     {
346       while (tc->next)
347         tc = tc->next;
348       tc->next = t;
349     }
350   discard_cleanups (old_chain);
351   return t;
352 }
353
354 /* Set a tracepoint according to ARG (function, linenum or *address) */
355 static void
356 trace_command (arg, from_tty)
357      char *arg;
358      int from_tty;
359 {
360   char **canonical = (char **)NULL;
361   struct symtabs_and_lines sals;
362   struct symtab_and_line sal;
363   struct tracepoint *t;
364   char *addr_start = 0, *addr_end = 0;
365   int i;
366
367   if (!arg || !*arg)
368     error ("trace command requires an argument");
369
370   if (from_tty && info_verbose)
371     printf_filtered ("TRACE %s\n", arg);
372
373   if (arg[0] == '/')
374     {
375       return;
376     }
377
378   addr_start = arg;
379   sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, &canonical);
380   addr_end   = arg;
381   if (! sals.nelts) 
382     return;     /* ??? Presumably decode_line_1 has already warned? */
383
384   /* Resolve all line numbers to PC's */
385   for (i = 0; i < sals.nelts; i++)
386     resolve_sal_pc (&sals.sals[i]);
387
388   /* Now set all the tracepoints.  */
389   for (i = 0; i < sals.nelts; i++)
390     {
391       sal = sals.sals[i];
392
393       t = set_raw_tracepoint (sal);
394       set_tracepoint_count (tracepoint_count + 1);
395       t->number = tracepoint_count;
396
397       /* If a canonical line spec is needed use that instead of the
398          command string.  */
399       if (canonical != (char **)NULL && canonical[i] != NULL)
400         t->addr_string = canonical[i];
401       else if (addr_start)
402         t->addr_string = savestring (addr_start, addr_end - addr_start);
403
404       /* Let the UI know of any additions */
405       if (create_tracepoint_hook)
406         create_tracepoint_hook (t);
407     }
408
409   if (sals.nelts > 1)
410     {
411       printf_filtered ("Multiple tracepoints were set.\n");
412       printf_filtered ("Use 'delete trace' to delete unwanted tracepoints.\n");
413     }
414 }
415
416 /* Print information on tracepoint number TPNUM_EXP, or all if omitted.  */
417
418 static void
419 tracepoints_info (tpnum_exp, from_tty)
420      char *tpnum_exp;
421      int from_tty;
422 {
423   struct tracepoint *t;
424   struct action_line *action;
425   int found_a_tracepoint = 0;
426   char wrap_indent[80];
427   struct symbol *sym;
428   int tpnum = -1;
429 #if 0
430   char *i1 = "\t", *i2 = "\t  ";
431   char *indent, *actionline;;
432 #endif
433
434   if (tpnum_exp)
435     tpnum = parse_and_eval_address (tpnum_exp);
436
437   ALL_TRACEPOINTS (t)
438     if (tpnum == -1 || tpnum == t->number)
439       {
440         extern int addressprint;        /* print machine addresses? */
441
442         if (!found_a_tracepoint++)
443           {
444             printf_filtered ("Num Enb ");
445             if (addressprint)
446               printf_filtered ("Address    ");
447             printf_filtered ("PassC StepC What\n");
448           }
449         strcpy (wrap_indent, "                           ");
450         if (addressprint)
451           strcat (wrap_indent, "           ");
452
453         printf_filtered ("%-3d %-3s ", t->number, 
454                          t->enabled == enabled ? "y" : "n");
455         if (addressprint)
456           printf_filtered ("%s ", 
457                            local_hex_string_custom ((unsigned long) t->address, 
458                                                     "08l"));
459         printf_filtered ("%-5d %-5d ", t->pass_count, t->step_count);
460
461         if (t->source_file)
462           {
463             sym = find_pc_function (t->address);
464             if (sym)
465               {
466                 fputs_filtered ("in ", gdb_stdout);
467                 fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout);
468                 wrap_here (wrap_indent);
469                 fputs_filtered (" at ", gdb_stdout);
470               }
471             fputs_filtered (t->source_file, gdb_stdout);
472             printf_filtered (":%d", t->line_number);
473           }
474         else
475           print_address_symbolic (t->address, gdb_stdout, demangle, " ");
476
477         printf_filtered ("\n");
478         if (t->actions)
479           {
480             printf_filtered ("  Actions for tracepoint %d: \n", t->number);
481 /*          indent = i1; */
482             for (action = t->actions; action; action = action->next)
483               {
484 #if 0
485                 actionline = action->action;
486                 while (isspace(*actionline))
487                   actionline++;
488
489                 printf_filtered ("%s%s\n", indent, actionline);
490                 if (0 == strncasecmp (actionline, "while-stepping", 14))
491                   indent = i2;
492                 else if (0 == strncasecmp (actionline, "end", 3))
493                   indent = i1;
494 #else
495                 printf_filtered ("\t%s\n", action->action);
496 #endif
497               }
498           }
499       }
500   if (!found_a_tracepoint)
501     {
502       if (tpnum == -1)
503         printf_filtered ("No tracepoints.\n");
504       else
505         printf_filtered ("No tracepoint number %d.\n", tpnum);
506     }
507 }
508
509 /* Optimization: the code to parse an enable, disable, or delete TP command
510    is virtually identical except for whether it performs an enable, disable,
511    or delete.  Therefore I've combined them into one function with an opcode.
512    */
513 enum tracepoint_opcode 
514 {
515   enable, 
516   disable,
517   delete
518 };
519
520 /* This function implements enable, disable and delete. */
521 static void
522 tracepoint_operation (t, from_tty, opcode)
523      struct tracepoint *t;
524      int from_tty;
525      enum tracepoint_opcode opcode;
526 {
527   struct tracepoint *t2;
528
529   switch (opcode) {
530   case enable:
531     t->enabled = enabled;
532     if (modify_tracepoint_hook)
533       modify_tracepoint_hook (t);
534     break;
535   case disable:
536     t->enabled = disabled;
537     if (modify_tracepoint_hook)
538       modify_tracepoint_hook (t);
539     break;
540   case delete:
541     if (tracepoint_chain == t)
542       tracepoint_chain = t->next;
543
544     ALL_TRACEPOINTS (t2)
545       if (t2->next == t)
546         {
547           t2->next = t->next;
548           break;
549         }
550
551     /* Let the UI know of any deletions */
552     if (delete_tracepoint_hook)
553       delete_tracepoint_hook (t);
554
555     if (t->addr_string)
556       free (t->addr_string);
557     if (t->source_file)
558       free (t->source_file);
559     if (t->actions)
560       free_actions (t);
561
562     free (t);
563     break;
564   }
565 }
566
567 /* Utility: parse a tracepoint number and look it up in the list.  */
568 struct tracepoint *
569 get_tracepoint_by_number (arg)
570      char **arg;
571 {
572   struct tracepoint *t;
573   char *end, *copy;
574   value_ptr val;
575   int tpnum;
576
577   if (arg == 0)
578     error ("Bad tracepoint argument");
579
580   if (*arg == 0 || **arg == 0)  /* empty arg means refer to last tp */
581     tpnum = tracepoint_count;
582   else if (**arg == '$')        /* handle convenience variable */
583     {
584       /* Make a copy of the name, so we can null-terminate it
585          to pass to lookup_internalvar().  */
586       end = *arg + 1;
587       while (isalnum(*end) || *end == '_')
588         end++;
589       copy = (char *) alloca (end - *arg);
590       strncpy (copy, *arg + 1, (end - *arg - 1));
591       copy[end - *arg - 1] = '\0';
592       *arg = end;
593
594       val = value_of_internalvar (lookup_internalvar (copy));
595       if (TYPE_CODE( VALUE_TYPE (val)) != TYPE_CODE_INT)
596         error ("Convenience variable must have integral type.");
597       tpnum = (int) value_as_long (val);
598     }
599   else          /* handle tracepoint number */
600     {
601       tpnum = strtol (*arg, arg, 10);
602     }
603   ALL_TRACEPOINTS (t)
604     if (t->number == tpnum)
605       {
606         return t;
607       }
608   warning ("No tracepoint number %d.\n", tpnum);
609   return NULL;
610 }
611
612 /* Utility: parse a list of tracepoint numbers, and call a func for each. */
613 static void
614 map_args_over_tracepoints (args, from_tty, opcode)
615      char *args;
616      int from_tty;
617      enum tracepoint_opcode opcode;
618 {
619   struct tracepoint *t, *tmp;
620   int tpnum;
621   char *cp;
622
623   if (args == 0 || *args == 0)  /* do them all */
624     ALL_TRACEPOINTS_SAFE (t, tmp)
625       tracepoint_operation (t, from_tty, opcode);
626   else
627     while (*args)
628       {
629         if (t = get_tracepoint_by_number (&args))
630           tracepoint_operation (t, from_tty, opcode);
631         while (*args == ' ' || *args == '\t')
632           args++;
633       }
634 }
635
636 /* The 'enable trace' command enables tracepoints.  Not supported by all targets.  */
637 static void
638 enable_trace_command (args, from_tty)
639      char *args;
640      int from_tty;
641 {
642   dont_repeat ();
643   map_args_over_tracepoints (args, from_tty, enable);
644 }
645
646 /* The 'disable trace' command enables tracepoints.  Not supported by all targets.  */
647 static void
648 disable_trace_command (args, from_tty)
649      char *args;
650      int from_tty;
651 {
652   dont_repeat ();
653   map_args_over_tracepoints (args, from_tty, disable);
654 }
655
656 /* Remove a tracepoint (or all if no argument) */
657 static void
658 delete_trace_command (args, from_tty)
659      char *args;
660      int from_tty;
661 {
662   dont_repeat ();
663   if (!args || !*args)
664     if (!query ("Delete all tracepoints? "))
665       return;
666
667   map_args_over_tracepoints (args, from_tty, delete);
668 }
669
670 /* Set passcount for tracepoint.
671
672    First command argument is passcount, second is tracepoint number.
673    If tracepoint number omitted, apply to most recently defined.
674    Also accepts special argument "all".  */
675
676 static void
677 trace_pass_command (args, from_tty)
678      char *args;
679      int from_tty;
680 {
681   struct tracepoint *t1 = (struct tracepoint *) -1, *t2;
682   unsigned long count;
683
684   if (args == 0 || *args == 0)
685     error ("PASS command requires an argument (count + optional TP num)");
686
687   count = strtoul (args, &args, 10);    /* count comes first, then TP num */
688
689   while (*args && isspace (*args))
690     args++;
691
692   if (*args && strncasecmp (args, "all", 3) == 0)
693     args += 3;  /* skip special argument "all" */
694   else
695     t1 = get_tracepoint_by_number (&args);
696
697   if (t1 == NULL)
698     return;     /* error, bad tracepoint number */
699
700   ALL_TRACEPOINTS (t2)
701     if (t1 == (struct tracepoint *) -1 || t1 == t2)
702       {
703         t2->pass_count = count;
704         if (from_tty)
705           printf_filtered ("Setting tracepoint %d's passcount to %d\n", 
706                            t2->number, count);
707       }
708 }
709
710 /* ACTIONS functions: */
711
712 /* Prototypes for action-parsing utility commands  */
713 static void  read_actions PARAMS((struct tracepoint *));
714 static char *parse_and_eval_memrange PARAMS ((char *,
715                                               CORE_ADDR, 
716                                               long *,
717                                               bfd_signed_vma *,
718                                               long *));
719
720 /* The three functions:
721         collect_pseudocommand, 
722         while_stepping_pseudocommand, and 
723         end_actions_pseudocommand
724    are placeholders for "commands" that are actually ONLY to be used
725    within a tracepoint action list.  If the actual function is ever called,
726    it means that somebody issued the "command" at the top level,
727    which is always an error.  */
728
729 static void 
730 end_actions_pseudocommand (args, from_tty)
731      char *args;
732      int from_tty;
733 {
734   error ("This command cannot be used at the top level.");
735 }
736
737 static void
738 while_stepping_pseudocommand (args, from_tty)
739      char *args;
740      int from_tty;
741 {
742   error ("This command can only be used in a tracepoint actions list.");
743 }
744
745 static void
746 collect_pseudocommand (args, from_tty)
747      char *args;
748      int from_tty;
749 {
750   error ("This command can only be used in a tracepoint actions list.");
751 }
752
753 /* Enter a list of actions for a tracepoint.  */
754 static void
755 trace_actions_command (args, from_tty)
756      char *args;
757      int from_tty;
758 {
759   struct tracepoint *t;
760   char *actions;
761   char tmpbuf[128];
762   char *end_msg = "End with a line saying just \"end\".";
763
764   if (t = get_tracepoint_by_number (&args))
765     {
766       sprintf (tmpbuf, "Enter actions for tracepoint %d, one per line.",
767                t->number);
768
769       if (from_tty)
770         {
771           if (readline_begin_hook)
772             (*readline_begin_hook) ("%s  %s\n", tmpbuf, end_msg);
773           else if (input_from_terminal_p ())
774             printf_filtered ("%s\n%s\n", tmpbuf, end_msg);
775         }
776
777       free_actions (t);
778       read_actions (t);
779
780       if (readline_end_hook)
781         (*readline_end_hook) ();
782
783       /* tracepoints_changed () */
784     }
785   /* else error, just return; */
786 }
787
788 enum actionline_type
789 {
790   BADLINE  = -1, 
791   GENERIC  =  0,
792   END      =  1,
793   STEPPING =  2,
794 };
795
796 static enum actionline_type validate_actionline PARAMS((char **, 
797                                                         struct tracepoint *));
798
799 /* worker function */
800 static void
801 read_actions (t)
802      struct tracepoint *t;
803 {
804   char *line;
805   char *prompt1 = "> ", *prompt2 = "  > ";
806   char *prompt = prompt1;
807   enum actionline_type linetype;
808   extern FILE *instream;
809   struct action_line *next = NULL, *temp;
810   struct cleanup *old_chain;
811
812   /* Control-C quits instantly if typed while in this loop
813      since it should not wait until the user types a newline.  */
814   immediate_quit++;
815 #ifdef STOP_SIGNAL
816   if (job_control)
817     signal (STOP_SIGNAL, stop_sig);
818 #endif
819   old_chain = make_cleanup (free_actions, (void *) t);
820   while (1)
821     {
822       /* Make sure that all output has been output.  Some machines may let
823          you get away with leaving out some of the gdb_flush, but not all.  */
824       wrap_here ("");
825       gdb_flush (gdb_stdout);
826       gdb_flush (gdb_stderr);
827
828       if (readline_hook && instream == NULL)
829         line = (*readline_hook) (prompt);
830       else if (instream == stdin && ISATTY (instream))
831         {
832           line = readline (prompt);
833           if (line && *line)            /* add it to command history */
834             add_history (line);
835         }
836       else
837         line = gdb_readline (0);
838
839       linetype = validate_actionline (&line, t);
840       if (linetype == BADLINE)
841         continue;       /* already warned -- collect another line */
842
843       temp = xmalloc (sizeof (struct action_line));
844       temp->next = NULL;
845       temp->action = line;
846
847       if (next == NULL)         /* first action for this tracepoint? */
848         t->actions = next = temp;
849       else
850         {
851           next->next = temp;
852           next = temp;
853         }
854
855       if (linetype == STEPPING) /* begin "while-stepping" */
856         if (prompt == prompt2)
857           {
858             warning ("Already processing 'while-stepping'");
859             continue;
860           }
861         else
862           prompt = prompt2;     /* change prompt for stepping actions */
863       else if (linetype == END)
864         if (prompt == prompt2)
865           prompt = prompt1;     /* end of single-stepping actions */
866         else
867           break;                /* end of actions */
868     }
869 #ifdef STOP_SIGNAL
870   if (job_control)
871     signal (STOP_SIGNAL, SIG_DFL);
872 #endif
873   immediate_quit = 0;
874   discard_cleanups (old_chain);
875 }
876
877 /* worker function */
878 static enum actionline_type
879 validate_actionline (line, t)
880      char **line;
881      struct tracepoint *t;
882 {
883   struct cmd_list_element *c;
884   struct expression *exp;
885   value_ptr temp, temp2;
886   char *p;
887
888   for (p = *line; isspace (*p); )
889     p++;
890
891   /* symbol lookup etc. */
892   if (*p == '\0')       /* empty line: just prompt for another line. */
893     return BADLINE;
894
895   if (*p == '#')        /* comment line */
896     return GENERIC;
897
898   c = lookup_cmd (&p, cmdlist, "", -1, 1);
899   if (c == 0)
900     {
901       warning ("'%s' is not an action that I know, or is ambiguous.", p);
902       return BADLINE;
903     }
904     
905   if (c->function.cfunc == collect_pseudocommand)
906     {
907       do {                      /* repeat over a comma-separated list */
908         while (isspace (*p))
909           p++;
910
911         if (*p == '$')                  /* look for special pseudo-symbols */
912           {
913             long typecode, size;
914             bfd_signed_vma offset;
915
916             if ((0 == strncasecmp ("reg", p + 1, 3)) ||
917                 (0 == strncasecmp ("arg", p + 1, 3)) ||
918                 (0 == strncasecmp ("loc", p + 1, 3)))
919               p = strchr (p, ',');
920
921             else if (p[1] == '(')       /* literal memrange */
922               {
923                 char *temp, *newline;
924
925                 newline = malloc (strlen (*line) + 32);
926                 strcpy (newline, *line);
927                 newline[p - *line] = '\0';
928                 /* newline is now a copy of line, up to "p" (the memrange) */
929                 temp = parse_and_eval_memrange (p, t->address, 
930                                                 &typecode, &offset, &size) + 1;
931                 /* now compose the memrange as a literal value */
932                 if (typecode == -1)
933                   sprintf (newline + strlen (newline), 
934                            "$(0x%x, %d)",
935                            offset, size);
936                 else
937                   sprintf (newline + strlen (newline), 
938                            "$($%s, 0x%x, %d)", 
939                            reg_names[typecode], offset, size);
940                 /* now add the remainder of the old line to the new one */
941                 p = newline + strlen (newline);
942                 if (temp && *temp)
943                   strcat (newline, temp);
944                 free (*line);
945                 *line = newline;
946               }
947           }
948         else
949           {
950             exp   = parse_exp_1 (&p, block_for_pc (t->address), 1);
951
952             if (exp->elts[0].opcode != OP_VAR_VALUE &&
953                 exp->elts[0].opcode != UNOP_MEMVAL  &&
954               /*exp->elts[0].opcode != OP_LONG      && */
955               /*exp->elts[0].opcode != UNOP_CAST    && */
956                 exp->elts[0].opcode != OP_REGISTER)
957               {
958                 warning ("collect requires a variable or register name.\n");
959                 return BADLINE;
960               }
961             if (exp->elts[0].opcode == OP_VAR_VALUE)
962               if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
963                 {
964                   warning ("%s is constant (value %d): will not be collected.",
965                            SYMBOL_NAME (exp->elts[2].symbol),
966                            SYMBOL_VALUE (exp->elts[2].symbol));
967                   return BADLINE;
968                 }
969               else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT)
970                 {
971                   warning ("%s is optimized away and cannot be collected.",
972                            SYMBOL_NAME (exp->elts[2].symbol));
973                   return BADLINE;
974                 }
975           }
976       } while (p && *p++ == ',');
977       return GENERIC;
978     }
979   else if (c->function.cfunc == while_stepping_pseudocommand)
980     {
981       char *steparg;    /* in case warning is necessary */
982
983       while (isspace (*p))
984         p++;
985       steparg = p;
986
987       if (*p)
988         {
989           t->step_count = strtol (p, &p, 0);
990           if (t->step_count == 0)
991             {
992               warning ("'%s' evaluates to zero -- command ignored.");
993               return BADLINE;
994             }
995         }
996       else 
997         t->step_count = -1;
998       return STEPPING;
999     }
1000   else if (c->function.cfunc == end_actions_pseudocommand)
1001     return END;
1002   else
1003     {
1004       warning ("'%s' is not a supported tracepoint action.", *line);
1005       return BADLINE;
1006     }
1007 }
1008
1009 /* worker function */
1010 void 
1011 free_actions (t)
1012      struct tracepoint *t;
1013 {
1014   struct action_line *line, *next;
1015
1016   for (line = t->actions; line; line = next)
1017     {
1018       next = line->next;
1019       if (line->action) 
1020         free (line->action);
1021       free (line);
1022     }
1023   t->actions = NULL;
1024 }
1025
1026 struct memrange {
1027   int type;             /* 0 for absolute memory range, else basereg number */
1028   bfd_signed_vma start;
1029   bfd_signed_vma end;
1030 };
1031
1032 struct collection_list {
1033   unsigned char regs_mask[8];   /* room for up to 256 regs */
1034   long listsize;
1035   long next_memrange;
1036   struct memrange *list;
1037 } tracepoint_list, stepping_list;
1038
1039 /* MEMRANGE functions: */
1040
1041 /* parse a memrange spec from command input */
1042 static char *
1043 parse_and_eval_memrange (arg, addr, typecode, offset, size)
1044      char *arg;
1045      CORE_ADDR addr;
1046      long *typecode, *size;
1047      bfd_signed_vma *offset;
1048 {
1049   char *start      = arg;
1050   struct expression *exp;
1051   value_ptr          val;
1052
1053   if (*arg++ != '$' || *arg++ != '(')
1054     error ("Internal: bad argument to parse_and_eval_memrange: %s", start);
1055
1056   if (*arg == '$')      /* register for relative memrange? */
1057     {
1058       exp = parse_exp_1 (&arg, block_for_pc (addr), 1);
1059       if (exp->elts[0].opcode != OP_REGISTER)
1060         error ("Bad register operand for memrange: %s", start);
1061       if (*arg++ != ',')
1062         error ("missing comma for memrange: %s", start);
1063       *typecode = exp->elts[1].longconst;
1064     }
1065   else
1066     *typecode = -1;     /* absolute memrange; */
1067
1068   exp = parse_exp_1 (&arg, 0, 1);
1069   *offset = value_as_pointer (evaluate_expression (exp));
1070
1071   /* now parse the size */
1072   if (*arg++ != ',')
1073     error ("missing comma for memrange: %s", start);
1074
1075   exp = parse_exp_1 (&arg, 0, 0);
1076   *size = value_as_long (evaluate_expression (exp));
1077
1078   if (info_verbose)
1079     printf_filtered ("Collecting memrange: (0x%x,0x%x,0x%x)\n", 
1080                      *typecode, *offset, *size);
1081
1082   return arg;
1083 }
1084
1085 /* compare memranges for qsort */
1086 static int
1087 memrange_cmp (a, b)
1088      struct memrange *a, *b;
1089 {
1090   if (a->type < b->type) return -1;
1091   if (a->type > b->type) return  1;
1092   if (a->type == 0)
1093     {
1094       if ((bfd_vma) a->start  < (bfd_vma) b->start)  return -1;
1095       if ((bfd_vma) a->start  > (bfd_vma) b->start)  return  1;
1096     }
1097   else
1098     {
1099       if (a->start  < b->start)  return -1;
1100       if (a->start  > b->start)  return  1;
1101     }
1102   return 0;
1103 }
1104
1105 /* Sort the memrange list using qsort, and merge adjacent memranges */
1106 static void
1107 memrange_sortmerge (memranges)
1108      struct collection_list *memranges;
1109 {
1110   int a, b;
1111
1112   qsort (memranges->list, memranges->next_memrange, 
1113          sizeof (struct memrange), memrange_cmp);
1114   if (memranges->next_memrange > 0)
1115     {
1116       for (a = 0, b = 1; b < memranges->next_memrange; b++)
1117         {
1118           if (memranges->list[a].type == memranges->list[b].type &&
1119               memranges->list[b].start - memranges->list[a].end <= 
1120               MAX_REGISTER_VIRTUAL_SIZE)
1121             {
1122               /* memrange b starts before memrange a ends; merge them.  */
1123               if (memranges->list[b].end > memranges->list[a].end)
1124                 memranges->list[a].end = memranges->list[b].end;
1125               continue;         /* next b, same a */
1126             }
1127           a++;                  /* next a */
1128           if (a != b)
1129             memcpy (&memranges->list[a], &memranges->list[b], 
1130                     sizeof (struct memrange));
1131         }
1132       memranges->next_memrange = a + 1;
1133     }
1134 }
1135
1136 /* Add a register to a collection list */
1137 void
1138 add_register (collection, regno)
1139      struct collection_list *collection;
1140      unsigned long regno;
1141 {
1142   if (info_verbose)
1143     printf_filtered ("collect register %d\n", regno);
1144   if (regno > (8 * sizeof (collection->regs_mask)))
1145     error ("Internal: register number %d too large for tracepoint",
1146            regno);
1147   collection->regs_mask [regno / 8] |= 1 << (regno  % 8);
1148 }
1149
1150 /* Add a memrange to a collection list */
1151 static void
1152 add_memrange (memranges, type, base, len)
1153      struct collection_list *memranges;
1154      int type;
1155      bfd_signed_vma base;
1156      unsigned long len;
1157 {
1158   if (info_verbose)
1159     printf_filtered ("(%d,0x%x,%d)\n", type, base, len);
1160   /* type: 0 == memory, n == basereg */
1161   memranges->list[memranges->next_memrange].type  = type;
1162   /* base: addr if memory, offset if reg relative. */
1163   memranges->list[memranges->next_memrange].start = base;
1164   /* len: we actually save end (base + len) for convenience */
1165   memranges->list[memranges->next_memrange].end   = base + len;
1166   memranges->next_memrange++;
1167   if (memranges->next_memrange >= memranges->listsize)
1168     {
1169       memranges->listsize *= 2;
1170       memranges->list = xrealloc (memranges->list, 
1171                                   memranges->listsize);
1172     }
1173
1174   if (type != -1)       /* better collect the base register! */
1175     add_register (memranges, type);
1176 }
1177
1178 /* Add a symbol to a collection list */
1179 static void
1180 collect_symbol (collect, sym)
1181      struct collection_list *collect;
1182      struct symbol *sym;
1183 {
1184   unsigned long  len;
1185   unsigned long  reg;
1186   bfd_signed_vma offset;
1187
1188   len  = TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym)));
1189   switch (SYMBOL_CLASS (sym)) {
1190   default:
1191     printf_filtered ("%s: don't know symbol class %d\n",
1192                      SYMBOL_NAME (sym), SYMBOL_CLASS (sym));
1193     break;
1194   case LOC_CONST:
1195     printf_filtered ("%s is constant, value is %d: will not be collected.\n",
1196                      SYMBOL_NAME (sym), SYMBOL_VALUE (sym));
1197     break;
1198   case LOC_STATIC:
1199     offset = SYMBOL_VALUE_ADDRESS (sym); 
1200     if (info_verbose)
1201       printf_filtered ("LOC_STATIC %s: collect %d bytes at 0x%08x\n",
1202                        SYMBOL_NAME (sym), len, offset);
1203     add_memrange (collect, -1, offset, len);    /* 0 == memory */
1204     break;
1205   case LOC_REGISTER:
1206   case LOC_REGPARM:
1207     reg = SYMBOL_VALUE (sym); 
1208     if (info_verbose)
1209       printf_filtered ("LOC_REG[parm] %s: ", SYMBOL_NAME (sym));
1210     add_register (collect, reg);
1211     break;
1212   case LOC_ARG:
1213   case LOC_REF_ARG:
1214     printf_filtered ("Sorry, don't know how to do LOC_ARGs yet.\n");
1215     printf_filtered ("       (will not collect %s)\n", 
1216                      SYMBOL_NAME (sym));
1217     break;
1218   case LOC_REGPARM_ADDR:
1219     reg = SYMBOL_VALUE (sym);
1220     offset = 0;
1221     if (info_verbose)
1222       {
1223         printf_filtered ("LOC_REGPARM_ADDR %s: Collect %d bytes at offset %d from reg %d\n", 
1224                          SYMBOL_NAME (sym), len, offset, reg);
1225       }
1226     add_memrange (collect, reg, offset, len);
1227     break;
1228   case LOC_LOCAL:
1229   case LOC_LOCAL_ARG:
1230     offset = SYMBOL_VALUE (sym);
1231     reg = FP_REGNUM;
1232     if (info_verbose)
1233       {
1234         printf_filtered ("LOC_LOCAL %s: Collect %d bytes at offset %d from frame ptr reg %d\n", 
1235                          SYMBOL_NAME (sym), len, offset, reg);
1236       }
1237     add_memrange (collect, reg, offset, len);
1238     break;
1239   case LOC_BASEREG:
1240   case LOC_BASEREG_ARG:
1241     reg = SYMBOL_BASEREG (sym);
1242     offset  = SYMBOL_VALUE (sym);
1243     if (info_verbose)
1244       {
1245         printf_filtered ("LOC_BASEREG %s: collect %d bytes at offset %d from basereg %d\n", 
1246                          SYMBOL_NAME (sym), len, offset, reg);
1247       }
1248     add_memrange (collect, reg, offset, len);
1249     break;
1250   case LOC_UNRESOLVED:
1251     printf_filtered ("Don't know LOC_UNRESOLVED %s\n", SYMBOL_NAME (sym));
1252     break;
1253   case LOC_OPTIMIZED_OUT:
1254     printf_filtered ("%s has been optimized out of existance.\n",
1255                      SYMBOL_NAME (sym));
1256     break;
1257   }
1258 }
1259
1260 /* Add all locals (or args) symbols to collection list */
1261 static void
1262 add_local_symbols (collect, pc, type)
1263      struct collection_list *collect;
1264      CORE_ADDR pc;
1265      char type;
1266 {
1267   struct symbol *sym;
1268   struct block  *block;
1269   int i, nsyms, count = 0;
1270
1271   block = block_for_pc (pc);
1272   while (block != 0)
1273     {
1274       nsyms = BLOCK_NSYMS (block);
1275       for (i = 0; i < nsyms; i++)
1276         {
1277           sym = BLOCK_SYM (block, i);
1278           switch (SYMBOL_CLASS (sym)) {
1279           case LOC_LOCAL:
1280           case LOC_STATIC:
1281           case LOC_REGISTER:
1282           case LOC_BASEREG:
1283             if (type == 'L')    /* collecting Locals */
1284               {
1285                 count++;
1286                 collect_symbol (collect, sym);
1287               }
1288             break;
1289           case LOC_ARG:
1290           case LOC_LOCAL_ARG:
1291           case LOC_REF_ARG:
1292           case LOC_REGPARM:
1293           case LOC_REGPARM_ADDR:
1294           case LOC_BASEREG_ARG:
1295             if (type == 'A')    /* collecting Arguments */
1296               {
1297                 count++;
1298                 collect_symbol (collect, sym);
1299               }
1300           }
1301         }
1302       if (BLOCK_FUNCTION (block))
1303         break;
1304       else
1305         block = BLOCK_SUPERBLOCK (block);
1306     }
1307   if (count == 0)
1308     warning ("No %s found in scope.", type == 'L' ? "locals" : "args");
1309 }
1310
1311 /* worker function */
1312 static void
1313 clear_collection_list (list)
1314      struct collection_list *list;
1315 {
1316   list->next_memrange = 0;
1317   memset (list->regs_mask, 0, sizeof (list->regs_mask));
1318 }
1319
1320 /* reduce a collection list to string form (for gdb protocol) */
1321 static char *
1322 stringify_collection_list (list, string)
1323      struct collection_list *list;
1324      char *string;
1325 {
1326   char *end = string;
1327   long  i;
1328
1329   for (i = sizeof (list->regs_mask) - 1; i > 0; i--)
1330     if (list->regs_mask[i] != 0)        /* skip leading zeroes in regs_mask */
1331       break;
1332   if (list->regs_mask[i] != 0)  /* prepare to send regs_mask to the stub */
1333     {
1334       if (info_verbose)
1335         printf_filtered ("\nCollecting registers (mask): 0x");
1336       *end++='R';
1337       for (; i >= 0; i--)
1338         {
1339           if (info_verbose)
1340             printf_filtered ("%02X", list->regs_mask[i]);
1341           sprintf (end,  "%02X", list->regs_mask[i]);
1342           end += 2;
1343         }
1344     }
1345   if (info_verbose)
1346     printf_filtered ("\n");
1347   if (list->next_memrange > 0 && info_verbose)
1348     printf_filtered ("Collecting memranges: \n");
1349   for (i = 0; i < list->next_memrange; i++)
1350     {
1351       if (info_verbose)
1352         printf_filtered ("(%d, 0x%x, %d)\n", 
1353                          list->list[i].type, 
1354                          list->list[i].start, 
1355                          list->list[i].end - list->list[i].start);
1356       sprintf (end, "M%X,%X,%X", 
1357                list->list[i].type, 
1358                list->list[i].start, 
1359                list->list[i].end - list->list[i].start);
1360       end += strlen (end);
1361     }
1362   if (end == string)
1363     return NULL;
1364   else
1365     return string;
1366 }
1367
1368 /* render all actions into gdb protocol */
1369 static void
1370 encode_actions (t, tdp_actions, step_count, stepping_actions)
1371      struct tracepoint  *t;
1372      char              **tdp_actions;
1373      unsigned long      *step_count;
1374      char              **stepping_actions;
1375 {
1376   static char        tdp_buff[2048], step_buff[2048];
1377   char               *action_exp;
1378   struct expression  *exp;
1379   struct action_line *action;
1380   bfd_signed_vma      offset;
1381   long                i;
1382   value_ptr           tempval;
1383   struct collection_list  *collect;
1384   struct cmd_list_element *cmd;
1385
1386   clear_collection_list (&tracepoint_list);
1387   clear_collection_list (&stepping_list);
1388   collect = &tracepoint_list;
1389
1390   *tdp_actions = NULL;
1391   *stepping_actions = NULL;
1392
1393   for (action = t->actions; action; action = action->next)
1394     {
1395       action_exp = action->action;
1396       while (isspace (*action_exp))
1397         action_exp++;
1398
1399       if (*action_exp == '#')   /* comment line */
1400         return;
1401
1402       cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
1403       if (cmd == 0)
1404         error ("Bad action list item: %s", action_exp);
1405
1406       if (cmd->function.cfunc == collect_pseudocommand)
1407         {
1408           do {  /* repeat over a comma-separated list */
1409             while (isspace (*action_exp))
1410               action_exp++;
1411
1412             if (0 == strncasecmp ("$reg", action_exp, 4))
1413               {
1414                 for (i = 0; i < NUM_REGS; i++)
1415                   add_register (collect, i);
1416                 action_exp = strchr (action_exp, ','); /* more? */
1417               }
1418             else if (0 == strncasecmp ("$arg", action_exp, 4))
1419               {
1420                 add_local_symbols (collect, t->address, 'A');
1421                 action_exp = strchr (action_exp, ','); /* more? */
1422               }
1423             else if (0 == strncasecmp ("$loc", action_exp, 4))
1424               {
1425                 add_local_symbols (collect, t->address, 'L');
1426                 action_exp = strchr (action_exp, ','); /* more? */
1427               }
1428             else if (action_exp[0] == '$' &&
1429                      action_exp[1] == '(')      /* literal memrange */
1430               {
1431                 long typecode, size;
1432                 bfd_signed_vma offset;
1433
1434                 action_exp = parse_and_eval_memrange (action_exp,
1435                                                       t->address,
1436                                                       &typecode,
1437                                                       &offset,
1438                                                       &size);
1439                 add_memrange (collect, typecode, offset, size);
1440               }
1441             else
1442               {
1443                 unsigned long addr, len;
1444
1445                 exp = parse_exp_1 (&action_exp, block_for_pc (t->address), 1);
1446                 switch (exp->elts[0].opcode) {
1447                 case OP_REGISTER:
1448                   i = exp->elts[1].longconst; 
1449                   if (info_verbose)
1450                     printf_filtered ("OP_REGISTER: ");
1451                   add_register (collect, i);
1452                   break;
1453
1454                 case UNOP_MEMVAL:
1455                   /* safe because we know it's a simple expression */
1456                   tempval = evaluate_expression (exp);
1457                   addr = VALUE_ADDRESS (tempval) + VALUE_OFFSET (tempval);
1458                   len = TYPE_LENGTH (check_typedef (exp->elts[1].type));
1459                   add_memrange (collect, -1, addr, len);
1460                   break;
1461
1462                 case OP_VAR_VALUE:
1463                   collect_symbol (collect, exp->elts[2].symbol);
1464                   break;
1465 #if 0
1466                 case OP_LONG:
1467                   addr = exp->elts[2].longconst;
1468                   if (*action_exp == ':')
1469                     {
1470                       exp = parse_exp_1 (&action_exp, 
1471                                          block_for_pc (t->address), 
1472                                          1);
1473                       if (exp->elts[0].opcode == OP_LONG)
1474                         len = exp->elts[2].longconst;
1475                       else
1476                         error ("length field requires a literal long const");
1477                     }
1478                   else 
1479                     len = 4;
1480
1481                   add_memrange (collect, -1, addr, len);
1482                   break;
1483 #endif
1484                 }
1485               }
1486           } while (action_exp && *action_exp++ == ',');
1487         }
1488       else if (cmd->function.cfunc == while_stepping_pseudocommand)
1489         {
1490           collect = &stepping_list;
1491         }
1492       else if (cmd->function.cfunc == end_actions_pseudocommand)
1493         {
1494           if (collect == &stepping_list)        /* end stepping actions */
1495             collect = &tracepoint_list;
1496           else
1497             break;                      /* end tracepoint actions */
1498         }
1499     }
1500   memrange_sortmerge (&tracepoint_list); 
1501   memrange_sortmerge (&stepping_list); 
1502
1503   *tdp_actions      = stringify_collection_list (&tracepoint_list, &tdp_buff);
1504   *stepping_actions = stringify_collection_list (&stepping_list,   &step_buff);
1505 }
1506
1507 static char target_buf[2048];
1508
1509 /* tstart command:
1510  
1511    Tell target to lear any previous trace experiment.
1512    Walk the list of tracepoints, and send them (and their actions)
1513    to the target.  If no errors, 
1514    Tell target to start a new trace experiment.  */
1515
1516 static void
1517 trace_start_command (args, from_tty)
1518      char *args;
1519      int from_tty;
1520 { /* STUB_COMM MOSTLY_IMPLEMENTED */
1521   struct tracepoint *t;
1522   char buf[2048];
1523   char *tdp_actions;
1524   char *stepping_actions;
1525   unsigned long step_count;
1526
1527   dont_repeat ();       /* like "run", dangerous to repeat accidentally */
1528   
1529   if (target_is_remote ())
1530     {
1531       putpkt ("QTinit");
1532       remote_get_noisy_reply (target_buf);
1533       if (strcmp (target_buf, "OK"))
1534         error ("Target does not support this command.");
1535
1536       ALL_TRACEPOINTS (t)
1537         {
1538           int ss_count;         /* if actions include singlestepping */
1539           int disable_mask;     /* ??? */
1540           int enable_mask;      /* ??? */
1541
1542           sprintf (buf, "QTDP:%x:%x:%c:%x:%x", t->number, t->address, 
1543                    t->enabled == enabled ? 'E' : 'D', 
1544                    t->step_count, t->pass_count);
1545           if (t->actions)
1546             {
1547               encode_actions (t, &tdp_actions, &step_count, &stepping_actions);
1548               /* do_single_steps (t); */
1549               if (tdp_actions)
1550                 {
1551                   if (strlen (buf) + strlen (tdp_actions) >= sizeof (buf))
1552                     error ("Actions for tracepoint %d too complex; please simplify.",
1553                            t->number);
1554                   strcat (buf, tdp_actions);
1555                 }
1556               if (stepping_actions)
1557                 {
1558                   strcat (buf, "S");
1559                   if (strlen (buf) + strlen (stepping_actions) >= sizeof (buf))
1560                     error ("Actions for tracepoint %d too complex; please simplify.",
1561                            t->number);
1562                   strcat (buf, stepping_actions);
1563                 }
1564             }
1565           putpkt (buf);
1566           remote_get_noisy_reply (target_buf);
1567           if (strcmp (target_buf, "OK"))
1568             error ("Target does not support tracepoints.");
1569         }
1570       putpkt ("QTStart");
1571       remote_get_noisy_reply (target_buf);
1572       if (strcmp (target_buf, "OK"))
1573         error ("Bogus reply from target: %s", target_buf);
1574       set_traceframe_num (-1);  /* all old traceframes invalidated */
1575       set_tracepoint_num (-1);
1576       set_traceframe_context(-1);
1577     }
1578   else
1579     printf_filtered ("Trace can only be run on remote targets.\n");
1580 }
1581
1582 /* tstop command */
1583 static void
1584 trace_stop_command (args, from_tty)
1585      char *args;
1586      int from_tty;
1587 { /* STUB_COMM IS_IMPLEMENTED */
1588   if (target_is_remote ())
1589     {
1590       putpkt ("QTStop");
1591       remote_get_noisy_reply (target_buf);
1592       if (strcmp (target_buf, "OK"))
1593         error ("Bogus reply from target: %s", target_buf);
1594     }
1595   else
1596     error ("Trace can only be run on remote targets.");
1597 }
1598
1599 /* tstatus command */
1600 static void
1601 trace_status_command (args, from_tty)
1602      char *args;
1603      int from_tty;
1604 { /* STUB_COMM IS_IMPLEMENTED */
1605   if (target_is_remote ())
1606     {
1607       putpkt ("qTStatus");
1608       remote_get_noisy_reply (target_buf);
1609       if (strcmp (target_buf, "OK"))
1610         error ("Bogus reply from target: %s", target_buf);
1611     }
1612   else
1613     error ("Trace can only be run on remote targets.");
1614 }
1615
1616 /* Worker function for the various flavors of the tfind command */
1617 static void
1618 finish_tfind_command (msg, from_tty)
1619      char *msg;
1620      int from_tty;
1621 {
1622   int target_frameno = -1, target_tracept = -1;
1623   CORE_ADDR old_frame_addr;
1624   struct symbol *old_func;
1625   char *reply;
1626
1627   old_frame_addr = FRAME_FP (get_current_frame ());
1628   old_func       = find_pc_function (read_pc ());
1629
1630   putpkt (msg);
1631   reply = remote_get_noisy_reply (msg);
1632
1633   while (reply && *reply)
1634     switch (*reply) {
1635     case 'F':
1636       if ((target_frameno = strtol (++reply, &reply, 16)) == -1)
1637         { 
1638           /* A request for a non-existant trace frame has failed.
1639              Our response will be different, depending on FROM_TTY:
1640
1641              If FROM_TTY is true, meaning that this command was 
1642              typed interactively by the user, then give an error
1643              and DO NOT change the state of traceframe_number etc.
1644
1645              However if FROM_TTY is false, meaning that we're either
1646              in a script, a loop, or a user-defined command, then 
1647              DON'T give an error, but DO change the state of
1648              traceframe_number etc. to invalid.
1649
1650              The rationalle is that if you typed the command, you
1651              might just have committed a typo or something, and you'd
1652              like to NOT lose your current debugging state.  However
1653              if you're in a user-defined command or especially in a
1654              loop, then you need a way to detect that the command
1655              failed WITHOUT aborting.  This allows you to write
1656              scripts that search thru the trace buffer until the end,
1657              and then continue on to do something else.  */
1658
1659           if (from_tty)
1660             error ("Target failed to find requested trace frame.");
1661           else
1662             {
1663               if (info_verbose)
1664                 printf_filtered ("End of trace buffer.\n");
1665               /* The following will not recurse, since it's special-cased */
1666               trace_find_command ("-1", from_tty);
1667               reply = NULL;     /* break out of loop, 
1668                                    (avoid recursive nonsense) */
1669             }
1670         }
1671       break;
1672     case 'T':
1673       if ((target_tracept = strtol (++reply, &reply, 16)) == -1)
1674         error ("Target failed to find requested trace frame.");
1675       break;
1676     case 'O':   /* "OK"? */
1677       if (reply[1] == 'K' && reply[2] == '\0')
1678         reply += 2;
1679       else
1680         error ("Bogus reply from target: %s", reply);
1681       break;
1682     default:
1683       error ("Bogus reply from target: %s", reply);
1684     }
1685
1686   flush_cached_frames ();
1687   registers_changed ();
1688   select_frame (get_current_frame (), 0);
1689   set_traceframe_num (target_frameno);
1690   set_tracepoint_num (target_tracept);
1691   if (target_frameno == -1)
1692     set_traceframe_context (-1);
1693   else
1694     set_traceframe_context (read_pc ());
1695
1696   if (from_tty)
1697     {
1698       int source_only;
1699
1700       /* NOTE: in immitation of the step command, try to determine
1701          whether we have made a transition from one function to another.
1702          If so, we'll print the "stack frame" (ie. the new function and
1703          it's arguments) -- otherwise we'll just show the new source line.
1704
1705          This determination is made by checking (1) whether the current
1706          function has changed, and (2) whether the current FP has changed.
1707          Hack: if the FP wasn't collected, either at the current or the
1708          previous frame, assume that the FP has NOT changed.  */
1709
1710       if (old_func       == find_pc_function (read_pc ()) &&
1711          (old_frame_addr == 0 ||
1712           FRAME_FP (get_current_frame ()) == 0 ||
1713           old_frame_addr == FRAME_FP (get_current_frame ())))
1714         source_only = -1;
1715       else
1716         source_only =  1;
1717
1718       print_stack_frame (selected_frame, selected_frame_level, source_only);
1719       do_displays ();
1720     }
1721 }
1722
1723 /* trace_find_command takes a trace frame number n, 
1724    sends "QTFrame:<n>" to the target, 
1725    and accepts a reply that may contain several optional pieces
1726    of information: a frame number, a tracepoint number, and an
1727    indication of whether this is a trap frame or a stepping frame.
1728
1729    The minimal response is just "OK" (which indicates that the 
1730    target does not give us a frame number or a tracepoint number).
1731    Instead of that, the target may send us a string containing
1732    any combination of:
1733         F<hexnum>       (gives the selected frame number)
1734         T<hexnum>       (gives the selected tracepoint number)
1735    */
1736
1737 /* tfind command */
1738 static void
1739 trace_find_command (args, from_tty)
1740      char *args;
1741      int from_tty;
1742 { /* STUB_COMM PART_IMPLEMENTED */
1743   /* this should only be called with a numeric argument */
1744   int frameno = -1;
1745   int target_frameno = -1, target_tracept = -1, target_stepfrm = 0;
1746   char *tmp;
1747
1748   if (target_is_remote ())
1749     {
1750       if (args == 0 || *args == 0)
1751         { /* TFIND with no args means find NEXT trace frame. */
1752           if (traceframe_number == -1)
1753             frameno = 0;        /* "next" is first one */
1754           else
1755             frameno = traceframe_number + 1;
1756         }
1757       else if (0 == strcmp (args, "-"))
1758         {
1759           if (traceframe_number == -1)
1760             error ("not debugging trace buffer");
1761           else if (from_tty && traceframe_number == 0)
1762             error ("already at start of trace buffer");
1763
1764           frameno = traceframe_number - 1;
1765         }
1766       else
1767         frameno = parse_and_eval_address (args);
1768
1769       sprintf (target_buf, "QTFrame:%x", frameno);
1770 #if 0
1771       putpkt  (target_buf);
1772       tmp = remote_get_noisy_reply (target_buf);
1773
1774       if (frameno == -1)        /* end trace debugging */
1775         {                       /* hopefully the stub has complied! */
1776           if (0 != strcmp (tmp, "OK"))
1777             error ("Bogus response from target: %s", tmp);
1778
1779         finish_tfind_command (NULL, from_tty);
1780         }
1781       else
1782         finish_tfind_command (tmp, from_tty);
1783 #else
1784       finish_tfind_command (target_buf, from_tty);
1785 #endif
1786     }
1787   else
1788     error ("Trace can only be run on remote targets.");
1789 }
1790
1791 /* tfind end */
1792 static void
1793 trace_find_end_command (args, from_tty)
1794      char *args;
1795      int from_tty;
1796 {
1797   trace_find_command ("-1", from_tty);
1798 }
1799
1800 /* tfind none */
1801 static void
1802 trace_find_none_command (args, from_tty)
1803      char *args;
1804      int from_tty;
1805 {
1806   trace_find_command ("-1", from_tty);
1807 }
1808
1809 /* tfind start */
1810 static void
1811 trace_find_start_command (args, from_tty)
1812      char *args;
1813      int from_tty;
1814 {
1815   trace_find_command ("0", from_tty);
1816 }
1817
1818 /* tfind pc command */
1819 static void
1820 trace_find_pc_command (args, from_tty)
1821      char *args;
1822      int from_tty;
1823 { /* STUB_COMM PART_IMPLEMENTED */
1824   CORE_ADDR pc;
1825   int target_frameno;
1826   char *tmp;
1827
1828   if (target_is_remote ())
1829     {
1830       if (args == 0 || *args == 0)
1831         pc = read_pc ();        /* default is current pc */
1832       else
1833         pc = parse_and_eval_address (args);
1834
1835       sprintf (target_buf, "QTFrame:pc:%x", pc);
1836 #if 0
1837       putpkt (target_buf);
1838       tmp = remote_get_noisy_reply (target_buf);
1839
1840       finish_tfind_command (tmp, from_tty);
1841 #else
1842       finish_tfind_command (target_buf, from_tty);
1843 #endif
1844     }
1845   else
1846     error ("Trace can only be run on remote targets.");
1847 }
1848
1849 /* tfind tracepoint command */
1850 static void
1851 trace_find_tracepoint_command (args, from_tty)
1852      char *args;
1853      int from_tty;
1854 { /* STUB_COMM PART_IMPLEMENTED */
1855   int target_frameno, tdp;
1856   char buf[40], *tmp;
1857
1858   if (target_is_remote ())
1859     {
1860       if (args == 0 || *args == 0)
1861         if (tracepoint_number == -1)
1862           error ("No current tracepoint -- please supply an argument.");
1863         else
1864           tdp = tracepoint_number;      /* default is current TDP */
1865       else
1866         tdp = parse_and_eval_address (args);
1867
1868       sprintf (target_buf, "QTFrame:tdp:%x", tdp);
1869 #if 0
1870       putpkt (target_buf);
1871       tmp = remote_get_noisy_reply (target_buf);
1872
1873       finish_tfind_command (tmp, from_tty);
1874 #else
1875       finish_tfind_command (target_buf, from_tty);
1876 #endif
1877     }
1878   else
1879     error ("Trace can only be run on remote targets.");
1880 }
1881
1882 /* TFIND LINE command:
1883  
1884    This command will take a sourceline for argument, just like BREAK
1885    or TRACE (ie. anything that "decode_line_1" can handle).  
1886    
1887    With no argument, this command will find the next trace frame 
1888    corresponding to a source line OTHER THAN THE CURRENT ONE.  */
1889
1890 static void
1891 trace_find_line_command (args, from_tty)
1892      char *args;
1893      int from_tty;
1894 { /* STUB_COMM PART_IMPLEMENTED */
1895   static CORE_ADDR start_pc, end_pc;
1896   struct symtabs_and_lines sals;
1897   struct symtab_and_line sal;
1898   int target_frameno;
1899   char *tmp;
1900   struct cleanup *old_chain;
1901
1902   if (target_is_remote ())
1903     {
1904       if (args == 0 || *args == 0)
1905         {
1906           sal = find_pc_line ((get_current_frame ())->pc, 0);
1907           sals.nelts = 1;
1908           sals.sals = (struct symtab_and_line *)
1909             xmalloc (sizeof (struct symtab_and_line));
1910           sals.sals[0] = sal;
1911         }
1912       else
1913         {
1914           sals = decode_line_spec (args, 1);
1915           sal  = sals.sals[0];
1916         }
1917
1918       old_chain = make_cleanup (free, sals.sals);
1919       if (sal.symtab == 0)
1920         {
1921           printf_filtered ("TFIND: No line number information available");
1922           if (sal.pc != 0)
1923             {
1924               /* This is useful for "info line *0x7f34".  If we can't tell the
1925                  user about a source line, at least let them have the symbolic
1926                  address.  */
1927               printf_filtered (" for address ");
1928               wrap_here ("  ");
1929               print_address (sal.pc, gdb_stdout);
1930               printf_filtered (";\n -- will attempt to find by PC. \n");
1931             }
1932           else
1933             {
1934               printf_filtered (".\n");
1935               return;   /* no line, no PC; what can we do? */
1936             }
1937         }
1938       else if (sal.line > 0
1939                && find_line_pc_range (sal, &start_pc, &end_pc))
1940         {
1941           if (start_pc == end_pc)
1942             {
1943               printf_filtered ("Line %d of \"%s\"",
1944                                sal.line, sal.symtab->filename);
1945               wrap_here ("  ");
1946               printf_filtered (" is at address ");
1947               print_address (start_pc, gdb_stdout);
1948               wrap_here ("  ");
1949               printf_filtered (" but contains no code.\n");
1950               sal = find_pc_line (start_pc, 0);
1951               if (sal.line > 0 &&
1952                   find_line_pc_range (sal, &start_pc, &end_pc) &&
1953                   start_pc != end_pc)
1954                 printf_filtered ("Attempting to find line %d instead.\n",
1955                                  sal.line);
1956               else
1957                 error ("Cannot find a good line.");
1958             }
1959         }
1960       else
1961         /* Is there any case in which we get here, and have an address
1962            which the user would want to see?  If we have debugging symbols
1963            and no line numbers?  */
1964         error ("Line number %d is out of range for \"%s\".\n",
1965                sal.line, sal.symtab->filename);
1966
1967       if (args && *args)        /* find within range of stated line */
1968         sprintf (target_buf, "QTFrame:range:%x:%x", start_pc, end_pc - 1);
1969       else                      /* find OUTSIDE OF range of CURRENT line */
1970         sprintf (target_buf, "QTFrame:outside:%x:%x", start_pc, end_pc - 1);
1971 #if 0
1972       putpkt (target_buf);
1973       tmp = remote_get_noisy_reply (target_buf);
1974
1975       finish_tfind_command (tmp, from_tty);
1976 #else
1977       finish_tfind_command (target_buf, from_tty);
1978 #endif
1979       do_cleanups (old_chain);
1980     }
1981   else
1982       error ("Trace can only be run on remote targets.");
1983 }
1984
1985 /* tfind range command */
1986 static void
1987 trace_find_range_command (args, from_tty)
1988      char *args;
1989      int from_tty;
1990 { /* STUB_COMM PART_IMPLEMENTED */
1991   static CORE_ADDR start, stop;
1992   int target_frameno;
1993   char *tmp;
1994
1995   if (target_is_remote ())
1996     {
1997       if (args == 0 || *args == 0)
1998         { /* XXX FIXME: what should default behavior be? */
1999           printf_filtered ("Usage: tfind range <startaddr>,<endaddr>\n");
2000           return;
2001         }
2002
2003       if (0 != (tmp = strchr (args, ',' )))
2004         {
2005           *tmp++ = '\0';        /* terminate start address */
2006           while (isspace (*tmp))
2007             tmp++;
2008           start = parse_and_eval_address (args);
2009           stop  = parse_and_eval_address (tmp);
2010         }
2011       else
2012         { /* no explicit end address? */
2013           start = parse_and_eval_address (args);
2014           stop  = start + 1; /* ??? */
2015         }
2016
2017       sprintf (target_buf, "QTFrame:range:%x:%x", start, stop);
2018 #if 0
2019       putpkt (target_buf);
2020       tmp = remote_get_noisy_reply (target_buf);
2021
2022       finish_tfind_command (tmp, from_tty);
2023 #else
2024       finish_tfind_command (target_buf, from_tty);
2025 #endif
2026     }
2027   else
2028       error ("Trace can only be run on remote targets.");
2029 }
2030
2031 /* tfind outside command */
2032 static void
2033 trace_find_outside_command (args, from_tty)
2034      char *args;
2035      int from_tty;
2036 { /* STUB_COMM PART_IMPLEMENTED */
2037   CORE_ADDR start, stop;
2038   int target_frameno;
2039   char *tmp;
2040
2041   if (target_is_remote ())
2042     {
2043       if (args == 0 || *args == 0)
2044         { /* XXX FIXME: what should default behavior be? */
2045           printf_filtered ("Usage: tfind outside <startaddr>,<endaddr>\n");
2046           return;
2047         }
2048
2049       if (0 != (tmp = strchr (args, ',' )))
2050         {
2051           *tmp++ = '\0';        /* terminate start address */
2052           while (isspace (*tmp))
2053             tmp++;
2054           start = parse_and_eval_address (args);
2055           stop  = parse_and_eval_address (tmp);
2056         }
2057       else
2058         { /* no explicit end address? */
2059           start = parse_and_eval_address (args);
2060           stop  = start + 1; /* ??? */
2061         }
2062
2063       sprintf (target_buf, "QTFrame:outside:%x:%x", start, stop);
2064 #if 0
2065       putpkt (target_buf);
2066       tmp = remote_get_noisy_reply (target_buf);
2067
2068       finish_tfind_command (tmp, from_tty);
2069 #else
2070       finish_tfind_command (target_buf, from_tty);
2071 #endif
2072     }
2073   else
2074       error ("Trace can only be run on remote targets.");
2075 }
2076
2077 /* save-tracepoints command */
2078 static void
2079 tracepoint_save_command (args, from_tty)
2080      char *args;
2081      int from_tty;
2082 {
2083   struct tracepoint  *tp;
2084   struct action_line *line;
2085   FILE *fp;
2086   char *i1 = "    ", *i2 = "      ";
2087   char *indent, *actionline;
2088
2089   if (args == 0 || *args == 0)
2090     error ("Argument required (file name in which to save tracepoints");
2091
2092   if (tracepoint_chain == 0)
2093     {
2094       warning ("save-tracepoints: no tracepoints to save.\n");
2095       return;
2096     }
2097
2098   if (!(fp = fopen (args, "w")))
2099     error ("Unable to open file '%s' for saving tracepoints");
2100
2101   ALL_TRACEPOINTS (tp)
2102     {
2103       if (tp->addr_string)
2104         fprintf (fp, "trace %s\n", tp->addr_string);
2105       else
2106         fprintf (fp, "trace *0x%x\n", tp->address);
2107
2108       if (tp->pass_count)
2109         fprintf (fp, "  passcount %d\n", tp->pass_count);
2110
2111       if (tp->actions)
2112         {
2113           fprintf (fp, "  actions\n");
2114           indent = i1;
2115           for (line = tp->actions; line; line = line->next)
2116             {
2117               struct cmd_list_element *cmd;
2118
2119               actionline = line->action;
2120               while (isspace(*actionline))
2121                 actionline++;
2122
2123               fprintf (fp, "%s%s\n", indent, actionline);
2124               if (*actionline != '#')   /* skip for comment lines */
2125                 {
2126                   cmd = lookup_cmd (&actionline, cmdlist, "", -1, 1);
2127                   if (cmd == 0)
2128                     error ("Bad action list item: %s", actionline);
2129                   if (cmd->function.cfunc == while_stepping_pseudocommand)
2130                     indent = i2;
2131                   else if (cmd->function.cfunc == end_actions_pseudocommand)
2132                     indent = i1;
2133                 }
2134             }
2135         }
2136     }
2137   fclose (fp);
2138   if (from_tty)
2139     printf_filtered ("Tracepoints saved to file '%s'.\n", args);
2140   return;
2141 }
2142
2143 /* info scope command: list the locals for a scope.  */
2144 static void
2145 scope_info (args, from_tty)
2146      char *args;
2147      int from_tty;
2148 {
2149   struct symtab_and_line sal;
2150   struct symtabs_and_lines sals;
2151   struct symbol *sym;
2152   struct minimal_symbol *msym;
2153   struct block *block;
2154   char **canonical, *symname, *save_args = args;
2155   int i, nsyms, count = 0;
2156
2157   if (args == 0 || *args == 0)
2158     error ("requires an argument (function, line or *addr) to define a scope");
2159
2160   sals = decode_line_1 (&args, 1, NULL, 0, &canonical);
2161   if (sals.nelts == 0)
2162     return;             /* presumably decode_line_1 has already warned */
2163
2164   /* Resolve line numbers to PC */
2165   resolve_sal_pc (&sals.sals[0]);
2166   block = block_for_pc (sals.sals[0].pc);
2167
2168   while (block != 0)
2169     {
2170       nsyms = BLOCK_NSYMS (block);
2171       for (i = 0; i < nsyms; i++)
2172         {
2173           if (count == 0)
2174             printf_filtered ("Scope for %s:\n", save_args);
2175           count++;
2176           sym = BLOCK_SYM (block, i);
2177           symname = SYMBOL_NAME (sym);
2178           if (symname == NULL || *symname == '\0')
2179             continue;   /* probably botched, certainly useless */
2180
2181           printf_filtered ("Symbol %s is ", symname);
2182           switch (SYMBOL_CLASS (sym)) {
2183           default:
2184           case LOC_UNDEF:               /* messed up symbol? */
2185             printf_filtered ("a bogus symbol, class %d.\n", 
2186                              SYMBOL_CLASS (sym));
2187             count--;                    /* don't count this one */
2188             continue;
2189           case LOC_CONST:
2190             printf_filtered ("a constant with value %d (0x%x)", 
2191                              SYMBOL_VALUE (sym), SYMBOL_VALUE (sym));
2192             break;
2193           case LOC_CONST_BYTES:
2194             printf_filtered ("constant bytes: ");
2195             if (SYMBOL_TYPE (sym))
2196               for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (sym)); i++)
2197                 fprintf_filtered (gdb_stdout, " %02x",
2198                                   (unsigned) SYMBOL_VALUE_BYTES (sym) [i]);
2199             break;
2200           case LOC_STATIC:
2201             printf_filtered ("in static storage at address ");
2202             print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout);
2203             break;
2204           case LOC_REGISTER:
2205             printf_filtered ("a local variable in register $%s",
2206                              reg_names [SYMBOL_VALUE (sym)]);
2207             break;
2208           case LOC_ARG:
2209           case LOC_LOCAL_ARG:
2210             printf_filtered ("an argument at stack/frame offset %ld",
2211                              SYMBOL_VALUE (sym));
2212             break;
2213           case LOC_LOCAL:
2214             printf_filtered ("a local variable at frame offset %ld",
2215                              SYMBOL_VALUE (sym));
2216             break;
2217           case LOC_REF_ARG:
2218             printf_filtered ("a reference argument at offset %ld",
2219                              SYMBOL_VALUE (sym));
2220             break;
2221           case LOC_REGPARM:
2222             printf_filtered ("an argument in register $%s",
2223                              reg_names[SYMBOL_VALUE (sym)]);
2224             break;
2225           case LOC_REGPARM_ADDR:
2226             printf_filtered ("the address of an argument, in register $%s",
2227                              reg_names[SYMBOL_VALUE (sym)]);
2228             break;
2229           case LOC_TYPEDEF:
2230             printf_filtered ("a typedef.\n");
2231             continue;
2232           case LOC_LABEL:
2233             printf_filtered ("a label at address ");
2234             print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout);
2235             break;
2236           case LOC_BLOCK:
2237             printf_filtered ("a function at address ");
2238             print_address_numeric (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)), 1,
2239                                    gdb_stdout);
2240             break;
2241           case LOC_BASEREG:
2242             printf_filtered ("a variable at offset %d from register $%s",
2243                              SYMBOL_VALUE (sym),
2244                              reg_names [SYMBOL_BASEREG (sym)]);
2245             break;
2246           case LOC_BASEREG_ARG:
2247             printf_filtered ("an argument at offset %d from register $%s",
2248                              SYMBOL_VALUE (sym),
2249                              reg_names [SYMBOL_BASEREG (sym)]);
2250             break;
2251           case LOC_UNRESOLVED:
2252             msym = lookup_minimal_symbol (SYMBOL_NAME (sym), NULL, NULL);
2253             if (msym == NULL)
2254               printf_filtered ("Unresolved Static");
2255             else
2256               {
2257                 printf_filtered ("static storage at address ");
2258                 print_address_numeric (SYMBOL_VALUE_ADDRESS (msym), 1, 
2259                                        gdb_stdout);
2260               }
2261             break;
2262           case LOC_OPTIMIZED_OUT:
2263             printf_filtered ("optimized out.\n");
2264             continue;
2265           }
2266           if (SYMBOL_TYPE (sym))
2267             printf_filtered (", length %d.\n", 
2268                              TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym))));
2269         }
2270       if (BLOCK_FUNCTION (block))
2271         break;
2272       else
2273         block = BLOCK_SUPERBLOCK (block);
2274     }
2275   if (count <= 0)
2276     printf_filtered ("Scope for %s contains no locals or arguments.\n",
2277                      save_args);
2278 }
2279
2280 /* worker function (cleanup) */
2281 static void
2282 replace_comma (comma)
2283      char *comma;
2284 {
2285   *comma = ',';
2286 }
2287
2288 /* tdump command */
2289 static void
2290 trace_dump_command (args, from_tty)
2291      char *args;
2292      int from_tty;
2293 {
2294   struct tracepoint  *t;
2295   struct action_line *action;
2296   char               *action_exp, *next_comma;
2297   struct cleanup     *old_cleanups;
2298   int                 stepping_actions = 0;
2299   int                 stepping_frame   = 0;
2300
2301   if (tracepoint_number == -1)
2302     {
2303       warning ("No current trace frame.");
2304       return;
2305     }
2306
2307   ALL_TRACEPOINTS (t)
2308     if (t->number == tracepoint_number)
2309       break;
2310
2311   if (t == NULL)
2312     error ("No known tracepoint matches 'current' tracepoint #%d.", 
2313            tracepoint_number);
2314
2315   old_cleanups = make_cleanup (null_cleanup, NULL);
2316
2317   printf_filtered ("Data collected at tracepoint %d, trace frame %d:\n", 
2318                    tracepoint_number, traceframe_number);
2319
2320   /* The current frame is a trap frame if the frame PC is equal
2321      to the tracepoint PC.  If not, then the current frame was
2322      collected during single-stepping.  */
2323
2324   stepping_frame = (t->address != read_pc());
2325
2326   for (action = t->actions; action; action = action->next)
2327     {
2328       struct cmd_list_element *cmd;
2329
2330       action_exp = action->action;
2331       while (isspace (*action_exp))
2332         action_exp++;
2333
2334       /* The collection actions to be done while stepping are
2335          bracketed by the commands "while-stepping" and "end".  */
2336
2337       if (*action_exp == '#')   /* comment line */
2338         continue;
2339
2340       cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
2341       if (cmd == 0)
2342         error ("Bad action list item: %s", action_exp);
2343
2344       if (cmd->function.cfunc == while_stepping_pseudocommand)
2345         stepping_actions = 1;
2346       else if (cmd->function.cfunc == end_actions_pseudocommand)
2347         stepping_actions = 0;
2348       else if (cmd->function.cfunc == collect_pseudocommand)
2349         {
2350           /* Display the collected data.
2351              For the trap frame, display only what was collected at the trap.
2352              Likewise for stepping frames, display only what was collected
2353              while stepping.  This means that the two boolean variables,
2354              STEPPING_FRAME and STEPPING_ACTIONS should be equal.  */
2355           if (stepping_frame == stepping_actions)
2356             {
2357               do { /* repeat over a comma-separated list */
2358                 QUIT;
2359                 if (*action_exp == ',')
2360                   action_exp++;
2361                 while (isspace (*action_exp))
2362                   action_exp++;
2363
2364                 next_comma = strchr (action_exp, ',');
2365
2366                 if      (0 == strncasecmp (action_exp, "$reg", 4))
2367                   registers_info (NULL, from_tty);
2368                 else if (0 == strncasecmp (action_exp, "$loc", 4))
2369                   locals_info (NULL, from_tty);
2370                 else if (0 == strncasecmp (action_exp, "$arg", 4))
2371                   args_info (NULL, from_tty);
2372                 else if (action_exp[0] == '$' && action_exp[1] == '(')
2373                   { /* memrange */
2374                     long typecode, size;
2375                     bfd_signed_vma offset;
2376                     char fmt[40];
2377
2378                     action_exp = parse_and_eval_memrange (action_exp,
2379                                                           read_pc (),
2380                                                           &typecode, 
2381                                                           &offset,
2382                                                           &size);
2383                     if (typecode != 0 && typecode != -1)
2384                       offset += read_register (typecode);
2385                     sprintf (fmt, "/%dxb 0x%x", size, offset);
2386                     x_command (fmt, from_tty);
2387                     next_comma = strchr (action_exp, ',');
2388                   }
2389                 else
2390                   { /* variable */
2391                     if (next_comma)
2392                       {
2393                         make_cleanup (replace_comma, next_comma);
2394                         *next_comma = '\0';
2395                       }
2396                     printf_filtered ("%s = ", action_exp);
2397                     output_command (action_exp, from_tty);
2398                     printf_filtered ("\n");
2399                   }
2400                 if (next_comma)
2401                   *next_comma = ',';
2402                 action_exp = next_comma;
2403               } while (action_exp && *action_exp == ',');
2404             }
2405         }
2406     }
2407   discard_cleanups (old_cleanups);
2408 }
2409
2410 /* module initialization */
2411 void
2412 _initialize_tracepoint ()
2413 {
2414   tracepoint_chain  = 0;
2415   tracepoint_count  = 0;
2416   traceframe_number = -1;
2417   tracepoint_number = -1;
2418
2419   set_internalvar (lookup_internalvar ("tpnum"), 
2420                    value_from_longest (builtin_type_int, (LONGEST) 0));
2421   set_internalvar (lookup_internalvar ("trace_frame"), 
2422                    value_from_longest (builtin_type_int, (LONGEST) 0));
2423
2424   if (tracepoint_list.list == NULL)
2425     {
2426       tracepoint_list.listsize = 128;
2427       tracepoint_list.list = xmalloc 
2428         (tracepoint_list.listsize * sizeof (struct memrange));
2429     }
2430   if (stepping_list.list == NULL)
2431     {
2432       stepping_list.listsize = 128;
2433       stepping_list.list = xmalloc 
2434         (stepping_list.listsize * sizeof (struct memrange));
2435     }
2436
2437   add_info ("scope", scope_info, 
2438             "List the variables local to a scope");
2439
2440   add_cmd ("tracepoints", class_trace, NO_FUNCTION, 
2441            "Tracing of program execution without stopping the program.", 
2442            &cmdlist);
2443
2444   add_info ("tracepoints", tracepoints_info,
2445             "Status of tracepoints, or tracepoint number NUMBER.\n\
2446 Convenience variable \"$tpnum\" contains the number of the\n\
2447 last tracepoint set.");
2448
2449   add_info_alias ("tp", "tracepoints", 1);
2450
2451   add_com ("save-tracepoints", class_trace, tracepoint_save_command, 
2452            "Save current tracepoint definitions as a script.\n\
2453 Use the 'source' command in another debug session to restore them.");
2454
2455   add_com ("tdump", class_trace, trace_dump_command, 
2456            "Print everything collected at the current tracepoint.");
2457
2458   add_prefix_cmd ("tfind",  class_trace, trace_find_command,
2459                   "Select a trace frame;\n\
2460 No argument means forward by one frame; '-' meand backward by one frame.",
2461                   &tfindlist, "tfind ", 1, &cmdlist);
2462
2463   add_cmd ("outside", class_trace, trace_find_outside_command,
2464            "Select a trace frame whose PC is outside the given \
2465 range.\nUsage: tfind outside addr1, addr2", 
2466            &tfindlist);
2467
2468   add_cmd ("range", class_trace, trace_find_range_command,
2469            "Select a trace frame whose PC is in the given range.\n\
2470 Usage: tfind range addr1,addr2", 
2471            &tfindlist);
2472
2473   add_cmd ("line", class_trace, trace_find_line_command,
2474            "Select a trace frame by source line.\n\
2475 Argument can be a line number (with optional source file), \n\
2476 a function name, or '*' followed by an address.\n\
2477 Default argument is 'the next source line that was traced'.",
2478            &tfindlist);
2479
2480   add_cmd ("tracepoint", class_trace, trace_find_tracepoint_command,
2481            "Select a trace frame by tracepoint number.\n\
2482 Default is the tracepoint for the current trace frame.",
2483            &tfindlist);
2484
2485   add_cmd ("pc", class_trace, trace_find_pc_command,
2486            "Select a trace frame by PC.\n\
2487 Default is the current PC, or the PC of the current trace frame.",
2488            &tfindlist);
2489
2490   add_cmd ("end", class_trace, trace_find_end_command,
2491            "Synonym for 'none'.\n\
2492 De-select any trace frame and resume 'live' debugging.",
2493            &tfindlist);
2494
2495   add_cmd ("none", class_trace, trace_find_none_command,
2496            "De-select any trace frame and resume 'live' debugging.",
2497            &tfindlist);
2498
2499   add_cmd ("start", class_trace, trace_find_start_command,
2500            "Select the first trace frame in the trace buffer.",
2501            &tfindlist);
2502
2503   add_com ("tstatus",  class_trace, trace_status_command,
2504            "Display the status of the current trace data collection.");
2505
2506   add_com ("tstop",  class_trace, trace_stop_command,
2507            "Stop trace data collection.");
2508
2509   add_com ("tstart", class_trace, trace_start_command,
2510            "Start trace data collection.");
2511
2512   add_com ("passcount", class_trace, trace_pass_command, 
2513            "Set the passcount for a tracepoint.\n\
2514 The trace will end when the tracepoint has been passed 'count' times.\n\
2515 Usage: passcount COUNT TPNUM, where TPNUM may also be \"all\";\n\
2516 if TPNUM is omitted, passcount refers to the last tracepoint defined.");
2517
2518   add_com ("end", class_trace, end_actions_pseudocommand,
2519            "Ends a list of commands or actions.\n\
2520 Several GDB commands allow you to enter a list of commands or actions.\n\
2521 Entering \"end\" on a line by itself is the normal way to terminate\n\
2522 such a list.\n\n\
2523 Note: the \"end\" command cannot be used at the gdb prompt.");
2524
2525   add_com ("while-stepping", class_trace, while_stepping_pseudocommand,
2526            "Specify single-stepping behavior at a tracepoint.\n\
2527 Argument is number of instructions to trace in single-step mode\n\
2528 following the tracepoint.  This command is normally followed by\n\
2529 one or more \"collect\" commands, to specify what to collect\n\
2530 while single-stepping.\n\n\
2531 Note: this command can only be used in a tracepoint \"actions\" list.");
2532
2533   add_com_alias ("ws",         "while-stepping", class_alias, 0);
2534   add_com_alias ("stepping",   "while-stepping", class_alias, 0);
2535
2536   add_com ("collect", class_trace, collect_pseudocommand, 
2537            "Specify one or more data items to be collected at a tracepoint.\n\
2538 Accepts a comma-separated list of (one or more) arguments.\n\
2539 Things that may be collected include registers, variables, plus\n\
2540 the following special arguments:\n\
2541     $regs   -- all registers.\n\
2542     $args   -- all function arguments.\n\
2543     $locals -- all variables local to the block/function scope.\n\
2544     $(addr,len) -- a literal memory range.\n\
2545     $($reg,addr,len) -- a register-relative literal memory range.\n\n\
2546 Note: this command can only be used in a tracepoint \"actions\" list.");
2547
2548   add_com ("actions", class_trace, trace_actions_command,
2549            "Specify the actions to be taken at a tracepoint.\n\
2550 Tracepoint actions may include collecting of specified data, \n\
2551 single-stepping, or enabling/disabling other tracepoints, \n\
2552 depending on target's capabilities.");
2553
2554   add_cmd ("tracepoints", class_trace, delete_trace_command, 
2555            "Delete specified tracepoints.\n\
2556 Arguments are tracepoint numbers, separated by spaces.\n\
2557 No argument means delete all tracepoints.",
2558            &deletelist);
2559
2560   add_cmd ("tracepoints", class_trace, disable_trace_command, 
2561            "Disable specified tracepoints.\n\
2562 Arguments are tracepoint numbers, separated by spaces.\n\
2563 No argument means disable all tracepoints.",
2564            &disablelist);
2565
2566   add_cmd ("tracepoints", class_trace, enable_trace_command, 
2567            "Enable specified tracepoints.\n\
2568 Arguments are tracepoint numbers, separated by spaces.\n\
2569 No argument means enable all tracepoints.",
2570            &enablelist);
2571
2572   add_com ("trace", class_trace, trace_command,
2573            "Set a tracepoint at a specified line or function or address.\n\
2574 Argument may be a line number, function name, or '*' plus an address.\n\
2575 For a line number or function, trace at the start of its code.\n\
2576 If an address is specified, trace at that exact address.\n\n\
2577 Do \"help tracepoints\" for info on other tracepoint commands.");
2578
2579   add_com_alias ("tp",   "trace", class_alias, 0);
2580   add_com_alias ("tr",   "trace", class_alias, 1);
2581   add_com_alias ("tra",  "trace", class_alias, 1);
2582   add_com_alias ("trac", "trace", class_alias, 1);
2583 }
2584