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