/* GDB-specific functions for operating on agent expressions.
- Copyright (C) 1998, 1999, 2000, 2001, 2003, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 1998-2001, 2003, 2007-2012 Free Software Foundation,
+ Inc.
This file is part of GDB.
#include "breakpoint.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,
struct axs_value *value,
LONGEST k, struct type *type);
-
-static void require_rvalue (struct agent_expr *ax, struct axs_value *value);
static void gen_usual_unary (struct expression *exp, struct agent_expr *ax,
struct axs_value *value);
static int type_wider_than (struct type *type1, struct type *type2);
static void gen_sizeof (struct expression *exp, union exp_element **pc,
struct agent_expr *ax, struct axs_value *value,
struct type *size_type);
-static void gen_expr (struct expression *exp, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value);
static void gen_expr_binop_rest (struct expression *exp,
enum exp_opcode op, union exp_element **pc,
struct agent_expr *ax,
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. */
gen_traced_pop (struct gdbarch *gdbarch,
struct agent_expr *ax, struct axs_value *value)
{
+ int string_trace = 0;
+ if (trace_string_kludge
+ && 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)
switch (value->kind)
{
case axs_rvalue:
- /* We don't trace rvalues, just the lvalues necessary to
- produce them. So just dispose of this value. */
- ax_simple (ax, aop_pop);
+ if (string_trace)
+ {
+ ax_const_l (ax, trace_string_kludge);
+ ax_simple (ax, aop_tracenz);
+ }
+ else
+ /* We don't trace rvalues, just the lvalues necessary to
+ produce them. So just dispose of this value. */
+ ax_simple (ax, aop_pop);
break;
case axs_lvalue_memory:
{
int length = TYPE_LENGTH (check_typedef (value->type));
+ if (string_trace)
+ ax_simple (ax, aop_dup);
+
/* 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
work correctly for objects with large sizes. */
ax_const_l (ax, length);
ax_simple (ax, aop_trace);
+
+ if (string_trace)
+ {
+ ax_simple (ax, aop_ref32);
+ ax_const_l (ax, trace_string_kludge);
+ ax_simple (ax, aop_tracenz);
+ }
}
break;
larger than will fit in a stack, so just mark it for
collection and be done with it. */
ax_reg_mask (ax, value->u.reg);
+
+ /* But if the register points to a string, assume the value
+ will fit on the stack and push it anyway. */
+ if (string_trace)
+ {
+ ax_reg (ax, value->u.reg);
+ ax_const_l (ax, trace_string_kludge);
+ ax_simple (ax, aop_tracenz);
+ }
break;
}
else
ax_trace_quick (ax, TYPE_LENGTH (type));
}
+ if (TYPE_CODE (type) == TYPE_CODE_RANGE)
+ type = TYPE_TARGET_TYPE (type);
+
switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
break;
default:
- /* Either our caller shouldn't have asked us to dereference that
- pointer (other code's fault), or we're not implementing
- something we should be (this code's fault). In any case,
- it's a bug the user shouldn't see. */
- internal_error (__FILE__, __LINE__,
- _("gen_fetch: bad type code"));
+ /* Our caller requested us to dereference a pointer from an unsupported
+ type. Error out and give callers a chance to handle the failure
+ gracefully. */
+ error (_("gen_fetch: Unsupported type code `%s'."),
+ TYPE_NAME (type));
}
}
/* Take what's on the top of the stack (as described by VALUE), and
try to make an rvalue out of it. Signal an error if we can't do
that. */
-static void
+void
require_rvalue (struct agent_expr *ax, struct axs_value *value)
{
/* Only deal with scalars, structs and such may be too large
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
return;
-
- /* If the value is an enum or a bool, call it an integer. */
- case TYPE_CODE_ENUM:
- case TYPE_CODE_BOOL:
- value->type = builtin_type (exp->gdbarch)->builtin_int;
- break;
}
/* If the value is an lvalue, dereference it. */
for (i = TYPE_NFIELDS (type) - 1; i >= nbases; i--)
{
- char *this_name = TYPE_FIELD_NAME (type, i);
+ const char *this_name = TYPE_FIELD_NAME (type, i);
if (this_name)
{
}
else
{
- char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno);
+ const char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno);
struct symbol *sym = lookup_symbol (phys_name, 0, VAR_DOMAIN, 0);
if (sym)
for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--)
{
- char *t_field_name = TYPE_FIELD_NAME (t, i);
+ const char *t_field_name = TYPE_FIELD_NAME (t, i);
if (t_field_name && strcmp (t_field_name, fieldname) == 0)
{
/* XXX: i18n */
/* A gen_expr function written by a Gen-X'er guy.
Append code for the subexpression of EXPR starting at *POS_P to AX. */
-static void
+void
gen_expr (struct expression *exp, union exp_element **pc,
struct agent_expr *ax, struct axs_value *value)
{
case OP_INTERNALVAR:
{
- const char *name = internalvar_name ((*pc)[1].internalvar);
+ struct internalvar *var = (*pc)[1].internalvar;
+ const char *name = internalvar_name (var);
struct trace_state_variable *tsv;
(*pc) += 3;
value->kind = axs_rvalue;
value->type = builtin_type (exp->gdbarch)->builtin_long_long;
}
- else
+ else if (! compile_internalvar_to_ax (var, ax, value))
error (_("$%s is not a trace state variable; GDB agent "
"expressions cannot use convenience variables."), name);
}
}
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. */
case OP_THIS:
{
- char *this_name;
- struct symbol *func, *sym;
+ struct symbol *sym, *func;
struct block *b;
+ const struct language_defn *lang;
- func = block_linkage_function (block_for_pc (ax->scope));
- this_name = language_def (SYMBOL_LANGUAGE (func))->la_name_of_this;
- b = SYMBOL_BLOCK_VALUE (func);
+ b = block_for_pc (ax->scope);
+ func = block_linkage_function (b);
+ lang = language_def (SYMBOL_LANGUAGE (func));
- /* Calling lookup_block_symbol is necessary to get the LOC_REGISTER
- symbol instead of the LOC_ARG one (if both exist). */
- sym = lookup_block_symbol (b, this_name, VAR_DOMAIN);
+ sym = lookup_language_this (lang, b);
if (!sym)
- error (_("no `%s' found"), this_name);
+ error (_("no `%s' found"), lang->la_name_of_this);
gen_var_ref (exp->gdbarch, ax, value, sym);
break;
case OP_TYPE:
+ case OP_TYPEOF:
+ case OP_DECLTYPE:
error (_("Attempt to use a type name as an expression."));
default:
error (_("Unsupported operator %s (%d) in expression."),
- op_string (op), op);
+ op_name (exp, op), op);
}
}
return ax;
}
-void
-gen_printf_expr_callback (char *fbuf, char **expp, void *loc_v, void *aexpr_v)
+struct agent_expr *
+gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch)
{
- struct bp_location *loc = loc_v;
- struct agent_expr *aexpr = aexpr_v;
+ struct cleanup *old_chain = 0;
+ struct agent_expr *ax = new_agent_expr (gdbarch, scope);
+ struct axs_value value;
- if (expp)
- {
- struct cleanup *old_chain = NULL;
- struct expression *expr = NULL;
- union exp_element *pc;
- struct axs_value value;
+ old_chain = make_cleanup_free_agent_expr (ax);
- expr = parse_exp_1 (expp, block_for_pc (loc->address), 1);
- old_chain = make_cleanup (free_current_contents, &expr);
+ trace_kludge = 1;
+
+ gdbarch_gen_return_address (gdbarch, ax, &value, scope);
- pc = expr->elts;
+ /* Make sure we record the final object, and get rid of it. */
+ gen_traced_pop (gdbarch, ax, &value);
+
+ /* Oh, 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;
+}
+
+/* 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,
+ 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;
+
+ old_chain = make_cleanup_free_agent_expr (ax);
+
+ /* 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 (expr, &pc, aexpr, &value);
+ gen_expr (exprs[tem], &pc, ax, &value);
+ require_rvalue (ax, &value);
+ }
- if (value.optimized_out)
- error (_("value has been optimized out"));
- switch (value.kind)
- {
- case axs_lvalue_memory:
- if (TYPE_CODE (value.type) != TYPE_CODE_ARRAY)
- {
- int length = TYPE_LENGTH (check_typedef (value.type));
- switch (length)
- {
- case 4:
- ax_simple (aexpr, aop_ref32);
- break;
- case 8:
- ax_simple (aexpr, aop_ref64);
- break;
- default:
- error (_("Size of value is not OK."));
- break;
- }
- }
- break;
- case axs_lvalue_register:
- ax_reg (aexpr, value.u.reg);
- break;
- }
+ /* Push function and channel. */
+ ax_const_l (ax, channel);
+ ax_const_l (ax, function);
- do_cleanups (old_chain);
- }
+ /* Issue the printf bytecode proper. */
+ ax_simple (ax, aop_printf);
+ ax_simple (ax, nargs);
+ ax_string (ax, format, fmtlen);
- ax_simple (aexpr, aop_printf);
- if (expp)
- ax_simple (aexpr, 1);
- else
- ax_simple (aexpr, 0);
- ax_memcpy (aexpr, fbuf, strlen (fbuf) + 1);
+ /* 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 (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 */
+ if (!eval)
+ {
+ trace_string_kludge = 0;
+ if (*exp == '/')
+ exp = decode_agent_options (exp);
+ }
+
+ if (!eval && strcmp (exp, "$_ret") == 0)
+ {
+ agent = gen_trace_for_return_address (pc, get_current_arch ());
+ old_chain = make_cleanup_free_agent_expr (agent);
+ }
+ else
+ {
+ expr = parse_exp_1 (&exp, pc, block_for_pc (pc), 0);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ if (eval)
+ agent = gen_eval_for_expr (pc, expr);
+ else
+ agent = gen_trace_for_expr (pc, expr);
+ make_cleanup_free_agent_expr (agent);
+ }
+
+ ax_reqs (agent);
+ ax_print (gdb_stdout, agent);
+
+ /* It would be nice to call ax_reqs here to gather some general info
+ about the expression, and then print out the result. */
+
+ do_cleanups (old_chain);
+ 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
if (exp == 0)
error_no_arg (_("expression to translate"));
- expr = parse_expression (exp);
- old_chain = make_cleanup (free_current_contents, &expr);
- agent = gen_trace_for_expr (get_frame_pc (fi), expr);
- make_cleanup_free_agent_expr (agent);
- ax_reqs (agent);
- ax_print (gdb_stdout, agent);
+ 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;
- /* It would be nice to call ax_reqs here to gather some general info
- about the expression, and then print out the result. */
+ 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 ()));
- do_cleanups (old_chain);
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 */
+ char *cmdrest;
+ 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 (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 (cmdrest);
+
+ if (*cmdrest != ',' && *cmdrest != 0)
+ error (_("Invalid argument syntax"));
+
+ if (*cmdrest == ',')
+ cmdrest++;
+ cmdrest = skip_spaces (cmdrest);
+
+ nargs = 0;
+ while (*cmdrest != '\0')
+ {
+ 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);
}