| 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);
|
| }
|
|
|