Index: gdb/ax-gdb.c |
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c |
index 31e91b93156630baf9aa9e0fb8888fa82f4e62d8..845153da8c9272385ee9b4a546b858ad30860d54 100644 |
--- a/gdb/ax-gdb.c |
+++ b/gdb/ax-gdb.c |
@@ -41,10 +41,14 @@ |
#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 |
@@ -95,8 +99,6 @@ static void gen_int_literal (struct agent_expr *ax, |
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); |
@@ -157,8 +159,6 @@ static void gen_repeat (struct expression *exp, union exp_element **pc, |
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, |
@@ -515,6 +515,9 @@ gen_fetch (struct agent_expr *ax, struct type *type) |
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: |
@@ -553,12 +556,11 @@ gen_fetch (struct agent_expr *ax, struct type *type) |
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)); |
} |
} |
@@ -789,7 +791,7 @@ gen_int_literal (struct agent_expr *ax, struct axs_value *value, LONGEST k, |
/* 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 |
@@ -878,12 +880,6 @@ gen_usual_unary (struct expression *exp, struct agent_expr *ax, |
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. */ |
@@ -1477,7 +1473,7 @@ gen_struct_ref_recursive (struct expression *exp, struct agent_expr *ax, |
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) |
{ |
@@ -1625,7 +1621,7 @@ gen_struct_elt_for_reference (struct expression *exp, |
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) |
{ |
@@ -1807,7 +1803,7 @@ gen_sizeof (struct expression *exp, union exp_element **pc, |
/* 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) |
{ |
@@ -2042,7 +2038,8 @@ gen_expr (struct expression *exp, union exp_element **pc, |
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; |
@@ -2056,7 +2053,7 @@ gen_expr (struct expression *exp, union exp_element **pc, |
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); |
} |
@@ -2178,7 +2175,6 @@ gen_expr (struct expression *exp, union exp_element **pc, |
case OP_THIS: |
{ |
- char *this_name; |
struct symbol *sym, *func; |
struct block *b; |
const struct language_defn *lang; |
@@ -2221,7 +2217,7 @@ gen_expr (struct expression *exp, union exp_element **pc, |
default: |
error (_("Unsupported operator %s (%d) in expression."), |
- op_string (op), op); |
+ op_name (exp, op), op); |
} |
} |
@@ -2511,41 +2507,86 @@ gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch) |
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 (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 (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 */ |
- /* 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) |
+ { |
+ trace_string_kludge = 0; |
+ if (*exp == '/') |
+ exp = decode_agent_options (exp); |
+ } |
- /* Recognize the return address collection directive specially. Note |
- that it is not really an expression of any sort. */ |
- if (strcmp (exp, "$_ret") == 0) |
+ if (!eval && strcmp (exp, "$_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 ()); |
old_chain = make_cleanup_free_agent_expr (agent); |
} |
else |
{ |
- expr = parse_expression (exp); |
+ expr = parse_exp_1 (&exp, 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) |
+ agent = gen_eval_for_expr (pc, expr); |
+ else |
+ agent = gen_trace_for_expr (pc, expr); |
make_cleanup_free_agent_expr (agent); |
} |
@@ -2559,6 +2600,59 @@ agent_command (char *exp, int from_tty) |
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. */ |
@@ -2566,10 +2660,24 @@ agent_command (char *exp, int from_tty) |
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 |
@@ -2581,9 +2689,52 @@ agent_eval_command (char *exp, int from_tty) |
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); |
@@ -2603,12 +2754,23 @@ void |
_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); |
} |