diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index 2916944897..fa5ac4db38 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -29,6 +29,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "language.h" #include "gdb_string.h" +#include "ax.h" +#include "ax-gdb.h" + /* readline include files */ #include "readline.h" #include "history.h" @@ -40,11 +43,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #endif +/* maximum length of an agent aexpression. + this accounts for the fact that packets are limited to 400 bytes + (which includes everything -- including the checksum), and assumes + the worst case of maximum length for each of the pieces of a + continuation packet. + + NOTE: expressions get mem2hex'ed otherwise this would be twice as + large. (400 - 31)/2 == 184 */ +#define MAX_AGENT_EXPR_LEN 184 + + extern int info_verbose; extern void (*readline_begin_hook) PARAMS ((char *, ...)); extern char * (*readline_hook) PARAMS ((char *)); extern void (*readline_end_hook) PARAMS ((void)); extern void x_command PARAMS ((char *, int)); +extern int addressprint; /* Print machine addresses? */ /* If this definition isn't overridden by the header files, assume that isatty and fileno exist on this system. */ @@ -121,6 +136,12 @@ static void trace_find_outside_command PARAMS ((char *, int)); static void tracepoint_save_command PARAMS ((char *, int)); static void trace_dump_command PARAMS ((char *, int)); +/* support routines */ +static void trace_mention PARAMS ((struct tracepoint *)); + +struct collection_list; +static void add_aexpr PARAMS ((struct collection_list *, struct agent_expr *)); +static unsigned char *mem2hex(unsigned char *, unsigned char *, int); /* Utility: returns true if "target remote" */ static int @@ -162,6 +183,7 @@ remote_get_noisy_reply (buf) { do /* loop on reply from remote stub */ { + QUIT; /* allow user to bail out with ^C */ getpkt (buf, 0); if (buf[0] == 0) error ("Target does not support this command."); @@ -370,11 +392,6 @@ trace_command (arg, from_tty) if (from_tty && info_verbose) printf_filtered ("TRACE %s\n", arg); - if (arg[0] == '/') - { - return; - } - addr_start = arg; sals = decode_line_1 (&arg, 1, (struct symtab *)NULL, 0, &canonical); addr_end = arg; @@ -401,6 +418,8 @@ trace_command (arg, from_tty) else if (addr_start) t->addr_string = savestring (addr_start, addr_end - addr_start); + trace_mention (t); + /* Let the UI know of any additions */ if (create_tracepoint_hook) create_tracepoint_hook (t); @@ -413,6 +432,26 @@ trace_command (arg, from_tty) } } +/* Tell the user we have just set a tracepoint TP. */ + +static void +trace_mention (tp) + struct tracepoint *tp; +{ + printf_filtered ("Tracepoint %d", tp->number); + + if (addressprint || (tp->source_file == NULL)) + { + printf_filtered (" at "); + print_address_numeric (tp->address, 1, gdb_stdout); + } + if (tp->source_file) + printf_filtered (": file %s, line %d.", + tp->source_file, tp->line_number); + + printf_filtered ("\n"); +} + /* Print information on tracepoint number TPNUM_EXP, or all if omitted. */ static void @@ -426,10 +465,6 @@ tracepoints_info (tpnum_exp, from_tty) char wrap_indent[80]; struct symbol *sym; int tpnum = -1; -#if 0 - char *i1 = "\t", *i2 = "\t "; - char *indent, *actionline;; -#endif if (tpnum_exp) tpnum = parse_and_eval_address (tpnum_exp); @@ -478,22 +513,9 @@ tracepoints_info (tpnum_exp, from_tty) if (t->actions) { printf_filtered (" Actions for tracepoint %d: \n", t->number); -/* indent = i1; */ for (action = t->actions; action; action = action->next) { -#if 0 - actionline = action->action; - while (isspace(*actionline)) - actionline++; - - printf_filtered ("%s%s\n", indent, actionline); - if (0 == strncasecmp (actionline, "while-stepping", 14)) - indent = i2; - else if (0 == strncasecmp (actionline, "end", 3)) - indent = i1; -#else printf_filtered ("\t%s\n", action->action); -#endif } } } @@ -598,14 +620,17 @@ get_tracepoint_by_number (arg) } else /* handle tracepoint number */ { - tpnum = strtol (*arg, arg, 10); + tpnum = strtol (*arg, arg, 0); + if (tpnum == 0) /* possible strtol failure */ + while (**arg && !isspace (**arg)) + (*arg)++; /* advance to next white space, if any */ } ALL_TRACEPOINTS (t) if (t->number == tpnum) { return t; } - warning ("No tracepoint number %d.\n", tpnum); + printf_unfiltered ("No tracepoint number %d.\n", tpnum); return NULL; } @@ -626,6 +651,7 @@ map_args_over_tracepoints (args, from_tty, opcode) else while (*args) { + QUIT; /* give user option to bail out with ^C */ if (t = get_tracepoint_by_number (&args)) tracepoint_operation (t, from_tty, opcode); while (*args == ' ' || *args == '\t') @@ -660,9 +686,11 @@ delete_trace_command (args, from_tty) int from_tty; { dont_repeat (); - if (!args || !*args) - if (!query ("Delete all tracepoints? ")) - return; + if (!args || !*args) /* No args implies all tracepoints; */ + if (from_tty) /* confirm only if from_tty... */ + if (tracepoint_chain) /* and if there are tracepoints to delete! */ + if (!query ("Delete all tracepoints? ")) + return; map_args_over_tracepoints (args, from_tty, delete); } @@ -694,6 +722,9 @@ trace_pass_command (args, from_tty) else t1 = get_tracepoint_by_number (&args); + if (*args) + error ("Junk at end of arguments."); + if (t1 == NULL) return; /* error, bad tracepoint number */ @@ -777,6 +808,7 @@ trace_actions_command (args, from_tty) } free_actions (t); + t->step_count = 0; /* read_actions may set this */ read_actions (t); if (readline_end_hook) @@ -787,17 +819,6 @@ trace_actions_command (args, from_tty) /* else error, just return; */ } -enum actionline_type -{ - BADLINE = -1, - GENERIC = 0, - END = 1, - STEPPING = 2, -}; - -static enum actionline_type validate_actionline PARAMS((char **, - struct tracepoint *)); - /* worker function */ static void read_actions (t) @@ -842,7 +863,7 @@ read_actions (t) if (linetype == BADLINE) continue; /* already warned -- collect another line */ - temp = (struct action_line *) xmalloc (sizeof (struct action_line)); + temp = xmalloc (sizeof (struct action_line)); temp->next = NULL; temp->action = line; @@ -864,9 +885,19 @@ read_actions (t) prompt = prompt2; /* change prompt for stepping actions */ else if (linetype == END) if (prompt == prompt2) - prompt = prompt1; /* end of single-stepping actions */ + { + prompt = prompt1; /* end of single-stepping actions */ + } else - break; /* end of actions */ + { /* end of actions */ + if (t->actions->next == NULL) + { + /* an "end" all by itself with no other actions means + this tracepoint has no actions. Discard empty list. */ + free_actions (t); + } + break; + } } #ifdef STOP_SIGNAL if (job_control) @@ -877,14 +908,15 @@ read_actions (t) } /* worker function */ -static enum actionline_type +enum actionline_type validate_actionline (line, t) char **line; struct tracepoint *t; { struct cmd_list_element *c; - struct expression *exp; + struct expression *exp = NULL; value_ptr temp, temp2; + struct cleanup *old_chain = NULL; char *p; for (p = *line; isspace (*p); ) @@ -906,7 +938,11 @@ validate_actionline (line, t) if (c->function.cfunc == collect_pseudocommand) { + struct agent_expr *aexpr; + struct agent_reqs areqs; + do { /* repeat over a comma-separated list */ + QUIT; /* allow user to bail out with ^C */ while (isspace (*p)) p++; @@ -918,63 +954,51 @@ validate_actionline (line, t) if ((0 == strncasecmp ("reg", p + 1, 3)) || (0 == strncasecmp ("arg", p + 1, 3)) || (0 == strncasecmp ("loc", p + 1, 3))) - p = strchr (p, ','); - - else if (p[1] == '(') /* literal memrange */ { - char *temp, *newline; - - newline = malloc (strlen (*line) + 32); - strcpy (newline, *line); - newline[p - *line] = '\0'; - /* newline is now a copy of line, up to "p" (the memrange) */ - temp = parse_and_eval_memrange (p, t->address, - &typecode, &offset, &size) + 1; - /* now compose the memrange as a literal value */ - if (typecode == -1) - sprintf (newline + strlen (newline), - "$(0x%x, %d)", - offset, size); - else - sprintf (newline + strlen (newline), - "$($%s, 0x%x, %d)", - reg_names[typecode], offset, size); - /* now add the remainder of the old line to the new one */ - p = newline + strlen (newline); - if (temp && *temp) - strcat (newline, temp); - free (*line); - *line = newline; + p = strchr (p, ','); + continue; } + /* else fall thru, treat p as an expression and parse it! */ } - else - { - exp = parse_exp_1 (&p, block_for_pc (t->address), 1); + exp = parse_exp_1 (&p, block_for_pc (t->address), 1); + old_chain = make_cleanup (free_current_contents, &exp); - if (exp->elts[0].opcode != OP_VAR_VALUE && - exp->elts[0].opcode != UNOP_MEMVAL && - /*exp->elts[0].opcode != OP_LONG && */ - /*exp->elts[0].opcode != UNOP_CAST && */ - exp->elts[0].opcode != OP_REGISTER) - { - warning ("collect requires a variable or register name.\n"); - return BADLINE; - } - if (exp->elts[0].opcode == OP_VAR_VALUE) - if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST) - { - warning ("%s is constant (value %d): will not be collected.", - SYMBOL_NAME (exp->elts[2].symbol), - SYMBOL_VALUE (exp->elts[2].symbol)); - return BADLINE; - } - else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT) - { - warning ("%s is optimized away and cannot be collected.", - SYMBOL_NAME (exp->elts[2].symbol)); - return BADLINE; - } - } + if (exp->elts[0].opcode == OP_VAR_VALUE) + if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_CONST) + { + warning ("%s is constant (value %d): will not be collected.", + SYMBOL_NAME (exp->elts[2].symbol), + SYMBOL_VALUE (exp->elts[2].symbol)); + return BADLINE; + } + else if (SYMBOL_CLASS (exp->elts[2].symbol) == LOC_OPTIMIZED_OUT) + { + warning ("%s is optimized away and cannot be collected.", + SYMBOL_NAME (exp->elts[2].symbol)); + return BADLINE; + } + + /* we have something to collect, make sure that the expr to + bytecode translator can handle it and that it's not too long */ + aexpr = gen_trace_for_expr(exp); + (void) make_cleanup (free_agent_expr, aexpr); + + if (aexpr->len > MAX_AGENT_EXPR_LEN) + error ("expression too complicated, try simplifying"); + + ax_reqs(aexpr, &areqs); + (void) make_cleanup (free, areqs.reg_mask); + + if (areqs.flaw != agent_flaw_none) + error ("malformed expression"); + + if (areqs.min_height < 0) + error ("gdb: Internal error: expression has min height < 0"); + + if (areqs.max_height > 20) + error ("expression too complicated, try simplifying"); + + do_cleanups (old_chain); } while (p && *p++ == ','); return GENERIC; } @@ -986,17 +1010,12 @@ validate_actionline (line, t) p++; steparg = p; - if (*p) + if (*p == '\0' || + (t->step_count = strtol (p, &p, 0)) == 0) { - t->step_count = strtol (p, &p, 0); - if (t->step_count == 0) - { - warning ("'%s' evaluates to zero -- command ignored."); - return BADLINE; - } + warning ("bad step-count: command ignored.", *line); + return BADLINE; } - else - t->step_count = -1; return STEPPING; } else if (c->function.cfunc == end_actions_pseudocommand) @@ -1036,66 +1055,28 @@ struct collection_list { long listsize; long next_memrange; struct memrange *list; + long aexpr_listsize; /* size of array pointed to by expr_list elt */ + long next_aexpr_elt; + struct agent_expr **aexpr_list; + } tracepoint_list, stepping_list; /* MEMRANGE functions: */ -/* parse a memrange spec from command input */ -static char * -parse_and_eval_memrange (arg, addr, typecode, offset, size) - char *arg; - CORE_ADDR addr; - long *typecode, *size; - bfd_signed_vma *offset; -{ - char *start = arg; - struct expression *exp; - value_ptr val; - - if (*arg++ != '$' || *arg++ != '(') - error ("Internal: bad argument to parse_and_eval_memrange: %s", start); - - if (*arg == '$') /* register for relative memrange? */ - { - exp = parse_exp_1 (&arg, block_for_pc (addr), 1); - if (exp->elts[0].opcode != OP_REGISTER) - error ("Bad register operand for memrange: %s", start); - if (*arg++ != ',') - error ("missing comma for memrange: %s", start); - *typecode = exp->elts[1].longconst; - } - else - *typecode = -1; /* absolute memrange; */ - - exp = parse_exp_1 (&arg, 0, 1); - *offset = value_as_pointer (evaluate_expression (exp)); - - /* now parse the size */ - if (*arg++ != ',') - error ("missing comma for memrange: %s", start); - - exp = parse_exp_1 (&arg, 0, 0); - *size = value_as_long (evaluate_expression (exp)); - - if (info_verbose) - printf_filtered ("Collecting memrange: (0x%x,0x%x,0x%x)\n", - *typecode, *offset, *size); - - return arg; -} +static int memrange_cmp PARAMS ((const void *, const void *)); /* compare memranges for qsort */ static int -memrange_cmp (voidpa, voidpb) - void *voidpa, *voidpb; +memrange_cmp (va, vb) + const void *va; + const void *vb; { - struct memrange *a, *b; + const struct memrange *a = va, *b = vb; - a = (struct memrange *) voidpa; - b = (struct memrange *) voidpb; - - if (a->type < b->type) return -1; - if (a->type > b->type) return 1; + if (a->type < b->type) + return -1; + if (a->type > b->type) + return 1; if (a->type == 0) { if ((bfd_vma) a->start < (bfd_vma) b->start) return -1; @@ -1103,8 +1084,10 @@ memrange_cmp (voidpa, voidpb) } else { - if (a->start < b->start) return -1; - if (a->start > b->start) return 1; + if (a->start < b->start) + return -1; + if (a->start > b->start) + return 1; } return 0; } @@ -1174,7 +1157,7 @@ add_memrange (memranges, type, base, len) if (memranges->next_memrange >= memranges->listsize) { memranges->listsize *= 2; - memranges->list = (struct memrange *) xrealloc (memranges->list, + memranges->list = xrealloc (memranges->list, memranges->listsize); } @@ -1269,7 +1252,7 @@ static void add_local_symbols (collect, pc, type) struct collection_list *collect; CORE_ADDR pc; - char type; + int type; { struct symbol *sym; struct block *block; @@ -1278,6 +1261,7 @@ add_local_symbols (collect, pc, type) block = block_for_pc (pc); while (block != 0) { + QUIT; /* allow user to bail out with ^C */ nsyms = BLOCK_NSYMS (block); for (i = 0; i < nsyms; i++) { @@ -1320,19 +1304,34 @@ static void clear_collection_list (list) struct collection_list *list; { + int ndx; + list->next_memrange = 0; + for (ndx = 0; ndx < list->next_aexpr_elt; ndx++) + { + free_agent_expr(list->aexpr_list[ndx]); + list->aexpr_list[ndx] = NULL; + } + list->next_aexpr_elt = 0; memset (list->regs_mask, 0, sizeof (list->regs_mask)); } /* reduce a collection list to string form (for gdb protocol) */ -static char * +static char ** stringify_collection_list (list, string) struct collection_list *list; char *string; { - char *end = string; + char temp_buf[2048]; + int count; + int ndx = 0; + char *(*str_list)[]; + char *end; long i; + count = 1 + list->next_memrange + list->next_aexpr_elt + 1; + str_list = (char *(*)[])xmalloc(count * sizeof (char *)); + for (i = sizeof (list->regs_mask) - 1; i > 0; i--) if (list->regs_mask[i] != 0) /* skip leading zeroes in regs_mask */ break; @@ -1340,55 +1339,111 @@ stringify_collection_list (list, string) { if (info_verbose) printf_filtered ("\nCollecting registers (mask): 0x"); + end = temp_buf; *end++='R'; for (; i >= 0; i--) { + QUIT; /* allow user to bail out with ^C */ if (info_verbose) printf_filtered ("%02X", list->regs_mask[i]); sprintf (end, "%02X", list->regs_mask[i]); end += 2; } + (*str_list)[ndx] = savestring(temp_buf, end - temp_buf); + ndx++; } if (info_verbose) printf_filtered ("\n"); if (list->next_memrange > 0 && info_verbose) printf_filtered ("Collecting memranges: \n"); - for (i = 0; i < list->next_memrange; i++) + for (i = 0, count = 0, end = temp_buf; i < list->next_memrange; i++) { + QUIT; /* allow user to bail out with ^C */ if (info_verbose) printf_filtered ("(%d, 0x%x, %d)\n", list->list[i].type, list->list[i].start, list->list[i].end - list->list[i].start); + if (count + 27 > MAX_AGENT_EXPR_LEN) + { + (*str_list)[ndx] = savestring(temp_buf, count); + ndx++; + count = 0; + end = temp_buf; + } sprintf (end, "M%X,%X,%X", list->list[i].type, list->list[i].start, list->list[i].end - list->list[i].start); + count += strlen (end); end += strlen (end); } - if (end == string) + + for (i = 0; i < list->next_aexpr_elt; i++) + { + QUIT; /* allow user to bail out with ^C */ + if ((count + 10 + 2 * list->aexpr_list[i]->len) > MAX_AGENT_EXPR_LEN) + { + (*str_list)[ndx] = savestring(temp_buf, count); + ndx++; + count = 0; + end = temp_buf; + } + sprintf (end, "X%08X,", list->aexpr_list[i]->len); + end += 10; /* 'X' + 8 hex digits + ',' */ + count += 10; + + end = mem2hex(list->aexpr_list[i]->buf, end, list->aexpr_list[i]->len); + count += 2 * list->aexpr_list[i]->len; + } + + if (count != 0) + { + (*str_list)[ndx] = savestring(temp_buf, count); + ndx++; + count = 0; + end = temp_buf; + } + (*str_list)[ndx] = NULL; + + if (ndx == 0) return NULL; else - return string; + return *str_list; +} + +void +free_actions_list(actions_list) + char **actions_list; +{ + int ndx; + + if (actions_list == 0) + return; + + for (ndx = 0; actions_list[ndx]; ndx++) + free(actions_list[ndx]); + + free(actions_list); } /* render all actions into gdb protocol */ static void -encode_actions (t, tdp_actions, step_count, stepping_actions) +encode_actions (t, tdp_actions, stepping_actions) struct tracepoint *t; - char **tdp_actions; - unsigned long *step_count; - char **stepping_actions; + char ***tdp_actions; + char ***stepping_actions; { static char tdp_buff[2048], step_buff[2048]; char *action_exp; - struct expression *exp; + struct expression *exp = NULL; struct action_line *action; bfd_signed_vma offset; long i; value_ptr tempval; struct collection_list *collect; struct cmd_list_element *cmd; + struct agent_expr *aexpr; clear_collection_list (&tracepoint_list); clear_collection_list (&stepping_list); @@ -1399,6 +1454,7 @@ encode_actions (t, tdp_actions, step_count, stepping_actions) for (action = t->actions; action; action = action->next) { + QUIT; /* allow user to bail out with ^C */ action_exp = action->action; while (isspace (*action_exp)) action_exp++; @@ -1413,6 +1469,7 @@ encode_actions (t, tdp_actions, step_count, stepping_actions) if (cmd->function.cfunc == collect_pseudocommand) { do { /* repeat over a comma-separated list */ + QUIT; /* allow user to bail out with ^C */ while (isspace (*action_exp)) action_exp++; @@ -1432,63 +1489,53 @@ encode_actions (t, tdp_actions, step_count, stepping_actions) add_local_symbols (collect, t->address, 'L'); action_exp = strchr (action_exp, ','); /* more? */ } - else if (action_exp[0] == '$' && - action_exp[1] == '(') /* literal memrange */ - { - long typecode, size; - bfd_signed_vma offset; - - action_exp = parse_and_eval_memrange (action_exp, - t->address, - &typecode, - &offset, - &size); - add_memrange (collect, typecode, offset, size); - } else { unsigned long addr, len; + struct cleanup *old_chain = NULL; + struct cleanup *old_chain1 = NULL; + struct agent_reqs areqs; exp = parse_exp_1 (&action_exp, block_for_pc (t->address), 1); - switch (exp->elts[0].opcode) { - case OP_REGISTER: - i = exp->elts[1].longconst; - if (info_verbose) - printf_filtered ("OP_REGISTER: "); - add_register (collect, i); - break; - case UNOP_MEMVAL: - /* safe because we know it's a simple expression */ - tempval = evaluate_expression (exp); - addr = VALUE_ADDRESS (tempval) + VALUE_OFFSET (tempval); - len = TYPE_LENGTH (check_typedef (exp->elts[1].type)); - add_memrange (collect, -1, addr, len); - break; + old_chain = make_cleanup (free_current_contents, &exp); - case OP_VAR_VALUE: - collect_symbol (collect, exp->elts[2].symbol); - break; -#if 0 - case OP_LONG: - addr = exp->elts[2].longconst; - if (*action_exp == ':') - { - exp = parse_exp_1 (&action_exp, - block_for_pc (t->address), - 1); - if (exp->elts[0].opcode == OP_LONG) - len = exp->elts[2].longconst; - else - error ("length field requires a literal long const"); - } - else - len = 4; + aexpr = gen_trace_for_expr (exp); - add_memrange (collect, -1, addr, len); - break; -#endif - } + old_chain1 = make_cleanup (free_agent_expr, aexpr); + + ax_reqs (aexpr, &areqs); + if (areqs.flaw != agent_flaw_none) + error ("malformed expression"); + + if (areqs.min_height < 0) + error ("gdb: Internal error: expression has min height < 0"); + if (areqs.max_height > 20) + error ("expression too complicated, try simplifying"); + + discard_cleanups (old_chain1); + add_aexpr (collect, aexpr); + + /* take care of the registers */ + if (areqs.reg_mask_len > 0) + { + int ndx1; + int ndx2; + + for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++) + { + QUIT; /* allow user to bail out with ^C */ + if (areqs.reg_mask[ndx1] != 0) + { + /* assume chars have 8 bits */ + for (ndx2 = 0; ndx2 < 8; ndx2++) + if (areqs.reg_mask[ndx1] & (1 << ndx2)) + /* it's used -- record it */ + add_register (collect, ndx1 * 8 + ndx2); + } + } + } + do_cleanups (old_chain); } } while (action_exp && *action_exp++ == ','); } @@ -1507,15 +1554,32 @@ encode_actions (t, tdp_actions, step_count, stepping_actions) memrange_sortmerge (&tracepoint_list); memrange_sortmerge (&stepping_list); - *tdp_actions = stringify_collection_list (&tracepoint_list, tdp_buff); - *stepping_actions = stringify_collection_list (&stepping_list, step_buff); + *tdp_actions = stringify_collection_list (&tracepoint_list, &tdp_buff); + *stepping_actions = stringify_collection_list (&stepping_list, &step_buff); } +static void +add_aexpr(collect, aexpr) + struct collection_list *collect; + struct agent_expr *aexpr; +{ + if (collect->next_aexpr_elt >= collect->aexpr_listsize) + { + collect->aexpr_list = + xrealloc (collect->aexpr_list, + 2 * collect->aexpr_listsize * sizeof (struct agent_expr *)); + collect->aexpr_listsize *= 2; + } + collect->aexpr_list[collect->next_aexpr_elt] = aexpr; + collect->next_aexpr_elt++; +} + + static char target_buf[2048]; /* tstart command: - Tell target to lear any previous trace experiment. + Tell target to clear any previous trace experiment. Walk the list of tracepoints, and send them (and their actions) to the target. If no errors, Tell target to start a new trace experiment. */ @@ -1527,9 +1591,10 @@ trace_start_command (args, from_tty) { /* STUB_COMM MOSTLY_IMPLEMENTED */ struct tracepoint *t; char buf[2048]; - char *tdp_actions; - char *stepping_actions; - unsigned long step_count; + char **tdp_actions; + char **stepping_actions; + int ndx; + struct cleanup *old_chain = NULL; dont_repeat (); /* like "run", dangerous to repeat accidentally */ @@ -1549,30 +1614,56 @@ trace_start_command (args, from_tty) sprintf (buf, "QTDP:%x:%x:%c:%x:%x", t->number, t->address, t->enabled == enabled ? 'E' : 'D', t->step_count, t->pass_count); + if (t->actions) - { - encode_actions (t, &tdp_actions, &step_count, &stepping_actions); - /* do_single_steps (t); */ - if (tdp_actions) - { - if (strlen (buf) + strlen (tdp_actions) >= sizeof (buf)) - error ("Actions for tracepoint %d too complex; please simplify.", - t->number); - strcat (buf, tdp_actions); - } - if (stepping_actions) - { - strcat (buf, "S"); - if (strlen (buf) + strlen (stepping_actions) >= sizeof (buf)) - error ("Actions for tracepoint %d too complex; please simplify.", - t->number); - strcat (buf, stepping_actions); - } - } + strcat (buf, "-"); putpkt (buf); remote_get_noisy_reply (target_buf); if (strcmp (target_buf, "OK")) error ("Target does not support tracepoints."); + + if (t->actions) + { + encode_actions (t, &tdp_actions, &stepping_actions); + old_chain = make_cleanup (free_actions_list, tdp_actions); + (void) make_cleanup (free_actions_list, stepping_actions); + + /* do_single_steps (t); */ + if (tdp_actions) + { + for (ndx = 0; tdp_actions[ndx]; ndx++) + { + QUIT; /* allow user to bail out with ^C */ + sprintf (buf, "QTDP:-%x:%x:%s%c", + t->number, t->address, + tdp_actions[ndx], + ((tdp_actions[ndx+1] || stepping_actions) + ? '-' : 0)); + putpkt (buf); + remote_get_noisy_reply (target_buf); + if (strcmp (target_buf, "OK")) + error ("Error on target while setting tracepoints."); + } + } + if (stepping_actions) + { + for (ndx = 0; stepping_actions[ndx]; ndx++) + { + QUIT; /* allow user to bail out with ^C */ + sprintf (buf, "QTDP:-%x:%x:%s%s%s", + t->number, t->address, + ((ndx == 0) ? "S" : ""), + stepping_actions[ndx], + (stepping_actions[ndx+1] ? "-" : "")); + putpkt (buf); + remote_get_noisy_reply (target_buf); + if (strcmp (target_buf, "OK")) + error ("Error on target while setting tracepoints."); + } + } + + do_cleanups (old_chain); + } } putpkt ("QTStart"); remote_get_noisy_reply (target_buf); @@ -1584,7 +1675,7 @@ trace_start_command (args, from_tty) trace_running_p = 1; } else - printf_filtered ("Trace can only be run on remote targets.\n"); + error ("Trace can only be run on remote targets."); } /* tstop command */ @@ -1619,9 +1710,9 @@ trace_status_command (args, from_tty) remote_get_noisy_reply (target_buf); if (target_buf[0] != 'T' || - (target_buf[1] != '0' && target_buf[1] != '1')) - error ("Bogus reply from target: %s", target_buf); - + (target_buf[1] != '0' && target_buf[1] != '1')) + error ("Bogus reply from target: %s", target_buf); + /* exported for use by the GUI */ trace_running_p = (target_buf[1] == '1'); } @@ -1782,23 +1873,11 @@ trace_find_command (args, from_tty) else frameno = parse_and_eval_address (args); + if (frameno < -1) + error ("invalid input (%d is less than zero)", frameno); + sprintf (target_buf, "QTFrame:%x", frameno); -#if 0 - putpkt (target_buf); - tmp = remote_get_noisy_reply (target_buf); - - if (frameno == -1) /* end trace debugging */ - { /* hopefully the stub has complied! */ - if (0 != strcmp (tmp, "OK")) - error ("Bogus response from target: %s", tmp); - - finish_tfind_command (NULL, from_tty); - } - else - finish_tfind_command (tmp, from_tty); -#else finish_tfind_command (target_buf, from_tty); -#endif } else error ("Trace can only be run on remote targets."); @@ -1849,14 +1928,7 @@ trace_find_pc_command (args, from_tty) pc = parse_and_eval_address (args); sprintf (target_buf, "QTFrame:pc:%x", pc); -#if 0 - putpkt (target_buf); - tmp = remote_get_noisy_reply (target_buf); - - finish_tfind_command (tmp, from_tty); -#else finish_tfind_command (target_buf, from_tty); -#endif } else error ("Trace can only be run on remote targets."); @@ -1882,14 +1954,7 @@ trace_find_tracepoint_command (args, from_tty) tdp = parse_and_eval_address (args); sprintf (target_buf, "QTFrame:tdp:%x", tdp); -#if 0 - putpkt (target_buf); - tmp = remote_get_noisy_reply (target_buf); - - finish_tfind_command (tmp, from_tty); -#else finish_tfind_command (target_buf, from_tty); -#endif } else error ("Trace can only be run on remote targets."); @@ -1984,14 +2049,7 @@ trace_find_line_command (args, from_tty) sprintf (target_buf, "QTFrame:range:%x:%x", start_pc, end_pc - 1); else /* find OUTSIDE OF range of CURRENT line */ sprintf (target_buf, "QTFrame:outside:%x:%x", start_pc, end_pc - 1); -#if 0 - putpkt (target_buf); - tmp = remote_get_noisy_reply (target_buf); - - finish_tfind_command (tmp, from_tty); -#else finish_tfind_command (target_buf, from_tty); -#endif do_cleanups (old_chain); } else @@ -2031,14 +2089,7 @@ trace_find_range_command (args, from_tty) } sprintf (target_buf, "QTFrame:range:%x:%x", start, stop); -#if 0 - putpkt (target_buf); - tmp = remote_get_noisy_reply (target_buf); - - finish_tfind_command (tmp, from_tty); -#else finish_tfind_command (target_buf, from_tty); -#endif } else error ("Trace can only be run on remote targets."); @@ -2077,14 +2128,7 @@ trace_find_outside_command (args, from_tty) } sprintf (target_buf, "QTFrame:outside:%x:%x", start, stop); -#if 0 - putpkt (target_buf); - tmp = remote_get_noisy_reply (target_buf); - - finish_tfind_command (tmp, from_tty); -#else finish_tfind_command (target_buf, from_tty); -#endif } else error ("Trace can only be run on remote targets."); @@ -2132,6 +2176,7 @@ tracepoint_save_command (args, from_tty) { struct cmd_list_element *cmd; + QUIT; /* allow user to bail out with ^C */ actionline = line->action; while (isspace(*actionline)) actionline++; @@ -2183,9 +2228,11 @@ scope_info (args, from_tty) while (block != 0) { + QUIT; /* allow user to bail out with ^C */ nsyms = BLOCK_NSYMS (block); for (i = 0; i < nsyms; i++) { + QUIT; /* allow user to bail out with ^C */ if (count == 0) printf_filtered ("Scope for %s:\n", save_args); count++; @@ -2314,6 +2361,12 @@ trace_dump_command (args, from_tty) int stepping_actions = 0; int stepping_frame = 0; + if (!target_is_remote ()) + { + error ("Trace can only be run on remote targets."); + return; + } + if (tracepoint_number == -1) { warning ("No current trace frame."); @@ -2343,6 +2396,7 @@ trace_dump_command (args, from_tty) { struct cmd_list_element *cmd; + QUIT; /* allow user to bail out with ^C */ action_exp = action->action; while (isspace (*action_exp)) action_exp++; @@ -2371,7 +2425,7 @@ trace_dump_command (args, from_tty) if (stepping_frame == stepping_actions) { do { /* repeat over a comma-separated list */ - QUIT; + QUIT; /* allow user to bail out with ^C */ if (*action_exp == ',') action_exp++; while (isspace (*action_exp)) @@ -2385,23 +2439,6 @@ trace_dump_command (args, from_tty) locals_info (NULL, from_tty); else if (0 == strncasecmp (action_exp, "$arg", 4)) args_info (NULL, from_tty); - else if (action_exp[0] == '$' && action_exp[1] == '(') - { /* memrange */ - long typecode, size; - bfd_signed_vma offset; - char fmt[40]; - - action_exp = parse_and_eval_memrange (action_exp, - read_pc (), - &typecode, - &offset, - &size); - if (typecode != 0 && typecode != -1) - offset += read_register (typecode); - sprintf (fmt, "/%dxb 0x%x", size, offset); - x_command (fmt, from_tty); - next_comma = strchr (action_exp, ','); - } else { /* variable */ if (next_comma) @@ -2423,6 +2460,40 @@ trace_dump_command (args, from_tty) discard_cleanups (old_cleanups); } +/* Convert the memory pointed to by mem into hex, placing result in buf. + * Return a pointer to the last char put in buf (null) + * "stolen" from sparc-stub.c + */ + +static const char hexchars[]="0123456789abcdef"; + +static unsigned char * +mem2hex(mem, buf, count) + unsigned char *mem; + unsigned char *buf; + int count; +{ + unsigned char ch; + + while (count-- > 0) + { + ch = *mem++; + + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch & 0xf]; + } + + *buf = 0; + + return buf; +} + +int get_traceframe_number() +{ + return traceframe_number; +} + + /* module initialization */ void _initialize_tracepoint () @@ -2435,21 +2506,35 @@ _initialize_tracepoint () set_internalvar (lookup_internalvar ("tpnum"), value_from_longest (builtin_type_int, (LONGEST) 0)); set_internalvar (lookup_internalvar ("trace_frame"), - value_from_longest (builtin_type_int, (LONGEST) 0)); + value_from_longest (builtin_type_int, (LONGEST) -1)); if (tracepoint_list.list == NULL) { tracepoint_list.listsize = 128; - tracepoint_list.list = (struct memrange *) xmalloc + tracepoint_list.list = xmalloc (tracepoint_list.listsize * sizeof (struct memrange)); } + if (tracepoint_list.aexpr_list == NULL) + { + tracepoint_list.aexpr_listsize = 128; + tracepoint_list.aexpr_list = xmalloc + (tracepoint_list.aexpr_listsize * sizeof (struct agent_expr *)); + } + if (stepping_list.list == NULL) { stepping_list.listsize = 128; - stepping_list.list = (struct memrange *) xmalloc + stepping_list.list = xmalloc (stepping_list.listsize * sizeof (struct memrange)); } + if (stepping_list.aexpr_list == NULL) + { + stepping_list.aexpr_listsize = 128; + stepping_list.aexpr_list = xmalloc + (stepping_list.aexpr_listsize * sizeof (struct agent_expr *)); + } + add_info ("scope", scope_info, "List the variables local to a scope"); @@ -2551,14 +2636,12 @@ Note: this command can only be used in a tracepoint \"actions\" list."); add_com ("collect", class_trace, collect_pseudocommand, "Specify one or more data items to be collected at a tracepoint.\n\ -Accepts a comma-separated list of (one or more) arguments.\n\ -Things that may be collected include registers, variables, plus\n\ -the following special arguments:\n\ +Accepts a comma-separated list of (one or more) expressions. GDB will\n\ +collect all data (variables, registers) referenced by that expression.\n\ +Also accepts the following special arguments:\n\ $regs -- all registers.\n\ $args -- all function arguments.\n\ $locals -- all variables local to the block/function scope.\n\ - $(addr,len) -- a literal memory range.\n\ - $($reg,addr,len) -- a register-relative literal memory range.\n\n\ Note: this command can only be used in a tracepoint \"actions\" list."); add_com ("actions", class_trace, trace_actions_command, diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h index 8f6198fe90..889cd54e33 100644 --- a/gdb/tracepoint.h +++ b/gdb/tracepoint.h @@ -90,6 +90,15 @@ struct tracepoint int thread; }; +enum actionline_type +{ + BADLINE = -1, + GENERIC = 0, + END = 1, + STEPPING = 2, +}; + + /* The tracepont chain of all tracepoints */ extern struct tracepoint *tracepoint_chain; @@ -103,7 +112,11 @@ void (*delete_tracepoint_hook) PARAMS ((struct tracepoint *)); void (*modify_tracepoint_hook) PARAMS ((struct tracepoint *)); struct tracepoint *get_tracepoint_by_number PARAMS ((char **)); +int get_traceframe_number PARAMS ((void)); void free_actions PARAMS((struct tracepoint *)); +enum actionline_type validate_actionline PARAMS((char **, + struct tracepoint *)); + /* Walk the following statement or block through all tracepoints. ALL_TRACEPOINTS_SAFE does so even if the statment deletes the current