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