Create CVS files tracepoint.c and tracepoint.h. This is new work,
[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
31 /* readline include files */
32 #include "readline.h"
33 #include "history.h"
34
35 /* readline defines this.  */
36 #undef savestring
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 extern int info_verbose;
43
44 /* If this definition isn't overridden by the header files, assume
45    that isatty and fileno exist on this system.  */
46 #ifndef ISATTY
47 #define ISATTY(FP)      (isatty (fileno (FP)))
48 #endif
49
50 /* Walk the following statement or block through all tracepoints.
51    ALL_TRACEPOINTS_SAFE does so even if the statment deletes the current
52    breakpoint.  */
53
54 #define ALL_TRACEPOINTS(t)  for (t = tracepoint_chain; t; t = t->next)
55
56 #define ALL_TRACEPOINTS_SAFE(t,tmp)     \
57         for (t = tracepoint_chain;      \
58              t ? (tmp = t->next, 1) : 0;\
59              t = tmp)
60
61 /* Chain of all tracepoints defined.  */
62 struct tracepoint *tracepoint_chain;
63
64 /* Number of last tracepoint made.  */
65 static int tracepoint_count;
66
67 /* Number of last traceframe collected.  */
68 static int traceframe_number;
69
70 /* Utility: returns true if "target remote" */
71 static int
72 target_is_remote ()
73 {
74   if (current_target.to_shortname &&
75       strcmp (current_target.to_shortname, "remote") == 0)
76     return 1;
77   else
78     return 0;
79 }
80
81 /* Utility: generate error from an incoming stub packet.  */
82 static void 
83 trace_error (buf)
84      char *buf;
85 {
86   if (*buf++ != 'E')
87     return;                     /* not an error msg */
88   switch (*buf) 
89     {
90     case '1':                   /* malformed packet error */
91       if (*++buf == '0')        /*   general case: */
92         error ("tracepoint.c: badly formed packet.");
93       else
94         error ("tracepoint.c: badly formed packet at field #%d.", 
95                *buf - '0');
96     case '2':
97       error ("trace API error '%s'.", buf);
98     default:
99       error ("Target returns error code '%s'.", buf);
100     }
101 }
102
103 /* Obsolete: collect regs from a trace frame */
104 static void
105 trace_receive_regs (buf)
106      char *buf;
107 {
108   long regno, i;
109   char regbuf[MAX_REGISTER_RAW_SIZE], *tmp, *p = buf;
110
111   while (*p)
112     {
113       regno = strtol (p, &tmp, 16);
114       if (p == tmp || *tmp++ != ':')
115         error ("tracepoint.c: malformed 'R' packet");
116       else p = tmp;
117
118       for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
119         {
120           if (p[0] == 0 || p[1] == 0)
121             warning ("Remote reply is too short: %s", buf);
122           regbuf[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
123           p += 2;
124         }
125
126       if (*p++ != ';')
127         error ("tracepoint.c: malformed 'R' packet");
128
129       supply_register (regno, regbuf);
130     }
131 }
132
133 /* Utility: wait for reply from stub, while accepting "O" packets */
134 static void
135 remote_get_noisy_reply (buf)
136      char *buf;
137 {
138   do    /* loop on reply from remote stub */
139     {
140       getpkt (buf, 0);
141       if (buf[0] == 0)
142         error ("Target does not support this command.");
143       else if (buf[0] == 'E')
144         trace_error (buf);
145       else if (buf[0] == 'R')
146         {
147           flush_cached_frames ();
148           registers_changed ();
149           select_frame (get_current_frame (), 0);
150           trace_receive_regs (buf);
151         }
152       else if (buf[0] == 'O' &&
153                buf[1] != 'K')
154         remote_console_output (buf + 1);        /* 'O' message from stub */
155       else
156         return;                 /* here's the actual reply */
157     } while (1);
158 }
159
160 /* Set tracepoint count to NUM.  */
161 static void
162 set_tracepoint_count (num)
163      int num;
164 {
165   tracepoint_count = num;
166   set_internalvar (lookup_internalvar ("tpnum"),
167                    value_from_longest (builtin_type_int, (LONGEST) num));
168 }
169
170 /* Set traceframe number to NUM.  */
171 static void
172 set_traceframe_num (num)
173      int num;
174 {
175   traceframe_number = num;
176   set_internalvar (lookup_internalvar ("trace_frame"),
177                    value_from_longest (builtin_type_int, (LONGEST) num));
178 }
179
180 /* Low level routine to set a tracepoint.
181    Returns the tracepoint object so caller can set other things.
182    Does not set the tracepoint number!
183    Does not print anything.
184
185    ==> This routine should not be called if there is a chance of later
186    error(); otherwise it leaves a bogus tracepoint on the chain.  Validate
187    your arguments BEFORE calling this routine!  */
188
189 static struct tracepoint *
190 set_raw_tracepoint (sal)
191      struct symtab_and_line sal;
192 {
193   register struct tracepoint *t, *tc;
194   struct cleanup *old_chain;
195
196   t = (struct tracepoint *) xmalloc (sizeof (struct tracepoint));
197   old_chain = make_cleanup (free, t);
198   memset (t, 0, sizeof (*t));
199   t->address = sal.pc;
200   if (sal.symtab == NULL)
201     t->source_file = NULL;
202   else
203     t->source_file = savestring (sal.symtab->filename,
204                                  strlen (sal.symtab->filename));
205   t->language = current_language->la_language;
206   t->input_radix = input_radix;
207   t->line_number = sal.line;
208   t->enabled = enabled;
209   t->next = 0;
210   t->step_count = 0;
211   t->pass_count = 0;
212
213   /* Add this tracepoint to the end of the chain
214      so that a list of tracepoints will come out in order
215      of increasing numbers.  */
216
217   tc = tracepoint_chain;
218   if (tc == 0)
219     tracepoint_chain = t;
220   else
221     {
222       while (tc->next)
223         tc = tc->next;
224       tc->next = t;
225     }
226   discard_cleanups (old_chain);
227   return t;
228 }
229
230 static void
231 trace_command (arg, from_tty)
232      char *arg;
233      int from_tty;
234 {
235   char **canonical = (char **)NULL;
236   struct symtabs_and_lines sals;
237   struct symtab_and_line sal;
238   struct tracepoint *t;
239   char *addr_start = 0, *addr_end = 0, *cond_start = 0, *cond_end = 0;
240   int i;
241
242   if (!arg || !*arg)
243     error ("trace command requires an argument");
244
245   if (from_tty && info_verbose)
246     printf_filtered ("TRACE %s\n", arg);
247
248   if (arg[0] == '/')
249     {
250       return;
251     }
252
253   addr_start = arg;
254   sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, &canonical);
255   addr_end   = arg;
256   if (! sals.nelts) 
257     return;     /* ??? Presumably decode_line_1 has already warned? */
258
259   /* Resolve all line numbers to PC's */
260   for (i = 0; i < sals.nelts; i++)
261     resolve_sal_pc (&sals.sals[i]);
262
263   /* Now set all the tracepoints.  */
264   for (i = 0; i < sals.nelts; i++)
265     {
266       sal = sals.sals[i];
267
268       t = set_raw_tracepoint (sal);
269       set_tracepoint_count (tracepoint_count + 1);
270       t->number = tracepoint_count;
271
272       /* If a canonical line spec is needed use that instead of the
273          command string.  */
274       if (canonical != (char **)NULL && canonical[i] != NULL)
275         t->addr_string = canonical[i];
276       else if (addr_start)
277         t->addr_string = savestring (addr_start, addr_end - addr_start);
278       if (cond_start)
279         t->cond_string = savestring (cond_start, cond_end - cond_start);
280     }
281
282   if (sals.nelts > 1)
283     {
284       printf_filtered ("Multiple tracepoints were set.\n");
285       printf_filtered ("Use the \"delete\" command to delete unwanted tracepoints.\n");
286     }
287 }
288
289 static void
290 tracepoints_info (tpnum_exp, from_tty)
291      char *tpnum_exp;
292      int from_tty;
293 {
294   struct tracepoint *t;
295   struct action_line *action;
296   int found_a_tracepoint = 0;
297   char wrap_indent[80];
298   struct symbol *sym;
299   int tpnum = -1;
300 #if 0
301   char *i1 = "\t", *i2 = "\t  ";
302   char *indent, *actionline;;
303 #endif
304
305   if (tpnum_exp)
306     tpnum = parse_and_eval_address (tpnum_exp);
307
308   ALL_TRACEPOINTS (t)
309     if (tpnum == -1 || tpnum == t->number)
310       {
311         extern int addressprint;        /* print machine addresses? */
312
313         if (!found_a_tracepoint++)
314           printf_filtered (" *** [info tracepoints header line] ***\n");
315
316         strcpy (wrap_indent, "                           ");
317         if (addressprint)
318           strcat (wrap_indent, "           ");
319
320         printf_filtered ("%-3d %-10s ", t->number, 
321                          t->enabled == enabled ? "enabled" : "disabled");
322         if (addressprint)
323           { /* FIXME-32x64: need a print_address_numeric with field width */
324             printf_filtered ("%s ", local_hex_string_custom ((unsigned long) t->address, "08l"));
325           }
326         if (t->source_file)
327           {
328             sym = find_pc_function (t->address);
329             if (sym)
330               {
331                 fputs_filtered ("in ", gdb_stdout);
332                 fputs_filtered (SYMBOL_SOURCE_NAME (sym), gdb_stdout);
333                 wrap_here (wrap_indent);
334                 fputs_filtered (" at ", gdb_stdout);
335               }
336             fputs_filtered (t->source_file, gdb_stdout);
337             printf_filtered (":%d", t->line_number);
338           }
339         else
340           print_address_symbolic (t->address, gdb_stdout, demangle, " ");
341
342         if (t->pass_count != 0)
343           printf_filtered (" passcount = %d", t->pass_count);
344         printf_filtered ("\n");
345         if (t->actions)
346           {
347             printf_filtered ("  Actions for tracepoint %d: \n", t->number);
348 /*          indent = i1; */
349             for (action = t->actions; action; action = action->next)
350               {
351 #if 0
352                 actionline = action->action;
353                 while (isspace(*actionline))
354                   actionline++;
355
356                 printf_filtered ("%s%s\n", indent, actionline);
357                 if (0 == strncasecmp (actionline, "while-stepping", 14))
358                   indent = i2;
359                 else if (0 == strncasecmp (actionline, "end", 3))
360                   indent = i1;
361 #else
362                 printf_filtered ("\t%s\n", action->action);
363 #endif
364               }
365           }
366       }
367   if (!found_a_tracepoint)
368     {
369       if (tpnum == -1)
370         printf_filtered ("No tracepoints.\n");
371       else
372         printf_filtered ("No tracepoint number %d.\n", tpnum);
373     }
374 }
375
376 /* Optimization: the code to parse an enable, disable, or delete TP command
377    is virtually identical except for whether it performs an enable, disable,
378    or delete.  Therefore I've combined them into one function with an opcode.
379    */
380 enum tracepoint_opcode 
381 {
382   enable, 
383   disable,
384   delete
385 };
386
387 /* This function implements enable, disable and delete. */
388 static void
389 tracepoint_operation (t, from_tty, opcode)
390      struct tracepoint *t;
391      int from_tty;
392      enum tracepoint_opcode opcode;
393 {
394   struct tracepoint *t2;
395   struct action_line *action, *next;
396
397   switch (opcode) {
398   case enable:
399     t->enabled = enabled;
400     break;
401   case disable:
402     t->enabled = disabled;
403     break;
404   case delete:
405     if (tracepoint_chain == t)
406       tracepoint_chain = t->next;
407
408     ALL_TRACEPOINTS (t2)
409       if (t2->next == t)
410         {
411           t2->next = t->next;
412           break;
413         }
414     if (t->cond_string)
415       free (t->cond_string);
416     if (t->addr_string)
417       free (t->addr_string);
418     if (t->source_file)
419       free (t->source_file);
420     for (action = t->actions; action; action = next)
421       {
422         next = action->next;
423         if (action->action) 
424           free (action->action);
425         free (action);
426       }
427     free (t);
428     break;
429   }
430 }
431
432 /* Utility: parse a tracepoint number and look it up in the list.  */
433 static struct tracepoint *
434 get_tracepoint_by_number (arg)
435      char **arg;
436 {
437   struct tracepoint *t;
438   char *cp;
439   value_ptr val;
440   int tpnum;
441
442   if (arg == 0)
443     error ("Bad tracepoint argument");
444
445   if (*arg == 0 || **arg == 0)  /* empty arg means refer to last tp */
446     tpnum = tracepoint_count;
447   else if (**arg == '$')        /* handle convenience variable */
448     {
449       cp = *arg + 1;
450       /* find end of convenience variable name */
451       while (**arg && **arg != ' ' && **arg != '\t')
452         *arg++;
453       /* null-terminate if necessary */
454       if (**arg != 0)
455         *(*arg++) = 0;
456       val = value_of_internalvar (lookup_internalvar (cp));
457       if (TYPE_CODE( VALUE_TYPE (val)) != TYPE_CODE_INT)
458         error ("Convenience variable must have integral type.");
459       tpnum = (int) value_as_long (val);
460     }
461   else          /* handle tracepoint number */
462     {
463       tpnum = strtol (*arg, arg, 10);
464     }
465   ALL_TRACEPOINTS (t)
466     if (t->number == tpnum)
467       {
468         return t;
469       }
470   warning ("No tracepoint number %d.\n", tpnum);
471   return NULL;
472 }
473
474 /* Utility: parse a list of tracepoint numbers, and call a func for each. */
475 static void
476 map_args_over_tracepoints (args, from_tty, opcode)
477      char *args;
478      int from_tty;
479      enum tracepoint_opcode opcode;
480 {
481   struct tracepoint *t;
482   int tpnum;
483   char *cp;
484
485   if (args == 0 || *args == 0)  /* do them all */
486     ALL_TRACEPOINTS (t)
487       tracepoint_operation (t, from_tty, opcode);
488   else
489     while (*args)
490       {
491         if (t = get_tracepoint_by_number (&args))
492           tracepoint_operation (t, from_tty, opcode);
493         while (*args == ' ' || *args == '\t')
494           args++;
495       }
496 }
497
498 static void
499 enable_trace_command (args, from_tty)
500      char *args;
501      int from_tty;
502 {
503   dont_repeat ();
504   map_args_over_tracepoints (args, from_tty, enable);
505 }
506
507 static void
508 disable_trace_command (args, from_tty)
509      char *args;
510      int from_tty;
511 {
512   dont_repeat ();
513   map_args_over_tracepoints (args, from_tty, disable);
514 }
515
516 static void
517 delete_trace_command (args, from_tty)
518      char *args;
519      int from_tty;
520 {
521   dont_repeat ();
522   if (!args || !*args)
523     if (!query ("Delete all tracepoints? "))
524       return;
525
526   map_args_over_tracepoints (args, from_tty, delete);
527 }
528
529 static void
530 trace_pass_command (args, from_tty)
531      char *args;
532      int from_tty;
533 {
534   struct tracepoint *t1 = (struct tracepoint *) -1, *t2;
535   unsigned long count;
536
537   if (args == 0 || *args == 0)
538     error ("PASS command requires an argument (count + optional TP num)");
539
540   count = strtoul (args, &args, 10);    /* count comes first, then TP num */
541
542   while (*args && isspace (*args))
543     args++;
544
545   if (*args && strncasecmp (args, "all", 3) == 0)
546     args += 3;  /* skip special argument "all" */
547   else
548     t1 = get_tracepoint_by_number (&args);
549
550   if (t1 == NULL)
551     return;     /* error, bad tracepoint number */
552
553   ALL_TRACEPOINTS (t2)
554     if (t1 == (struct tracepoint *) -1 || t1 == t2)
555       {
556         t2->pass_count = count;
557         if (from_tty)
558           printf_filtered ("Setting tracepoint %d's passcount to %d\n", 
559                            t2->number, count);
560       }
561 }
562
563 /* ACTIONS ACTIONS ACTIONS */
564
565 static void read_actions PARAMS((struct tracepoint *));
566 static void free_actions PARAMS((struct tracepoint *));
567 static int  validate_actionline PARAMS((char *, struct tracepoint *));
568
569 static void
570 trace_actions_command (args, from_tty)
571      char *args;
572      int from_tty;
573 {
574   struct tracepoint *t;
575   char *actions;
576
577   if (t = get_tracepoint_by_number (&args))
578     {
579       if (from_tty)
580         printf_filtered ("Enter actions for tracepoint %d, one per line.\n", 
581                          t->number);
582       free_actions (t);
583       read_actions (t);
584       /* tracepoints_changed () */
585     }
586   /* else error, just return; */
587 }
588
589 enum actionline_type
590 {
591   BADLINE  = -1, 
592   GENERIC  =  0,
593   END      =  1,
594   STEPPING =  2,
595 };
596
597 static void
598 read_actions (t)
599      struct tracepoint *t;
600 {
601   char *line;
602   char *prompt1 = "> ", *prompt2 = "  > ";
603   char *prompt = prompt1;
604   enum actionline_type linetype;
605   extern FILE *instream;
606   struct action_line *next = NULL, *temp;
607   struct cleanup *old_chain;
608
609   /* Control-C quits instantly if typed while in this loop
610      since it should not wait until the user types a newline.  */
611   immediate_quit++;
612 #ifdef STOP_SIGNAL
613   if (job_control)
614     signal (STOP_SIGNAL, stop_sig);
615 #endif
616   old_chain = make_cleanup (free_actions, (void *) t);
617   while (1)
618     {
619       /* Make sure that all output has been output.  Some machines may let
620          you get away with leaving out some of the gdb_flush, but not all.  */
621       wrap_here ("");
622       gdb_flush (gdb_stdout);
623       gdb_flush (gdb_stderr);
624       if (instream == stdin && ISATTY (instream))
625         line = readline (prompt);
626       else
627         line = gdb_readline (0);
628
629       linetype = validate_actionline (line, t);
630       if (linetype == BADLINE)
631         continue;       /* already warned -- collect another line */
632
633       temp = xmalloc (sizeof (struct action_line));
634       temp->next = NULL;
635       temp->action = line;
636
637       if (next == NULL)         /* first action for this tracepoint? */
638         t->actions = next = temp;
639       else
640         {
641           next->next = temp;
642           next = temp;
643         }
644
645       if (linetype == STEPPING) /* begin "while-stepping" */
646         if (prompt == prompt2)
647           {
648             warning ("Already processing 'while-stepping'");
649             continue;
650           }
651         else
652           prompt = prompt2;     /* change prompt for stepping actions */
653       else if (linetype == END)
654         if (prompt == prompt2)
655           prompt = prompt1;     /* end of single-stepping actions */
656         else
657           break;                /* end of actions */
658     }
659 #ifdef STOP_SIGNAL
660   if (job_control)
661     signal (STOP_SIGNAL, SIG_DFL);
662 #endif
663   immediate_quit = 0;
664   discard_cleanups (old_chain);
665 }
666
667 static enum actionline_type
668 validate_actionline (line, t)
669      char *line;
670      struct tracepoint *t;
671 {
672   char *p;
673   struct expression *exp;
674   value_ptr temp, temp2;
675
676   for (p = line; isspace (*p); )
677     p++;
678
679   /* symbol lookup etc. */
680   if (*p == '\0')       /* empty line: just prompt for another line. */
681     return BADLINE;
682   else if (0 == strncasecmp (p, "collect", 7))
683     {
684       p += 7;
685       do {                      /* repeat over a comma-separated list */
686         while (isspace (*p))
687           p++;
688
689         if (*p == '$' &&                /* look for special pseudo-symbols */
690             ((0 == strncasecmp ("reg", p + 1, 3)) ||
691              (0 == strncasecmp ("arg", p + 1, 3)) ||
692              (0 == strncasecmp ("loc", p + 1, 3))))
693           p = (char *) strchr (p, ',');
694         else
695           {
696             exp   = parse_exp_1 (&p, block_for_pc (t->address), 1);
697             if (exp->elts[0].opcode != OP_VAR_VALUE &&
698               /*exp->elts[0].opcode != OP_LONG      && */
699               /*exp->elts[0].opcode != UNOP_CAST    && */
700                 exp->elts[0].opcode != OP_REGISTER)
701               {
702                 warning ("collect: enter variable name or register.\n");
703                 return BADLINE;
704               }
705             if (exp->elts[0].opcode == OP_VAR_VALUE)
706               if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
707                 {
708                   warning ("%s is constant (value %d): will not be collected.",
709                            SYMBOL_NAME (exp->elts[2].symbol),
710                            SYMBOL_VALUE (exp->elts[2].symbol));
711                   return BADLINE;
712                 }
713               else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT)
714                 {
715                   warning ("%s is optimized away and cannot be collected.",
716                            SYMBOL_NAME (exp->elts[2].symbol));
717                   return BADLINE;
718                 }
719           }
720       } while (p && *p++ == ',');
721       return GENERIC;
722     }
723   else if (0 == strncasecmp (p, "while-stepping", 14))
724     {
725       char *steparg;    /* in case warning is necessary */
726
727       p += 14;
728       while (isspace (*p))
729         p++;
730       steparg = p;
731
732       if (*p)
733         {
734           t->step_count = strtol (p, &p, 0);
735           if (t->step_count == 0)
736             {
737               warning ("'%s' evaluates to zero -- command ignored.");
738               return BADLINE;
739             }
740         }
741       else 
742         t->step_count = -1;
743       return STEPPING;
744     }
745   else if (0 == strncasecmp (p, "end", 3))
746     return END;
747   else
748     {
749       warning ("'%s' is not a supported tracepoint action.", p);
750       return BADLINE;
751     }
752 }
753
754 static void 
755 free_actions (t)
756      struct tracepoint *t;
757 {
758   struct action_line *line, *next;
759
760   for (line = t->actions; line; line = next)
761     {
762       next = line->next;
763       free (line);
764     }
765   t->actions = NULL;
766 }
767
768 struct memrange {
769   int type;             /* 0 for absolute memory range, else basereg number */
770   bfd_signed_vma start;
771   bfd_signed_vma end;
772 };
773
774 struct collection_list {
775   unsigned char regs_mask[8];   /* room for up to 256 regs */
776   long listsize;
777   long next_memrange;
778   struct memrange *list;
779 } tracepoint_list, stepping_list;
780
781 static int
782 memrange_cmp (a, b)
783      struct memrange *a, *b;
784 {
785   if (a->type < b->type) return -1;
786   if (a->type > b->type) return  1;
787   if (a->type == 0)
788     {
789       if ((bfd_vma) a->start  < (bfd_vma) b->start)  return -1;
790       if ((bfd_vma) a->start  > (bfd_vma) b->start)  return  1;
791     }
792   else
793     {
794       if (a->start  < b->start)  return -1;
795       if (a->start  > b->start)  return  1;
796     }
797   return 0;
798 }
799
800 static void
801 memrange_sortmerge (memranges)
802      struct collection_list *memranges;
803 {
804   int a, b;
805
806   qsort (memranges->list, memranges->next_memrange, 
807          sizeof (struct memrange), memrange_cmp);
808   if (memranges->next_memrange > 0)
809     {
810       for (a = 0, b = 1; b < memranges->next_memrange; b++)
811         {
812           if (memranges->list[a].type == memranges->list[b].type &&
813               memranges->list[b].start - memranges->list[a].end <= 
814               MAX_REGISTER_VIRTUAL_SIZE)
815             {
816               memranges->list[a].end = memranges->list[b].end;
817               continue;         /* next b, same a */
818             }
819           a++;                  /* next a */
820           if (a != b)
821             memcpy (&memranges->list[a], &memranges->list[b], 
822                     sizeof (struct memrange));
823         }
824       memranges->next_memrange = a + 1;
825     }
826 }
827
828 void
829 add_register (collection, regno)
830      struct collection_list *collection;
831      unsigned long regno;
832 {
833   if (info_verbose)
834     printf_filtered ("collect register %d\n", regno);
835   if (regno > (8 * sizeof (collection->regs_mask)))
836     error ("Internal: register number %d too large for tracepoint",
837            regno);
838   collection->regs_mask [regno / 8] |= 1 << (regno  % 8);
839 }
840
841 static void
842 add_memrange (memranges, type, base, len)
843      struct collection_list *memranges;
844      int type;
845      bfd_signed_vma base;
846      unsigned long len;
847 {
848   if (info_verbose)
849     printf_filtered ("(%d,0x%x,%d)\n", type, base, len);
850   /* type: 0 == memory, n == basereg */
851   memranges->list[memranges->next_memrange].type  = type;
852   /* base: addr if memory, offset if reg relative. */
853   memranges->list[memranges->next_memrange].start = base;
854   /* len: we actually save end (base + len) for convenience */
855   memranges->list[memranges->next_memrange].end   = base + len;
856   memranges->next_memrange++;
857   if (memranges->next_memrange >= memranges->listsize)
858     {
859       memranges->listsize *= 2;
860       memranges->list = xrealloc (memranges->list, 
861                                   memranges->listsize);
862     }
863
864   if (type != 0)        /* better collect the base register! */
865     add_register (memranges, type);
866 }
867
868 static void
869 collect_symbol (collect, sym)
870      struct collection_list *collect;
871      struct symbol *sym;
872 {
873   unsigned long  len;
874   unsigned long  reg;
875   bfd_signed_vma offset;
876
877   len  = TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym)));
878   switch (SYMBOL_CLASS (sym)) {
879   default:
880     printf_filtered ("%s: don't know symbol class %d\n",
881                      SYMBOL_NAME (sym), SYMBOL_CLASS (sym));
882     break;
883   case LOC_CONST:
884     printf_filtered ("%s is constant, value is %d: will not be collected.\n",
885                      SYMBOL_NAME (sym), SYMBOL_VALUE (sym));
886     break;
887   case LOC_STATIC:
888     offset = SYMBOL_VALUE_ADDRESS (sym); 
889     if (info_verbose)
890       printf_filtered ("LOC_STATIC %s: collect %d bytes "
891                        "at 0x%08x\n",
892                        SYMBOL_NAME (sym), len, offset);
893     add_memrange (collect, 0, offset, len);     /* 0 == memory */
894     break;
895   case LOC_REGISTER:
896   case LOC_REGPARM:
897     reg = SYMBOL_VALUE (sym); 
898     if (info_verbose)
899       printf_filtered ("LOC_REG[parm] %s: ", SYMBOL_NAME (sym));
900     add_register (collect, reg);
901     break;
902   case LOC_ARG:
903   case LOC_REF_ARG:
904     printf_filtered ("Sorry, don't know how to do LOC_ARGs yet.\n");
905     printf_filtered ("       (will not collect %s)\n", 
906                      SYMBOL_NAME (sym));
907     break;
908   case LOC_REGPARM_ADDR:
909     reg = SYMBOL_VALUE (sym);
910     offset = 0;
911     if (info_verbose)
912       {
913         printf_filtered ("LOC_REGPARM_ADDR %s: Collect %d bytes at offset %d from reg %d\n", 
914                          SYMBOL_NAME (sym), len, offset, reg);
915       }
916     add_memrange (collect, reg, offset, len);
917     break;
918   case LOC_LOCAL:
919   case LOC_LOCAL_ARG:
920     offset = SYMBOL_VALUE (sym);
921     reg = FP_REGNUM;
922     if (info_verbose)
923       {
924         printf_filtered ("LOC_LOCAL %s: Collect %d bytes at offset %d from frame ptr reg %d\n", 
925                          SYMBOL_NAME (sym), len, offset, reg);
926       }
927     add_memrange (collect, reg, offset, len);
928     break;
929   case LOC_BASEREG:
930   case LOC_BASEREG_ARG:
931     reg = SYMBOL_BASEREG (sym);
932     offset  = SYMBOL_VALUE (sym);
933     if (info_verbose)
934       {
935         printf_filtered ("LOC_BASEREG %s: collect %d bytes at offset %d from basereg %d\n", 
936                          SYMBOL_NAME (sym), len, offset, reg);
937       }
938     add_memrange (collect, reg, offset, len);
939     break;
940   case LOC_UNRESOLVED:
941     printf_filtered ("Don't know LOC_UNRESOLVED %s\n", SYMBOL_NAME (sym));
942     break;
943   case LOC_OPTIMIZED_OUT:
944     printf_filtered ("%s has been optimized out of existance.\n",
945                      SYMBOL_NAME (sym));
946     break;
947   }
948 }
949
950 static void
951 add_local_symbols (collect, pc, type)
952      struct collection_list *collect;
953      CORE_ADDR pc;
954      char type;
955 {
956   struct symbol *sym;
957   struct block  *block;
958   int i, nsyms, count = 0;
959
960   block = block_for_pc (pc);
961   while (block != 0)
962     {
963       nsyms = BLOCK_NSYMS (block);
964       for (i = 0; i < nsyms; i++)
965         {
966           sym = BLOCK_SYM (block, i);
967           switch (SYMBOL_CLASS (sym)) {
968           case LOC_LOCAL:
969           case LOC_STATIC:
970           case LOC_REGISTER:
971           case LOC_BASEREG:
972             if (type == 'L')    /* collecting Locals */
973               {
974                 count++;
975                 collect_symbol (collect, sym);
976               }
977             break;
978           case LOC_ARG:
979           case LOC_LOCAL_ARG:
980           case LOC_REF_ARG:
981           case LOC_REGPARM:
982           case LOC_REGPARM_ADDR:
983           case LOC_BASEREG_ARG:
984             if (type == 'A')    /* collecting Arguments */
985               {
986                 count++;
987                 collect_symbol (collect, sym);
988               }
989           }
990         }
991       if (BLOCK_FUNCTION (block))
992         break;
993       else
994         block = BLOCK_SUPERBLOCK (block);
995     }
996   if (count == 0)
997     warning ("No %s found in scope.", type == 'L' ? "locals" : "args");
998 }
999
1000 static void
1001 clear_collection_list (list)
1002      struct collection_list *list;
1003 {
1004   list->next_memrange = 0;
1005   memset (list->regs_mask, 0, sizeof (list->regs_mask));
1006 }
1007
1008 static char *
1009 stringify_collection_list (list, string)
1010      struct collection_list *list;
1011      char *string;
1012 {
1013   char *end = string;
1014   long  i;
1015
1016   for (i = sizeof (list->regs_mask) - 1; i > 0; i--)
1017     if (list->regs_mask[i] != 0)        /* skip leading zeroes in regs_mask */
1018       break;
1019   if (list->regs_mask[i] != 0)  /* prepare to send regs_mask to the stub */
1020     {
1021       if (info_verbose)
1022         printf_filtered ("\nCollecting registers (mask): 0x");
1023       *end++='R';
1024       for (; i >= 0; i--)
1025         {
1026           if (info_verbose)
1027             printf_filtered ("%02X", list->regs_mask[i]);
1028           sprintf (end,  "%02X", list->regs_mask[i]);
1029           end += 2;
1030         }
1031     }
1032   if (info_verbose)
1033     printf_filtered ("\n");
1034   if (list->next_memrange > 0 && info_verbose)
1035     printf_filtered ("Collecting memranges: \n");
1036   for (i = 0; i < list->next_memrange; i++)
1037     {
1038       if (info_verbose)
1039         printf_filtered ("(%d, 0x%x, %d)\n", 
1040                          list->list[i].type, 
1041                          list->list[i].start, 
1042                          list->list[i].end - list->list[i].start);
1043       sprintf (end, "M%X,%X,%X", 
1044                list->list[i].type, 
1045                list->list[i].start, 
1046                list->list[i].end - list->list[i].start);
1047       end += strlen (end);
1048     }
1049   if (end == string)
1050     return NULL;
1051   else
1052     return string;
1053 }
1054
1055 static void
1056 encode_actions (t, tdp_actions, step_count, stepping_actions)
1057      struct tracepoint  *t;
1058      char              **tdp_actions;
1059      unsigned long      *step_count;
1060      char              **stepping_actions;
1061 {
1062   struct expression  *exp;
1063   static char        tdp_buff[2048], step_buff[2048];
1064   struct action_line *action;
1065   char               *action_exp;
1066   bfd_signed_vma      offset;
1067   long                i;
1068   struct collection_list *collect;
1069
1070   clear_collection_list (&tracepoint_list);
1071   clear_collection_list (&stepping_list);
1072   collect = &tracepoint_list;
1073
1074   *tdp_actions = NULL;
1075   *stepping_actions = NULL;
1076
1077   for (action = t->actions; action; action = action->next)
1078     {
1079       action_exp = action->action;
1080       while (isspace (*action_exp))
1081         action_exp++;
1082
1083       if (0 == strncasecmp (action_exp, "collect", 7))
1084         {
1085           action_exp = action_exp + 7;
1086           do {  /* repeat over a comma-separated list */
1087             while (isspace (*action_exp))
1088               action_exp++;
1089
1090             if (0 == strncasecmp ("$reg", action_exp, 4))
1091               {
1092                 for (i = 0; i < NUM_REGS; i++)
1093                   add_register (collect, i);
1094                 action_exp = (char *) strchr (action_exp, ','); /* more? */
1095               }
1096             else if (0 == strncasecmp ("$arg", action_exp, 4))
1097               {
1098                 add_local_symbols (collect, t->address, 'A');
1099                 action_exp = (char *) strchr (action_exp, ','); /* more? */
1100               }
1101             else if (0 == strncasecmp ("$loc", action_exp, 4))
1102               {
1103                 add_local_symbols (collect, t->address, 'L');
1104                 action_exp = (char *) strchr (action_exp, ','); /* more? */
1105               }
1106             else
1107               {
1108                 unsigned long addr, len;
1109
1110                 exp = parse_exp_1 (&action_exp, block_for_pc (t->address), 1);
1111                 switch (exp->elts[0].opcode) {
1112                 case OP_REGISTER:
1113                   i = exp->elts[1].longconst; 
1114                   if (info_verbose)
1115                     printf_filtered ("OP_REGISTER: ");
1116                   add_register (collect, i);
1117                   break;
1118                 case OP_VAR_VALUE:
1119                   collect_symbol (collect, exp->elts[2].symbol);
1120                   break;
1121 #if 0
1122                 case OP_LONG:
1123                   addr = exp->elts[2].longconst;
1124                   if (*action_exp == ':')
1125                     {
1126                       exp = parse_exp_1 (&action_exp, 
1127                                          block_for_pc (t->address), 
1128                                          1);
1129                       if (exp->elts[0].opcode == OP_LONG)
1130                         len = exp->elts[2].longconst;
1131                       else
1132                         error ("length field requires a literal long const");
1133                     }
1134                   else 
1135                     len = 4;
1136
1137                   add_memrange (collect, 0, addr, len);
1138                   break;
1139 #endif
1140                 }
1141               }
1142           } while (action_exp && *action_exp++ == ',');
1143         }
1144       else if (0 == strncasecmp (action_exp, "while-stepping", 14))
1145         {
1146           collect = &stepping_list;
1147         }
1148       else if (0 == strncasecmp (action_exp, "end", 3))
1149         {
1150           if (collect == &stepping_list)        /* end stepping actions */
1151             collect = &tracepoint_list;
1152           else
1153             break;                      /* end tracepoint actions */
1154         }
1155     }
1156   memrange_sortmerge (&tracepoint_list); 
1157   memrange_sortmerge (&stepping_list); 
1158
1159   *tdp_actions      = stringify_collection_list (&tracepoint_list, &tdp_buff);
1160   *stepping_actions = stringify_collection_list (&stepping_list,   &step_buff);
1161 }
1162
1163 static char target_buf[2048];
1164
1165 static void
1166 trace_start_command (args, from_tty)
1167      char *args;
1168      int from_tty;
1169 { /* STUB_COMM MOSTLY_IMPLEMENTED */
1170   struct tracepoint *t;
1171   char buf[2048];
1172   char *tdp_actions;
1173   char *stepping_actions;
1174   unsigned long step_count;
1175
1176   dont_repeat ();       /* like "run", dangerous to repeat accidentally */
1177   
1178   if (target_is_remote ())
1179     {
1180       putpkt ("QTinit");
1181       remote_get_noisy_reply (target_buf);
1182       if (strcmp (target_buf, "OK"))
1183         error ("Target does not support this command.");
1184
1185       ALL_TRACEPOINTS (t)
1186         {
1187           int ss_count;         /* if actions include singlestepping */
1188           int disable_mask;     /* ??? */
1189           int enable_mask;      /* ??? */
1190
1191           sprintf (buf, "QTDP:%x:%x:%c:%x:%x", t->number, t->address, 
1192                    t->enabled == enabled ? 'E' : 'D', 
1193                    t->step_count, t->pass_count);
1194           if (t->actions)
1195             {
1196               encode_actions (t, &tdp_actions, &step_count, &stepping_actions);
1197               /* do_single_steps (t); */
1198               if (tdp_actions)
1199                 {
1200                   if (strlen (buf) + strlen (tdp_actions) >= sizeof (buf))
1201                     error ("Actions for tracepoint %d too complex; "
1202                            "please simplify.", t->number);
1203                   strcat (buf, tdp_actions);
1204                 }
1205               if (stepping_actions)
1206                 {
1207                   strcat (buf, "S");
1208                   if (strlen (buf) + strlen (stepping_actions) >= sizeof (buf))
1209                     error ("Actions for tracepoint %d too complex; "
1210                            "please simplify.", t->number);
1211                   strcat (buf, stepping_actions);
1212                 }
1213             }
1214           putpkt (buf);
1215           remote_get_noisy_reply (target_buf);
1216           if (strcmp (target_buf, "OK"))
1217             error ("Target does not support tracepoints.");
1218         }
1219       putpkt ("QTStart");
1220       remote_get_noisy_reply (target_buf);
1221       if (strcmp (target_buf, "OK"))
1222         error ("Bogus reply from target: %s", target_buf);
1223     }
1224   else
1225     printf_filtered ("Trace can only be run on remote targets.\n");
1226 }
1227
1228 static void
1229 trace_stop_command (args, from_tty)
1230      char *args;
1231      int from_tty;
1232 { /* STUB_COMM IS_IMPLEMENTED */
1233   if (target_is_remote ())
1234     {
1235       putpkt ("QTStop");
1236       remote_get_noisy_reply (target_buf);
1237       if (strcmp (target_buf, "OK"))
1238         error ("Bogus reply from target: %s", target_buf);
1239     }
1240   else
1241     error ("Trace can only be run on remote targets.");
1242 }
1243
1244 static void
1245 trace_status_command (args, from_tty)
1246      char *args;
1247      int from_tty;
1248 { /* STUB_COMM IS_IMPLEMENTED */
1249   if (target_is_remote ())
1250     {
1251       putpkt ("qTStatus");
1252       remote_get_noisy_reply (target_buf);
1253       if (strcmp (target_buf, "OK"))
1254         error ("Bogus reply from target: %s", target_buf);
1255     }
1256   else
1257     error ("Trace can only be run on remote targets.");
1258 }
1259
1260 static void
1261 trace_buff_command (args, from_tty)
1262      char *args;
1263      int from_tty;
1264 { /* STUB_COMM NOT_IMPLEMENTED */
1265   if (args == 0 || *args == 0)
1266     printf_filtered ("TBUFFER command requires argument (on or off)\n");
1267   else if (strcasecmp (args, "on") == 0)
1268     printf_filtered ("tbuffer overflow on.\n");
1269   else if (strcasecmp (args, "off") == 0)
1270     printf_filtered ("tbuffer overflow off.\n");
1271   else
1272     printf_filtered ("TBUFFER: unknown argument (use on or off)\n");
1273 }
1274
1275 static void
1276 trace_limit_command (args, from_tty)
1277      char *args;
1278      int from_tty;
1279 { /* STUB_COMM NOT_IMPLEMENTED */
1280   printf_filtered ("Limit it to what?\n");
1281 }
1282
1283 static void
1284 trace_find_command (args, from_tty)
1285      char *args;
1286      int from_tty;
1287 { /* STUB_COMM PART_IMPLEMENTED */
1288   /* this should only be called with a numeric argument */
1289   int frameno, target_frameno;
1290   char buf[40], *tmp;
1291   
1292   if (target_is_remote ())
1293     {
1294       if (args == 0 || *args == 0)
1295         frameno = traceframe_number + 1;
1296       else if (*args != '-' && !isdigit(*args))
1297         error ("tfind requires a literal (for now): %s rejected.", args);
1298       else
1299         frameno = strtol (args, 0, 0);  /* for now, literals only */
1300
1301       sprintf (buf, "QTFrame:%x", frameno);
1302       putpkt (buf);
1303       remote_get_noisy_reply (target_buf);
1304
1305       if (target_buf[0] != 'F')
1306         error ("Bogus reply from target: %s", target_buf);
1307       target_frameno = strtol (&target_buf[1], &tmp, 16);
1308       if (tmp == &target_buf[1])
1309         error ("Bogus reply from target: %s", target_buf);
1310       if (target_frameno != frameno)
1311         warning ("Target replied with different framenumber, %s != %x",
1312                  target_buf, frameno);
1313
1314       set_traceframe_num (target_frameno);
1315       flush_cached_frames ();
1316       registers_changed ();
1317       select_frame (get_current_frame (), 0);
1318     }
1319   else
1320     error ("Trace can only be run on remote targets.");
1321 }
1322
1323 static void
1324 trace_find_pc_command (args, from_tty)
1325      char *args;
1326      int from_tty;
1327 { /* STUB_COMM PART_IMPLEMENTED */
1328   CORE_ADDR pc;
1329   int target_frameno;
1330   char buf[40], *tmp;
1331
1332   if (target_is_remote ())
1333     {
1334       if (args == 0 || *args == 0)
1335         {       /* TFIND PC <no args> is the same as TFIND <no args> */
1336           trace_find_command (args, from_tty);
1337           return;
1338         }
1339       if (!isdigit(*args))
1340         error ("tfind pc requires a literal argument (for now): %s rejected.",
1341                args);
1342
1343       pc = strtol (args, 0, 0);  /* for now, literals only */
1344       sprintf (buf, "QTFrame:pc:%x", pc);
1345       putpkt (buf);
1346       remote_get_noisy_reply (target_buf);
1347
1348       if (target_buf[0] != 'F')
1349         error ("Bogus reply from target: %s", target_buf);
1350       target_frameno = strtol (&target_buf[1], &tmp, 16);
1351       if (tmp == &target_buf[1])
1352         error ("Bogus reply from target: %s", target_buf);
1353
1354       set_traceframe_num (target_frameno);
1355       flush_cached_frames ();
1356       registers_changed ();
1357       select_frame (get_current_frame (), 0);
1358     }
1359   else
1360     error ("Trace can only be run on remote targets.");
1361 }
1362
1363 static void
1364 trace_find_tdp_command (args, from_tty)
1365      char *args;
1366      int from_tty;
1367 { /* STUB_COMM PART_IMPLEMENTED */
1368   int target_frameno, tdp;
1369   char buf[40], *tmp;
1370
1371   if (target_is_remote ())
1372     {
1373       if (args == 0 || *args == 0)
1374         { /* TFIND TDP <no args> is the same as TFIND <no args> */
1375           trace_find_command (args, from_tty);
1376           return;
1377         }
1378       if (!isdigit(*args))
1379         error ("tfind tdp command requires a literal argument (for now): %s",
1380                args);
1381
1382       tdp = strtol (args, 0, 0);  /* for now, literals only */
1383       sprintf (buf, "QTFrame:tdp:%x", tdp);
1384       putpkt (buf);
1385       remote_get_noisy_reply (target_buf);
1386
1387       if (target_buf[0] != 'F')
1388         error ("Bogus reply from target: %s", target_buf);
1389       target_frameno = strtol (&target_buf[1], &tmp, 16);
1390       if (tmp == &target_buf[1])
1391         error ("Bogus reply from target: %s", target_buf);
1392
1393       set_traceframe_num (target_frameno);
1394       flush_cached_frames ();
1395       registers_changed ();
1396       select_frame (get_current_frame (), 0);
1397     }
1398   else
1399     error ("Trace can only be run on remote targets.");
1400 }
1401
1402 static void
1403 trace_find_range_command (args, from_tty)
1404      char *args;
1405      int from_tty;
1406 { /* STUB_COMM PART_IMPLEMENTED */
1407   static CORE_ADDR start, stop;
1408   int target_frameno;
1409   char buf[50], *tmp;
1410
1411   if (target_is_remote ())
1412     {
1413       if (args == 0 || *args == 0 || !isdigit(*args))
1414         { /* XXX FIXME: what should default behavior be? */
1415           printf_filtered ("Usage: tfind range <address> <address>\n");
1416           return;
1417         }
1418
1419       start = strtol (args, &args, 0); /* for now, literals only */
1420       while (args && *args && isspace (*args))
1421         args++;
1422
1423       if (args == 0 || *args == 0 || !isdigit(*args))
1424         {
1425           printf_filtered ("Usage: tfind range <address> <address>\n");
1426           return;
1427         }
1428
1429       stop = strtol (args, &args, 0); /* for now, literals only */
1430
1431       sprintf (buf, "QTFrame:range:%x:%x", start, stop);
1432       putpkt (buf);
1433       remote_get_noisy_reply (target_buf);
1434
1435       if (target_buf[0] != 'F')
1436         error ("Bogus reply from target: %s", target_buf);
1437       target_frameno = strtol (&target_buf[1], &tmp, 16);
1438       if (tmp == &target_buf[1])
1439         error ("Bogus reply from target: %s", target_buf);
1440
1441       set_traceframe_num (target_frameno);
1442       flush_cached_frames ();
1443       registers_changed ();
1444       select_frame (get_current_frame (), 0);
1445     }
1446   else
1447       error ("Trace can only be run on remote targets.");
1448 }
1449
1450 static void
1451 trace_find_outside_command (args, from_tty)
1452      char *args;
1453      int from_tty;
1454 { /* STUB_COMM PART_IMPLEMENTED */
1455   CORE_ADDR start, stop;
1456   int target_frameno;
1457   char buf[50], *tmp;
1458
1459   if (target_is_remote ())
1460     {
1461       if (args == 0 || *args == 0 || !isdigit(*args))
1462         { /* XXX FIXME: what should default behavior be? */
1463           printf_filtered ("Usage: tfind outside <address> <address>\n");
1464           return;
1465         }
1466
1467       start = strtol (args, &args, 0);
1468       while (args && *args && isspace (*args))
1469         args++;
1470
1471       if (args == 0 || *args == 0 || !isdigit(*args))
1472         {
1473           printf_filtered ("Usage: tfind outside <address> <address>\n");
1474           return;
1475         }
1476
1477       stop = strtol (args, &args, 0);
1478
1479       sprintf (buf, "QTFrame:outside:%x:%x", start, stop);
1480       putpkt (buf);
1481       remote_get_noisy_reply (target_buf);
1482
1483       if (target_buf[0] != 'F')
1484         error ("Bogus reply from target: %s", target_buf);
1485       target_frameno = strtol (&target_buf[1], &tmp, 16);
1486       if (tmp == &target_buf[1])
1487         error ("Bogus reply from target: %s", target_buf);
1488
1489       set_traceframe_num (target_frameno);
1490       flush_cached_frames ();
1491       registers_changed ();
1492       select_frame (get_current_frame (), 0);
1493     }
1494   else
1495       error ("Trace can only be run on remote targets.");
1496 }
1497
1498 static void
1499 trace_display_command (args, from_tty)
1500      char *args;
1501      int from_tty;
1502 { /* STUB_COMM NOT_IMPLEMENTED */
1503   if (!target_is_remote ())
1504     {
1505       printf_filtered ("Trace can only be run on remote targets.\n");
1506       return;
1507     }
1508
1509   if (args && *args)
1510     printf_filtered ("Displaying trace as %s.\n", args);
1511   else
1512     printf_filtered ("Displaying trace.\n");
1513 }
1514
1515 static void
1516 tracepoint_save_command (args, from_tty)
1517      char *args;
1518      int from_tty;
1519 {
1520   struct tracepoint  *tp;
1521   struct action_line *line;
1522   FILE *fp;
1523   char *i1 = "    ", *i2 = "      ";
1524   char *indent, *actionline;
1525
1526   if (args == 0 || *args == 0)
1527     error ("Argument required (file name in which to save tracepoints");
1528
1529   if (tracepoint_chain == 0)
1530     {
1531       warning ("save-tracepoints: no tracepoints to save.\n");
1532       return;
1533     }
1534
1535   if (!(fp = fopen (args, "w")))
1536     error ("Unable to open file '%s' for saving tracepoints");
1537
1538   ALL_TRACEPOINTS (tp)
1539     {
1540       if (tp->addr_string)
1541         fprintf (fp, "trace %s\n", tp->addr_string);
1542       else
1543         fprintf (fp, "trace *0x%x\n", tp->address);
1544
1545       if (tp->pass_count)
1546         fprintf (fp, "  passcount %d\n", tp->pass_count);
1547
1548       if (tp->actions)
1549         {
1550           fprintf (fp, "  actions\n");
1551           indent = i1;
1552           for (line = tp->actions; line; line = line->next)
1553             {
1554               actionline = line->action;
1555               while (isspace(*actionline))
1556                 actionline++;
1557
1558               fprintf (fp, "%s%s\n", indent, actionline);
1559               if (0 == strncasecmp (actionline, "while-stepping", 14))
1560                 indent = i2;
1561               else if (0 == strncasecmp (actionline, "end", 3))
1562                 indent = i1;
1563             }
1564         }
1565     }
1566   fclose (fp);
1567   if (from_tty)
1568     printf_filtered ("Tracepoints saved to file '%s'.\n", args);
1569   return;
1570 }
1571
1572 static void
1573 scope_info (args, from_tty)
1574      char *args;
1575      int from_tty;
1576 {
1577   struct symtab_and_line sal;
1578   struct symtabs_and_lines sals;
1579   struct symbol *sym;
1580   struct block *block;
1581   char **canonical, *save_args = args, *symname;
1582   int i, nsyms, count = 0;
1583     enum address_class aclass;
1584
1585   if (args == 0 || *args == 0)
1586     error ("requires an argument (function, line or *addr) to define a scope");
1587
1588   sals = decode_line_1 (&args, 1, NULL, 0, &canonical);
1589   if (sals.nelts == 0)
1590     return;             /* presumably decode_line_1 has already warned */
1591
1592   printf_filtered ("Block for %s", save_args);
1593   /* Resolve all line numbers to PC's */
1594   for (i = 0; i < sals.nelts; i++)
1595     resolve_sal_pc (&sals.sals[i]);
1596
1597   block = block_for_pc (sals.sals[0].pc);
1598   while (block != 0)
1599     {
1600       nsyms = BLOCK_NSYMS (block);
1601       for (i = 0; i < nsyms; i++)
1602         {
1603           count++;
1604           sym = BLOCK_SYM (block, i);
1605           switch (SYMBOL_CLASS (sym)) {
1606           default:
1607           case LOC_UNDEF:               /* messed up symbol? */
1608             symname = SYMBOL_NAME (sym);
1609             if (symname && *symname)    /* guard against messed up name */
1610               printf_filtered ("Bogus symbol %s, class %d\n", 
1611                                symname, SYMBOL_CLASS (sym));
1612             else 
1613               printf_filtered ("Completely bogus symbol, class %d.\n",
1614                                SYMBOL_CLASS (sym));
1615             count--;                    /* don't count this one */
1616             continue;
1617           case LOC_CONST:        printf_filtered ("\nConstant       "); break;
1618           case LOC_STATIC:       printf_filtered ("\nStatic         "); break;
1619           case LOC_REGISTER:     printf_filtered ("\nRegister       "); break;
1620           case LOC_ARG:          printf_filtered ("\nArg            "); break;
1621           case LOC_REF_ARG:      printf_filtered ("\nReference Arg  "); break;
1622           case LOC_REGPARM:      printf_filtered ("\nRegister Arg   "); break;
1623           case LOC_REGPARM_ADDR:
1624             printf_filtered ("\nIndirect Register Arg ");               break;
1625           case LOC_LOCAL:        printf_filtered ("\nStack Local    "); break;
1626           case LOC_TYPEDEF:      printf_filtered ("\nLocal Typedef  "); break;
1627           case LOC_LABEL:        printf_filtered ("\nLocal Label    "); break;
1628           case LOC_BLOCK:        printf_filtered ("\nLocal Function "); break;
1629           case LOC_CONST_BYTES:  printf_filtered ("\nLoc. Byte Seq. "); break;
1630           case LOC_LOCAL_ARG:    printf_filtered ("\nStack Arg      "); break;
1631           case LOC_BASEREG:      printf_filtered ("\nBasereg Local  "); break;
1632           case LOC_BASEREG_ARG:  printf_filtered ("\nBasereg Arg    "); break;
1633           case LOC_UNRESOLVED:
1634             printf_filtered ("\nUnresolved Static ");                   break;
1635           case LOC_OPTIMIZED_OUT: printf_filtered ("\nOptimized-Out "); break;
1636           }
1637           type_print (SYMBOL_TYPE (sym), SYMBOL_NAME (sym), gdb_stdout, -1);
1638         }
1639       if (BLOCK_FUNCTION (block))
1640         break;
1641       else
1642         block = BLOCK_SUPERBLOCK (block);
1643     }
1644   if (count <= 0)
1645     printf_filtered (" contains no locals or arguments.");
1646   printf_filtered ("\n");
1647 }
1648
1649 static struct cmd_list_element *tfindlist;
1650 static struct cmd_list_element *tracelist;
1651
1652 void
1653 _initialize_tracepoint ()
1654 {
1655   tracepoint_chain  = 0;
1656   tracepoint_count  = 0;
1657   traceframe_number = 0;
1658
1659   set_internalvar (lookup_internalvar ("tpnum"), 
1660                    value_from_longest (builtin_type_int, (LONGEST) 0));
1661   set_internalvar (lookup_internalvar ("trace_frame"), 
1662                    value_from_longest (builtin_type_int, (LONGEST) 0));
1663
1664   if (tracepoint_list.list == NULL)
1665     {
1666       tracepoint_list.listsize = 128;
1667       tracepoint_list.list = xmalloc 
1668         (tracepoint_list.listsize * sizeof (struct memrange));
1669     }
1670   if (stepping_list.list == NULL)
1671     {
1672       stepping_list.listsize = 128;
1673       stepping_list.list = xmalloc 
1674         (stepping_list.listsize * sizeof (struct memrange));
1675     }
1676
1677   add_info ("scope", scope_info, 
1678             "List the variables local to a scope");
1679
1680 #if 1
1681   add_cmd ("tracepoints", class_trace, NO_FUNCTION, 
1682            "Tracing program execution without stopping the program.", 
1683            &cmdlist);
1684
1685   add_info ("tracepoints", tracepoints_info,
1686             "Display tracepoints, or tracepoint number NUMBER.\n"
1687             "Convenience variable \"$tpnum\" contains the number of the\n"
1688             "last tracepoint set.");
1689
1690   add_info_alias ("tp", "tracepoints", 1);
1691
1692   add_com ("save-tracepoints", class_trace, tracepoint_save_command, 
1693            "Save current tracepoint definitions as a script.\n"
1694            "Use the SOURCE command in another debug session to restore them.");
1695
1696   add_com ("tlimit",  class_trace, trace_limit_command,
1697            "Not sure what this should do yet....");
1698
1699   add_com ("tbuffer",  class_trace, trace_buff_command,
1700            "See also 'set trace buffer overflow'.");
1701
1702   add_prefix_cmd ("tfind",  class_trace,
1703                   trace_find_command,
1704                   "Select a trace frame (default by frame number).",
1705                   &tfindlist, "tfind ", 1, &cmdlist);
1706
1707   add_cmd ("outside", class_trace, trace_find_outside_command,
1708            "Select a trace frame by falling outside of a PC range", 
1709            &tfindlist);
1710
1711   add_cmd ("range", class_trace, trace_find_range_command,
1712            "Select a trace frame by PC range", &tfindlist);
1713
1714   add_cmd ("tdp", class_trace, trace_find_tdp_command,
1715            "Select a trace frame by TDP", &tfindlist);
1716
1717   add_cmd ("pc", class_trace, trace_find_pc_command,
1718            "Select a trace frame by PC", &tfindlist);
1719
1720   add_com ("tdisplay",  class_trace, trace_display_command,
1721            "Display the results of a trace");
1722
1723   add_com ("tstatus",  class_trace, trace_status_command,
1724            "Inquire about trace data collection status.");
1725
1726   add_com ("tstop",  class_trace, trace_stop_command,
1727            "Stop trace data collection.");
1728
1729   add_com ("tstart", class_trace, trace_start_command,
1730            "Start trace data collection.");
1731
1732   add_com ("passcount", class_trace, trace_pass_command, 
1733            "Set the passcount for a tracepoint.\n"
1734            "The trace will end when the tracepoint has been passed "
1735            "'count' times.\n"
1736            "Usage: passcount COUNT TPNUM, where TPNUM may also be \"all\",\n"
1737            "or if omitted refers to the last tracepoint defined.");
1738
1739   add_com ("actions", class_trace, trace_actions_command,
1740            "Specify the actions to be taken at a tracepoint.\n"
1741            "Actions can include collection of data, enabling or \n"
1742            "disabling other tracepoints, or ending the trace.");
1743
1744   add_cmd ("tracepoints", class_trace, delete_trace_command, 
1745            "Delete specified tracepoints; or with no argument, delete all.",
1746            &deletelist);
1747
1748   add_cmd ("tracepoints", class_trace, disable_trace_command, 
1749            "Disable specified tracepoints; or with no argument, disable all.",
1750            &disablelist);
1751
1752   add_cmd ("tracepoints", class_trace, enable_trace_command, 
1753            "Enable specified tracepoints; or with no argument, enable all.", 
1754            &enablelist);
1755
1756   add_com ("trace", class_trace, trace_command,
1757            "Set a tracepoint at a specified line, function, or address.\n"
1758            "Argument may be a line number, function name, or "
1759            "'*' plus an address.\n"
1760            "For a line number or function, trace at the start of its code.\n"
1761            "If an address is specified, trace at that exact address.");
1762
1763   add_com_alias ("tp",   "trace", class_alias, 0);
1764   add_com_alias ("tr",   "trace", class_alias, 1);
1765   add_com_alias ("tra",  "trace", class_alias, 1);
1766   add_com_alias ("trac", "trace", class_alias, 1);
1767
1768
1769 #else /* command set based on TRACE as a prefix (incomplete) */
1770   add_cmd ("tracepoints", class_trace, NO_FUNCTION, 
1771            "Tracing program execution without stopping the program.", 
1772            &cmdlist);
1773
1774   add_prefix_cmd ("trace", class_trace, trace_command, 
1775                   "prefix for tracing commands", 
1776                   &tracelist, "trace ", 1, &cmdlist);
1777
1778   add_cmd ("limit", class_trace, trace_limit_command, 
1779            "Not sure what the hell this does....", &tracelist);
1780
1781   add_cmd ("buffer", class_trace, trace_buff_command, 
1782            "See also 'set trace buffer overflow'.", &tracelist);
1783
1784   add_prefix_cmd ("find", class_trace, trace_find_command, 
1785                   "Select a trace frame (default by frame number).", 
1786                   &tfindlist, "trace find ", 1, &tracelist);
1787
1788   add_cmd ("outside", class_trace, trace_find_outside_command, 
1789            "Select a tracepoint by falling outside of a PC range.", 
1790            &tfindlist);
1791
1792   add_cmd ("range", class_trace, trace_find_range_command, 
1793            "Select a tracepoint by PC range.", 
1794            &tfindlist);
1795
1796   add_cmd ("pc", class_trace, trace_find_pc_command, 
1797            "Select a tracepoint by PC.", 
1798            &tfindlist);
1799
1800   add_cmd ("display", class_trace, trace_display_command, 
1801            "Display the results of a trace.", &tracelist);
1802
1803   add_cmd ("delete", class_trace, delete_trace_command, 
1804            "Delete some tracepoints; no argument means all.", &tracelist);
1805
1806   add_cmd ("disable", class_trace, disable_trace_command, 
1807            "Disable some tracepoints; no argument means all.", &tracelist);
1808
1809   add_cmd ("enable", class_trace, enable_trace_command, 
1810            "Enable some tracepoints; no argument means all.", &tracelist);
1811
1812   add_cmd ("tracepoints", class_trace, delete_trace_command, 
1813            "Delete some tracepoints; no argument means all.",
1814            &deletelist);
1815
1816   add_cmd ("tracepoints", class_trace, disable_trace_command, 
1817            "Disable some tracepoints; no argument means all.",
1818            &disablelist);
1819
1820   add_cmd ("tracepoints", class_trace, enable_trace_command, 
1821            "Enable some tracepoints; no argument means all.", 
1822            &enablelist);
1823
1824   add_cmd ("at", class_trace, trace_command, 
1825            "Set a tracepoint at a specified line or function.\n"
1826            "Argument may be a line number, function name, or "
1827            "'*' and an address.\n"
1828            "For a line number or function, trace from the start of "
1829            "its code.\n"
1830            "If an address is specified, trace at that exact address.\n"
1831            "With no arg, uses current execution address of "
1832            "selected stack frame.\n"
1833            "This is useful for breaking on return to a stack frame.", 
1834            &tracelist);
1835
1836   add_cmd ("status", class_trace, trace_status_command, 
1837            "Inquire about trace data collection status.", &tracelist);
1838
1839   add_cmd ("stop", class_trace, trace_stop_command, 
1840            "Stop trace data collection.", &tracelist);
1841   
1842   add_cmd ("start", class_trace, trace_start_command, 
1843            "Start trace data collection.", &tracelist);
1844   
1845   add_cmd ("info", class_info, tracepoints_info,
1846            "Status of tracepoints, or tracepoint number NUMBER.\n"
1847            "The \"Address\" and \"What\" columns indicate the\n"
1848            "address and file/line number respectively.\n\n"
1849            "Convenience variable \"$tpnum\" contains the number of the\n"
1850            "last tracepoint set.", 
1851            &tracelist);
1852
1853   add_info ("tracepoints", tracepoints_info,
1854             "Status of tracepoints, or tracepoint number NUMBER.\n"
1855             "The \"Address\" and \"What\" columns indicate the\n"
1856             "address and file/line number respectively.\n\n"
1857             "Convenience variable \"$tpnum\" contains the number of the\n"
1858             "last tracepoint set.");
1859
1860   add_info_alias ("tp", "tracepoints", 1);
1861
1862 #endif
1863 }
1864