/* GDB-specific functions for operating on agent expressions.
- Copyright (C) 1998-2001, 2003, 2007-2012 Free Software Foundation,
- Inc.
+ Copyright (C) 1998-2014 Free Software Foundation, Inc.
This file is part of GDB.
#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"
#include "tracepoint.h"
#include "cp-support.h"
#include "arch-utils.h"
+#include "cli/cli-utils.h"
+#include "linespec.h"
#include "valprint.h"
#include "c-lang.h"
+#include "format.h"
+
/* To make sense of this file, you should read doc/agentexpr.texi.
Then look at the types and enums in ax-gdb.h. For the code itself,
look at gen_expr, towards the bottom; that's the main function that
sizes), and this is simpler.) */
\f
-/* 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. */
{
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;
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
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);
}
}
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;
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);
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));
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))
{
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
/* 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);
if (tsv)
{
ax_tsv (ax, aop_setv, tsv->number);
- if (trace_kludge)
+ if (ax->tracing)
ax_tsv (ax, aop_tracev, tsv->number);
}
else
{
/* 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;
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
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;
}
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);
}
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. */
break;
case OP_TYPE:
+ case OP_TYPEOF:
+ case OP_DECLTYPE:
error (_("Attempt to use a type name as an expression."));
default:
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);
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
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);
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);
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);
}
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);
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);
return ax;
}
+/* Given a collection of printf-style arguments, generate code to
+ evaluate the arguments and pass everything to a special
+ bytecode. */
+
+struct agent_expr *
+gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
+ CORE_ADDR function, LONGEST channel,
+ const char *format, int fmtlen,
+ struct format_piece *frags,
+ int nargs, struct expression **exprs)
+{
+ struct cleanup *old_chain = 0;
+ struct agent_expr *ax = new_agent_expr (gdbarch, scope);
+ union exp_element *pc;
+ struct axs_value value;
+ 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;
+ value.optimized_out = 0;
+ gen_expr (exprs[tem], &pc, ax, &value);
+ require_rvalue (ax, &value);
+ }
+
+ /* Push function and channel. */
+ ax_const_l (ax, channel);
+ ax_const_l (ax, function);
+
+ /* Issue the printf bytecode proper. */
+ ax_simple (ax, aop_printf);
+ ax_simple (ax, nargs);
+ ax_string (ax, format, fmtlen);
+
+ /* And terminate. */
+ ax_simple (ax, aop_end);
+
+ /* We have successfully built the agent expr, so cancel the cleanup
+ request. If we add more cleanups that we always want done, this
+ will have to get more complicated. */
+ discard_cleanups (old_chain);
+
+ return ax;
+}
+
static void
-agent_command (char *exp, int from_tty)
+agent_eval_command_one (const char *exp, int eval, CORE_ADDR pc)
{
struct cleanup *old_chain = 0;
struct expression *expr;
struct agent_expr *agent;
- struct frame_info *fi = get_current_frame (); /* need current scope */
+ const char *arg;
+ int trace_string = 0;
- /* We don't deal with overlay debugging at the moment. We need to
- think more carefully about this. If you copy this code into
- another command, change the error message; the user shouldn't
- have to know anything about agent expressions. */
- if (overlay_debugging)
- error (_("GDB can't do agent expression translation with overlays."));
-
- if (exp == 0)
- error_no_arg (_("expression to translate"));
-
- trace_string_kludge = 0;
- if (*exp == '/')
- exp = decode_agent_options (exp);
+ if (!eval)
+ {
+ if (*exp == '/')
+ exp = decode_agent_options (exp, &trace_string);
+ }
- /* Recognize the return address collection directive specially. Note
- that it is not really an expression of any sort. */
- if (strcmp (exp, "$_ret") == 0)
+ arg = exp;
+ if (!eval && strcmp (arg, "$_ret") == 0)
{
- agent = gen_trace_for_return_address (get_frame_pc (fi),
- 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_expression (exp);
+ expr = parse_exp_1 (&arg, pc, block_for_pc (pc), 0);
old_chain = make_cleanup (free_current_contents, &expr);
- agent = gen_trace_for_expr (get_frame_pc (fi), expr);
+ if (eval)
+ {
+ gdb_assert (trace_string == 0);
+ agent = gen_eval_for_expr (pc, expr);
+ }
+ else
+ agent = gen_trace_for_expr (pc, expr, trace_string);
make_cleanup_free_agent_expr (agent);
}
dont_repeat ();
}
+static void
+agent_command_1 (char *exp, int eval)
+{
+ /* We don't deal with overlay debugging at the moment. We need to
+ think more carefully about this. If you copy this code into
+ another command, change the error message; the user shouldn't
+ have to know anything about agent expressions. */
+ if (overlay_debugging)
+ error (_("GDB can't do agent expression translation with overlays."));
+
+ if (exp == 0)
+ error_no_arg (_("expression to translate"));
+
+ if (check_for_argument (&exp, "-at", sizeof ("-at") - 1))
+ {
+ struct linespec_result canonical;
+ int ix;
+ struct linespec_sals *iter;
+ struct cleanup *old_chain;
+
+ exp = skip_spaces (exp);
+ init_linespec_result (&canonical);
+ decode_line_full (&exp, DECODE_LINE_FUNFIRSTLINE,
+ (struct symtab *) NULL, 0, &canonical,
+ NULL, NULL);
+ old_chain = make_cleanup_destroy_linespec_result (&canonical);
+ exp = skip_spaces (exp);
+ if (exp[0] == ',')
+ {
+ exp++;
+ exp = skip_spaces (exp);
+ }
+ for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
+ {
+ int i;
+
+ for (i = 0; i < iter->sals.nelts; i++)
+ agent_eval_command_one (exp, eval, iter->sals.sals[i].pc);
+ }
+ do_cleanups (old_chain);
+ }
+ else
+ agent_eval_command_one (exp, eval, get_frame_pc (get_current_frame ()));
+
+ dont_repeat ();
+}
+
+static void
+agent_command (char *exp, int from_tty)
+{
+ agent_command_1 (exp, 0);
+}
+
/* Parse the given expression, compile it into an agent expression
that does direct evaluation, and display the resulting
expression. */
static void
agent_eval_command (char *exp, int from_tty)
+{
+ agent_command_1 (exp, 1);
+}
+
+/* Parse the given expression, compile it into an agent expression
+ that does a printf, and display the resulting expression. */
+
+static void
+maint_agent_printf_command (char *exp, int from_tty)
{
struct cleanup *old_chain = 0;
struct expression *expr;
+ struct expression *argvec[100];
struct agent_expr *agent;
struct frame_info *fi = get_current_frame (); /* need current scope */
+ const char *cmdrest;
+ const char *format_start, *format_end;
+ struct format_piece *fpieces;
+ int nargs;
/* We don't deal with overlay debugging at the moment. We need to
think more carefully about this. If you copy this code into
if (exp == 0)
error_no_arg (_("expression to translate"));
- expr = parse_expression (exp);
- old_chain = make_cleanup (free_current_contents, &expr);
- agent = gen_eval_for_expr (get_frame_pc (fi), expr);
+ cmdrest = exp;
+
+ cmdrest = skip_spaces_const (cmdrest);
+
+ if (*cmdrest++ != '"')
+ error (_("Must start with a format string."));
+
+ format_start = cmdrest;
+
+ fpieces = parse_format_string (&cmdrest);
+
+ old_chain = make_cleanup (free_format_pieces_cleanup, &fpieces);
+
+ format_end = cmdrest;
+
+ if (*cmdrest++ != '"')
+ error (_("Bad format string, non-terminated '\"'."));
+
+ cmdrest = skip_spaces_const (cmdrest);
+
+ if (*cmdrest != ',' && *cmdrest != 0)
+ error (_("Invalid argument syntax"));
+
+ if (*cmdrest == ',')
+ cmdrest++;
+ cmdrest = skip_spaces_const (cmdrest);
+
+ nargs = 0;
+ while (*cmdrest != '\0')
+ {
+ const char *cmd1;
+
+ cmd1 = cmdrest;
+ expr = parse_exp_1 (&cmd1, 0, (struct block *) 0, 1);
+ argvec[nargs] = expr;
+ ++nargs;
+ cmdrest = cmd1;
+ if (*cmdrest == ',')
+ ++cmdrest;
+ /* else complain? */
+ }
+
+
+ agent = gen_printf (get_frame_pc (fi), get_current_arch (), 0, 0,
+ format_start, format_end - format_start,
+ fpieces, nargs, argvec);
make_cleanup_free_agent_expr (agent);
ax_reqs (agent);
ax_print (gdb_stdout, agent);
_initialize_ax_gdb (void)
{
add_cmd ("agent", class_maintenance, agent_command,
- _("Translate an expression into "
- "remote agent bytecode for tracing."),
+ _("\
+Translate an expression into remote agent bytecode for tracing.\n\
+Usage: maint agent [-at location,] EXPRESSION\n\
+If -at is given, generate remote agent bytecode for this location.\n\
+If not, generate remote agent bytecode for current frame pc address."),
&maintenancelist);
add_cmd ("agent-eval", class_maintenance, agent_eval_command,
+ _("\
+Translate an expression into remote agent bytecode for evaluation.\n\
+Usage: maint agent-eval [-at location,] EXPRESSION\n\
+If -at is given, generate remote agent bytecode for this location.\n\
+If not, generate remote agent bytecode for current frame pc address."),
+ &maintenancelist);
+
+ add_cmd ("agent-printf", class_maintenance, maint_agent_printf_command,
_("Translate an expression into remote "
- "agent bytecode for evaluation."),
+ "agent bytecode for evaluation and display the bytecodes."),
&maintenancelist);
}