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