146283Sdfr/* Tracing functionality for remote targets in custom GDB protocol
246283Sdfr
3130803Smarcel   Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software
498944Sobrien   Foundation, Inc.
546283Sdfr
698944Sobrien   This file is part of GDB.
746283Sdfr
898944Sobrien   This program is free software; you can redistribute it and/or modify
998944Sobrien   it under the terms of the GNU General Public License as published by
1098944Sobrien   the Free Software Foundation; either version 2 of the License, or
1198944Sobrien   (at your option) any later version.
1246283Sdfr
1398944Sobrien   This program is distributed in the hope that it will be useful,
1498944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1598944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1698944Sobrien   GNU General Public License for more details.
1746283Sdfr
1898944Sobrien   You should have received a copy of the GNU General Public License
1998944Sobrien   along with this program; if not, write to the Free Software
2098944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2198944Sobrien   Boston, MA 02111-1307, USA.  */
2298944Sobrien
2346283Sdfr#include "defs.h"
2446283Sdfr#include "symtab.h"
2546283Sdfr#include "frame.h"
2646283Sdfr#include "gdbtypes.h"
2746283Sdfr#include "expression.h"
2846283Sdfr#include "gdbcmd.h"
2946283Sdfr#include "value.h"
3046283Sdfr#include "target.h"
3146283Sdfr#include "language.h"
3246283Sdfr#include "gdb_string.h"
3398944Sobrien#include "inferior.h"
3498944Sobrien#include "tracepoint.h"
3598944Sobrien#include "remote.h"
3698944Sobrien#include "linespec.h"
3798944Sobrien#include "regcache.h"
3898944Sobrien#include "completer.h"
3998944Sobrien#include "gdb-events.h"
40130803Smarcel#include "block.h"
41130803Smarcel#include "dictionary.h"
4246283Sdfr
4346283Sdfr#include "ax.h"
4446283Sdfr#include "ax-gdb.h"
4546283Sdfr
4646283Sdfr/* readline include files */
47130803Smarcel#include "readline/readline.h"
48130803Smarcel#include "readline/history.h"
4946283Sdfr
5046283Sdfr/* readline defines this.  */
5146283Sdfr#undef savestring
5246283Sdfr
5346283Sdfr#ifdef HAVE_UNISTD_H
5446283Sdfr#include <unistd.h>
5546283Sdfr#endif
5646283Sdfr
5746283Sdfr/* maximum length of an agent aexpression.
5846283Sdfr   this accounts for the fact that packets are limited to 400 bytes
5946283Sdfr   (which includes everything -- including the checksum), and assumes
6046283Sdfr   the worst case of maximum length for each of the pieces of a
6146283Sdfr   continuation packet.
6298944Sobrien
6346283Sdfr   NOTE: expressions get mem2hex'ed otherwise this would be twice as
6446283Sdfr   large.  (400 - 31)/2 == 184 */
6546283Sdfr#define MAX_AGENT_EXPR_LEN	184
6646283Sdfr
6746283Sdfr
6898944Sobrienextern void (*readline_begin_hook) (char *, ...);
6998944Sobrienextern char *(*readline_hook) (char *);
7098944Sobrienextern void (*readline_end_hook) (void);
7198944Sobrienextern void x_command (char *, int);
7298944Sobrienextern int addressprint;	/* Print machine addresses? */
7346283Sdfr
7498944Sobrien/* GDB commands implemented in other modules:
7598944Sobrien */
7698944Sobrien
7798944Sobrienextern void output_command (char *, int);
7898944Sobrien
7946283Sdfr/*
8046283Sdfr   Tracepoint.c:
8146283Sdfr
8246283Sdfr   This module defines the following debugger commands:
8346283Sdfr   trace            : set a tracepoint on a function, line, or address.
8446283Sdfr   info trace       : list all debugger-defined tracepoints.
8546283Sdfr   delete trace     : delete one or more tracepoints.
8646283Sdfr   enable trace     : enable one or more tracepoints.
8746283Sdfr   disable trace    : disable one or more tracepoints.
8846283Sdfr   actions          : specify actions to be taken at a tracepoint.
8946283Sdfr   passcount        : specify a pass count for a tracepoint.
9046283Sdfr   tstart           : start a trace experiment.
9146283Sdfr   tstop            : stop a trace experiment.
9246283Sdfr   tstatus          : query the status of a trace experiment.
9346283Sdfr   tfind            : find a trace frame in the trace buffer.
9446283Sdfr   tdump            : print everything collected at the current tracepoint.
9546283Sdfr   save-tracepoints : write tracepoint setup into a file.
9646283Sdfr
9746283Sdfr   This module defines the following user-visible debugger variables:
9846283Sdfr   $trace_frame : sequence number of trace frame currently being debugged.
9946283Sdfr   $trace_line  : source line of trace frame currently being debugged.
10046283Sdfr   $trace_file  : source file of trace frame currently being debugged.
10146283Sdfr   $tracepoint  : tracepoint number of trace frame currently being debugged.
10298944Sobrien */
10346283Sdfr
10446283Sdfr
10546283Sdfr/* ======= Important global variables: ======= */
10646283Sdfr
10746283Sdfr/* Chain of all tracepoints defined.  */
10846283Sdfrstruct tracepoint *tracepoint_chain;
10946283Sdfr
11046283Sdfr/* Number of last tracepoint made.  */
11146283Sdfrstatic int tracepoint_count;
11246283Sdfr
11346283Sdfr/* Number of last traceframe collected.  */
11446283Sdfrstatic int traceframe_number;
11546283Sdfr
11646283Sdfr/* Tracepoint for last traceframe collected.  */
11746283Sdfrstatic int tracepoint_number;
11846283Sdfr
11946283Sdfr/* Symbol for function for last traceframe collected */
12046283Sdfrstatic struct symbol *traceframe_fun;
12146283Sdfr
12246283Sdfr/* Symtab and line for last traceframe collected */
12346283Sdfrstatic struct symtab_and_line traceframe_sal;
12446283Sdfr
12546283Sdfr/* Tracing command lists */
12646283Sdfrstatic struct cmd_list_element *tfindlist;
12746283Sdfr
12846283Sdfr/* ======= Important command functions: ======= */
12998944Sobrienstatic void trace_command (char *, int);
13098944Sobrienstatic void tracepoints_info (char *, int);
13198944Sobrienstatic void delete_trace_command (char *, int);
13298944Sobrienstatic void enable_trace_command (char *, int);
13398944Sobrienstatic void disable_trace_command (char *, int);
13498944Sobrienstatic void trace_pass_command (char *, int);
13598944Sobrienstatic void trace_actions_command (char *, int);
13698944Sobrienstatic void trace_start_command (char *, int);
13798944Sobrienstatic void trace_stop_command (char *, int);
13898944Sobrienstatic void trace_status_command (char *, int);
13998944Sobrienstatic void trace_find_command (char *, int);
14098944Sobrienstatic void trace_find_pc_command (char *, int);
14198944Sobrienstatic void trace_find_tracepoint_command (char *, int);
14298944Sobrienstatic void trace_find_line_command (char *, int);
14398944Sobrienstatic void trace_find_range_command (char *, int);
14498944Sobrienstatic void trace_find_outside_command (char *, int);
14598944Sobrienstatic void tracepoint_save_command (char *, int);
14698944Sobrienstatic void trace_dump_command (char *, int);
14746283Sdfr
14846283Sdfr/* support routines */
14998944Sobrienstatic void trace_mention (struct tracepoint *);
15046283Sdfr
15146283Sdfrstruct collection_list;
15298944Sobrienstatic void add_aexpr (struct collection_list *, struct agent_expr *);
15398944Sobrienstatic unsigned char *mem2hex (unsigned char *, unsigned char *, int);
15498944Sobrienstatic void add_register (struct collection_list *collection,
15598944Sobrien			  unsigned int regno);
15698944Sobrienstatic struct cleanup *make_cleanup_free_actions (struct tracepoint *t);
15798944Sobrienstatic void free_actions_list (char **actions_list);
15898944Sobrienstatic void free_actions_list_cleanup_wrapper (void *);
15946283Sdfr
16098944Sobrienextern void _initialize_tracepoint (void);
16198944Sobrien
16246283Sdfr/* Utility: returns true if "target remote" */
16346283Sdfrstatic int
16498944Sobrientarget_is_remote (void)
16546283Sdfr{
16646283Sdfr  if (current_target.to_shortname &&
16746283Sdfr      strcmp (current_target.to_shortname, "remote") == 0)
16846283Sdfr    return 1;
16946283Sdfr  else
17046283Sdfr    return 0;
17146283Sdfr}
17246283Sdfr
17346283Sdfr/* Utility: generate error from an incoming stub packet.  */
17498944Sobrienstatic void
17598944Sobrientrace_error (char *buf)
17646283Sdfr{
17746283Sdfr  if (*buf++ != 'E')
17846283Sdfr    return;			/* not an error msg */
17998944Sobrien  switch (*buf)
18046283Sdfr    {
18146283Sdfr    case '1':			/* malformed packet error */
18246283Sdfr      if (*++buf == '0')	/*   general case: */
18346283Sdfr	error ("tracepoint.c: error in outgoing packet.");
18446283Sdfr      else
185130803Smarcel	error ("tracepoint.c: error in outgoing packet at field #%ld.",
18646283Sdfr	       strtol (buf, NULL, 16));
18746283Sdfr    case '2':
18846283Sdfr      error ("trace API error 0x%s.", ++buf);
18946283Sdfr    default:
19046283Sdfr      error ("Target returns error code '%s'.", buf);
19146283Sdfr    }
19246283Sdfr}
19346283Sdfr
19446283Sdfr/* Utility: wait for reply from stub, while accepting "O" packets */
19546283Sdfrstatic char *
19698944Sobrienremote_get_noisy_reply (char *buf,
19798944Sobrien			long sizeof_buf)
19846283Sdfr{
19998944Sobrien  do				/* loop on reply from remote stub */
20046283Sdfr    {
20198944Sobrien      QUIT;			/* allow user to bail out with ^C */
20298944Sobrien      getpkt (buf, sizeof_buf, 0);
20346283Sdfr      if (buf[0] == 0)
20446283Sdfr	error ("Target does not support this command.");
20546283Sdfr      else if (buf[0] == 'E')
20646283Sdfr	trace_error (buf);
20746283Sdfr      else if (buf[0] == 'O' &&
20846283Sdfr	       buf[1] != 'K')
20946283Sdfr	remote_console_output (buf + 1);	/* 'O' message from stub */
21046283Sdfr      else
21198944Sobrien	return buf;		/* here's the actual reply */
21298944Sobrien    }
21398944Sobrien  while (1);
21446283Sdfr}
21546283Sdfr
21646283Sdfr/* Set tracepoint count to NUM.  */
21746283Sdfrstatic void
21898944Sobrienset_tracepoint_count (int num)
21946283Sdfr{
22046283Sdfr  tracepoint_count = num;
22146283Sdfr  set_internalvar (lookup_internalvar ("tpnum"),
22246283Sdfr		   value_from_longest (builtin_type_int, (LONGEST) num));
22346283Sdfr}
22446283Sdfr
22546283Sdfr/* Set traceframe number to NUM.  */
22646283Sdfrstatic void
22798944Sobrienset_traceframe_num (int num)
22846283Sdfr{
22946283Sdfr  traceframe_number = num;
23046283Sdfr  set_internalvar (lookup_internalvar ("trace_frame"),
23146283Sdfr		   value_from_longest (builtin_type_int, (LONGEST) num));
23246283Sdfr}
23346283Sdfr
23446283Sdfr/* Set tracepoint number to NUM.  */
23546283Sdfrstatic void
23698944Sobrienset_tracepoint_num (int num)
23746283Sdfr{
23846283Sdfr  tracepoint_number = num;
23946283Sdfr  set_internalvar (lookup_internalvar ("tracepoint"),
24046283Sdfr		   value_from_longest (builtin_type_int, (LONGEST) num));
24146283Sdfr}
24246283Sdfr
24346283Sdfr/* Set externally visible debug variables for querying/printing
24446283Sdfr   the traceframe context (line, function, file) */
24546283Sdfr
24646283Sdfrstatic void
24798944Sobrienset_traceframe_context (CORE_ADDR trace_pc)
24846283Sdfr{
24946283Sdfr  static struct type *func_string, *file_string;
25098944Sobrien  static struct type *func_range, *file_range;
25198944Sobrien  struct value *func_val;
25298944Sobrien  struct value *file_val;
25346283Sdfr  static struct type *charstar;
25446283Sdfr  int len;
25546283Sdfr
25646283Sdfr  if (charstar == (struct type *) NULL)
25746283Sdfr    charstar = lookup_pointer_type (builtin_type_char);
25846283Sdfr
25998944Sobrien  if (trace_pc == -1)		/* cease debugging any trace buffers */
26046283Sdfr    {
26146283Sdfr      traceframe_fun = 0;
26246283Sdfr      traceframe_sal.pc = traceframe_sal.line = 0;
26346283Sdfr      traceframe_sal.symtab = NULL;
26498944Sobrien      set_internalvar (lookup_internalvar ("trace_func"),
26598944Sobrien		       value_from_pointer (charstar, (LONGEST) 0));
26698944Sobrien      set_internalvar (lookup_internalvar ("trace_file"),
26798944Sobrien		       value_from_pointer (charstar, (LONGEST) 0));
26846283Sdfr      set_internalvar (lookup_internalvar ("trace_line"),
269130803Smarcel		       value_from_longest (builtin_type_int, (LONGEST) - 1));
27046283Sdfr      return;
27146283Sdfr    }
27246283Sdfr
27346283Sdfr  /* save as globals for internal use */
27446283Sdfr  traceframe_sal = find_pc_line (trace_pc, 0);
27546283Sdfr  traceframe_fun = find_pc_function (trace_pc);
27646283Sdfr
27746283Sdfr  /* save linenumber as "$trace_line", a debugger variable visible to users */
27846283Sdfr  set_internalvar (lookup_internalvar ("trace_line"),
27998944Sobrien		   value_from_longest (builtin_type_int,
28046283Sdfr				       (LONGEST) traceframe_sal.line));
28146283Sdfr
28246283Sdfr  /* save func name as "$trace_func", a debugger variable visible to users */
28398944Sobrien  if (traceframe_fun == NULL ||
284130803Smarcel      DEPRECATED_SYMBOL_NAME (traceframe_fun) == NULL)
28598944Sobrien    set_internalvar (lookup_internalvar ("trace_func"),
28698944Sobrien		     value_from_pointer (charstar, (LONGEST) 0));
28746283Sdfr  else
28846283Sdfr    {
289130803Smarcel      len = strlen (DEPRECATED_SYMBOL_NAME (traceframe_fun));
29098944Sobrien      func_range = create_range_type (func_range,
29198944Sobrien				      builtin_type_int, 0, len - 1);
29298944Sobrien      func_string = create_array_type (func_string,
29346283Sdfr				       builtin_type_char, func_range);
29446283Sdfr      func_val = allocate_value (func_string);
29546283Sdfr      VALUE_TYPE (func_val) = func_string;
29698944Sobrien      memcpy (VALUE_CONTENTS_RAW (func_val),
297130803Smarcel	      DEPRECATED_SYMBOL_NAME (traceframe_fun),
29846283Sdfr	      len);
29946283Sdfr      func_val->modifiable = 0;
30046283Sdfr      set_internalvar (lookup_internalvar ("trace_func"), func_val);
30146283Sdfr    }
30246283Sdfr
30346283Sdfr  /* save file name as "$trace_file", a debugger variable visible to users */
30498944Sobrien  if (traceframe_sal.symtab == NULL ||
30546283Sdfr      traceframe_sal.symtab->filename == NULL)
30698944Sobrien    set_internalvar (lookup_internalvar ("trace_file"),
30798944Sobrien		     value_from_pointer (charstar, (LONGEST) 0));
30846283Sdfr  else
30946283Sdfr    {
31046283Sdfr      len = strlen (traceframe_sal.symtab->filename);
31198944Sobrien      file_range = create_range_type (file_range,
31298944Sobrien				      builtin_type_int, 0, len - 1);
31398944Sobrien      file_string = create_array_type (file_string,
31446283Sdfr				       builtin_type_char, file_range);
31546283Sdfr      file_val = allocate_value (file_string);
31646283Sdfr      VALUE_TYPE (file_val) = file_string;
31798944Sobrien      memcpy (VALUE_CONTENTS_RAW (file_val),
31898944Sobrien	      traceframe_sal.symtab->filename,
31946283Sdfr	      len);
32046283Sdfr      file_val->modifiable = 0;
32146283Sdfr      set_internalvar (lookup_internalvar ("trace_file"), file_val);
32246283Sdfr    }
32346283Sdfr}
32446283Sdfr
32546283Sdfr/* Low level routine to set a tracepoint.
32646283Sdfr   Returns the tracepoint object so caller can set other things.
32746283Sdfr   Does not set the tracepoint number!
32846283Sdfr   Does not print anything.
32946283Sdfr
33046283Sdfr   ==> This routine should not be called if there is a chance of later
33146283Sdfr   error(); otherwise it leaves a bogus tracepoint on the chain.  Validate
33246283Sdfr   your arguments BEFORE calling this routine!  */
33346283Sdfr
33446283Sdfrstatic struct tracepoint *
33598944Sobrienset_raw_tracepoint (struct symtab_and_line sal)
33646283Sdfr{
337130803Smarcel  struct tracepoint *t, *tc;
33846283Sdfr  struct cleanup *old_chain;
33946283Sdfr
34046283Sdfr  t = (struct tracepoint *) xmalloc (sizeof (struct tracepoint));
34198944Sobrien  old_chain = make_cleanup (xfree, t);
34246283Sdfr  memset (t, 0, sizeof (*t));
34346283Sdfr  t->address = sal.pc;
34446283Sdfr  if (sal.symtab == NULL)
34546283Sdfr    t->source_file = NULL;
34646283Sdfr  else
34798944Sobrien    t->source_file = savestring (sal.symtab->filename,
34846283Sdfr				 strlen (sal.symtab->filename));
34946283Sdfr
35098944Sobrien  t->section = sal.section;
35198944Sobrien  t->language = current_language->la_language;
35246283Sdfr  t->input_radix = input_radix;
35346283Sdfr  t->line_number = sal.line;
35498944Sobrien  t->enabled_p = 1;
35598944Sobrien  t->next = 0;
35698944Sobrien  t->step_count = 0;
35798944Sobrien  t->pass_count = 0;
35846283Sdfr  t->addr_string = NULL;
35946283Sdfr
36046283Sdfr  /* Add this tracepoint to the end of the chain
36146283Sdfr     so that a list of tracepoints will come out in order
36246283Sdfr     of increasing numbers.  */
36346283Sdfr
36446283Sdfr  tc = tracepoint_chain;
36546283Sdfr  if (tc == 0)
36646283Sdfr    tracepoint_chain = t;
36746283Sdfr  else
36846283Sdfr    {
36946283Sdfr      while (tc->next)
37046283Sdfr	tc = tc->next;
37146283Sdfr      tc->next = t;
37246283Sdfr    }
37346283Sdfr  discard_cleanups (old_chain);
37446283Sdfr  return t;
37546283Sdfr}
37646283Sdfr
37746283Sdfr/* Set a tracepoint according to ARG (function, linenum or *address) */
37846283Sdfrstatic void
37998944Sobrientrace_command (char *arg, int from_tty)
38046283Sdfr{
38198944Sobrien  char **canonical = (char **) NULL;
38246283Sdfr  struct symtabs_and_lines sals;
38346283Sdfr  struct symtab_and_line sal;
38446283Sdfr  struct tracepoint *t;
38546283Sdfr  char *addr_start = 0, *addr_end = 0;
38646283Sdfr  int i;
38746283Sdfr
38846283Sdfr  if (!arg || !*arg)
38946283Sdfr    error ("trace command requires an argument");
39046283Sdfr
39146283Sdfr  if (from_tty && info_verbose)
39246283Sdfr    printf_filtered ("TRACE %s\n", arg);
39346283Sdfr
39446283Sdfr  addr_start = arg;
395130803Smarcel  sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, &canonical, NULL);
39698944Sobrien  addr_end = arg;
39798944Sobrien  if (!sals.nelts)
39898944Sobrien    return;			/* ??? Presumably decode_line_1 has already warned? */
39946283Sdfr
40046283Sdfr  /* Resolve all line numbers to PC's */
40146283Sdfr  for (i = 0; i < sals.nelts; i++)
40246283Sdfr    resolve_sal_pc (&sals.sals[i]);
40346283Sdfr
40446283Sdfr  /* Now set all the tracepoints.  */
40546283Sdfr  for (i = 0; i < sals.nelts; i++)
40646283Sdfr    {
40746283Sdfr      sal = sals.sals[i];
40846283Sdfr
40946283Sdfr      t = set_raw_tracepoint (sal);
41046283Sdfr      set_tracepoint_count (tracepoint_count + 1);
41146283Sdfr      t->number = tracepoint_count;
41246283Sdfr
41346283Sdfr      /* If a canonical line spec is needed use that instead of the
41498944Sobrien         command string.  */
41598944Sobrien      if (canonical != (char **) NULL && canonical[i] != NULL)
41646283Sdfr	t->addr_string = canonical[i];
41746283Sdfr      else if (addr_start)
41846283Sdfr	t->addr_string = savestring (addr_start, addr_end - addr_start);
41946283Sdfr
42046283Sdfr      trace_mention (t);
42146283Sdfr    }
42246283Sdfr
42346283Sdfr  if (sals.nelts > 1)
42446283Sdfr    {
42546283Sdfr      printf_filtered ("Multiple tracepoints were set.\n");
42646283Sdfr      printf_filtered ("Use 'delete trace' to delete unwanted tracepoints.\n");
42746283Sdfr    }
42846283Sdfr}
42946283Sdfr
43046283Sdfr/* Tell the user we have just set a tracepoint TP. */
43146283Sdfr
43246283Sdfrstatic void
43398944Sobrientrace_mention (struct tracepoint *tp)
43446283Sdfr{
43546283Sdfr  printf_filtered ("Tracepoint %d", tp->number);
43646283Sdfr
43746283Sdfr  if (addressprint || (tp->source_file == NULL))
43846283Sdfr    {
43946283Sdfr      printf_filtered (" at ");
44046283Sdfr      print_address_numeric (tp->address, 1, gdb_stdout);
44146283Sdfr    }
44246283Sdfr  if (tp->source_file)
44346283Sdfr    printf_filtered (": file %s, line %d.",
44446283Sdfr		     tp->source_file, tp->line_number);
44546283Sdfr
44646283Sdfr  printf_filtered ("\n");
44746283Sdfr}
44846283Sdfr
44946283Sdfr/* Print information on tracepoint number TPNUM_EXP, or all if omitted.  */
45046283Sdfr
45146283Sdfrstatic void
45298944Sobrientracepoints_info (char *tpnum_exp, int from_tty)
45346283Sdfr{
45446283Sdfr  struct tracepoint *t;
45546283Sdfr  struct action_line *action;
45646283Sdfr  int found_a_tracepoint = 0;
45746283Sdfr  char wrap_indent[80];
45846283Sdfr  struct symbol *sym;
45946283Sdfr  int tpnum = -1;
46046283Sdfr
46146283Sdfr  if (tpnum_exp)
46298944Sobrien    tpnum = parse_and_eval_long (tpnum_exp);
46346283Sdfr
46446283Sdfr  ALL_TRACEPOINTS (t)
46546283Sdfr    if (tpnum == -1 || tpnum == t->number)
46698944Sobrien    {
46798944Sobrien      extern int addressprint;	/* print machine addresses? */
46846283Sdfr
46998944Sobrien      if (!found_a_tracepoint++)
47098944Sobrien	{
47198944Sobrien	  printf_filtered ("Num Enb ");
47298944Sobrien	  if (addressprint)
47398944Sobrien	    {
47498944Sobrien	      if (TARGET_ADDR_BIT <= 32)
47598944Sobrien		printf_filtered ("Address    ");
47698944Sobrien	      else
47798944Sobrien		printf_filtered ("Address            ");
47898944Sobrien	    }
47998944Sobrien	  printf_filtered ("PassC StepC What\n");
48098944Sobrien	}
48198944Sobrien      strcpy (wrap_indent, "                           ");
48298944Sobrien      if (addressprint)
48398944Sobrien	{
48498944Sobrien	  if (TARGET_ADDR_BIT <= 32)
48598944Sobrien	    strcat (wrap_indent, "           ");
48698944Sobrien	  else
48798944Sobrien	    strcat (wrap_indent, "                   ");
48898944Sobrien	}
48946283Sdfr
49098944Sobrien      printf_filtered ("%-3d %-3s ", t->number,
49198944Sobrien		       t->enabled_p ? "y" : "n");
49298944Sobrien      if (addressprint)
49398944Sobrien	{
49498944Sobrien	  char *tmp;
49546283Sdfr
49698944Sobrien	  if (TARGET_ADDR_BIT <= 32)
497130803Smarcel	    tmp = local_hex_string_custom (t->address
498130803Smarcel					   & (CORE_ADDR) 0xffffffff,
499130803Smarcel					   "08l");
50098944Sobrien	  else
501130803Smarcel	    tmp = local_hex_string_custom (t->address, "016l");
50246283Sdfr
50398944Sobrien	  printf_filtered ("%s ", tmp);
50498944Sobrien	}
50598944Sobrien      printf_filtered ("%-5d %-5ld ", t->pass_count, t->step_count);
50698944Sobrien
50798944Sobrien      if (t->source_file)
50898944Sobrien	{
50998944Sobrien	  sym = find_pc_sect_function (t->address, t->section);
51098944Sobrien	  if (sym)
51198944Sobrien	    {
51298944Sobrien	      fputs_filtered ("in ", gdb_stdout);
513130803Smarcel	      fputs_filtered (SYMBOL_PRINT_NAME (sym), gdb_stdout);
51498944Sobrien	      wrap_here (wrap_indent);
51598944Sobrien	      fputs_filtered (" at ", gdb_stdout);
51698944Sobrien	    }
51798944Sobrien	  fputs_filtered (t->source_file, gdb_stdout);
51898944Sobrien	  printf_filtered (":%d", t->line_number);
51998944Sobrien	}
52098944Sobrien      else
52198944Sobrien	print_address_symbolic (t->address, gdb_stdout, demangle, " ");
52298944Sobrien
52398944Sobrien      printf_filtered ("\n");
52498944Sobrien      if (t->actions)
52598944Sobrien	{
52698944Sobrien	  printf_filtered ("  Actions for tracepoint %d: \n", t->number);
52798944Sobrien	  for (action = t->actions; action; action = action->next)
52898944Sobrien	    {
52998944Sobrien	      printf_filtered ("\t%s\n", action->action);
53098944Sobrien	    }
53198944Sobrien	}
53298944Sobrien    }
53346283Sdfr  if (!found_a_tracepoint)
53446283Sdfr    {
53546283Sdfr      if (tpnum == -1)
53698944Sobrien	printf_filtered ("No tracepoints.\n");
53746283Sdfr      else
53898944Sobrien	printf_filtered ("No tracepoint number %d.\n", tpnum);
53946283Sdfr    }
54046283Sdfr}
54146283Sdfr
54246283Sdfr/* Optimization: the code to parse an enable, disable, or delete TP command
54346283Sdfr   is virtually identical except for whether it performs an enable, disable,
54446283Sdfr   or delete.  Therefore I've combined them into one function with an opcode.
54598944Sobrien */
54698944Sobrienenum tracepoint_opcode
54746283Sdfr{
54898944Sobrien  enable_op,
54998944Sobrien  disable_op,
55098944Sobrien  delete_op
55146283Sdfr};
55246283Sdfr
55398944Sobrien/* This function implements enable, disable and delete commands. */
55446283Sdfrstatic void
55598944Sobrientracepoint_operation (struct tracepoint *t, int from_tty,
55698944Sobrien		      enum tracepoint_opcode opcode)
55746283Sdfr{
55846283Sdfr  struct tracepoint *t2;
55946283Sdfr
56098944Sobrien  if (t == NULL)	/* no tracepoint operand */
56198944Sobrien    return;
56246283Sdfr
56398944Sobrien  switch (opcode)
56498944Sobrien    {
56598944Sobrien    case enable_op:
56698944Sobrien      t->enabled_p = 1;
56798944Sobrien      tracepoint_modify_event (t->number);
56898944Sobrien      break;
56998944Sobrien    case disable_op:
57098944Sobrien      t->enabled_p = 0;
57198944Sobrien      tracepoint_modify_event (t->number);
57298944Sobrien      break;
57398944Sobrien    case delete_op:
57498944Sobrien      if (tracepoint_chain == t)
57598944Sobrien	tracepoint_chain = t->next;
57698944Sobrien
57798944Sobrien      ALL_TRACEPOINTS (t2)
57898944Sobrien	if (t2->next == t)
57946283Sdfr	{
58098944Sobrien	  tracepoint_delete_event (t2->number);
58146283Sdfr	  t2->next = t->next;
58246283Sdfr	  break;
58346283Sdfr	}
58446283Sdfr
58598944Sobrien      if (t->addr_string)
58698944Sobrien	xfree (t->addr_string);
58798944Sobrien      if (t->source_file)
58898944Sobrien	xfree (t->source_file);
58998944Sobrien      if (t->actions)
59098944Sobrien	free_actions (t);
59146283Sdfr
59298944Sobrien      xfree (t);
59398944Sobrien      break;
59498944Sobrien    }
59546283Sdfr}
59646283Sdfr
59798944Sobrien/* Utility: parse a tracepoint number and look it up in the list.
59898944Sobrien   If MULTI_P is true, there might be a range of tracepoints in ARG.
59998944Sobrien   if OPTIONAL_P is true, then if the argument is missing, the most
60098944Sobrien   recent tracepoint (tracepoint_count) is returned.  */
60146283Sdfrstruct tracepoint *
60298944Sobrienget_tracepoint_by_number (char **arg, int multi_p, int optional_p)
60346283Sdfr{
60446283Sdfr  struct tracepoint *t;
60546283Sdfr  int tpnum;
60698944Sobrien  char *instring = arg == NULL ? NULL : *arg;
60746283Sdfr
60898944Sobrien  if (arg == NULL || *arg == NULL || ! **arg)
60946283Sdfr    {
61098944Sobrien      if (optional_p)
61198944Sobrien	tpnum = tracepoint_count;
61298944Sobrien      else
61398944Sobrien	error_no_arg ("tracepoint number");
61498944Sobrien    }
61598944Sobrien  else
61698944Sobrien    tpnum = multi_p ? get_number_or_range (arg) : get_number (arg);
61746283Sdfr
61898944Sobrien  if (tpnum <= 0)
61946283Sdfr    {
62098944Sobrien      if (instring && *instring)
62198944Sobrien	printf_filtered ("bad tracepoint number at or near '%s'\n", instring);
62298944Sobrien      else
62398944Sobrien	printf_filtered ("Tracepoint argument missing and no previous tracepoint\n");
62498944Sobrien      return NULL;
62546283Sdfr    }
62698944Sobrien
62746283Sdfr  ALL_TRACEPOINTS (t)
62846283Sdfr    if (t->number == tpnum)
62998944Sobrien    {
63098944Sobrien      return t;
63198944Sobrien    }
63298944Sobrien
63398944Sobrien  /* FIXME: if we are in the middle of a range we don't want to give
63498944Sobrien     a message.  The current interface to get_number_or_range doesn't
63598944Sobrien     allow us to discover this.  */
63646283Sdfr  printf_unfiltered ("No tracepoint number %d.\n", tpnum);
63746283Sdfr  return NULL;
63846283Sdfr}
63946283Sdfr
64046283Sdfr/* Utility: parse a list of tracepoint numbers, and call a func for each. */
64146283Sdfrstatic void
64298944Sobrienmap_args_over_tracepoints (char *args, int from_tty,
64398944Sobrien			   enum tracepoint_opcode opcode)
64446283Sdfr{
64546283Sdfr  struct tracepoint *t, *tmp;
64646283Sdfr
64746283Sdfr  if (args == 0 || *args == 0)	/* do them all */
64846283Sdfr    ALL_TRACEPOINTS_SAFE (t, tmp)
64946283Sdfr      tracepoint_operation (t, from_tty, opcode);
65046283Sdfr  else
65146283Sdfr    while (*args)
65246283Sdfr      {
65398944Sobrien	QUIT;			/* give user option to bail out with ^C */
65498944Sobrien	t = get_tracepoint_by_number (&args, 1, 0);
65598944Sobrien	tracepoint_operation (t, from_tty, opcode);
65646283Sdfr	while (*args == ' ' || *args == '\t')
65746283Sdfr	  args++;
65846283Sdfr      }
65946283Sdfr}
66046283Sdfr
66146283Sdfr/* The 'enable trace' command enables tracepoints.  Not supported by all targets.  */
66246283Sdfrstatic void
66398944Sobrienenable_trace_command (char *args, int from_tty)
66446283Sdfr{
66546283Sdfr  dont_repeat ();
66698944Sobrien  map_args_over_tracepoints (args, from_tty, enable_op);
66746283Sdfr}
66846283Sdfr
66946283Sdfr/* The 'disable trace' command enables tracepoints.  Not supported by all targets.  */
67046283Sdfrstatic void
67198944Sobriendisable_trace_command (char *args, int from_tty)
67246283Sdfr{
67346283Sdfr  dont_repeat ();
67498944Sobrien  map_args_over_tracepoints (args, from_tty, disable_op);
67546283Sdfr}
67646283Sdfr
67746283Sdfr/* Remove a tracepoint (or all if no argument) */
67846283Sdfrstatic void
67998944Sobriendelete_trace_command (char *args, int from_tty)
68046283Sdfr{
68146283Sdfr  dont_repeat ();
68246283Sdfr  if (!args || !*args)		/* No args implies all tracepoints; */
68346283Sdfr    if (from_tty)		/* confirm only if from_tty... */
68498944Sobrien      if (tracepoint_chain)	/* and if there are tracepoints to delete! */
68546283Sdfr	if (!query ("Delete all tracepoints? "))
68646283Sdfr	  return;
68746283Sdfr
68898944Sobrien  map_args_over_tracepoints (args, from_tty, delete_op);
68946283Sdfr}
69046283Sdfr
69146283Sdfr/* Set passcount for tracepoint.
69246283Sdfr
69346283Sdfr   First command argument is passcount, second is tracepoint number.
69446283Sdfr   If tracepoint number omitted, apply to most recently defined.
69546283Sdfr   Also accepts special argument "all".  */
69646283Sdfr
69746283Sdfrstatic void
69898944Sobrientrace_pass_command (char *args, int from_tty)
69946283Sdfr{
70046283Sdfr  struct tracepoint *t1 = (struct tracepoint *) -1, *t2;
70198944Sobrien  unsigned int count;
70298944Sobrien  int all = 0;
70346283Sdfr
70446283Sdfr  if (args == 0 || *args == 0)
70598944Sobrien    error ("passcount command requires an argument (count + optional TP num)");
70646283Sdfr
70746283Sdfr  count = strtoul (args, &args, 10);	/* count comes first, then TP num */
70846283Sdfr
70998944Sobrien  while (*args && isspace ((int) *args))
71046283Sdfr    args++;
71146283Sdfr
71246283Sdfr  if (*args && strncasecmp (args, "all", 3) == 0)
71398944Sobrien    {
71498944Sobrien      args += 3;			/* skip special argument "all" */
71598944Sobrien      all = 1;
71698944Sobrien      if (*args)
71798944Sobrien	error ("Junk at end of arguments.");
71898944Sobrien    }
71946283Sdfr  else
72098944Sobrien    t1 = get_tracepoint_by_number (&args, 1, 1);
72146283Sdfr
72298944Sobrien  do
72398944Sobrien    {
72498944Sobrien      if (t1)
72598944Sobrien	{
72698944Sobrien	  ALL_TRACEPOINTS (t2)
72798944Sobrien	    if (t1 == (struct tracepoint *) -1 || t1 == t2)
72898944Sobrien	      {
72998944Sobrien		t2->pass_count = count;
73098944Sobrien		tracepoint_modify_event (t2->number);
73198944Sobrien		if (from_tty)
73298944Sobrien		  printf_filtered ("Setting tracepoint %d's passcount to %d\n",
73398944Sobrien				   t2->number, count);
73498944Sobrien	      }
73598944Sobrien	  if (! all && *args)
73698944Sobrien	    t1 = get_tracepoint_by_number (&args, 1, 0);
73798944Sobrien	}
73898944Sobrien    }
73998944Sobrien  while (*args);
74046283Sdfr}
74146283Sdfr
74246283Sdfr/* ACTIONS functions: */
74346283Sdfr
74446283Sdfr/* Prototypes for action-parsing utility commands  */
74598944Sobrienstatic void read_actions (struct tracepoint *);
74646283Sdfr
74746283Sdfr/* The three functions:
74898944Sobrien   collect_pseudocommand,
74998944Sobrien   while_stepping_pseudocommand, and
75098944Sobrien   end_actions_pseudocommand
75146283Sdfr   are placeholders for "commands" that are actually ONLY to be used
75246283Sdfr   within a tracepoint action list.  If the actual function is ever called,
75346283Sdfr   it means that somebody issued the "command" at the top level,
75446283Sdfr   which is always an error.  */
75546283Sdfr
75698944Sobrienstatic void
75798944Sobrienend_actions_pseudocommand (char *args, int from_tty)
75846283Sdfr{
75946283Sdfr  error ("This command cannot be used at the top level.");
76046283Sdfr}
76146283Sdfr
76246283Sdfrstatic void
76398944Sobrienwhile_stepping_pseudocommand (char *args, int from_tty)
76446283Sdfr{
76546283Sdfr  error ("This command can only be used in a tracepoint actions list.");
76646283Sdfr}
76746283Sdfr
76846283Sdfrstatic void
76998944Sobriencollect_pseudocommand (char *args, int from_tty)
77046283Sdfr{
77146283Sdfr  error ("This command can only be used in a tracepoint actions list.");
77246283Sdfr}
77346283Sdfr
77446283Sdfr/* Enter a list of actions for a tracepoint.  */
77546283Sdfrstatic void
77698944Sobrientrace_actions_command (char *args, int from_tty)
77746283Sdfr{
77846283Sdfr  struct tracepoint *t;
77946283Sdfr  char tmpbuf[128];
78046283Sdfr  char *end_msg = "End with a line saying just \"end\".";
78146283Sdfr
78298944Sobrien  t = get_tracepoint_by_number (&args, 0, 1);
78398944Sobrien  if (t)
78446283Sdfr    {
78546283Sdfr      sprintf (tmpbuf, "Enter actions for tracepoint %d, one per line.",
78646283Sdfr	       t->number);
78746283Sdfr
78846283Sdfr      if (from_tty)
78946283Sdfr	{
79046283Sdfr	  if (readline_begin_hook)
79146283Sdfr	    (*readline_begin_hook) ("%s  %s\n", tmpbuf, end_msg);
79246283Sdfr	  else if (input_from_terminal_p ())
79346283Sdfr	    printf_filtered ("%s\n%s\n", tmpbuf, end_msg);
79446283Sdfr	}
79546283Sdfr
79646283Sdfr      free_actions (t);
79746283Sdfr      t->step_count = 0;	/* read_actions may set this */
79846283Sdfr      read_actions (t);
79946283Sdfr
80046283Sdfr      if (readline_end_hook)
80146283Sdfr	(*readline_end_hook) ();
80246283Sdfr      /* tracepoints_changed () */
80346283Sdfr    }
80498944Sobrien  /* else just return */
80546283Sdfr}
80646283Sdfr
80746283Sdfr/* worker function */
80846283Sdfrstatic void
80998944Sobrienread_actions (struct tracepoint *t)
81046283Sdfr{
81146283Sdfr  char *line;
81246283Sdfr  char *prompt1 = "> ", *prompt2 = "  > ";
81346283Sdfr  char *prompt = prompt1;
81446283Sdfr  enum actionline_type linetype;
81546283Sdfr  extern FILE *instream;
81646283Sdfr  struct action_line *next = NULL, *temp;
81746283Sdfr  struct cleanup *old_chain;
81846283Sdfr
81946283Sdfr  /* Control-C quits instantly if typed while in this loop
82046283Sdfr     since it should not wait until the user types a newline.  */
82146283Sdfr  immediate_quit++;
82298944Sobrien  /* FIXME: kettenis/20010823: Something is wrong here.  In this file
82398944Sobrien     STOP_SIGNAL is never defined.  So this code has been left out, at
82498944Sobrien     least for quite a while now.  Replacing STOP_SIGNAL with SIGTSTP
82598944Sobrien     leads to compilation failures since the variable job_control
82698944Sobrien     isn't declared.  Leave this alone for now.  */
82746283Sdfr#ifdef STOP_SIGNAL
82846283Sdfr  if (job_control)
82998944Sobrien    {
83098944Sobrien      if (event_loop_p)
83198944Sobrien	signal (STOP_SIGNAL, handle_stop_sig);
83298944Sobrien      else
83398944Sobrien	signal (STOP_SIGNAL, stop_sig);
83498944Sobrien    }
83546283Sdfr#endif
83698944Sobrien  old_chain = make_cleanup_free_actions (t);
83746283Sdfr  while (1)
83846283Sdfr    {
83946283Sdfr      /* Make sure that all output has been output.  Some machines may let
84098944Sobrien         you get away with leaving out some of the gdb_flush, but not all.  */
84146283Sdfr      wrap_here ("");
84246283Sdfr      gdb_flush (gdb_stdout);
84346283Sdfr      gdb_flush (gdb_stderr);
84446283Sdfr
84546283Sdfr      if (readline_hook && instream == NULL)
84646283Sdfr	line = (*readline_hook) (prompt);
84746283Sdfr      else if (instream == stdin && ISATTY (instream))
84846283Sdfr	{
849130803Smarcel	  line = gdb_readline_wrapper (prompt);
85098944Sobrien	  if (line && *line)	/* add it to command history */
85146283Sdfr	    add_history (line);
85246283Sdfr	}
85346283Sdfr      else
85446283Sdfr	line = gdb_readline (0);
85546283Sdfr
85646283Sdfr      linetype = validate_actionline (&line, t);
85746283Sdfr      if (linetype == BADLINE)
85898944Sobrien	continue;		/* already warned -- collect another line */
85946283Sdfr
86046283Sdfr      temp = xmalloc (sizeof (struct action_line));
86146283Sdfr      temp->next = NULL;
86246283Sdfr      temp->action = line;
86346283Sdfr
86446283Sdfr      if (next == NULL)		/* first action for this tracepoint? */
86546283Sdfr	t->actions = next = temp;
86646283Sdfr      else
86746283Sdfr	{
86846283Sdfr	  next->next = temp;
86946283Sdfr	  next = temp;
87046283Sdfr	}
87146283Sdfr
87246283Sdfr      if (linetype == STEPPING)	/* begin "while-stepping" */
87398944Sobrien	{
87498944Sobrien	  if (prompt == prompt2)
87598944Sobrien	    {
87698944Sobrien	      warning ("Already processing 'while-stepping'");
87798944Sobrien	      continue;
87898944Sobrien	    }
87998944Sobrien	  else
88098944Sobrien	    prompt = prompt2;	/* change prompt for stepping actions */
88198944Sobrien	}
88246283Sdfr      else if (linetype == END)
88398944Sobrien	{
88498944Sobrien	  if (prompt == prompt2)
88598944Sobrien	    {
88698944Sobrien	      prompt = prompt1;	/* end of single-stepping actions */
88798944Sobrien	    }
88898944Sobrien	  else
88998944Sobrien	    {			/* end of actions */
89098944Sobrien	      if (t->actions->next == NULL)
89198944Sobrien		{
89298944Sobrien		  /* an "end" all by itself with no other actions means
89398944Sobrien		     this tracepoint has no actions.  Discard empty list. */
89498944Sobrien		  free_actions (t);
89598944Sobrien		}
89698944Sobrien	      break;
89798944Sobrien	    }
89898944Sobrien	}
89946283Sdfr    }
90046283Sdfr#ifdef STOP_SIGNAL
90146283Sdfr  if (job_control)
90246283Sdfr    signal (STOP_SIGNAL, SIG_DFL);
90346283Sdfr#endif
90498944Sobrien  immediate_quit--;
90546283Sdfr  discard_cleanups (old_chain);
90646283Sdfr}
90746283Sdfr
90846283Sdfr/* worker function */
90946283Sdfrenum actionline_type
91098944Sobrienvalidate_actionline (char **line, struct tracepoint *t)
91146283Sdfr{
91246283Sdfr  struct cmd_list_element *c;
91346283Sdfr  struct expression *exp = NULL;
91446283Sdfr  struct cleanup *old_chain = NULL;
91546283Sdfr  char *p;
91646283Sdfr
917130803Smarcel  /* if EOF is typed, *line is NULL */
918130803Smarcel  if (*line == NULL)
919130803Smarcel    return END;
920130803Smarcel
92198944Sobrien  for (p = *line; isspace ((int) *p);)
92246283Sdfr    p++;
92346283Sdfr
92446283Sdfr  /* symbol lookup etc. */
92598944Sobrien  if (*p == '\0')		/* empty line: just prompt for another line. */
92646283Sdfr    return BADLINE;
92746283Sdfr
92898944Sobrien  if (*p == '#')		/* comment line */
92946283Sdfr    return GENERIC;
93046283Sdfr
93146283Sdfr  c = lookup_cmd (&p, cmdlist, "", -1, 1);
93246283Sdfr  if (c == 0)
93346283Sdfr    {
93446283Sdfr      warning ("'%s' is not an action that I know, or is ambiguous.", p);
93546283Sdfr      return BADLINE;
93646283Sdfr    }
93798944Sobrien
93898944Sobrien  if (cmd_cfunc_eq (c, collect_pseudocommand))
93946283Sdfr    {
94046283Sdfr      struct agent_expr *aexpr;
94146283Sdfr      struct agent_reqs areqs;
94246283Sdfr
94398944Sobrien      do
94498944Sobrien	{			/* repeat over a comma-separated list */
94598944Sobrien	  QUIT;			/* allow user to bail out with ^C */
94698944Sobrien	  while (isspace ((int) *p))
94798944Sobrien	    p++;
94846283Sdfr
94998944Sobrien	  if (*p == '$')	/* look for special pseudo-symbols */
95046283Sdfr	    {
95198944Sobrien	      if ((0 == strncasecmp ("reg", p + 1, 3)) ||
95298944Sobrien		  (0 == strncasecmp ("arg", p + 1, 3)) ||
95398944Sobrien		  (0 == strncasecmp ("loc", p + 1, 3)))
95498944Sobrien		{
95598944Sobrien		  p = strchr (p, ',');
95698944Sobrien		  continue;
95798944Sobrien		}
95898944Sobrien	      /* else fall thru, treat p as an expression and parse it! */
95946283Sdfr	    }
96098944Sobrien	  exp = parse_exp_1 (&p, block_for_pc (t->address), 1);
96198944Sobrien	  old_chain = make_cleanup (free_current_contents, &exp);
96298944Sobrien
96398944Sobrien	  if (exp->elts[0].opcode == OP_VAR_VALUE)
96446283Sdfr	    {
96598944Sobrien	      if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST)
96698944Sobrien		{
96798944Sobrien		  warning ("constant %s (value %ld) will not be collected.",
968130803Smarcel			   DEPRECATED_SYMBOL_NAME (exp->elts[2].symbol),
96998944Sobrien			   SYMBOL_VALUE (exp->elts[2].symbol));
97098944Sobrien		  return BADLINE;
97198944Sobrien		}
97298944Sobrien	      else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT)
97398944Sobrien		{
97498944Sobrien		  warning ("%s is optimized away and cannot be collected.",
975130803Smarcel			   DEPRECATED_SYMBOL_NAME (exp->elts[2].symbol));
97698944Sobrien		  return BADLINE;
97798944Sobrien		}
97846283Sdfr	    }
97946283Sdfr
98098944Sobrien	  /* we have something to collect, make sure that the expr to
98198944Sobrien	     bytecode translator can handle it and that it's not too long */
98298944Sobrien	  aexpr = gen_trace_for_expr (t->address, exp);
98398944Sobrien	  make_cleanup_free_agent_expr (aexpr);
98446283Sdfr
98598944Sobrien	  if (aexpr->len > MAX_AGENT_EXPR_LEN)
98698944Sobrien	    error ("expression too complicated, try simplifying");
98746283Sdfr
98898944Sobrien	  ax_reqs (aexpr, &areqs);
98998944Sobrien	  (void) make_cleanup (xfree, areqs.reg_mask);
99046283Sdfr
99198944Sobrien	  if (areqs.flaw != agent_flaw_none)
99298944Sobrien	    error ("malformed expression");
99346283Sdfr
99498944Sobrien	  if (areqs.min_height < 0)
99598944Sobrien	    error ("gdb: Internal error: expression has min height < 0");
99646283Sdfr
99798944Sobrien	  if (areqs.max_height > 20)
99898944Sobrien	    error ("expression too complicated, try simplifying");
99946283Sdfr
100098944Sobrien	  do_cleanups (old_chain);
100198944Sobrien	}
100298944Sobrien      while (p && *p++ == ',');
100346283Sdfr      return GENERIC;
100446283Sdfr    }
100598944Sobrien  else if (cmd_cfunc_eq (c, while_stepping_pseudocommand))
100646283Sdfr    {
100798944Sobrien      char *steparg;		/* in case warning is necessary */
100846283Sdfr
100998944Sobrien      while (isspace ((int) *p))
101046283Sdfr	p++;
101146283Sdfr      steparg = p;
101246283Sdfr
101346283Sdfr      if (*p == '\0' ||
101446283Sdfr	  (t->step_count = strtol (p, &p, 0)) == 0)
101546283Sdfr	{
101698944Sobrien	  warning ("'%s': bad step-count; command ignored.", *line);
101746283Sdfr	  return BADLINE;
101846283Sdfr	}
101946283Sdfr      return STEPPING;
102046283Sdfr    }
102198944Sobrien  else if (cmd_cfunc_eq (c, end_actions_pseudocommand))
102246283Sdfr    return END;
102346283Sdfr  else
102446283Sdfr    {
102546283Sdfr      warning ("'%s' is not a supported tracepoint action.", *line);
102646283Sdfr      return BADLINE;
102746283Sdfr    }
102846283Sdfr}
102946283Sdfr
103046283Sdfr/* worker function */
103198944Sobrienvoid
103298944Sobrienfree_actions (struct tracepoint *t)
103346283Sdfr{
103446283Sdfr  struct action_line *line, *next;
103546283Sdfr
103646283Sdfr  for (line = t->actions; line; line = next)
103746283Sdfr    {
103846283Sdfr      next = line->next;
103998944Sobrien      if (line->action)
104098944Sobrien	xfree (line->action);
104198944Sobrien      xfree (line);
104246283Sdfr    }
104346283Sdfr  t->actions = NULL;
104446283Sdfr}
104546283Sdfr
104698944Sobrienstatic void
104798944Sobriendo_free_actions_cleanup (void *t)
104898944Sobrien{
104998944Sobrien  free_actions (t);
105098944Sobrien}
105198944Sobrien
105298944Sobrienstatic struct cleanup *
105398944Sobrienmake_cleanup_free_actions (struct tracepoint *t)
105498944Sobrien{
105598944Sobrien  return make_cleanup (do_free_actions_cleanup, t);
105698944Sobrien}
105798944Sobrien
105898944Sobrienstruct memrange
105998944Sobrien{
106046283Sdfr  int type;		/* 0 for absolute memory range, else basereg number */
106146283Sdfr  bfd_signed_vma start;
106246283Sdfr  bfd_signed_vma end;
106346283Sdfr};
106446283Sdfr
106598944Sobrienstruct collection_list
106698944Sobrien  {
106798944Sobrien    unsigned char regs_mask[8];	/* room for up to 256 regs */
106898944Sobrien    long listsize;
106998944Sobrien    long next_memrange;
107098944Sobrien    struct memrange *list;
107198944Sobrien    long aexpr_listsize;	/* size of array pointed to by expr_list elt */
107298944Sobrien    long next_aexpr_elt;
107398944Sobrien    struct agent_expr **aexpr_list;
107446283Sdfr
107598944Sobrien  }
107698944Sobrientracepoint_list, stepping_list;
107798944Sobrien
107846283Sdfr/* MEMRANGE functions: */
107946283Sdfr
108098944Sobrienstatic int memrange_cmp (const void *, const void *);
108146283Sdfr
108246283Sdfr/* compare memranges for qsort */
108346283Sdfrstatic int
108498944Sobrienmemrange_cmp (const void *va, const void *vb)
108546283Sdfr{
108646283Sdfr  const struct memrange *a = va, *b = vb;
108746283Sdfr
108846283Sdfr  if (a->type < b->type)
108946283Sdfr    return -1;
109046283Sdfr  if (a->type > b->type)
109198944Sobrien    return 1;
109246283Sdfr  if (a->type == 0)
109346283Sdfr    {
109498944Sobrien      if ((bfd_vma) a->start < (bfd_vma) b->start)
109598944Sobrien	return -1;
109698944Sobrien      if ((bfd_vma) a->start > (bfd_vma) b->start)
109798944Sobrien	return 1;
109846283Sdfr    }
109946283Sdfr  else
110046283Sdfr    {
110198944Sobrien      if (a->start < b->start)
110246283Sdfr	return -1;
110398944Sobrien      if (a->start > b->start)
110498944Sobrien	return 1;
110546283Sdfr    }
110646283Sdfr  return 0;
110746283Sdfr}
110846283Sdfr
110946283Sdfr/* Sort the memrange list using qsort, and merge adjacent memranges */
111046283Sdfrstatic void
111198944Sobrienmemrange_sortmerge (struct collection_list *memranges)
111246283Sdfr{
111346283Sdfr  int a, b;
111446283Sdfr
111598944Sobrien  qsort (memranges->list, memranges->next_memrange,
111646283Sdfr	 sizeof (struct memrange), memrange_cmp);
111746283Sdfr  if (memranges->next_memrange > 0)
111846283Sdfr    {
111946283Sdfr      for (a = 0, b = 1; b < memranges->next_memrange; b++)
112046283Sdfr	{
112146283Sdfr	  if (memranges->list[a].type == memranges->list[b].type &&
112298944Sobrien	      memranges->list[b].start - memranges->list[a].end <=
1123130803Smarcel	      MAX_REGISTER_SIZE)
112446283Sdfr	    {
112546283Sdfr	      /* memrange b starts before memrange a ends; merge them.  */
112646283Sdfr	      if (memranges->list[b].end > memranges->list[a].end)
112746283Sdfr		memranges->list[a].end = memranges->list[b].end;
112846283Sdfr	      continue;		/* next b, same a */
112946283Sdfr	    }
113046283Sdfr	  a++;			/* next a */
113146283Sdfr	  if (a != b)
113298944Sobrien	    memcpy (&memranges->list[a], &memranges->list[b],
113346283Sdfr		    sizeof (struct memrange));
113446283Sdfr	}
113546283Sdfr      memranges->next_memrange = a + 1;
113646283Sdfr    }
113746283Sdfr}
113846283Sdfr
113946283Sdfr/* Add a register to a collection list */
114098944Sobrienstatic void
114198944Sobrienadd_register (struct collection_list *collection, unsigned int regno)
114246283Sdfr{
114346283Sdfr  if (info_verbose)
114446283Sdfr    printf_filtered ("collect register %d\n", regno);
114546283Sdfr  if (regno > (8 * sizeof (collection->regs_mask)))
114646283Sdfr    error ("Internal: register number %d too large for tracepoint",
114746283Sdfr	   regno);
114898944Sobrien  collection->regs_mask[regno / 8] |= 1 << (regno % 8);
114946283Sdfr}
115046283Sdfr
115146283Sdfr/* Add a memrange to a collection list */
115246283Sdfrstatic void
115398944Sobrienadd_memrange (struct collection_list *memranges, int type, bfd_signed_vma base,
115498944Sobrien	      unsigned long len)
115546283Sdfr{
115646283Sdfr  if (info_verbose)
115798944Sobrien    {
115898944Sobrien      printf_filtered ("(%d,", type);
115998944Sobrien      printf_vma (base);
116098944Sobrien      printf_filtered (",%ld)\n", len);
116198944Sobrien    }
116298944Sobrien
116346283Sdfr  /* type: 0 == memory, n == basereg */
116498944Sobrien  memranges->list[memranges->next_memrange].type = type;
116546283Sdfr  /* base: addr if memory, offset if reg relative. */
116646283Sdfr  memranges->list[memranges->next_memrange].start = base;
116746283Sdfr  /* len: we actually save end (base + len) for convenience */
116898944Sobrien  memranges->list[memranges->next_memrange].end = base + len;
116946283Sdfr  memranges->next_memrange++;
117046283Sdfr  if (memranges->next_memrange >= memranges->listsize)
117146283Sdfr    {
117246283Sdfr      memranges->listsize *= 2;
117398944Sobrien      memranges->list = xrealloc (memranges->list,
117446283Sdfr				  memranges->listsize);
117546283Sdfr    }
117646283Sdfr
117798944Sobrien  if (type != -1)		/* better collect the base register! */
117846283Sdfr    add_register (memranges, type);
117946283Sdfr}
118046283Sdfr
118146283Sdfr/* Add a symbol to a collection list */
118246283Sdfrstatic void
118398944Sobriencollect_symbol (struct collection_list *collect, struct symbol *sym,
118498944Sobrien		long frame_regno, long frame_offset)
118546283Sdfr{
118698944Sobrien  unsigned long len;
118798944Sobrien  unsigned int reg;
118846283Sdfr  bfd_signed_vma offset;
118946283Sdfr
119098944Sobrien  len = TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym)));
119198944Sobrien  switch (SYMBOL_CLASS (sym))
119298944Sobrien    {
119398944Sobrien    default:
119498944Sobrien      printf_filtered ("%s: don't know symbol class %d\n",
1195130803Smarcel		       DEPRECATED_SYMBOL_NAME (sym), SYMBOL_CLASS (sym));
119698944Sobrien      break;
119798944Sobrien    case LOC_CONST:
119898944Sobrien      printf_filtered ("constant %s (value %ld) will not be collected.\n",
1199130803Smarcel		       DEPRECATED_SYMBOL_NAME (sym), SYMBOL_VALUE (sym));
120098944Sobrien      break;
120198944Sobrien    case LOC_STATIC:
120298944Sobrien      offset = SYMBOL_VALUE_ADDRESS (sym);
120398944Sobrien      if (info_verbose)
120498944Sobrien	{
120598944Sobrien	  char tmp[40];
120698944Sobrien
120798944Sobrien	  sprintf_vma (tmp, offset);
120898944Sobrien	  printf_filtered ("LOC_STATIC %s: collect %ld bytes at %s.\n",
1209130803Smarcel			   DEPRECATED_SYMBOL_NAME (sym), len, tmp /* address */);
121098944Sobrien	}
121198944Sobrien      add_memrange (collect, -1, offset, len);	/* 0 == memory */
121298944Sobrien      break;
121398944Sobrien    case LOC_REGISTER:
121498944Sobrien    case LOC_REGPARM:
121598944Sobrien      reg = SYMBOL_VALUE (sym);
121698944Sobrien      if (info_verbose)
1217130803Smarcel	printf_filtered ("LOC_REG[parm] %s: ", DEPRECATED_SYMBOL_NAME (sym));
121898944Sobrien      add_register (collect, reg);
121998944Sobrien      /* check for doubles stored in two registers */
122098944Sobrien      /* FIXME: how about larger types stored in 3 or more regs? */
122198944Sobrien      if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_FLT &&
1222130803Smarcel	  len > DEPRECATED_REGISTER_RAW_SIZE (reg))
122398944Sobrien	add_register (collect, reg + 1);
122498944Sobrien      break;
122598944Sobrien    case LOC_REF_ARG:
122698944Sobrien      printf_filtered ("Sorry, don't know how to do LOC_REF_ARG yet.\n");
122798944Sobrien      printf_filtered ("       (will not collect %s)\n",
1228130803Smarcel		       DEPRECATED_SYMBOL_NAME (sym));
122998944Sobrien      break;
123098944Sobrien    case LOC_ARG:
123198944Sobrien      reg = frame_regno;
123298944Sobrien      offset = frame_offset + SYMBOL_VALUE (sym);
123398944Sobrien      if (info_verbose)
123498944Sobrien	{
123598944Sobrien	  printf_filtered ("LOC_LOCAL %s: Collect %ld bytes at offset ",
1236130803Smarcel			   DEPRECATED_SYMBOL_NAME (sym), len);
123798944Sobrien	  printf_vma (offset);
123898944Sobrien	  printf_filtered (" from frame ptr reg %d\n", reg);
123998944Sobrien	}
124098944Sobrien      add_memrange (collect, reg, offset, len);
124198944Sobrien      break;
124298944Sobrien    case LOC_REGPARM_ADDR:
124398944Sobrien      reg = SYMBOL_VALUE (sym);
124498944Sobrien      offset = 0;
124598944Sobrien      if (info_verbose)
124698944Sobrien	{
124798944Sobrien	  printf_filtered ("LOC_REGPARM_ADDR %s: Collect %ld bytes at offset ",
1248130803Smarcel			   DEPRECATED_SYMBOL_NAME (sym), len);
124998944Sobrien	  printf_vma (offset);
125098944Sobrien	  printf_filtered (" from reg %d\n", reg);
125198944Sobrien	}
125298944Sobrien      add_memrange (collect, reg, offset, len);
125398944Sobrien      break;
125498944Sobrien    case LOC_LOCAL:
125598944Sobrien    case LOC_LOCAL_ARG:
125698944Sobrien      reg = frame_regno;
125798944Sobrien      offset = frame_offset + SYMBOL_VALUE (sym);
125898944Sobrien      if (info_verbose)
125998944Sobrien	{
126098944Sobrien	  printf_filtered ("LOC_LOCAL %s: Collect %ld bytes at offset ",
1261130803Smarcel			   DEPRECATED_SYMBOL_NAME (sym), len);
126298944Sobrien	  printf_vma (offset);
126398944Sobrien	  printf_filtered (" from frame ptr reg %d\n", reg);
126498944Sobrien	}
126598944Sobrien      add_memrange (collect, reg, offset, len);
126698944Sobrien      break;
126798944Sobrien    case LOC_BASEREG:
126898944Sobrien    case LOC_BASEREG_ARG:
126998944Sobrien      reg = SYMBOL_BASEREG (sym);
127098944Sobrien      offset = SYMBOL_VALUE (sym);
127198944Sobrien      if (info_verbose)
127298944Sobrien	{
127398944Sobrien	  printf_filtered ("LOC_BASEREG %s: collect %ld bytes at offset ",
1274130803Smarcel			   DEPRECATED_SYMBOL_NAME (sym), len);
127598944Sobrien	  printf_vma (offset);
127698944Sobrien	  printf_filtered (" from basereg %d\n", reg);
127798944Sobrien	}
127898944Sobrien      add_memrange (collect, reg, offset, len);
127998944Sobrien      break;
128098944Sobrien    case LOC_UNRESOLVED:
1281130803Smarcel      printf_filtered ("Don't know LOC_UNRESOLVED %s\n", DEPRECATED_SYMBOL_NAME (sym));
128298944Sobrien      break;
128398944Sobrien    case LOC_OPTIMIZED_OUT:
128498944Sobrien      printf_filtered ("%s has been optimized out of existence.\n",
1285130803Smarcel		       DEPRECATED_SYMBOL_NAME (sym));
128698944Sobrien      break;
128798944Sobrien    }
128846283Sdfr}
128946283Sdfr
129046283Sdfr/* Add all locals (or args) symbols to collection list */
129146283Sdfrstatic void
129298944Sobrienadd_local_symbols (struct collection_list *collect, CORE_ADDR pc,
129398944Sobrien		   long frame_regno, long frame_offset, int type)
129446283Sdfr{
129546283Sdfr  struct symbol *sym;
129698944Sobrien  struct block *block;
1297130803Smarcel  struct dict_iterator iter;
1298130803Smarcel  int count = 0;
129946283Sdfr
130046283Sdfr  block = block_for_pc (pc);
130146283Sdfr  while (block != 0)
130246283Sdfr    {
130398944Sobrien      QUIT;			/* allow user to bail out with ^C */
1304130803Smarcel      ALL_BLOCK_SYMBOLS (block, iter, sym)
130546283Sdfr	{
130698944Sobrien	  switch (SYMBOL_CLASS (sym))
130798944Sobrien	    {
130898944Sobrien	    default:
130998944Sobrien	      warning ("don't know how to trace local symbol %s",
1310130803Smarcel		       DEPRECATED_SYMBOL_NAME (sym));
131198944Sobrien	    case LOC_LOCAL:
131298944Sobrien	    case LOC_STATIC:
131398944Sobrien	    case LOC_REGISTER:
131498944Sobrien	    case LOC_BASEREG:
131598944Sobrien	      if (type == 'L')	/* collecting Locals */
131698944Sobrien		{
131798944Sobrien		  count++;
131898944Sobrien		  collect_symbol (collect, sym, frame_regno, frame_offset);
131998944Sobrien		}
132098944Sobrien	      break;
132198944Sobrien	    case LOC_ARG:
132298944Sobrien	    case LOC_LOCAL_ARG:
132398944Sobrien	    case LOC_REF_ARG:
132498944Sobrien	    case LOC_REGPARM:
132598944Sobrien	    case LOC_REGPARM_ADDR:
132698944Sobrien	    case LOC_BASEREG_ARG:
132798944Sobrien	      if (type == 'A')	/* collecting Arguments */
132898944Sobrien		{
132998944Sobrien		  count++;
133098944Sobrien		  collect_symbol (collect, sym, frame_regno, frame_offset);
133198944Sobrien		}
133298944Sobrien	    }
133346283Sdfr	}
133446283Sdfr      if (BLOCK_FUNCTION (block))
133546283Sdfr	break;
133646283Sdfr      else
133746283Sdfr	block = BLOCK_SUPERBLOCK (block);
133846283Sdfr    }
133946283Sdfr  if (count == 0)
134046283Sdfr    warning ("No %s found in scope.", type == 'L' ? "locals" : "args");
134146283Sdfr}
134246283Sdfr
134346283Sdfr/* worker function */
134446283Sdfrstatic void
134598944Sobrienclear_collection_list (struct collection_list *list)
134646283Sdfr{
134746283Sdfr  int ndx;
134846283Sdfr
134946283Sdfr  list->next_memrange = 0;
135046283Sdfr  for (ndx = 0; ndx < list->next_aexpr_elt; ndx++)
135146283Sdfr    {
135298944Sobrien      free_agent_expr (list->aexpr_list[ndx]);
135346283Sdfr      list->aexpr_list[ndx] = NULL;
135446283Sdfr    }
135546283Sdfr  list->next_aexpr_elt = 0;
135646283Sdfr  memset (list->regs_mask, 0, sizeof (list->regs_mask));
135746283Sdfr}
135846283Sdfr
135946283Sdfr/* reduce a collection list to string form (for gdb protocol) */
136046283Sdfrstatic char **
136198944Sobrienstringify_collection_list (struct collection_list *list, char *string)
136246283Sdfr{
136346283Sdfr  char temp_buf[2048];
136498944Sobrien  char tmp2[40];
136546283Sdfr  int count;
136646283Sdfr  int ndx = 0;
136746283Sdfr  char *(*str_list)[];
136846283Sdfr  char *end;
136998944Sobrien  long i;
137046283Sdfr
137146283Sdfr  count = 1 + list->next_memrange + list->next_aexpr_elt + 1;
137298944Sobrien  str_list = (char *(*)[]) xmalloc (count * sizeof (char *));
137346283Sdfr
137446283Sdfr  for (i = sizeof (list->regs_mask) - 1; i > 0; i--)
137546283Sdfr    if (list->regs_mask[i] != 0)	/* skip leading zeroes in regs_mask */
137646283Sdfr      break;
137746283Sdfr  if (list->regs_mask[i] != 0)	/* prepare to send regs_mask to the stub */
137846283Sdfr    {
137946283Sdfr      if (info_verbose)
138046283Sdfr	printf_filtered ("\nCollecting registers (mask): 0x");
138146283Sdfr      end = temp_buf;
138298944Sobrien      *end++ = 'R';
138346283Sdfr      for (; i >= 0; i--)
138446283Sdfr	{
138598944Sobrien	  QUIT;			/* allow user to bail out with ^C */
138646283Sdfr	  if (info_verbose)
138746283Sdfr	    printf_filtered ("%02X", list->regs_mask[i]);
138898944Sobrien	  sprintf (end, "%02X", list->regs_mask[i]);
138946283Sdfr	  end += 2;
139046283Sdfr	}
139198944Sobrien      (*str_list)[ndx] = savestring (temp_buf, end - temp_buf);
139246283Sdfr      ndx++;
139346283Sdfr    }
139446283Sdfr  if (info_verbose)
139546283Sdfr    printf_filtered ("\n");
139646283Sdfr  if (list->next_memrange > 0 && info_verbose)
139746283Sdfr    printf_filtered ("Collecting memranges: \n");
139846283Sdfr  for (i = 0, count = 0, end = temp_buf; i < list->next_memrange; i++)
139946283Sdfr    {
140046283Sdfr      QUIT;			/* allow user to bail out with ^C */
140198944Sobrien      sprintf_vma (tmp2, list->list[i].start);
140246283Sdfr      if (info_verbose)
140398944Sobrien	{
140498944Sobrien	  printf_filtered ("(%d, %s, %ld)\n",
140598944Sobrien			   list->list[i].type,
140698944Sobrien			   tmp2,
140798944Sobrien			   (long) (list->list[i].end - list->list[i].start));
140898944Sobrien	}
140946283Sdfr      if (count + 27 > MAX_AGENT_EXPR_LEN)
141046283Sdfr	{
141198944Sobrien	  (*str_list)[ndx] = savestring (temp_buf, count);
141246283Sdfr	  ndx++;
141346283Sdfr	  count = 0;
141446283Sdfr	  end = temp_buf;
141546283Sdfr	}
141698944Sobrien
141798944Sobrien      sprintf (end, "M%X,%s,%lX",
141898944Sobrien	       list->list[i].type,
141998944Sobrien	       tmp2,
142098944Sobrien	       (long) (list->list[i].end - list->list[i].start));
142198944Sobrien
142246283Sdfr      count += strlen (end);
142398944Sobrien      end += count;
142446283Sdfr    }
142546283Sdfr
142646283Sdfr  for (i = 0; i < list->next_aexpr_elt; i++)
142746283Sdfr    {
142846283Sdfr      QUIT;			/* allow user to bail out with ^C */
142946283Sdfr      if ((count + 10 + 2 * list->aexpr_list[i]->len) > MAX_AGENT_EXPR_LEN)
143046283Sdfr	{
143198944Sobrien	  (*str_list)[ndx] = savestring (temp_buf, count);
143246283Sdfr	  ndx++;
143346283Sdfr	  count = 0;
143446283Sdfr	  end = temp_buf;
143546283Sdfr	}
143646283Sdfr      sprintf (end, "X%08X,", list->aexpr_list[i]->len);
143746283Sdfr      end += 10;		/* 'X' + 8 hex digits + ',' */
143846283Sdfr      count += 10;
143946283Sdfr
144098944Sobrien      end = mem2hex (list->aexpr_list[i]->buf, end, list->aexpr_list[i]->len);
144146283Sdfr      count += 2 * list->aexpr_list[i]->len;
144246283Sdfr    }
144346283Sdfr
144446283Sdfr  if (count != 0)
144546283Sdfr    {
144698944Sobrien      (*str_list)[ndx] = savestring (temp_buf, count);
144746283Sdfr      ndx++;
144846283Sdfr      count = 0;
144946283Sdfr      end = temp_buf;
145046283Sdfr    }
145146283Sdfr  (*str_list)[ndx] = NULL;
145246283Sdfr
145346283Sdfr  if (ndx == 0)
145446283Sdfr    return NULL;
145546283Sdfr  else
145646283Sdfr    return *str_list;
145746283Sdfr}
145846283Sdfr
145998944Sobrienstatic void
146098944Sobrienfree_actions_list_cleanup_wrapper (void *al)
146146283Sdfr{
146298944Sobrien  free_actions_list (al);
146398944Sobrien}
146498944Sobrien
146598944Sobrienstatic void
146698944Sobrienfree_actions_list (char **actions_list)
146798944Sobrien{
146846283Sdfr  int ndx;
146946283Sdfr
147046283Sdfr  if (actions_list == 0)
147146283Sdfr    return;
147246283Sdfr
147346283Sdfr  for (ndx = 0; actions_list[ndx]; ndx++)
147498944Sobrien    xfree (actions_list[ndx]);
147546283Sdfr
147698944Sobrien  xfree (actions_list);
147746283Sdfr}
147846283Sdfr
147946283Sdfr/* render all actions into gdb protocol */
148046283Sdfrstatic void
148198944Sobrienencode_actions (struct tracepoint *t, char ***tdp_actions,
148298944Sobrien		char ***stepping_actions)
148346283Sdfr{
148498944Sobrien  static char tdp_buff[2048], step_buff[2048];
148598944Sobrien  char *action_exp;
148698944Sobrien  struct expression *exp = NULL;
148746283Sdfr  struct action_line *action;
148898944Sobrien  int i;
148998944Sobrien  struct value *tempval;
149098944Sobrien  struct collection_list *collect;
149146283Sdfr  struct cmd_list_element *cmd;
149246283Sdfr  struct agent_expr *aexpr;
149398944Sobrien  int frame_reg;
149498944Sobrien  LONGEST frame_offset;
149546283Sdfr
149646283Sdfr
149746283Sdfr  clear_collection_list (&tracepoint_list);
149846283Sdfr  clear_collection_list (&stepping_list);
149946283Sdfr  collect = &tracepoint_list;
150046283Sdfr
150146283Sdfr  *tdp_actions = NULL;
150246283Sdfr  *stepping_actions = NULL;
150346283Sdfr
150446283Sdfr  TARGET_VIRTUAL_FRAME_POINTER (t->address, &frame_reg, &frame_offset);
150546283Sdfr
150646283Sdfr  for (action = t->actions; action; action = action->next)
150746283Sdfr    {
150846283Sdfr      QUIT;			/* allow user to bail out with ^C */
150946283Sdfr      action_exp = action->action;
151098944Sobrien      while (isspace ((int) *action_exp))
151146283Sdfr	action_exp++;
151246283Sdfr
151346283Sdfr      if (*action_exp == '#')	/* comment line */
151446283Sdfr	return;
151546283Sdfr
151646283Sdfr      cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
151746283Sdfr      if (cmd == 0)
151846283Sdfr	error ("Bad action list item: %s", action_exp);
151946283Sdfr
152098944Sobrien      if (cmd_cfunc_eq (cmd, collect_pseudocommand))
152146283Sdfr	{
152298944Sobrien	  do
152398944Sobrien	    {			/* repeat over a comma-separated list */
152498944Sobrien	      QUIT;		/* allow user to bail out with ^C */
152598944Sobrien	      while (isspace ((int) *action_exp))
152698944Sobrien		action_exp++;
152746283Sdfr
152898944Sobrien	      if (0 == strncasecmp ("$reg", action_exp, 4))
152998944Sobrien		{
153098944Sobrien		  for (i = 0; i < NUM_REGS; i++)
153198944Sobrien		    add_register (collect, i);
153298944Sobrien		  action_exp = strchr (action_exp, ',');	/* more? */
153398944Sobrien		}
153498944Sobrien	      else if (0 == strncasecmp ("$arg", action_exp, 4))
153598944Sobrien		{
153698944Sobrien		  add_local_symbols (collect,
153798944Sobrien				     t->address,
153898944Sobrien				     frame_reg,
153998944Sobrien				     frame_offset,
154098944Sobrien				     'A');
154198944Sobrien		  action_exp = strchr (action_exp, ',');	/* more? */
154298944Sobrien		}
154398944Sobrien	      else if (0 == strncasecmp ("$loc", action_exp, 4))
154498944Sobrien		{
154598944Sobrien		  add_local_symbols (collect,
154698944Sobrien				     t->address,
154798944Sobrien				     frame_reg,
154898944Sobrien				     frame_offset,
154998944Sobrien				     'L');
155098944Sobrien		  action_exp = strchr (action_exp, ',');	/* more? */
155198944Sobrien		}
155298944Sobrien	      else
155398944Sobrien		{
155498944Sobrien		  unsigned long addr, len;
155598944Sobrien		  struct cleanup *old_chain = NULL;
155698944Sobrien		  struct cleanup *old_chain1 = NULL;
155798944Sobrien		  struct agent_reqs areqs;
155846283Sdfr
155998944Sobrien		  exp = parse_exp_1 (&action_exp,
156098944Sobrien				     block_for_pc (t->address), 1);
156198944Sobrien		  old_chain = make_cleanup (free_current_contents, &exp);
156246283Sdfr
156398944Sobrien		  switch (exp->elts[0].opcode)
156498944Sobrien		    {
156598944Sobrien		    case OP_REGISTER:
156698944Sobrien		      i = exp->elts[1].longconst;
156798944Sobrien		      if (info_verbose)
156898944Sobrien			printf_filtered ("OP_REGISTER: ");
156998944Sobrien		      add_register (collect, i);
157098944Sobrien		      break;
157146283Sdfr
157298944Sobrien		    case UNOP_MEMVAL:
157398944Sobrien		      /* safe because we know it's a simple expression */
157498944Sobrien		      tempval = evaluate_expression (exp);
157598944Sobrien		      addr = VALUE_ADDRESS (tempval) + VALUE_OFFSET (tempval);
157698944Sobrien		      len = TYPE_LENGTH (check_typedef (exp->elts[1].type));
157798944Sobrien		      add_memrange (collect, -1, addr, len);
157898944Sobrien		      break;
157946283Sdfr
158098944Sobrien		    case OP_VAR_VALUE:
158198944Sobrien		      collect_symbol (collect,
158298944Sobrien				      exp->elts[2].symbol,
158398944Sobrien				      frame_reg,
158498944Sobrien				      frame_offset);
158598944Sobrien		      break;
158646283Sdfr
158798944Sobrien		    default:	/* full-fledged expression */
158898944Sobrien		      aexpr = gen_trace_for_expr (t->address, exp);
158946283Sdfr
159098944Sobrien		      old_chain1 = make_cleanup_free_agent_expr (aexpr);
159146283Sdfr
159298944Sobrien		      ax_reqs (aexpr, &areqs);
159398944Sobrien		      if (areqs.flaw != agent_flaw_none)
159498944Sobrien			error ("malformed expression");
159546283Sdfr
159698944Sobrien		      if (areqs.min_height < 0)
159798944Sobrien			error ("gdb: Internal error: expression has min height < 0");
159898944Sobrien		      if (areqs.max_height > 20)
159998944Sobrien			error ("expression too complicated, try simplifying");
160046283Sdfr
160198944Sobrien		      discard_cleanups (old_chain1);
160298944Sobrien		      add_aexpr (collect, aexpr);
160346283Sdfr
160498944Sobrien		      /* take care of the registers */
160598944Sobrien		      if (areqs.reg_mask_len > 0)
160698944Sobrien			{
160798944Sobrien			  int ndx1;
160898944Sobrien			  int ndx2;
160946283Sdfr
161098944Sobrien			  for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
161146283Sdfr			    {
161298944Sobrien			      QUIT;	/* allow user to bail out with ^C */
161398944Sobrien			      if (areqs.reg_mask[ndx1] != 0)
161498944Sobrien				{
161598944Sobrien				  /* assume chars have 8 bits */
161698944Sobrien				  for (ndx2 = 0; ndx2 < 8; ndx2++)
161798944Sobrien				    if (areqs.reg_mask[ndx1] & (1 << ndx2))
161898944Sobrien				      /* it's used -- record it */
161998944Sobrien				      add_register (collect, ndx1 * 8 + ndx2);
162098944Sobrien				}
162146283Sdfr			    }
162246283Sdfr			}
162398944Sobrien		      break;
162498944Sobrien		    }		/* switch */
162598944Sobrien		  do_cleanups (old_chain);
162698944Sobrien		}		/* do */
162798944Sobrien	    }
162898944Sobrien	  while (action_exp && *action_exp++ == ',');
162998944Sobrien	}			/* if */
163098944Sobrien      else if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
163146283Sdfr	{
163246283Sdfr	  collect = &stepping_list;
163346283Sdfr	}
163498944Sobrien      else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
163546283Sdfr	{
163646283Sdfr	  if (collect == &stepping_list)	/* end stepping actions */
163746283Sdfr	    collect = &tracepoint_list;
163846283Sdfr	  else
163998944Sobrien	    break;		/* end tracepoint actions */
164046283Sdfr	}
164198944Sobrien    }				/* for */
164298944Sobrien  memrange_sortmerge (&tracepoint_list);
164398944Sobrien  memrange_sortmerge (&stepping_list);
164446283Sdfr
164598944Sobrien  *tdp_actions = stringify_collection_list (&tracepoint_list, tdp_buff);
164698944Sobrien  *stepping_actions = stringify_collection_list (&stepping_list, step_buff);
164746283Sdfr}
164846283Sdfr
164946283Sdfrstatic void
165098944Sobrienadd_aexpr (struct collection_list *collect, struct agent_expr *aexpr)
165146283Sdfr{
165246283Sdfr  if (collect->next_aexpr_elt >= collect->aexpr_listsize)
165346283Sdfr    {
165446283Sdfr      collect->aexpr_list =
165546283Sdfr	xrealloc (collect->aexpr_list,
165698944Sobrien		2 * collect->aexpr_listsize * sizeof (struct agent_expr *));
165746283Sdfr      collect->aexpr_listsize *= 2;
165846283Sdfr    }
165946283Sdfr  collect->aexpr_list[collect->next_aexpr_elt] = aexpr;
166046283Sdfr  collect->next_aexpr_elt++;
166146283Sdfr}
166246283Sdfr
166346283Sdfrstatic char target_buf[2048];
166446283Sdfr
166546283Sdfr/* Set "transparent" memory ranges
166646283Sdfr
166746283Sdfr   Allow trace mechanism to treat text-like sections
166846283Sdfr   (and perhaps all read-only sections) transparently,
166946283Sdfr   i.e. don't reject memory requests from these address ranges
167046283Sdfr   just because they haven't been collected.  */
167146283Sdfr
167246283Sdfrstatic void
167346283Sdfrremote_set_transparent_ranges (void)
167446283Sdfr{
167546283Sdfr  extern bfd *exec_bfd;
167646283Sdfr  asection *s;
167746283Sdfr  bfd_size_type size;
167846283Sdfr  bfd_vma lma;
167946283Sdfr  int anysecs = 0;
168046283Sdfr
168146283Sdfr  if (!exec_bfd)
168298944Sobrien    return;			/* no information to give. */
168346283Sdfr
168446283Sdfr  strcpy (target_buf, "QTro");
168546283Sdfr  for (s = exec_bfd->sections; s; s = s->next)
168646283Sdfr    {
168798944Sobrien      char tmp1[40], tmp2[40];
168846283Sdfr
168998944Sobrien      if ((s->flags & SEC_LOAD) == 0 ||
169098944Sobrien      /* (s->flags & SEC_CODE)     == 0 || */
169146283Sdfr	  (s->flags & SEC_READONLY) == 0)
169246283Sdfr	continue;
169346283Sdfr
169446283Sdfr      anysecs = 1;
169598944Sobrien      lma = s->lma;
1696218822Sdim      size = bfd_get_section_size (s);
169798944Sobrien      sprintf_vma (tmp1, lma);
169898944Sobrien      sprintf_vma (tmp2, lma + size);
169998944Sobrien      sprintf (target_buf + strlen (target_buf),
170098944Sobrien	       ":%s,%s", tmp1, tmp2);
170146283Sdfr    }
170246283Sdfr  if (anysecs)
170346283Sdfr    {
170446283Sdfr      putpkt (target_buf);
170598944Sobrien      getpkt (target_buf, sizeof (target_buf), 0);
170646283Sdfr    }
170746283Sdfr}
170846283Sdfr
170946283Sdfr/* tstart command:
171098944Sobrien
171146283Sdfr   Tell target to clear any previous trace experiment.
171246283Sdfr   Walk the list of tracepoints, and send them (and their actions)
171346283Sdfr   to the target.  If no errors,
171446283Sdfr   Tell target to start a new trace experiment.  */
171546283Sdfr
171646283Sdfrstatic void
171798944Sobrientrace_start_command (char *args, int from_tty)
171898944Sobrien{				/* STUB_COMM MOSTLY_IMPLEMENTED */
171946283Sdfr  struct tracepoint *t;
172046283Sdfr  char buf[2048];
172146283Sdfr  char **tdp_actions;
172246283Sdfr  char **stepping_actions;
172346283Sdfr  int ndx;
172446283Sdfr  struct cleanup *old_chain = NULL;
172546283Sdfr
172698944Sobrien  dont_repeat ();		/* like "run", dangerous to repeat accidentally */
172798944Sobrien
172846283Sdfr  if (target_is_remote ())
172946283Sdfr    {
173046283Sdfr      putpkt ("QTinit");
173198944Sobrien      remote_get_noisy_reply (target_buf, sizeof (target_buf));
173246283Sdfr      if (strcmp (target_buf, "OK"))
173346283Sdfr	error ("Target does not support this command.");
173446283Sdfr
173546283Sdfr      ALL_TRACEPOINTS (t)
173698944Sobrien      {
173798944Sobrien	char tmp[40];
173846283Sdfr
173998944Sobrien	sprintf_vma (tmp, t->address);
174098944Sobrien	sprintf (buf, "QTDP:%x:%s:%c:%lx:%x", t->number, tmp, /* address */
174198944Sobrien		 t->enabled_p ? 'E' : 'D',
174298944Sobrien		 t->step_count, t->pass_count);
174346283Sdfr
174498944Sobrien	if (t->actions)
174598944Sobrien	  strcat (buf, "-");
174698944Sobrien	putpkt (buf);
174798944Sobrien	remote_get_noisy_reply (target_buf, sizeof (target_buf));
174898944Sobrien	if (strcmp (target_buf, "OK"))
174998944Sobrien	  error ("Target does not support tracepoints.");
175046283Sdfr
175198944Sobrien	if (t->actions)
175298944Sobrien	  {
175398944Sobrien	    encode_actions (t, &tdp_actions, &stepping_actions);
175498944Sobrien	    old_chain = make_cleanup (free_actions_list_cleanup_wrapper,
175598944Sobrien				      tdp_actions);
175698944Sobrien	    (void) make_cleanup (free_actions_list_cleanup_wrapper,
175798944Sobrien				 stepping_actions);
175846283Sdfr
175998944Sobrien	    /* do_single_steps (t); */
176098944Sobrien	    if (tdp_actions)
176198944Sobrien	      {
176298944Sobrien		for (ndx = 0; tdp_actions[ndx]; ndx++)
176398944Sobrien		  {
176498944Sobrien		    QUIT;	/* allow user to bail out with ^C */
176598944Sobrien		    sprintf (buf, "QTDP:-%x:%s:%s%c",
176698944Sobrien			     t->number, tmp, /* address */
176798944Sobrien			     tdp_actions[ndx],
176898944Sobrien			     ((tdp_actions[ndx + 1] || stepping_actions)
176998944Sobrien			      ? '-' : 0));
177098944Sobrien		    putpkt (buf);
177198944Sobrien		    remote_get_noisy_reply (target_buf, sizeof (target_buf));
177298944Sobrien		    if (strcmp (target_buf, "OK"))
177398944Sobrien		      error ("Error on target while setting tracepoints.");
177498944Sobrien		  }
177598944Sobrien	      }
177698944Sobrien	    if (stepping_actions)
177798944Sobrien	      {
177898944Sobrien		for (ndx = 0; stepping_actions[ndx]; ndx++)
177998944Sobrien		  {
178098944Sobrien		    QUIT;	/* allow user to bail out with ^C */
178198944Sobrien		    sprintf (buf, "QTDP:-%x:%s:%s%s%s",
178298944Sobrien			     t->number, tmp, /* address */
178398944Sobrien			     ((ndx == 0) ? "S" : ""),
178498944Sobrien			     stepping_actions[ndx],
178598944Sobrien			     (stepping_actions[ndx + 1] ? "-" : ""));
178698944Sobrien		    putpkt (buf);
178798944Sobrien		    remote_get_noisy_reply (target_buf, sizeof (target_buf));
178898944Sobrien		    if (strcmp (target_buf, "OK"))
178998944Sobrien		      error ("Error on target while setting tracepoints.");
179098944Sobrien		  }
179198944Sobrien	      }
179246283Sdfr
179398944Sobrien	    do_cleanups (old_chain);
179498944Sobrien	  }
179598944Sobrien      }
179646283Sdfr      /* Tell target to treat text-like sections as transparent */
179746283Sdfr      remote_set_transparent_ranges ();
179846283Sdfr      /* Now insert traps and begin collecting data */
179946283Sdfr      putpkt ("QTStart");
180098944Sobrien      remote_get_noisy_reply (target_buf, sizeof (target_buf));
180146283Sdfr      if (strcmp (target_buf, "OK"))
180246283Sdfr	error ("Bogus reply from target: %s", target_buf);
180346283Sdfr      set_traceframe_num (-1);	/* all old traceframes invalidated */
180446283Sdfr      set_tracepoint_num (-1);
180598944Sobrien      set_traceframe_context (-1);
180646283Sdfr      trace_running_p = 1;
180746283Sdfr      if (trace_start_stop_hook)
180898944Sobrien	trace_start_stop_hook (1, from_tty);
180998944Sobrien
181046283Sdfr    }
181146283Sdfr  else
181246283Sdfr    error ("Trace can only be run on remote targets.");
181346283Sdfr}
181446283Sdfr
181546283Sdfr/* tstop command */
181646283Sdfrstatic void
181798944Sobrientrace_stop_command (char *args, int from_tty)
181898944Sobrien{				/* STUB_COMM IS_IMPLEMENTED */
181946283Sdfr  if (target_is_remote ())
182046283Sdfr    {
182146283Sdfr      putpkt ("QTStop");
182298944Sobrien      remote_get_noisy_reply (target_buf, sizeof (target_buf));
182346283Sdfr      if (strcmp (target_buf, "OK"))
182446283Sdfr	error ("Bogus reply from target: %s", target_buf);
182546283Sdfr      trace_running_p = 0;
182646283Sdfr      if (trace_start_stop_hook)
182798944Sobrien	trace_start_stop_hook (0, from_tty);
182846283Sdfr    }
182946283Sdfr  else
183046283Sdfr    error ("Trace can only be run on remote targets.");
183146283Sdfr}
183246283Sdfr
183346283Sdfrunsigned long trace_running_p;
183446283Sdfr
183546283Sdfr/* tstatus command */
183646283Sdfrstatic void
183798944Sobrientrace_status_command (char *args, int from_tty)
183898944Sobrien{				/* STUB_COMM IS_IMPLEMENTED */
183946283Sdfr  if (target_is_remote ())
184046283Sdfr    {
184146283Sdfr      putpkt ("qTStatus");
184298944Sobrien      remote_get_noisy_reply (target_buf, sizeof (target_buf));
184346283Sdfr
184446283Sdfr      if (target_buf[0] != 'T' ||
184546283Sdfr	  (target_buf[1] != '0' && target_buf[1] != '1'))
184646283Sdfr	error ("Bogus reply from target: %s", target_buf);
184746283Sdfr
184846283Sdfr      /* exported for use by the GUI */
184946283Sdfr      trace_running_p = (target_buf[1] == '1');
185046283Sdfr    }
185146283Sdfr  else
185246283Sdfr    error ("Trace can only be run on remote targets.");
185346283Sdfr}
185446283Sdfr
185546283Sdfr/* Worker function for the various flavors of the tfind command */
185646283Sdfrstatic void
185798944Sobrienfinish_tfind_command (char *msg,
185898944Sobrien		      long sizeof_msg,
185998944Sobrien		      int from_tty)
186046283Sdfr{
186146283Sdfr  int target_frameno = -1, target_tracept = -1;
186246283Sdfr  CORE_ADDR old_frame_addr;
186346283Sdfr  struct symbol *old_func;
186446283Sdfr  char *reply;
186546283Sdfr
1866130803Smarcel  old_frame_addr = get_frame_base (get_current_frame ());
186798944Sobrien  old_func = find_pc_function (read_pc ());
186846283Sdfr
186946283Sdfr  putpkt (msg);
187098944Sobrien  reply = remote_get_noisy_reply (msg, sizeof_msg);
187146283Sdfr
187246283Sdfr  while (reply && *reply)
187398944Sobrien    switch (*reply)
187498944Sobrien      {
187598944Sobrien      case 'F':
187698944Sobrien	if ((target_frameno = (int) strtol (++reply, &reply, 16)) == -1)
187798944Sobrien	  {
187898944Sobrien	    /* A request for a non-existant trace frame has failed.
187998944Sobrien	       Our response will be different, depending on FROM_TTY:
188046283Sdfr
188198944Sobrien	       If FROM_TTY is true, meaning that this command was
188298944Sobrien	       typed interactively by the user, then give an error
188398944Sobrien	       and DO NOT change the state of traceframe_number etc.
188446283Sdfr
188598944Sobrien	       However if FROM_TTY is false, meaning that we're either
188698944Sobrien	       in a script, a loop, or a user-defined command, then
188798944Sobrien	       DON'T give an error, but DO change the state of
188898944Sobrien	       traceframe_number etc. to invalid.
188946283Sdfr
189098944Sobrien	       The rationalle is that if you typed the command, you
189198944Sobrien	       might just have committed a typo or something, and you'd
189298944Sobrien	       like to NOT lose your current debugging state.  However
189398944Sobrien	       if you're in a user-defined command or especially in a
189498944Sobrien	       loop, then you need a way to detect that the command
189598944Sobrien	       failed WITHOUT aborting.  This allows you to write
189698944Sobrien	       scripts that search thru the trace buffer until the end,
189798944Sobrien	       and then continue on to do something else.  */
189846283Sdfr
189998944Sobrien	    if (from_tty)
190098944Sobrien	      error ("Target failed to find requested trace frame.");
190198944Sobrien	    else
190298944Sobrien	      {
190398944Sobrien		if (info_verbose)
190498944Sobrien		  printf_filtered ("End of trace buffer.\n");
190598944Sobrien		/* The following will not recurse, since it's special-cased */
190698944Sobrien		trace_find_command ("-1", from_tty);
190798944Sobrien		reply = NULL;	/* break out of loop,
190846283Sdfr				   (avoid recursive nonsense) */
190998944Sobrien	      }
191098944Sobrien	  }
191198944Sobrien	break;
191298944Sobrien      case 'T':
191398944Sobrien	if ((target_tracept = (int) strtol (++reply, &reply, 16)) == -1)
191498944Sobrien	  error ("Target failed to find requested trace frame.");
191598944Sobrien	break;
191698944Sobrien      case 'O':		/* "OK"? */
191798944Sobrien	if (reply[1] == 'K' && reply[2] == '\0')
191898944Sobrien	  reply += 2;
191998944Sobrien	else
192098944Sobrien	  error ("Bogus reply from target: %s", reply);
192198944Sobrien	break;
192298944Sobrien      default:
192346283Sdfr	error ("Bogus reply from target: %s", reply);
192498944Sobrien      }
192546283Sdfr
192646283Sdfr  flush_cached_frames ();
192746283Sdfr  registers_changed ();
1928130803Smarcel  select_frame (get_current_frame ());
192946283Sdfr  set_traceframe_num (target_frameno);
193046283Sdfr  set_tracepoint_num (target_tracept);
193146283Sdfr  if (target_frameno == -1)
193246283Sdfr    set_traceframe_context (-1);
193346283Sdfr  else
193446283Sdfr    set_traceframe_context (read_pc ());
193546283Sdfr
193646283Sdfr  if (from_tty)
193746283Sdfr    {
193846283Sdfr      int source_only;
193946283Sdfr
194046283Sdfr      /* NOTE: in immitation of the step command, try to determine
194198944Sobrien         whether we have made a transition from one function to another.
194298944Sobrien         If so, we'll print the "stack frame" (ie. the new function and
194398944Sobrien         it's arguments) -- otherwise we'll just show the new source line.
194446283Sdfr
194598944Sobrien         This determination is made by checking (1) whether the current
194698944Sobrien         function has changed, and (2) whether the current FP has changed.
194798944Sobrien         Hack: if the FP wasn't collected, either at the current or the
194898944Sobrien         previous frame, assume that the FP has NOT changed.  */
194946283Sdfr
195098944Sobrien      if (old_func == find_pc_function (read_pc ()) &&
195198944Sobrien	  (old_frame_addr == 0 ||
1952130803Smarcel	   get_frame_base (get_current_frame ()) == 0 ||
1953130803Smarcel	   old_frame_addr == get_frame_base (get_current_frame ())))
195446283Sdfr	source_only = -1;
195546283Sdfr      else
195698944Sobrien	source_only = 1;
195746283Sdfr
1958130803Smarcel      print_stack_frame (deprecated_selected_frame,
1959130803Smarcel			 frame_relative_level (deprecated_selected_frame),
1960130803Smarcel			 source_only);
196146283Sdfr      do_displays ();
196246283Sdfr    }
196346283Sdfr}
196446283Sdfr
196546283Sdfr/* trace_find_command takes a trace frame number n,
196646283Sdfr   sends "QTFrame:<n>" to the target,
196746283Sdfr   and accepts a reply that may contain several optional pieces
196846283Sdfr   of information: a frame number, a tracepoint number, and an
196946283Sdfr   indication of whether this is a trap frame or a stepping frame.
197046283Sdfr
197146283Sdfr   The minimal response is just "OK" (which indicates that the
197246283Sdfr   target does not give us a frame number or a tracepoint number).
197346283Sdfr   Instead of that, the target may send us a string containing
197446283Sdfr   any combination of:
197598944Sobrien   F<hexnum>    (gives the selected frame number)
197698944Sobrien   T<hexnum>    (gives the selected tracepoint number)
197798944Sobrien */
197846283Sdfr
197946283Sdfr/* tfind command */
198046283Sdfrstatic void
198198944Sobrientrace_find_command (char *args, int from_tty)
198298944Sobrien{				/* STUB_COMM PART_IMPLEMENTED */
198346283Sdfr  /* this should only be called with a numeric argument */
198446283Sdfr  int frameno = -1;
198546283Sdfr
198646283Sdfr  if (target_is_remote ())
198746283Sdfr    {
198846283Sdfr      if (trace_find_hook)
198998944Sobrien	trace_find_hook (args, from_tty);
199098944Sobrien
199146283Sdfr      if (args == 0 || *args == 0)
199298944Sobrien	{			/* TFIND with no args means find NEXT trace frame. */
199346283Sdfr	  if (traceframe_number == -1)
199446283Sdfr	    frameno = 0;	/* "next" is first one */
199546283Sdfr	  else
199646283Sdfr	    frameno = traceframe_number + 1;
199746283Sdfr	}
199846283Sdfr      else if (0 == strcmp (args, "-"))
199946283Sdfr	{
200046283Sdfr	  if (traceframe_number == -1)
200146283Sdfr	    error ("not debugging trace buffer");
200246283Sdfr	  else if (from_tty && traceframe_number == 0)
200346283Sdfr	    error ("already at start of trace buffer");
200446283Sdfr
200546283Sdfr	  frameno = traceframe_number - 1;
200646283Sdfr	}
200746283Sdfr      else
200898944Sobrien	frameno = parse_and_eval_long (args);
200946283Sdfr
201046283Sdfr      if (frameno < -1)
201146283Sdfr	error ("invalid input (%d is less than zero)", frameno);
201246283Sdfr
201346283Sdfr      sprintf (target_buf, "QTFrame:%x", frameno);
201498944Sobrien      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
201546283Sdfr    }
201646283Sdfr  else
201746283Sdfr    error ("Trace can only be run on remote targets.");
201846283Sdfr}
201946283Sdfr
202046283Sdfr/* tfind end */
202146283Sdfrstatic void
202298944Sobrientrace_find_end_command (char *args, int from_tty)
202346283Sdfr{
202446283Sdfr  trace_find_command ("-1", from_tty);
202546283Sdfr}
202646283Sdfr
202746283Sdfr/* tfind none */
202846283Sdfrstatic void
202998944Sobrientrace_find_none_command (char *args, int from_tty)
203046283Sdfr{
203146283Sdfr  trace_find_command ("-1", from_tty);
203246283Sdfr}
203346283Sdfr
203446283Sdfr/* tfind start */
203546283Sdfrstatic void
203698944Sobrientrace_find_start_command (char *args, int from_tty)
203746283Sdfr{
203846283Sdfr  trace_find_command ("0", from_tty);
203946283Sdfr}
204046283Sdfr
204146283Sdfr/* tfind pc command */
204246283Sdfrstatic void
204398944Sobrientrace_find_pc_command (char *args, int from_tty)
204498944Sobrien{				/* STUB_COMM PART_IMPLEMENTED */
204546283Sdfr  CORE_ADDR pc;
204698944Sobrien  char tmp[40];
204746283Sdfr
204846283Sdfr  if (target_is_remote ())
204946283Sdfr    {
205046283Sdfr      if (args == 0 || *args == 0)
205146283Sdfr	pc = read_pc ();	/* default is current pc */
205246283Sdfr      else
205346283Sdfr	pc = parse_and_eval_address (args);
205446283Sdfr
205598944Sobrien      sprintf_vma (tmp, pc);
205698944Sobrien      sprintf (target_buf, "QTFrame:pc:%s", tmp);
205798944Sobrien      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
205846283Sdfr    }
205946283Sdfr  else
206046283Sdfr    error ("Trace can only be run on remote targets.");
206146283Sdfr}
206246283Sdfr
206346283Sdfr/* tfind tracepoint command */
206446283Sdfrstatic void
206598944Sobrientrace_find_tracepoint_command (char *args, int from_tty)
206698944Sobrien{				/* STUB_COMM PART_IMPLEMENTED */
206746283Sdfr  int tdp;
206846283Sdfr
206946283Sdfr  if (target_is_remote ())
207046283Sdfr    {
207146283Sdfr      if (args == 0 || *args == 0)
2072130803Smarcel	{
2073130803Smarcel	  if (tracepoint_number == -1)
2074130803Smarcel	    error ("No current tracepoint -- please supply an argument.");
2075130803Smarcel	  else
2076130803Smarcel	    tdp = tracepoint_number;	/* default is current TDP */
2077130803Smarcel	}
207846283Sdfr      else
207998944Sobrien	tdp = parse_and_eval_long (args);
208046283Sdfr
208146283Sdfr      sprintf (target_buf, "QTFrame:tdp:%x", tdp);
208298944Sobrien      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
208346283Sdfr    }
208446283Sdfr  else
208546283Sdfr    error ("Trace can only be run on remote targets.");
208646283Sdfr}
208746283Sdfr
208846283Sdfr/* TFIND LINE command:
208998944Sobrien
209046283Sdfr   This command will take a sourceline for argument, just like BREAK
209146283Sdfr   or TRACE (ie. anything that "decode_line_1" can handle).
209298944Sobrien
209346283Sdfr   With no argument, this command will find the next trace frame
209446283Sdfr   corresponding to a source line OTHER THAN THE CURRENT ONE.  */
209546283Sdfr
209646283Sdfrstatic void
209798944Sobrientrace_find_line_command (char *args, int from_tty)
209898944Sobrien{				/* STUB_COMM PART_IMPLEMENTED */
209946283Sdfr  static CORE_ADDR start_pc, end_pc;
210046283Sdfr  struct symtabs_and_lines sals;
210146283Sdfr  struct symtab_and_line sal;
210246283Sdfr  struct cleanup *old_chain;
210398944Sobrien  char   startpc_str[40], endpc_str[40];
210446283Sdfr
210546283Sdfr  if (target_is_remote ())
210646283Sdfr    {
210746283Sdfr      if (args == 0 || *args == 0)
210846283Sdfr	{
2109130803Smarcel	  sal = find_pc_line (get_frame_pc (get_current_frame ()), 0);
211046283Sdfr	  sals.nelts = 1;
211146283Sdfr	  sals.sals = (struct symtab_and_line *)
211246283Sdfr	    xmalloc (sizeof (struct symtab_and_line));
211346283Sdfr	  sals.sals[0] = sal;
211446283Sdfr	}
211546283Sdfr      else
211646283Sdfr	{
211746283Sdfr	  sals = decode_line_spec (args, 1);
211898944Sobrien	  sal = sals.sals[0];
211946283Sdfr	}
212046283Sdfr
212198944Sobrien      old_chain = make_cleanup (xfree, sals.sals);
212246283Sdfr      if (sal.symtab == 0)
212346283Sdfr	{
212446283Sdfr	  printf_filtered ("TFIND: No line number information available");
212546283Sdfr	  if (sal.pc != 0)
212646283Sdfr	    {
212746283Sdfr	      /* This is useful for "info line *0x7f34".  If we can't tell the
212898944Sobrien	         user about a source line, at least let them have the symbolic
212998944Sobrien	         address.  */
213046283Sdfr	      printf_filtered (" for address ");
213146283Sdfr	      wrap_here ("  ");
213246283Sdfr	      print_address (sal.pc, gdb_stdout);
213346283Sdfr	      printf_filtered (";\n -- will attempt to find by PC. \n");
213446283Sdfr	    }
213546283Sdfr	  else
213646283Sdfr	    {
213746283Sdfr	      printf_filtered (".\n");
213898944Sobrien	      return;		/* no line, no PC; what can we do? */
213946283Sdfr	    }
214046283Sdfr	}
214146283Sdfr      else if (sal.line > 0
214246283Sdfr	       && find_line_pc_range (sal, &start_pc, &end_pc))
214346283Sdfr	{
214446283Sdfr	  if (start_pc == end_pc)
214546283Sdfr	    {
214646283Sdfr	      printf_filtered ("Line %d of \"%s\"",
214746283Sdfr			       sal.line, sal.symtab->filename);
214846283Sdfr	      wrap_here ("  ");
214946283Sdfr	      printf_filtered (" is at address ");
215046283Sdfr	      print_address (start_pc, gdb_stdout);
215146283Sdfr	      wrap_here ("  ");
215246283Sdfr	      printf_filtered (" but contains no code.\n");
215346283Sdfr	      sal = find_pc_line (start_pc, 0);
215446283Sdfr	      if (sal.line > 0 &&
215546283Sdfr		  find_line_pc_range (sal, &start_pc, &end_pc) &&
215646283Sdfr		  start_pc != end_pc)
215746283Sdfr		printf_filtered ("Attempting to find line %d instead.\n",
215846283Sdfr				 sal.line);
215946283Sdfr	      else
216046283Sdfr		error ("Cannot find a good line.");
216146283Sdfr	    }
216246283Sdfr	}
216346283Sdfr      else
216446283Sdfr	/* Is there any case in which we get here, and have an address
216546283Sdfr	   which the user would want to see?  If we have debugging symbols
216646283Sdfr	   and no line numbers?  */
216746283Sdfr	error ("Line number %d is out of range for \"%s\".\n",
216846283Sdfr	       sal.line, sal.symtab->filename);
216946283Sdfr
217098944Sobrien      sprintf_vma (startpc_str, start_pc);
217198944Sobrien      sprintf_vma (endpc_str, end_pc - 1);
217246283Sdfr      if (args && *args)	/* find within range of stated line */
217398944Sobrien	sprintf (target_buf, "QTFrame:range:%s:%s", startpc_str, endpc_str);
217446283Sdfr      else			/* find OUTSIDE OF range of CURRENT line */
217598944Sobrien	sprintf (target_buf, "QTFrame:outside:%s:%s", startpc_str, endpc_str);
217698944Sobrien      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
217746283Sdfr      do_cleanups (old_chain);
217846283Sdfr    }
217946283Sdfr  else
218098944Sobrien    error ("Trace can only be run on remote targets.");
218146283Sdfr}
218246283Sdfr
218346283Sdfr/* tfind range command */
218446283Sdfrstatic void
218598944Sobrientrace_find_range_command (char *args, int from_tty)
218698944Sobrien{
218746283Sdfr  static CORE_ADDR start, stop;
218898944Sobrien  char start_str[40], stop_str[40];
218946283Sdfr  char *tmp;
219046283Sdfr
219146283Sdfr  if (target_is_remote ())
219246283Sdfr    {
219346283Sdfr      if (args == 0 || *args == 0)
219498944Sobrien	{		/* XXX FIXME: what should default behavior be? */
219546283Sdfr	  printf_filtered ("Usage: tfind range <startaddr>,<endaddr>\n");
219646283Sdfr	  return;
219746283Sdfr	}
219846283Sdfr
219998944Sobrien      if (0 != (tmp = strchr (args, ',')))
220046283Sdfr	{
220146283Sdfr	  *tmp++ = '\0';	/* terminate start address */
220298944Sobrien	  while (isspace ((int) *tmp))
220346283Sdfr	    tmp++;
220446283Sdfr	  start = parse_and_eval_address (args);
220598944Sobrien	  stop = parse_and_eval_address (tmp);
220646283Sdfr	}
220746283Sdfr      else
220898944Sobrien	{			/* no explicit end address? */
220946283Sdfr	  start = parse_and_eval_address (args);
221098944Sobrien	  stop = start + 1;	/* ??? */
221146283Sdfr	}
221246283Sdfr
221398944Sobrien      sprintf_vma (start_str, start);
221498944Sobrien      sprintf_vma (stop_str, stop);
221598944Sobrien      sprintf (target_buf, "QTFrame:range:%s:%s", start_str, stop_str);
221698944Sobrien      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
221746283Sdfr    }
221846283Sdfr  else
221998944Sobrien    error ("Trace can only be run on remote targets.");
222046283Sdfr}
222146283Sdfr
222246283Sdfr/* tfind outside command */
222346283Sdfrstatic void
222498944Sobrientrace_find_outside_command (char *args, int from_tty)
222598944Sobrien{
222646283Sdfr  CORE_ADDR start, stop;
222798944Sobrien  char start_str[40], stop_str[40];
222846283Sdfr  char *tmp;
222946283Sdfr
223046283Sdfr  if (target_is_remote ())
223146283Sdfr    {
223246283Sdfr      if (args == 0 || *args == 0)
223398944Sobrien	{		/* XXX FIXME: what should default behavior be? */
223446283Sdfr	  printf_filtered ("Usage: tfind outside <startaddr>,<endaddr>\n");
223546283Sdfr	  return;
223646283Sdfr	}
223746283Sdfr
223898944Sobrien      if (0 != (tmp = strchr (args, ',')))
223946283Sdfr	{
224046283Sdfr	  *tmp++ = '\0';	/* terminate start address */
224198944Sobrien	  while (isspace ((int) *tmp))
224246283Sdfr	    tmp++;
224346283Sdfr	  start = parse_and_eval_address (args);
224498944Sobrien	  stop = parse_and_eval_address (tmp);
224546283Sdfr	}
224646283Sdfr      else
224798944Sobrien	{			/* no explicit end address? */
224846283Sdfr	  start = parse_and_eval_address (args);
224998944Sobrien	  stop = start + 1;	/* ??? */
225046283Sdfr	}
225146283Sdfr
225298944Sobrien      sprintf_vma (start_str, start);
225398944Sobrien      sprintf_vma (stop_str, stop);
225498944Sobrien      sprintf (target_buf, "QTFrame:outside:%s:%s", start_str, stop_str);
225598944Sobrien      finish_tfind_command (target_buf, sizeof (target_buf), from_tty);
225646283Sdfr    }
225746283Sdfr  else
225898944Sobrien    error ("Trace can only be run on remote targets.");
225946283Sdfr}
226046283Sdfr
226146283Sdfr/* save-tracepoints command */
226246283Sdfrstatic void
226398944Sobrientracepoint_save_command (char *args, int from_tty)
226446283Sdfr{
226598944Sobrien  struct tracepoint *tp;
226646283Sdfr  struct action_line *line;
226746283Sdfr  FILE *fp;
226846283Sdfr  char *i1 = "    ", *i2 = "      ";
226998944Sobrien  char *indent, *actionline, *pathname;
227098944Sobrien  char tmp[40];
227146283Sdfr
227246283Sdfr  if (args == 0 || *args == 0)
227346283Sdfr    error ("Argument required (file name in which to save tracepoints");
227446283Sdfr
227546283Sdfr  if (tracepoint_chain == 0)
227646283Sdfr    {
227746283Sdfr      warning ("save-tracepoints: no tracepoints to save.\n");
227846283Sdfr      return;
227946283Sdfr    }
228046283Sdfr
228198944Sobrien  pathname = tilde_expand (args);
228298944Sobrien  if (!(fp = fopen (pathname, "w")))
228398944Sobrien    error ("Unable to open file '%s' for saving tracepoints (%s)",
2284130803Smarcel	   args, safe_strerror (errno));
228598944Sobrien  xfree (pathname);
228698944Sobrien
228746283Sdfr  ALL_TRACEPOINTS (tp)
228898944Sobrien  {
228998944Sobrien    if (tp->addr_string)
229098944Sobrien      fprintf (fp, "trace %s\n", tp->addr_string);
229198944Sobrien    else
229298944Sobrien      {
229398944Sobrien	sprintf_vma (tmp, tp->address);
229498944Sobrien	fprintf (fp, "trace *0x%s\n", tmp);
229598944Sobrien      }
229646283Sdfr
229798944Sobrien    if (tp->pass_count)
229898944Sobrien      fprintf (fp, "  passcount %d\n", tp->pass_count);
229946283Sdfr
230098944Sobrien    if (tp->actions)
230198944Sobrien      {
230298944Sobrien	fprintf (fp, "  actions\n");
230398944Sobrien	indent = i1;
230498944Sobrien	for (line = tp->actions; line; line = line->next)
230598944Sobrien	  {
230698944Sobrien	    struct cmd_list_element *cmd;
230746283Sdfr
230898944Sobrien	    QUIT;		/* allow user to bail out with ^C */
230998944Sobrien	    actionline = line->action;
231098944Sobrien	    while (isspace ((int) *actionline))
231198944Sobrien	      actionline++;
231246283Sdfr
231398944Sobrien	    fprintf (fp, "%s%s\n", indent, actionline);
231498944Sobrien	    if (*actionline != '#')	/* skip for comment lines */
231598944Sobrien	      {
231698944Sobrien		cmd = lookup_cmd (&actionline, cmdlist, "", -1, 1);
231798944Sobrien		if (cmd == 0)
231898944Sobrien		  error ("Bad action list item: %s", actionline);
231998944Sobrien		if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
232098944Sobrien		  indent = i2;
232198944Sobrien		else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
232298944Sobrien		  indent = i1;
232398944Sobrien	      }
232498944Sobrien	  }
232598944Sobrien      }
232698944Sobrien  }
232746283Sdfr  fclose (fp);
232846283Sdfr  if (from_tty)
232946283Sdfr    printf_filtered ("Tracepoints saved to file '%s'.\n", args);
233046283Sdfr  return;
233146283Sdfr}
233246283Sdfr
233346283Sdfr/* info scope command: list the locals for a scope.  */
233446283Sdfrstatic void
233598944Sobrienscope_info (char *args, int from_tty)
233646283Sdfr{
233746283Sdfr  struct symtabs_and_lines sals;
233846283Sdfr  struct symbol *sym;
233946283Sdfr  struct minimal_symbol *msym;
234046283Sdfr  struct block *block;
234146283Sdfr  char **canonical, *symname, *save_args = args;
2342130803Smarcel  struct dict_iterator iter;
2343130803Smarcel  int j, count = 0;
234446283Sdfr
234546283Sdfr  if (args == 0 || *args == 0)
234646283Sdfr    error ("requires an argument (function, line or *addr) to define a scope");
234746283Sdfr
2348130803Smarcel  sals = decode_line_1 (&args, 1, NULL, 0, &canonical, NULL);
234946283Sdfr  if (sals.nelts == 0)
235098944Sobrien    return;			/* presumably decode_line_1 has already warned */
235146283Sdfr
235246283Sdfr  /* Resolve line numbers to PC */
235346283Sdfr  resolve_sal_pc (&sals.sals[0]);
235446283Sdfr  block = block_for_pc (sals.sals[0].pc);
235546283Sdfr
235646283Sdfr  while (block != 0)
235746283Sdfr    {
235898944Sobrien      QUIT;			/* allow user to bail out with ^C */
2359130803Smarcel      ALL_BLOCK_SYMBOLS (block, iter, sym)
236046283Sdfr	{
236198944Sobrien	  QUIT;			/* allow user to bail out with ^C */
236246283Sdfr	  if (count == 0)
236346283Sdfr	    printf_filtered ("Scope for %s:\n", save_args);
236446283Sdfr	  count++;
236598944Sobrien
2366130803Smarcel	  symname = DEPRECATED_SYMBOL_NAME (sym);
236746283Sdfr	  if (symname == NULL || *symname == '\0')
236898944Sobrien	    continue;		/* probably botched, certainly useless */
236946283Sdfr
237046283Sdfr	  printf_filtered ("Symbol %s is ", symname);
237198944Sobrien	  switch (SYMBOL_CLASS (sym))
237298944Sobrien	    {
237398944Sobrien	    default:
237498944Sobrien	    case LOC_UNDEF:	/* messed up symbol? */
237598944Sobrien	      printf_filtered ("a bogus symbol, class %d.\n",
237698944Sobrien			       SYMBOL_CLASS (sym));
237798944Sobrien	      count--;		/* don't count this one */
237898944Sobrien	      continue;
237998944Sobrien	    case LOC_CONST:
238098944Sobrien	      printf_filtered ("a constant with value %ld (0x%lx)",
238198944Sobrien			       SYMBOL_VALUE (sym), SYMBOL_VALUE (sym));
238298944Sobrien	      break;
238398944Sobrien	    case LOC_CONST_BYTES:
238498944Sobrien	      printf_filtered ("constant bytes: ");
238598944Sobrien	      if (SYMBOL_TYPE (sym))
238698944Sobrien		for (j = 0; j < TYPE_LENGTH (SYMBOL_TYPE (sym)); j++)
238798944Sobrien		  fprintf_filtered (gdb_stdout, " %02x",
238898944Sobrien				    (unsigned) SYMBOL_VALUE_BYTES (sym)[j]);
238998944Sobrien	      break;
239098944Sobrien	    case LOC_STATIC:
239198944Sobrien	      printf_filtered ("in static storage at address ");
239298944Sobrien	      print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout);
239398944Sobrien	      break;
239498944Sobrien	    case LOC_REGISTER:
239598944Sobrien	      printf_filtered ("a local variable in register $%s",
239698944Sobrien			       REGISTER_NAME (SYMBOL_VALUE (sym)));
239798944Sobrien	      break;
239898944Sobrien	    case LOC_ARG:
239998944Sobrien	    case LOC_LOCAL_ARG:
240098944Sobrien	      printf_filtered ("an argument at stack/frame offset %ld",
240198944Sobrien			       SYMBOL_VALUE (sym));
240298944Sobrien	      break;
240398944Sobrien	    case LOC_LOCAL:
240498944Sobrien	      printf_filtered ("a local variable at frame offset %ld",
240598944Sobrien			       SYMBOL_VALUE (sym));
240698944Sobrien	      break;
240798944Sobrien	    case LOC_REF_ARG:
240898944Sobrien	      printf_filtered ("a reference argument at offset %ld",
240998944Sobrien			       SYMBOL_VALUE (sym));
241098944Sobrien	      break;
241198944Sobrien	    case LOC_REGPARM:
241298944Sobrien	      printf_filtered ("an argument in register $%s",
241398944Sobrien			       REGISTER_NAME (SYMBOL_VALUE (sym)));
241498944Sobrien	      break;
241598944Sobrien	    case LOC_REGPARM_ADDR:
241698944Sobrien	      printf_filtered ("the address of an argument, in register $%s",
241798944Sobrien			       REGISTER_NAME (SYMBOL_VALUE (sym)));
241898944Sobrien	      break;
241998944Sobrien	    case LOC_TYPEDEF:
242098944Sobrien	      printf_filtered ("a typedef.\n");
242198944Sobrien	      continue;
242298944Sobrien	    case LOC_LABEL:
242398944Sobrien	      printf_filtered ("a label at address ");
242498944Sobrien	      print_address_numeric (SYMBOL_VALUE_ADDRESS (sym), 1, gdb_stdout);
242598944Sobrien	      break;
242698944Sobrien	    case LOC_BLOCK:
242798944Sobrien	      printf_filtered ("a function at address ");
242898944Sobrien	      print_address_numeric (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)), 1,
242998944Sobrien				     gdb_stdout);
243098944Sobrien	      break;
243198944Sobrien	    case LOC_BASEREG:
243298944Sobrien	      printf_filtered ("a variable at offset %ld from register $%s",
243398944Sobrien			       SYMBOL_VALUE (sym),
243498944Sobrien			       REGISTER_NAME (SYMBOL_BASEREG (sym)));
243598944Sobrien	      break;
243698944Sobrien	    case LOC_BASEREG_ARG:
243798944Sobrien	      printf_filtered ("an argument at offset %ld from register $%s",
243898944Sobrien			       SYMBOL_VALUE (sym),
243998944Sobrien			       REGISTER_NAME (SYMBOL_BASEREG (sym)));
244098944Sobrien	      break;
244198944Sobrien	    case LOC_UNRESOLVED:
2442130803Smarcel	      msym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (sym), NULL, NULL);
244398944Sobrien	      if (msym == NULL)
244498944Sobrien		printf_filtered ("Unresolved Static");
244598944Sobrien	      else
244698944Sobrien		{
244798944Sobrien		  printf_filtered ("static storage at address ");
244898944Sobrien		  print_address_numeric (SYMBOL_VALUE_ADDRESS (msym), 1,
244998944Sobrien					 gdb_stdout);
245098944Sobrien		}
245198944Sobrien	      break;
245298944Sobrien	    case LOC_OPTIMIZED_OUT:
245398944Sobrien	      printf_filtered ("optimized out.\n");
245498944Sobrien	      continue;
245598944Sobrien	    }
245646283Sdfr	  if (SYMBOL_TYPE (sym))
245798944Sobrien	    printf_filtered (", length %d.\n",
245898944Sobrien			   TYPE_LENGTH (check_typedef (SYMBOL_TYPE (sym))));
245946283Sdfr	}
246046283Sdfr      if (BLOCK_FUNCTION (block))
246146283Sdfr	break;
246246283Sdfr      else
246346283Sdfr	block = BLOCK_SUPERBLOCK (block);
246446283Sdfr    }
246546283Sdfr  if (count <= 0)
246646283Sdfr    printf_filtered ("Scope for %s contains no locals or arguments.\n",
246746283Sdfr		     save_args);
246846283Sdfr}
246946283Sdfr
247046283Sdfr/* worker function (cleanup) */
247146283Sdfrstatic void
247298944Sobrienreplace_comma (void *data)
247346283Sdfr{
247498944Sobrien  char *comma = data;
247546283Sdfr  *comma = ',';
247646283Sdfr}
247746283Sdfr
247846283Sdfr/* tdump command */
247946283Sdfrstatic void
248098944Sobrientrace_dump_command (char *args, int from_tty)
248146283Sdfr{
248298944Sobrien  struct tracepoint *t;
248346283Sdfr  struct action_line *action;
248498944Sobrien  char *action_exp, *next_comma;
248598944Sobrien  struct cleanup *old_cleanups;
248698944Sobrien  int stepping_actions = 0;
248798944Sobrien  int stepping_frame = 0;
248846283Sdfr
248946283Sdfr  if (!target_is_remote ())
249046283Sdfr    {
249146283Sdfr      error ("Trace can only be run on remote targets.");
249246283Sdfr      return;
249346283Sdfr    }
249446283Sdfr
249546283Sdfr  if (tracepoint_number == -1)
249646283Sdfr    {
249746283Sdfr      warning ("No current trace frame.");
249846283Sdfr      return;
249946283Sdfr    }
250046283Sdfr
250146283Sdfr  ALL_TRACEPOINTS (t)
250246283Sdfr    if (t->number == tracepoint_number)
250398944Sobrien    break;
250446283Sdfr
250546283Sdfr  if (t == NULL)
250698944Sobrien    error ("No known tracepoint matches 'current' tracepoint #%d.",
250746283Sdfr	   tracepoint_number);
250846283Sdfr
250946283Sdfr  old_cleanups = make_cleanup (null_cleanup, NULL);
251046283Sdfr
251198944Sobrien  printf_filtered ("Data collected at tracepoint %d, trace frame %d:\n",
251246283Sdfr		   tracepoint_number, traceframe_number);
251346283Sdfr
251446283Sdfr  /* The current frame is a trap frame if the frame PC is equal
251546283Sdfr     to the tracepoint PC.  If not, then the current frame was
251646283Sdfr     collected during single-stepping.  */
251746283Sdfr
2518130803Smarcel  stepping_frame = (t->address != (read_pc () - DECR_PC_AFTER_BREAK));
251946283Sdfr
252046283Sdfr  for (action = t->actions; action; action = action->next)
252146283Sdfr    {
252246283Sdfr      struct cmd_list_element *cmd;
252346283Sdfr
252498944Sobrien      QUIT;			/* allow user to bail out with ^C */
252546283Sdfr      action_exp = action->action;
252698944Sobrien      while (isspace ((int) *action_exp))
252746283Sdfr	action_exp++;
252846283Sdfr
252946283Sdfr      /* The collection actions to be done while stepping are
253098944Sobrien         bracketed by the commands "while-stepping" and "end".  */
253146283Sdfr
253246283Sdfr      if (*action_exp == '#')	/* comment line */
253346283Sdfr	continue;
253446283Sdfr
253546283Sdfr      cmd = lookup_cmd (&action_exp, cmdlist, "", -1, 1);
253646283Sdfr      if (cmd == 0)
253746283Sdfr	error ("Bad action list item: %s", action_exp);
253846283Sdfr
253998944Sobrien      if (cmd_cfunc_eq (cmd, while_stepping_pseudocommand))
254046283Sdfr	stepping_actions = 1;
254198944Sobrien      else if (cmd_cfunc_eq (cmd, end_actions_pseudocommand))
254246283Sdfr	stepping_actions = 0;
254398944Sobrien      else if (cmd_cfunc_eq (cmd, collect_pseudocommand))
254446283Sdfr	{
254546283Sdfr	  /* Display the collected data.
254646283Sdfr	     For the trap frame, display only what was collected at the trap.
254746283Sdfr	     Likewise for stepping frames, display only what was collected
254846283Sdfr	     while stepping.  This means that the two boolean variables,
254946283Sdfr	     STEPPING_FRAME and STEPPING_ACTIONS should be equal.  */
255046283Sdfr	  if (stepping_frame == stepping_actions)
255146283Sdfr	    {
255298944Sobrien	      do
255398944Sobrien		{		/* repeat over a comma-separated list */
255498944Sobrien		  QUIT;		/* allow user to bail out with ^C */
255598944Sobrien		  if (*action_exp == ',')
255698944Sobrien		    action_exp++;
255798944Sobrien		  while (isspace ((int) *action_exp))
255898944Sobrien		    action_exp++;
255946283Sdfr
256098944Sobrien		  next_comma = strchr (action_exp, ',');
256146283Sdfr
256298944Sobrien		  if (0 == strncasecmp (action_exp, "$reg", 4))
256398944Sobrien		    registers_info (NULL, from_tty);
256498944Sobrien		  else if (0 == strncasecmp (action_exp, "$loc", 4))
256598944Sobrien		    locals_info (NULL, from_tty);
256698944Sobrien		  else if (0 == strncasecmp (action_exp, "$arg", 4))
256798944Sobrien		    args_info (NULL, from_tty);
256898944Sobrien		  else
256998944Sobrien		    {		/* variable */
257098944Sobrien		      if (next_comma)
257198944Sobrien			{
257298944Sobrien			  make_cleanup (replace_comma, next_comma);
257398944Sobrien			  *next_comma = '\0';
257498944Sobrien			}
257598944Sobrien		      printf_filtered ("%s = ", action_exp);
257698944Sobrien		      output_command (action_exp, from_tty);
257798944Sobrien		      printf_filtered ("\n");
257898944Sobrien		    }
257998944Sobrien		  if (next_comma)
258098944Sobrien		    *next_comma = ',';
258198944Sobrien		  action_exp = next_comma;
258298944Sobrien		}
258398944Sobrien	      while (action_exp && *action_exp == ',');
258446283Sdfr	    }
258546283Sdfr	}
258646283Sdfr    }
258746283Sdfr  discard_cleanups (old_cleanups);
258846283Sdfr}
258946283Sdfr
259046283Sdfr/* Convert the memory pointed to by mem into hex, placing result in buf.
259146283Sdfr * Return a pointer to the last char put in buf (null)
259246283Sdfr * "stolen" from sparc-stub.c
259346283Sdfr */
259446283Sdfr
259598944Sobrienstatic const char hexchars[] = "0123456789abcdef";
259646283Sdfr
259746283Sdfrstatic unsigned char *
259898944Sobrienmem2hex (unsigned char *mem, unsigned char *buf, int count)
259946283Sdfr{
260046283Sdfr  unsigned char ch;
260146283Sdfr
260246283Sdfr  while (count-- > 0)
260346283Sdfr    {
260446283Sdfr      ch = *mem++;
260546283Sdfr
260646283Sdfr      *buf++ = hexchars[ch >> 4];
260746283Sdfr      *buf++ = hexchars[ch & 0xf];
260846283Sdfr    }
260946283Sdfr
261046283Sdfr  *buf = 0;
261146283Sdfr
261246283Sdfr  return buf;
261346283Sdfr}
261446283Sdfr
261598944Sobrienint
261698944Sobrienget_traceframe_number (void)
261746283Sdfr{
261898944Sobrien  return traceframe_number;
261946283Sdfr}
262046283Sdfr
262146283Sdfr
262246283Sdfr/* module initialization */
262346283Sdfrvoid
262498944Sobrien_initialize_tracepoint (void)
262546283Sdfr{
262698944Sobrien  struct cmd_list_element *c;
262798944Sobrien
262898944Sobrien  tracepoint_chain = 0;
262998944Sobrien  tracepoint_count = 0;
263046283Sdfr  traceframe_number = -1;
263146283Sdfr  tracepoint_number = -1;
263246283Sdfr
263398944Sobrien  set_internalvar (lookup_internalvar ("tpnum"),
263446283Sdfr		   value_from_longest (builtin_type_int, (LONGEST) 0));
263598944Sobrien  set_internalvar (lookup_internalvar ("trace_frame"),
263698944Sobrien		   value_from_longest (builtin_type_int, (LONGEST) - 1));
263746283Sdfr
263846283Sdfr  if (tracepoint_list.list == NULL)
263946283Sdfr    {
264046283Sdfr      tracepoint_list.listsize = 128;
264198944Sobrien      tracepoint_list.list = xmalloc
264246283Sdfr	(tracepoint_list.listsize * sizeof (struct memrange));
264346283Sdfr    }
264446283Sdfr  if (tracepoint_list.aexpr_list == NULL)
264546283Sdfr    {
264646283Sdfr      tracepoint_list.aexpr_listsize = 128;
264746283Sdfr      tracepoint_list.aexpr_list = xmalloc
264846283Sdfr	(tracepoint_list.aexpr_listsize * sizeof (struct agent_expr *));
264946283Sdfr    }
265046283Sdfr
265146283Sdfr  if (stepping_list.list == NULL)
265246283Sdfr    {
265346283Sdfr      stepping_list.listsize = 128;
265498944Sobrien      stepping_list.list = xmalloc
265546283Sdfr	(stepping_list.listsize * sizeof (struct memrange));
265646283Sdfr    }
265746283Sdfr
265846283Sdfr  if (stepping_list.aexpr_list == NULL)
265946283Sdfr    {
266046283Sdfr      stepping_list.aexpr_listsize = 128;
266146283Sdfr      stepping_list.aexpr_list = xmalloc
266246283Sdfr	(stepping_list.aexpr_listsize * sizeof (struct agent_expr *));
266346283Sdfr    }
266446283Sdfr
266598944Sobrien  add_info ("scope", scope_info,
266646283Sdfr	    "List the variables local to a scope");
266746283Sdfr
266898944Sobrien  add_cmd ("tracepoints", class_trace, NULL,
266998944Sobrien	   "Tracing of program execution without stopping the program.",
267046283Sdfr	   &cmdlist);
267146283Sdfr
267246283Sdfr  add_info ("tracepoints", tracepoints_info,
267346283Sdfr	    "Status of tracepoints, or tracepoint number NUMBER.\n\
267446283SdfrConvenience variable \"$tpnum\" contains the number of the\n\
267546283Sdfrlast tracepoint set.");
267646283Sdfr
267746283Sdfr  add_info_alias ("tp", "tracepoints", 1);
267846283Sdfr
267998944Sobrien  c = add_com ("save-tracepoints", class_trace, tracepoint_save_command,
268098944Sobrien	       "Save current tracepoint definitions as a script.\n\
268146283SdfrUse the 'source' command in another debug session to restore them.");
2682130803Smarcel  set_cmd_completer (c, filename_completer);
268346283Sdfr
268498944Sobrien  add_com ("tdump", class_trace, trace_dump_command,
268546283Sdfr	   "Print everything collected at the current tracepoint.");
268646283Sdfr
268798944Sobrien  add_prefix_cmd ("tfind", class_trace, trace_find_command,
268846283Sdfr		  "Select a trace frame;\n\
268946283SdfrNo argument means forward by one frame; '-' meand backward by one frame.",
269046283Sdfr		  &tfindlist, "tfind ", 1, &cmdlist);
269146283Sdfr
269246283Sdfr  add_cmd ("outside", class_trace, trace_find_outside_command,
269346283Sdfr	   "Select a trace frame whose PC is outside the given \
269498944Sobrienrange.\nUsage: tfind outside addr1, addr2",
269546283Sdfr	   &tfindlist);
269646283Sdfr
269746283Sdfr  add_cmd ("range", class_trace, trace_find_range_command,
269846283Sdfr	   "Select a trace frame whose PC is in the given range.\n\
269998944SobrienUsage: tfind range addr1,addr2",
270046283Sdfr	   &tfindlist);
270146283Sdfr
270246283Sdfr  add_cmd ("line", class_trace, trace_find_line_command,
270346283Sdfr	   "Select a trace frame by source line.\n\
270446283SdfrArgument can be a line number (with optional source file), \n\
270546283Sdfra function name, or '*' followed by an address.\n\
270646283SdfrDefault argument is 'the next source line that was traced'.",
270746283Sdfr	   &tfindlist);
270846283Sdfr
270946283Sdfr  add_cmd ("tracepoint", class_trace, trace_find_tracepoint_command,
271046283Sdfr	   "Select a trace frame by tracepoint number.\n\
271146283SdfrDefault is the tracepoint for the current trace frame.",
271246283Sdfr	   &tfindlist);
271346283Sdfr
271446283Sdfr  add_cmd ("pc", class_trace, trace_find_pc_command,
271546283Sdfr	   "Select a trace frame by PC.\n\
271646283SdfrDefault is the current PC, or the PC of the current trace frame.",
271746283Sdfr	   &tfindlist);
271846283Sdfr
271946283Sdfr  add_cmd ("end", class_trace, trace_find_end_command,
272046283Sdfr	   "Synonym for 'none'.\n\
272146283SdfrDe-select any trace frame and resume 'live' debugging.",
272246283Sdfr	   &tfindlist);
272346283Sdfr
272446283Sdfr  add_cmd ("none", class_trace, trace_find_none_command,
272546283Sdfr	   "De-select any trace frame and resume 'live' debugging.",
272646283Sdfr	   &tfindlist);
272746283Sdfr
272846283Sdfr  add_cmd ("start", class_trace, trace_find_start_command,
272946283Sdfr	   "Select the first trace frame in the trace buffer.",
273046283Sdfr	   &tfindlist);
273146283Sdfr
273298944Sobrien  add_com ("tstatus", class_trace, trace_status_command,
273346283Sdfr	   "Display the status of the current trace data collection.");
273446283Sdfr
273598944Sobrien  add_com ("tstop", class_trace, trace_stop_command,
273646283Sdfr	   "Stop trace data collection.");
273746283Sdfr
273846283Sdfr  add_com ("tstart", class_trace, trace_start_command,
273946283Sdfr	   "Start trace data collection.");
274046283Sdfr
274198944Sobrien  add_com ("passcount", class_trace, trace_pass_command,
274246283Sdfr	   "Set the passcount for a tracepoint.\n\
274346283SdfrThe trace will end when the tracepoint has been passed 'count' times.\n\
274446283SdfrUsage: passcount COUNT TPNUM, where TPNUM may also be \"all\";\n\
274546283Sdfrif TPNUM is omitted, passcount refers to the last tracepoint defined.");
274646283Sdfr
274746283Sdfr  add_com ("end", class_trace, end_actions_pseudocommand,
274846283Sdfr	   "Ends a list of commands or actions.\n\
274946283SdfrSeveral GDB commands allow you to enter a list of commands or actions.\n\
275046283SdfrEntering \"end\" on a line by itself is the normal way to terminate\n\
275146283Sdfrsuch a list.\n\n\
275246283SdfrNote: the \"end\" command cannot be used at the gdb prompt.");
275346283Sdfr
275446283Sdfr  add_com ("while-stepping", class_trace, while_stepping_pseudocommand,
275546283Sdfr	   "Specify single-stepping behavior at a tracepoint.\n\
275646283SdfrArgument is number of instructions to trace in single-step mode\n\
275746283Sdfrfollowing the tracepoint.  This command is normally followed by\n\
275846283Sdfrone or more \"collect\" commands, to specify what to collect\n\
275946283Sdfrwhile single-stepping.\n\n\
276046283SdfrNote: this command can only be used in a tracepoint \"actions\" list.");
276146283Sdfr
276298944Sobrien  add_com_alias ("ws", "while-stepping", class_alias, 0);
276398944Sobrien  add_com_alias ("stepping", "while-stepping", class_alias, 0);
276446283Sdfr
276598944Sobrien  add_com ("collect", class_trace, collect_pseudocommand,
276646283Sdfr	   "Specify one or more data items to be collected at a tracepoint.\n\
276746283SdfrAccepts a comma-separated list of (one or more) expressions.  GDB will\n\
276846283Sdfrcollect all data (variables, registers) referenced by that expression.\n\
276946283SdfrAlso accepts the following special arguments:\n\
277046283Sdfr    $regs   -- all registers.\n\
277146283Sdfr    $args   -- all function arguments.\n\
277246283Sdfr    $locals -- all variables local to the block/function scope.\n\
277346283SdfrNote: this command can only be used in a tracepoint \"actions\" list.");
277446283Sdfr
277546283Sdfr  add_com ("actions", class_trace, trace_actions_command,
277646283Sdfr	   "Specify the actions to be taken at a tracepoint.\n\
277746283SdfrTracepoint actions may include collecting of specified data, \n\
277846283Sdfrsingle-stepping, or enabling/disabling other tracepoints, \n\
277946283Sdfrdepending on target's capabilities.");
278046283Sdfr
278198944Sobrien  add_cmd ("tracepoints", class_trace, delete_trace_command,
278246283Sdfr	   "Delete specified tracepoints.\n\
278346283SdfrArguments are tracepoint numbers, separated by spaces.\n\
278446283SdfrNo argument means delete all tracepoints.",
278546283Sdfr	   &deletelist);
278646283Sdfr
278798944Sobrien  add_cmd ("tracepoints", class_trace, disable_trace_command,
278846283Sdfr	   "Disable specified tracepoints.\n\
278946283SdfrArguments are tracepoint numbers, separated by spaces.\n\
279046283SdfrNo argument means disable all tracepoints.",
279146283Sdfr	   &disablelist);
279246283Sdfr
279398944Sobrien  add_cmd ("tracepoints", class_trace, enable_trace_command,
279446283Sdfr	   "Enable specified tracepoints.\n\
279546283SdfrArguments are tracepoint numbers, separated by spaces.\n\
279646283SdfrNo argument means enable all tracepoints.",
279746283Sdfr	   &enablelist);
279846283Sdfr
279998944Sobrien  c = add_com ("trace", class_trace, trace_command,
280098944Sobrien	       "Set a tracepoint at a specified line or function or address.\n\
280146283SdfrArgument may be a line number, function name, or '*' plus an address.\n\
280246283SdfrFor a line number or function, trace at the start of its code.\n\
280346283SdfrIf an address is specified, trace at that exact address.\n\n\
280446283SdfrDo \"help tracepoints\" for info on other tracepoint commands.");
2805130803Smarcel  set_cmd_completer (c, location_completer);
280646283Sdfr
280798944Sobrien  add_com_alias ("tp", "trace", class_alias, 0);
280898944Sobrien  add_com_alias ("tr", "trace", class_alias, 1);
280998944Sobrien  add_com_alias ("tra", "trace", class_alias, 1);
281046283Sdfr  add_com_alias ("trac", "trace", class_alias, 1);
281146283Sdfr}
2812