| Index: gdb/ax-gdb.c
|
| diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
|
| index 845153da8c9272385ee9b4a546b858ad30860d54..4f68128cd854a5285724e6638de9217aa5848584 100644
|
| --- a/gdb/ax-gdb.c
|
| +++ b/gdb/ax-gdb.c
|
| @@ -1,7 +1,6 @@
|
| /* GDB-specific functions for operating on agent expressions.
|
|
|
| - Copyright (C) 1998-2001, 2003, 2007-2012 Free Software Foundation,
|
| - Inc.
|
| + Copyright (C) 1998-2013 Free Software Foundation, Inc.
|
|
|
| This file is part of GDB.
|
|
|
| @@ -31,7 +30,7 @@
|
| #include "target.h"
|
| #include "ax.h"
|
| #include "ax-gdb.h"
|
| -#include "gdb_string.h"
|
| +#include <string.h>
|
| #include "block.h"
|
| #include "regcache.h"
|
| #include "user-regs.h"
|
| @@ -313,36 +312,6 @@ maybe_const_expr (union exp_element **pc)
|
| sizes), and this is simpler.) */
|
|
|
|
|
| -/* Generating bytecode from GDB expressions: the `trace' kludge */
|
| -
|
| -/* The compiler in this file is a general-purpose mechanism for
|
| - translating GDB expressions into bytecode. One ought to be able to
|
| - find a million and one uses for it.
|
| -
|
| - However, at the moment it is HOPELESSLY BRAIN-DAMAGED for the sake
|
| - of expediency. Let he who is without sin cast the first stone.
|
| -
|
| - For the data tracing facility, we need to insert `trace' bytecodes
|
| - before each data fetch; this records all the memory that the
|
| - expression touches in the course of evaluation, so that memory will
|
| - be available when the user later tries to evaluate the expression
|
| - in GDB.
|
| -
|
| - This should be done (I think) in a post-processing pass, that walks
|
| - an arbitrary agent expression and inserts `trace' operations at the
|
| - appropriate points. But it's much faster to just hack them
|
| - directly into the code. And since we're in a crunch, that's what
|
| - I've done.
|
| -
|
| - Setting the flag trace_kludge to non-zero enables the code that
|
| - emits the trace bytecodes at the appropriate points. */
|
| -int trace_kludge;
|
| -
|
| -/* Inspired by trace_kludge, this indicates that pointers to chars
|
| - should get an added tracenz bytecode to record nonzero bytes, up to
|
| - a length that is the value of trace_string_kludge. */
|
| -int trace_string_kludge;
|
| -
|
| /* Scan for all static fields in the given class, including any base
|
| classes, and generate tracing bytecodes for each. */
|
|
|
| @@ -367,9 +336,9 @@ gen_trace_static_fields (struct gdbarch *gdbarch,
|
| {
|
| case axs_lvalue_memory:
|
| {
|
| - int length = TYPE_LENGTH (check_typedef (value.type));
|
| -
|
| - ax_const_l (ax, length);
|
| + /* Initialize the TYPE_LENGTH if it is a typedef. */
|
| + check_typedef (value.type);
|
| + ax_const_l (ax, TYPE_LENGTH (value.type));
|
| ax_simple (ax, aop_trace);
|
| }
|
| break;
|
| @@ -402,19 +371,19 @@ gen_traced_pop (struct gdbarch *gdbarch,
|
| struct agent_expr *ax, struct axs_value *value)
|
| {
|
| int string_trace = 0;
|
| - if (trace_string_kludge
|
| + if (ax->trace_string
|
| && TYPE_CODE (value->type) == TYPE_CODE_PTR
|
| && c_textual_element_type (check_typedef (TYPE_TARGET_TYPE (value->type)),
|
| 's'))
|
| string_trace = 1;
|
|
|
| - if (trace_kludge)
|
| + if (ax->tracing)
|
| switch (value->kind)
|
| {
|
| case axs_rvalue:
|
| if (string_trace)
|
| {
|
| - ax_const_l (ax, trace_string_kludge);
|
| + ax_const_l (ax, ax->trace_string);
|
| ax_simple (ax, aop_tracenz);
|
| }
|
| else
|
| @@ -425,23 +394,24 @@ gen_traced_pop (struct gdbarch *gdbarch,
|
|
|
| case axs_lvalue_memory:
|
| {
|
| - int length = TYPE_LENGTH (check_typedef (value->type));
|
| -
|
| if (string_trace)
|
| ax_simple (ax, aop_dup);
|
|
|
| + /* Initialize the TYPE_LENGTH if it is a typedef. */
|
| + check_typedef (value->type);
|
| +
|
| /* There's no point in trying to use a trace_quick bytecode
|
| here, since "trace_quick SIZE pop" is three bytes, whereas
|
| "const8 SIZE trace" is also three bytes, does the same
|
| thing, and the simplest code which generates that will also
|
| work correctly for objects with large sizes. */
|
| - ax_const_l (ax, length);
|
| + ax_const_l (ax, TYPE_LENGTH (value->type));
|
| ax_simple (ax, aop_trace);
|
|
|
| if (string_trace)
|
| {
|
| ax_simple (ax, aop_ref32);
|
| - ax_const_l (ax, trace_string_kludge);
|
| + ax_const_l (ax, ax->trace_string);
|
| ax_simple (ax, aop_tracenz);
|
| }
|
| }
|
| @@ -459,7 +429,7 @@ gen_traced_pop (struct gdbarch *gdbarch,
|
| if (string_trace)
|
| {
|
| ax_reg (ax, value->u.reg);
|
| - ax_const_l (ax, trace_string_kludge);
|
| + ax_const_l (ax, ax->trace_string);
|
| ax_simple (ax, aop_tracenz);
|
| }
|
| break;
|
| @@ -469,7 +439,7 @@ gen_traced_pop (struct gdbarch *gdbarch,
|
| ax_simple (ax, aop_pop);
|
|
|
| /* To trace C++ classes with static fields stored elsewhere. */
|
| - if (trace_kludge
|
| + if (ax->tracing
|
| && (TYPE_CODE (value->type) == TYPE_CODE_STRUCT
|
| || TYPE_CODE (value->type) == TYPE_CODE_UNION))
|
| gen_trace_static_fields (gdbarch, ax, value->type);
|
| @@ -509,7 +479,7 @@ gen_extend (struct agent_expr *ax, struct type *type)
|
| static void
|
| gen_fetch (struct agent_expr *ax, struct type *type)
|
| {
|
| - if (trace_kludge)
|
| + if (ax->tracing)
|
| {
|
| /* Record the area of memory we're about to fetch. */
|
| ax_trace_quick (ax, TYPE_LENGTH (type));
|
| @@ -662,6 +632,12 @@ gen_var_ref (struct gdbarch *gdbarch, struct agent_expr *ax,
|
| value->type = check_typedef (SYMBOL_TYPE (var));
|
| value->optimized_out = 0;
|
|
|
| + if (SYMBOL_COMPUTED_OPS (var) != NULL)
|
| + {
|
| + SYMBOL_COMPUTED_OPS (var)->tracepoint_var_ref (var, gdbarch, ax, value);
|
| + return;
|
| + }
|
| +
|
| /* I'm imitating the code in read_var_value. */
|
| switch (SYMBOL_CLASS (var))
|
| {
|
| @@ -750,13 +726,7 @@ gen_var_ref (struct gdbarch *gdbarch, struct agent_expr *ax,
|
| break;
|
|
|
| case LOC_COMPUTED:
|
| - /* FIXME: cagney/2004-01-26: It should be possible to
|
| - unconditionally call the SYMBOL_COMPUTED_OPS method when available.
|
| - Unfortunately DWARF 2 stores the frame-base (instead of the
|
| - function) location in a function's symbol. Oops! For the
|
| - moment enable this when/where applicable. */
|
| - SYMBOL_COMPUTED_OPS (var)->tracepoint_var_ref (var, gdbarch, ax, value);
|
| - break;
|
| + gdb_assert_not_reached (_("LOC_COMPUTED variable missing a method"));
|
|
|
| case LOC_OPTIMIZED_OUT:
|
| /* Flag this, but don't say anything; leave it up to callers to
|
| @@ -1361,7 +1331,7 @@ gen_bitfield_ref (struct expression *exp, struct agent_expr *ax,
|
| /* Add the offset. */
|
| gen_offset (ax, offset / TARGET_CHAR_BIT);
|
|
|
| - if (trace_kludge)
|
| + if (ax->tracing)
|
| {
|
| /* Record the area of memory we're about to fetch. */
|
| ax_trace_quick (ax, op_size / TARGET_CHAR_BIT);
|
| @@ -1930,7 +1900,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
|
| if (tsv)
|
| {
|
| ax_tsv (ax, aop_setv, tsv->number);
|
| - if (trace_kludge)
|
| + if (ax->tracing)
|
| ax_tsv (ax, aop_tracev, tsv->number);
|
| }
|
| else
|
| @@ -1957,7 +1927,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
|
| {
|
| /* The tsv will be the left half of the binary operation. */
|
| ax_tsv (ax, aop_getv, tsv->number);
|
| - if (trace_kludge)
|
| + if (ax->tracing)
|
| ax_tsv (ax, aop_tracev, tsv->number);
|
| /* Trace state variables are always 64-bit integers. */
|
| value1.kind = axs_rvalue;
|
| @@ -1966,7 +1936,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
|
| gen_expr_binop_rest (exp, op2, pc, ax, value, &value1, &value2);
|
| /* We have a result of the binary op, set the tsv. */
|
| ax_tsv (ax, aop_setv, tsv->number);
|
| - if (trace_kludge)
|
| + if (ax->tracing)
|
| ax_tsv (ax, aop_tracev, tsv->number);
|
| }
|
| else
|
| @@ -2047,7 +2017,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
|
| if (tsv)
|
| {
|
| ax_tsv (ax, aop_getv, tsv->number);
|
| - if (trace_kludge)
|
| + if (ax->tracing)
|
| ax_tsv (ax, aop_tracev, tsv->number);
|
| /* Trace state variables are always 64-bit integers. */
|
| value->kind = axs_rvalue;
|
| @@ -2076,6 +2046,23 @@ gen_expr (struct expression *exp, union exp_element **pc,
|
| }
|
| break;
|
|
|
| + case UNOP_CAST_TYPE:
|
| + {
|
| + int offset;
|
| + struct value *val;
|
| + struct type *type;
|
| +
|
| + ++*pc;
|
| + offset = *pc - exp->elts;
|
| + val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS);
|
| + type = value_type (val);
|
| + *pc = &exp->elts[offset];
|
| +
|
| + gen_expr (exp, pc, ax, value);
|
| + gen_cast (ax, value, type);
|
| + }
|
| + break;
|
| +
|
| case UNOP_MEMVAL:
|
| {
|
| struct type *type = check_typedef ((*pc)[1].type);
|
| @@ -2094,6 +2081,31 @@ gen_expr (struct expression *exp, union exp_element **pc,
|
| }
|
| break;
|
|
|
| + case UNOP_MEMVAL_TYPE:
|
| + {
|
| + int offset;
|
| + struct value *val;
|
| + struct type *type;
|
| +
|
| + ++*pc;
|
| + offset = *pc - exp->elts;
|
| + val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS);
|
| + type = value_type (val);
|
| + *pc = &exp->elts[offset];
|
| +
|
| + gen_expr (exp, pc, ax, value);
|
| +
|
| + /* If we have an axs_rvalue or an axs_lvalue_memory, then we
|
| + already have the right value on the stack. For
|
| + axs_lvalue_register, we must convert. */
|
| + if (value->kind == axs_lvalue_register)
|
| + require_rvalue (ax, value);
|
| +
|
| + value->type = type;
|
| + value->kind = axs_lvalue_memory;
|
| + }
|
| + break;
|
| +
|
| case UNOP_PLUS:
|
| (*pc)++;
|
| /* + FOO is equivalent to 0 + FOO, which can be optimized. */
|
| @@ -2213,6 +2225,8 @@ gen_expr (struct expression *exp, union exp_element **pc,
|
| break;
|
|
|
| case OP_TYPE:
|
| + case OP_TYPEOF:
|
| + case OP_DECLTYPE:
|
| error (_("Attempt to use a type name as an expression."));
|
|
|
| default:
|
| @@ -2380,7 +2394,7 @@ gen_expr_binop_rest (struct expression *exp,
|
|
|
| struct agent_expr *
|
| gen_trace_for_var (CORE_ADDR scope, struct gdbarch *gdbarch,
|
| - struct symbol *var)
|
| + struct symbol *var, int trace_string)
|
| {
|
| struct cleanup *old_chain = 0;
|
| struct agent_expr *ax = new_agent_expr (gdbarch, scope);
|
| @@ -2388,7 +2402,8 @@ gen_trace_for_var (CORE_ADDR scope, struct gdbarch *gdbarch,
|
|
|
| old_chain = make_cleanup_free_agent_expr (ax);
|
|
|
| - trace_kludge = 1;
|
| + ax->tracing = 1;
|
| + ax->trace_string = trace_string;
|
| gen_var_ref (gdbarch, ax, &value, var);
|
|
|
| /* If there is no actual variable to trace, flag it by returning
|
| @@ -2420,7 +2435,8 @@ gen_trace_for_var (CORE_ADDR scope, struct gdbarch *gdbarch,
|
| caller can then use the ax_reqs function to discover which
|
| registers it relies upon. */
|
| struct agent_expr *
|
| -gen_trace_for_expr (CORE_ADDR scope, struct expression *expr)
|
| +gen_trace_for_expr (CORE_ADDR scope, struct expression *expr,
|
| + int trace_string)
|
| {
|
| struct cleanup *old_chain = 0;
|
| struct agent_expr *ax = new_agent_expr (expr->gdbarch, scope);
|
| @@ -2430,7 +2446,8 @@ gen_trace_for_expr (CORE_ADDR scope, struct expression *expr)
|
| old_chain = make_cleanup_free_agent_expr (ax);
|
|
|
| pc = expr->elts;
|
| - trace_kludge = 1;
|
| + ax->tracing = 1;
|
| + ax->trace_string = trace_string;
|
| value.optimized_out = 0;
|
| gen_expr (expr, &pc, ax, &value);
|
|
|
| @@ -2465,7 +2482,7 @@ gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
|
| old_chain = make_cleanup_free_agent_expr (ax);
|
|
|
| pc = expr->elts;
|
| - trace_kludge = 0;
|
| + ax->tracing = 0;
|
| value.optimized_out = 0;
|
| gen_expr (expr, &pc, ax, &value);
|
|
|
| @@ -2482,7 +2499,8 @@ gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
|
| }
|
|
|
| struct agent_expr *
|
| -gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch)
|
| +gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch,
|
| + int trace_string)
|
| {
|
| struct cleanup *old_chain = 0;
|
| struct agent_expr *ax = new_agent_expr (gdbarch, scope);
|
| @@ -2490,7 +2508,8 @@ gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch)
|
|
|
| old_chain = make_cleanup_free_agent_expr (ax);
|
|
|
| - trace_kludge = 1;
|
| + ax->tracing = 1;
|
| + ax->trace_string = trace_string;
|
|
|
| gdbarch_gen_return_address (gdbarch, ax, &value, scope);
|
|
|
| @@ -2514,27 +2533,26 @@ gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch)
|
| struct agent_expr *
|
| gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
|
| CORE_ADDR function, LONGEST channel,
|
| - char *format, int fmtlen,
|
| + const char *format, int fmtlen,
|
| struct format_piece *frags,
|
| int nargs, struct expression **exprs)
|
| {
|
| - struct expression *expr;
|
| struct cleanup *old_chain = 0;
|
| struct agent_expr *ax = new_agent_expr (gdbarch, scope);
|
| union exp_element *pc;
|
| struct axs_value value;
|
| - int i, tem, bot, fr, flen;
|
| - char *fmt;
|
| + int tem;
|
|
|
| old_chain = make_cleanup_free_agent_expr (ax);
|
|
|
| + /* We're computing values, not doing side effects. */
|
| + ax->tracing = 0;
|
| +
|
| /* Evaluate and push the args on the stack in reverse order,
|
| for simplicity of collecting them on the target side. */
|
| for (tem = nargs - 1; tem >= 0; --tem)
|
| {
|
| pc = exprs[tem]->elts;
|
| - /* We're computing values, not doing side effects. */
|
| - trace_kludge = 0;
|
| value.optimized_out = 0;
|
| gen_expr (exprs[tem], &pc, ax, &value);
|
| require_rvalue (ax, &value);
|
| @@ -2561,32 +2579,38 @@ gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
|
| }
|
|
|
| static void
|
| -agent_eval_command_one (char *exp, int eval, CORE_ADDR pc)
|
| +agent_eval_command_one (const char *exp, int eval, CORE_ADDR pc)
|
| {
|
| struct cleanup *old_chain = 0;
|
| struct expression *expr;
|
| struct agent_expr *agent;
|
| + const char *arg;
|
| + int trace_string = 0;
|
|
|
| if (!eval)
|
| {
|
| - trace_string_kludge = 0;
|
| if (*exp == '/')
|
| - exp = decode_agent_options (exp);
|
| + exp = decode_agent_options (exp, &trace_string);
|
| }
|
|
|
| - if (!eval && strcmp (exp, "$_ret") == 0)
|
| + arg = exp;
|
| + if (!eval && strcmp (arg, "$_ret") == 0)
|
| {
|
| - agent = gen_trace_for_return_address (pc, get_current_arch ());
|
| + agent = gen_trace_for_return_address (pc, get_current_arch (),
|
| + trace_string);
|
| old_chain = make_cleanup_free_agent_expr (agent);
|
| }
|
| else
|
| {
|
| - expr = parse_exp_1 (&exp, pc, block_for_pc (pc), 0);
|
| + expr = parse_exp_1 (&arg, pc, block_for_pc (pc), 0);
|
| old_chain = make_cleanup (free_current_contents, &expr);
|
| if (eval)
|
| - agent = gen_eval_for_expr (pc, expr);
|
| + {
|
| + gdb_assert (trace_string == 0);
|
| + agent = gen_eval_for_expr (pc, expr);
|
| + }
|
| else
|
| - agent = gen_trace_for_expr (pc, expr);
|
| + agent = gen_trace_for_expr (pc, expr, trace_string);
|
| make_cleanup_free_agent_expr (agent);
|
| }
|
|
|
| @@ -2674,8 +2698,8 @@ maint_agent_printf_command (char *exp, int from_tty)
|
| struct expression *argvec[100];
|
| struct agent_expr *agent;
|
| struct frame_info *fi = get_current_frame (); /* need current scope */
|
| - char *cmdrest;
|
| - char *format_start, *format_end;
|
| + const char *cmdrest;
|
| + const char *format_start, *format_end;
|
| struct format_piece *fpieces;
|
| int nargs;
|
|
|
| @@ -2691,7 +2715,7 @@ maint_agent_printf_command (char *exp, int from_tty)
|
|
|
| cmdrest = exp;
|
|
|
| - cmdrest = skip_spaces (cmdrest);
|
| + cmdrest = skip_spaces_const (cmdrest);
|
|
|
| if (*cmdrest++ != '"')
|
| error (_("Must start with a format string."));
|
| @@ -2707,19 +2731,19 @@ maint_agent_printf_command (char *exp, int from_tty)
|
| if (*cmdrest++ != '"')
|
| error (_("Bad format string, non-terminated '\"'."));
|
|
|
| - cmdrest = skip_spaces (cmdrest);
|
| + cmdrest = skip_spaces_const (cmdrest);
|
|
|
| if (*cmdrest != ',' && *cmdrest != 0)
|
| error (_("Invalid argument syntax"));
|
|
|
| if (*cmdrest == ',')
|
| cmdrest++;
|
| - cmdrest = skip_spaces (cmdrest);
|
| + cmdrest = skip_spaces_const (cmdrest);
|
|
|
| nargs = 0;
|
| while (*cmdrest != '\0')
|
| {
|
| - char *cmd1;
|
| + const char *cmd1;
|
|
|
| cmd1 = cmdrest;
|
| expr = parse_exp_1 (&cmd1, 0, (struct block *) 0, 1);
|
|
|