X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gdb%2Fax-gdb.c;h=9f1b7a1e88b181d6e1617b0bce84fe45c115ff64;hb=7ce8f214f1af1dd593ad42665da416ac46033f97;hp=368b9df12a1d92eb30bec3ea7c42cce6014a7359;hpb=0004e5a2cf40bcf4485a7b552b5d19ed69d11eba;p=external%2Fbinutils.git
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 368b9df..9f1b7a1 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -1,11 +1,12 @@
-/* GDB-specific functions for operating on agent expressions
- Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+/* GDB-specific functions for operating on agent expressions.
+
+ Copyright (C) 1998-2019 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@@ -14,14 +15,13 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see . */
#include "defs.h"
#include "symtab.h"
#include "symfile.h"
#include "gdbtypes.h"
+#include "language.h"
#include "value.h"
#include "expression.h"
#include "command.h"
@@ -30,6 +30,23 @@
#include "target.h"
#include "ax.h"
#include "ax-gdb.h"
+#include "block.h"
+#include "regcache.h"
+#include "user-regs.h"
+#include "dictionary.h"
+#include "breakpoint.h"
+#include "tracepoint.h"
+#include "cp-support.h"
+#include "arch-utils.h"
+#include "cli/cli-utils.h"
+#include "linespec.h"
+#include "location.h"
+#include "objfiles.h"
+#include "typeprint.h"
+#include "valprint.h"
+#include "c-lang.h"
+
+#include "gdbsupport/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,
@@ -49,7 +66,7 @@
-/* Prototypes for local functions. */
+/* Prototypes for local functions. */
/* There's a standard order to the arguments of these functions:
union exp_element ** --- pointer into expression
@@ -72,16 +89,14 @@ static void gen_frame_args_address (struct agent_expr *);
static void gen_frame_locals_address (struct agent_expr *);
static void gen_offset (struct agent_expr *ax, int offset);
static void gen_sym_offset (struct agent_expr *, struct symbol *);
-static void gen_var_ref (struct agent_expr *ax,
- struct axs_value *value, struct symbol *var);
+static void gen_var_ref (struct agent_expr *ax, struct axs_value *value,
+ struct symbol *var);
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 agent_expr *ax, struct axs_value *value);
static int type_wider_than (struct type *type1, struct type *type2);
static struct type *max_type (struct type *type1, struct type *type2);
@@ -97,40 +112,52 @@ static void gen_cast (struct agent_expr *ax,
struct axs_value *value, struct type *type);
static void gen_scale (struct agent_expr *ax,
enum agent_op op, struct type *type);
-static void gen_add (struct agent_expr *ax,
- struct axs_value *value,
- struct axs_value *value1,
- struct axs_value *value2, char *name);
-static void gen_sub (struct agent_expr *ax,
- struct axs_value *value,
- struct axs_value *value1, struct axs_value *value2);
+static void gen_ptradd (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2);
+static void gen_ptrsub (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2);
+static void gen_ptrdiff (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2,
+ struct type *result_type);
static void gen_binop (struct agent_expr *ax,
struct axs_value *value,
struct axs_value *value1,
struct axs_value *value2,
enum agent_op op,
- enum agent_op op_unsigned, int may_carry, char *name);
-static void gen_logical_not (struct agent_expr *ax, struct axs_value *value);
+ enum agent_op op_unsigned, int may_carry,
+ const char *name);
+static void gen_logical_not (struct agent_expr *ax, struct axs_value *value,
+ struct type *result_type);
static void gen_complement (struct agent_expr *ax, struct axs_value *value);
-static void gen_deref (struct agent_expr *, struct axs_value *);
-static void gen_address_of (struct agent_expr *, struct axs_value *);
-static int find_field (struct type *type, char *name);
-static void gen_bitfield_ref (struct agent_expr *ax,
- struct axs_value *value,
+static void gen_deref (struct axs_value *);
+static void gen_address_of (struct axs_value *);
+static void gen_bitfield_ref (struct agent_expr *ax, struct axs_value *value,
struct type *type, int start, int end);
+static void gen_primitive_field (struct agent_expr *ax,
+ struct axs_value *value,
+ int offset, int fieldno, struct type *type);
+static int gen_struct_ref_recursive (struct agent_expr *ax,
+ struct axs_value *value,
+ const char *field, int offset,
+ struct type *type);
static void gen_struct_ref (struct agent_expr *ax,
struct axs_value *value,
- char *field,
- char *operator_name, char *operand_name);
-static void gen_repeat (union exp_element **pc,
+ const char *field,
+ const char *operator_name,
+ const char *operand_name);
+static void gen_static_field (struct agent_expr *ax, struct axs_value *value,
+ struct type *type, int fieldno);
+static void gen_repeat (struct expression *exp, union exp_element **pc,
struct agent_expr *ax, struct axs_value *value);
-static void gen_sizeof (union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value);
-static void gen_expr (union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value);
-
-static void print_axs_value (struct ui_file *f, struct axs_value * value);
-static void agent_command (char *exp, int from_tty);
+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_binop_rest (struct expression *exp,
+ enum exp_opcode op, union exp_element **pc,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct axs_value *value1,
+ struct axs_value *value2);
/* Detecting constant expressions. */
@@ -188,6 +215,7 @@ const_expr (union exp_element **pc)
{
struct type *type = (*pc)[1].type;
LONGEST k = (*pc)[2].longconst;
+
(*pc) += 4;
return value_from_longest (type, k);
}
@@ -195,6 +223,7 @@ const_expr (union exp_element **pc)
case OP_VAR_VALUE:
{
struct value *v = const_var_ref ((*pc)[2].symbol);
+
(*pc) += 4;
return v;
}
@@ -275,30 +304,55 @@ maybe_const_expr (union exp_element **pc)
sizes), and this is simpler.) */
-/* Generating bytecode from GDB expressions: the `trace' kludge */
+/* Scan for all static fields in the given class, including any base
+ classes, and generate tracing bytecodes for each. */
-/* 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.
+static void
+gen_trace_static_fields (struct agent_expr *ax,
+ struct type *type)
+{
+ int i, nbases = TYPE_N_BASECLASSES (type);
+ struct axs_value value;
- However, at the moment it is HOPELESSLY BRAIN-DAMAGED for the sake
- of expediency. Let he who is without sin cast the first stone.
+ type = check_typedef (type);
- 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.
+ for (i = TYPE_NFIELDS (type) - 1; i >= nbases; i--)
+ {
+ if (field_is_static (&TYPE_FIELD (type, i)))
+ {
+ gen_static_field (ax, &value, type, i);
+ if (value.optimized_out)
+ continue;
+ switch (value.kind)
+ {
+ case axs_lvalue_memory:
+ {
+ /* 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;
+
+ case axs_lvalue_register:
+ /* We don't actually need the register's value to be pushed,
+ just note that we need it to be collected. */
+ ax_reg_mask (ax, value.u.reg);
+
+ default:
+ break;
+ }
+ }
+ }
- 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.
+ /* Now scan through base classes recursively. */
+ for (i = 0; i < nbases; i++)
+ {
+ struct type *basetype = check_typedef (TYPE_BASECLASS (type, i));
- Setting the flag trace_kludge to non-zero enables the code that
- emits the trace bytecodes at the appropriate points. */
-static int trace_kludge;
+ gen_trace_static_fields (ax, basetype);
+ }
+}
/* Trace the lvalue on the stack, if it needs it. In either case, pop
the value. Useful on the left side of a comma, and at the end of
@@ -306,40 +360,78 @@ static int trace_kludge;
static void
gen_traced_pop (struct agent_expr *ax, struct axs_value *value)
{
- if (trace_kludge)
+ int string_trace = 0;
+ 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 (ax->tracing)
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, ax->trace_string);
+ 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 (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_simple (ax, aop_trace);
+ /* Initialize the TYPE_LENGTH if it is a typedef. */
+ check_typedef (value->type);
+
+ if (string_trace)
+ {
+ gen_fetch (ax, value->type);
+ ax_const_l (ax, ax->trace_string);
+ ax_simple (ax, aop_tracenz);
+ }
+ else
+ {
+ /* 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, TYPE_LENGTH (value->type));
+ ax_simple (ax, aop_trace);
+ }
}
break;
case axs_lvalue_register:
- /* We need to mention the register somewhere in the bytecode,
- so ax_reqs will pick it up and add it to the mask of
- registers used. */
- ax_reg (ax, value->u.reg);
- ax_simple (ax, aop_pop);
+ /* We don't actually need the register's value to be on the
+ stack, and the target will get heartburn if the register is
+ 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, ax->trace_string);
+ ax_simple (ax, aop_tracenz);
+ }
break;
}
else
/* If we're not tracing, just pop the value. */
ax_simple (ax, aop_pop);
+
+ /* To trace C++ classes with static fields stored elsewhere. */
+ if (ax->tracing
+ && (TYPE_CODE (value->type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (value->type) == TYPE_CODE_UNION))
+ gen_trace_static_fields (ax, value->type);
}
@@ -364,6 +456,7 @@ static void
gen_extend (struct agent_expr *ax, struct type *type)
{
int bits = TYPE_LENGTH (type) * TARGET_CHAR_BIT;
+
/* I just had to. */
((TYPE_UNSIGNED (type) ? ax_zero_ext : ax_ext) (ax, bits));
}
@@ -375,18 +468,24 @@ 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));
}
+ if (TYPE_CODE (type) == TYPE_CODE_RANGE)
+ type = TYPE_TARGET_TYPE (type);
+
switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
case TYPE_CODE_ENUM:
case TYPE_CODE_INT:
case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
/* It's a scalar value, so we know how to dereference it. How
many bytes long is it? */
switch (TYPE_LENGTH (type))
@@ -410,19 +509,18 @@ gen_fetch (struct agent_expr *ax, struct type *type)
In any case, it's a bug the user shouldn't see. */
default:
internal_error (__FILE__, __LINE__,
- "gen_fetch: strange size");
+ _("gen_fetch: strange size"));
}
gen_sign_extend (ax, 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));
}
}
@@ -457,7 +555,8 @@ gen_frame_args_address (struct agent_expr *ax)
int frame_reg;
LONGEST frame_offset;
- TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
+ gdbarch_virtual_frame_pointer (ax->gdbarch,
+ ax->scope, &frame_reg, &frame_offset);
ax_reg (ax, frame_reg);
gen_offset (ax, frame_offset);
}
@@ -471,7 +570,8 @@ gen_frame_locals_address (struct agent_expr *ax)
int frame_reg;
LONGEST frame_offset;
- TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
+ gdbarch_virtual_frame_pointer (ax->gdbarch,
+ ax->scope, &frame_reg, &frame_offset);
ax_reg (ax, frame_reg);
gen_offset (ax, frame_offset);
}
@@ -517,8 +617,15 @@ gen_sym_offset (struct agent_expr *ax, struct symbol *var)
static void
gen_var_ref (struct agent_expr *ax, struct axs_value *value, struct symbol *var)
{
- /* Dereference any typedefs. */
+ /* Dereference any typedefs. */
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, ax, value);
+ return;
+ }
/* I'm imitating the code in read_var_value. */
switch (SYMBOL_CLASS (var))
@@ -535,7 +642,8 @@ gen_var_ref (struct agent_expr *ax, struct axs_value *value, struct symbol *var)
case LOC_CONST_BYTES:
internal_error (__FILE__, __LINE__,
- "gen_var_ref: LOC_CONST_BYTES symbols are not supported");
+ _("gen_var_ref: LOC_CONST_BYTES "
+ "symbols are not supported"));
/* Variable at a fixed location in memory. Easy. */
case LOC_STATIC:
@@ -555,76 +663,91 @@ gen_var_ref (struct agent_expr *ax, struct axs_value *value, struct symbol *var)
gen_frame_args_address (ax);
gen_sym_offset (ax, var);
/* Don't assume any particular pointer size. */
- gen_fetch (ax, lookup_pointer_type (builtin_type_void));
+ gen_fetch (ax, builtin_type (ax->gdbarch)->builtin_data_ptr);
value->kind = axs_lvalue_memory;
break;
case LOC_LOCAL: /* var lives in locals area of frame */
- case LOC_LOCAL_ARG:
gen_frame_locals_address (ax);
gen_sym_offset (ax, var);
value->kind = axs_lvalue_memory;
break;
- case LOC_BASEREG: /* relative to some base register */
- case LOC_BASEREG_ARG:
- ax_reg (ax, SYMBOL_BASEREG (var));
- gen_sym_offset (ax, var);
- value->kind = axs_lvalue_memory;
- break;
-
case LOC_TYPEDEF:
- error ("Cannot compute value of typedef `%s'.",
- SYMBOL_SOURCE_NAME (var));
+ error (_("Cannot compute value of typedef `%s'."),
+ SYMBOL_PRINT_NAME (var));
break;
case LOC_BLOCK:
- ax_const_l (ax, BLOCK_START (SYMBOL_BLOCK_VALUE (var)));
+ ax_const_l (ax, BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (var)));
value->kind = axs_rvalue;
break;
case LOC_REGISTER:
- case LOC_REGPARM:
/* Don't generate any code at all; in the process of treating
this as an lvalue or rvalue, the caller will generate the
right code. */
value->kind = axs_lvalue_register;
- value->u.reg = SYMBOL_VALUE (var);
+ value->u.reg
+ = SYMBOL_REGISTER_OPS (var)->register_number (var, ax->gdbarch);
break;
/* A lot like LOC_REF_ARG, but the pointer lives directly in a
- register, not on the stack. Simpler than LOC_REGISTER and
- LOC_REGPARM, because it's just like any other case where the
- thing has a real address. */
+ register, not on the stack. Simpler than LOC_REGISTER
+ because it's just like any other case where the thing
+ has a real address. */
case LOC_REGPARM_ADDR:
- ax_reg (ax, SYMBOL_VALUE (var));
+ ax_reg (ax,
+ SYMBOL_REGISTER_OPS (var)->register_number (var, ax->gdbarch));
value->kind = axs_lvalue_memory;
break;
case LOC_UNRESOLVED:
{
- struct minimal_symbol *msym
- = lookup_minimal_symbol (SYMBOL_NAME (var), NULL, NULL);
- if (!msym)
- error ("Couldn't resolve symbol `%s'.", SYMBOL_SOURCE_NAME (var));
+ struct bound_minimal_symbol msym
+ = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (var), NULL, NULL);
+
+ if (!msym.minsym)
+ error (_("Couldn't resolve symbol `%s'."), SYMBOL_PRINT_NAME (var));
/* Push the address of the variable. */
- ax_const_l (ax, SYMBOL_VALUE_ADDRESS (msym));
+ ax_const_l (ax, BMSYMBOL_VALUE_ADDRESS (msym));
value->kind = axs_lvalue_memory;
}
break;
+ case LOC_COMPUTED:
+ gdb_assert_not_reached (_("LOC_COMPUTED variable missing a method"));
+
case LOC_OPTIMIZED_OUT:
- error ("The variable `%s' has been optimized out.",
- SYMBOL_SOURCE_NAME (var));
+ /* Flag this, but don't say anything; leave it up to callers to
+ warn the user. */
+ value->optimized_out = 1;
break;
default:
- error ("Cannot find value of botched symbol `%s'.",
- SYMBOL_SOURCE_NAME (var));
+ error (_("Cannot find value of botched symbol `%s'."),
+ SYMBOL_PRINT_NAME (var));
break;
}
}
+
+/* Generate code for a minimal symbol variable reference to AX. The
+ variable is the symbol MINSYM, of OBJFILE. Set VALUE to describe
+ the result. */
+
+static void
+gen_msym_var_ref (agent_expr *ax, axs_value *value,
+ minimal_symbol *msymbol, objfile *objf)
+{
+ CORE_ADDR address;
+ type *t = find_minsym_type_and_address (msymbol, objf, &address);
+ value->type = t;
+ value->optimized_out = false;
+ ax_const_l (ax, address);
+ value->kind = axs_lvalue_memory;
+}
+
@@ -636,7 +759,7 @@ gen_int_literal (struct agent_expr *ax, struct axs_value *value, LONGEST k,
{
ax_const_l (ax, k);
value->kind = axs_rvalue;
- value->type = type;
+ value->type = check_typedef (type);
}
@@ -646,9 +769,18 @@ 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
+ to fit in a stack entry. */
+ value->type = check_typedef (value->type);
+ if (TYPE_CODE (value->type) == TYPE_CODE_ARRAY
+ || TYPE_CODE (value->type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (value->type) == TYPE_CODE_UNION
+ || TYPE_CODE (value->type) == TYPE_CODE_FUNC)
+ error (_("Value not scalar: cannot be an rvalue."));
+
switch (value->kind)
{
case axs_rvalue:
@@ -712,6 +844,7 @@ gen_usual_unary (struct agent_expr *ax, struct axs_value *value)
case TYPE_CODE_ARRAY:
{
struct type *elements = TYPE_TARGET_TYPE (value->type);
+
value->type = lookup_pointer_type (elements);
value->kind = axs_rvalue;
/* We don't need to generate any code; the address of the array
@@ -724,11 +857,6 @@ gen_usual_unary (struct agent_expr *ax, struct axs_value *value)
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
return;
-
- /* If the value is an enum, call it an integer. */
- case TYPE_CODE_ENUM:
- value->type = builtin_type_int;
- break;
}
/* If the value is an lvalue, dereference it. */
@@ -765,7 +893,7 @@ gen_conversion (struct agent_expr *ax, struct type *from, struct type *to)
/* If we're converting to a narrower type, then we need to clear out
the upper bits. */
if (TYPE_LENGTH (to) < TYPE_LENGTH (from))
- gen_extend (ax, from);
+ gen_extend (ax, to);
/* If the two values have equal width, but different signednesses,
then we need to extend. */
@@ -790,7 +918,7 @@ gen_conversion (struct agent_expr *ax, struct type *from, struct type *to)
static int
is_nontrivial_conversion (struct type *from, struct type *to)
{
- struct agent_expr *ax = new_agent_expr (0);
+ agent_expr_up ax (new agent_expr (NULL, 0));
int nontrivial;
/* Actually generate the code, and see if anything came out. At the
@@ -799,9 +927,8 @@ is_nontrivial_conversion (struct type *from, struct type *to)
floating point and the like, it may not be. Doing things this
way allows this function to be independent of the logic in
gen_conversion. */
- gen_conversion (ax, from, to);
+ gen_conversion (ax.get (), from, to);
nontrivial = ax->len > 0;
- free_agent_expr (ax);
return nontrivial;
}
@@ -824,7 +951,7 @@ gen_usual_arithmetic (struct agent_expr *ax, struct axs_value *value1,
unsigned type is considered "wider" than an n-bit signed
type. Promote to the "wider" of the two types, and always
promote at least to int. */
- struct type *target = max_type (builtin_type_int,
+ struct type *target = max_type (builtin_type (ax->gdbarch)->builtin_int,
max_type (value1->type, value2->type));
/* Deal with value2, on the top of the stack. */
@@ -840,7 +967,7 @@ gen_usual_arithmetic (struct agent_expr *ax, struct axs_value *value1,
ax_simple (ax, aop_swap);
}
- value1->type = value2->type = target;
+ value1->type = value2->type = check_typedef (target);
}
}
@@ -851,15 +978,17 @@ gen_usual_arithmetic (struct agent_expr *ax, struct axs_value *value1,
static void
gen_integral_promotions (struct agent_expr *ax, struct axs_value *value)
{
- if (!type_wider_than (value->type, builtin_type_int))
+ const struct builtin_type *builtin = builtin_type (ax->gdbarch);
+
+ if (!type_wider_than (value->type, builtin->builtin_int))
{
- gen_conversion (ax, value->type, builtin_type_int);
- value->type = builtin_type_int;
+ gen_conversion (ax, value->type, builtin->builtin_int);
+ value->type = builtin->builtin_int;
}
- else if (!type_wider_than (value->type, builtin_type_unsigned_int))
+ else if (!type_wider_than (value->type, builtin->builtin_unsigned_int))
{
- gen_conversion (ax, value->type, builtin_type_unsigned_int);
- value->type = builtin_type_unsigned_int;
+ gen_conversion (ax, value->type, builtin->builtin_unsigned_int);
+ value->type = builtin->builtin_unsigned_int;
}
}
@@ -871,12 +1000,14 @@ gen_cast (struct agent_expr *ax, struct axs_value *value, struct type *type)
/* GCC does allow casts to yield lvalues, so this should be fixed
before merging these changes into the trunk. */
require_rvalue (ax, value);
- /* Dereference typedefs. */
+ /* Dereference typedefs. */
type = check_typedef (type);
switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
/* It's implementation-defined, and I'll bet this is what GCC
does. */
break;
@@ -885,15 +1016,15 @@ gen_cast (struct agent_expr *ax, struct axs_value *value, struct type *type)
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
case TYPE_CODE_FUNC:
- error ("Illegal type cast: intended type must be scalar.");
+ error (_("Invalid type cast: intended type must be scalar."));
case TYPE_CODE_ENUM:
+ case TYPE_CODE_BOOL:
/* We don't have to worry about the size of the value, because
all our integral values are fully sign-extended, and when
casting pointers we can do anything we like. Is there any
- way for us to actually know what GCC actually does with a
- cast like this? */
- value->type = type;
+ way for us to know what GCC actually does with a cast like
+ this? */
break;
case TYPE_CODE_INT:
@@ -908,7 +1039,7 @@ gen_cast (struct agent_expr *ax, struct axs_value *value, struct type *type)
break;
default:
- error ("Casts to requested type are not yet implemented.");
+ error (_("Casts to requested type are not yet implemented."));
}
value->type = type;
@@ -933,102 +1064,84 @@ gen_scale (struct agent_expr *ax, enum agent_op op, struct type *type)
}
-/* Generate code for an addition; non-trivial because we deal with
- pointer arithmetic. We set VALUE to describe the result value; we
- assume VALUE1 and VALUE2 describe the two operands, and that
- they've undergone the usual binary conversions. Used by both
- BINOP_ADD and BINOP_SUBSCRIPT. NAME is used in error messages. */
+/* Generate code for pointer arithmetic PTR + INT. */
static void
-gen_add (struct agent_expr *ax, struct axs_value *value,
- struct axs_value *value1, struct axs_value *value2, char *name)
+gen_ptradd (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2)
{
- /* Is it INT+PTR? */
- if (TYPE_CODE (value1->type) == TYPE_CODE_INT
- && TYPE_CODE (value2->type) == TYPE_CODE_PTR)
- {
- /* Swap the values and proceed normally. */
- ax_simple (ax, aop_swap);
- gen_scale (ax, aop_mul, value2->type);
- ax_simple (ax, aop_add);
- gen_extend (ax, value2->type); /* Catch overflow. */
- value->type = value2->type;
- }
+ gdb_assert (pointer_type (value1->type));
+ gdb_assert (TYPE_CODE (value2->type) == TYPE_CODE_INT);
- /* Is it PTR+INT? */
- else if (TYPE_CODE (value1->type) == TYPE_CODE_PTR
- && TYPE_CODE (value2->type) == TYPE_CODE_INT)
- {
- gen_scale (ax, aop_mul, value1->type);
- ax_simple (ax, aop_add);
- gen_extend (ax, value1->type); /* Catch overflow. */
- value->type = value1->type;
- }
+ gen_scale (ax, aop_mul, value1->type);
+ ax_simple (ax, aop_add);
+ gen_extend (ax, value1->type); /* Catch overflow. */
+ value->type = value1->type;
+ value->kind = axs_rvalue;
+}
- /* Must be number + number; the usual binary conversions will have
- brought them both to the same width. */
- else if (TYPE_CODE (value1->type) == TYPE_CODE_INT
- && TYPE_CODE (value2->type) == TYPE_CODE_INT)
- {
- ax_simple (ax, aop_add);
- gen_extend (ax, value1->type); /* Catch overflow. */
- value->type = value1->type;
- }
- else
- error ("Illegal combination of types in %s.", name);
+/* Generate code for pointer arithmetic PTR - INT. */
+static void
+gen_ptrsub (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2)
+{
+ gdb_assert (pointer_type (value1->type));
+ gdb_assert (TYPE_CODE (value2->type) == TYPE_CODE_INT);
+ gen_scale (ax, aop_mul, value1->type);
+ ax_simple (ax, aop_sub);
+ gen_extend (ax, value1->type); /* Catch overflow. */
+ value->type = value1->type;
value->kind = axs_rvalue;
}
-/* Generate code for an addition; non-trivial because we have to deal
- with pointer arithmetic. We set VALUE to describe the result
- value; we assume VALUE1 and VALUE2 describe the two operands, and
- that they've undergone the usual binary conversions. */
+/* Generate code for pointer arithmetic PTR - PTR. */
static void
-gen_sub (struct agent_expr *ax, struct axs_value *value,
- struct axs_value *value1, struct axs_value *value2)
+gen_ptrdiff (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2,
+ struct type *result_type)
{
- if (TYPE_CODE (value1->type) == TYPE_CODE_PTR)
- {
- /* Is it PTR - INT? */
- if (TYPE_CODE (value2->type) == TYPE_CODE_INT)
- {
- gen_scale (ax, aop_mul, value1->type);
- ax_simple (ax, aop_sub);
- gen_extend (ax, value1->type); /* Catch overflow. */
- value->type = value1->type;
- }
+ gdb_assert (pointer_type (value1->type));
+ gdb_assert (pointer_type (value2->type));
- /* Is it PTR - PTR? Strictly speaking, the types ought to
- match, but this is what the normal GDB expression evaluator
- tests for. */
- else if (TYPE_CODE (value2->type) == TYPE_CODE_PTR
- && (TYPE_LENGTH (TYPE_TARGET_TYPE (value1->type))
- == TYPE_LENGTH (TYPE_TARGET_TYPE (value2->type))))
- {
- ax_simple (ax, aop_sub);
- gen_scale (ax, aop_div_unsigned, value1->type);
- value->type = builtin_type_long; /* FIXME --- should be ptrdiff_t */
- }
- else
- error ("\
+ if (TYPE_LENGTH (TYPE_TARGET_TYPE (value1->type))
+ != TYPE_LENGTH (TYPE_TARGET_TYPE (value2->type)))
+ error (_("\
First argument of `-' is a pointer, but second argument is neither\n\
-an integer nor a pointer of the same type.");
- }
+an integer nor a pointer of the same type."));
- /* Must be number + number. */
- else if (TYPE_CODE (value1->type) == TYPE_CODE_INT
- && TYPE_CODE (value2->type) == TYPE_CODE_INT)
- {
- ax_simple (ax, aop_sub);
- gen_extend (ax, value1->type); /* Catch overflow. */
- value->type = value1->type;
- }
+ ax_simple (ax, aop_sub);
+ gen_scale (ax, aop_div_unsigned, value1->type);
+ value->type = result_type;
+ value->kind = axs_rvalue;
+}
+static void
+gen_equal (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2,
+ struct type *result_type)
+{
+ if (pointer_type (value1->type) || pointer_type (value2->type))
+ ax_simple (ax, aop_equal);
else
- error ("Illegal combination of types in subtraction.");
+ gen_binop (ax, value, value1, value2,
+ aop_equal, aop_equal, 0, "equal");
+ value->type = result_type;
+ value->kind = axs_rvalue;
+}
+static void
+gen_less (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2,
+ struct type *result_type)
+{
+ if (pointer_type (value1->type) || pointer_type (value2->type))
+ ax_simple (ax, aop_less_unsigned);
+ else
+ gen_binop (ax, value, value1, value2,
+ aop_less_signed, aop_less_unsigned, 0, "less than");
+ value->type = result_type;
value->kind = axs_rvalue;
}
@@ -1040,13 +1153,14 @@ an integer nor a pointer of the same type.");
operator, used in error messages */
static void
gen_binop (struct agent_expr *ax, struct axs_value *value,
- struct axs_value *value1, struct axs_value *value2, enum agent_op op,
- enum agent_op op_unsigned, int may_carry, char *name)
+ struct axs_value *value1, struct axs_value *value2,
+ enum agent_op op, enum agent_op op_unsigned,
+ int may_carry, const char *name)
{
/* We only handle INT op INT. */
if ((TYPE_CODE (value1->type) != TYPE_CODE_INT)
|| (TYPE_CODE (value2->type) != TYPE_CODE_INT))
- error ("Illegal combination of types in %s.", name);
+ error (_("Invalid combination of types in %s."), name);
ax_simple (ax,
TYPE_UNSIGNED (value1->type) ? op_unsigned : op);
@@ -1058,15 +1172,15 @@ gen_binop (struct agent_expr *ax, struct axs_value *value,
static void
-gen_logical_not (struct agent_expr *ax, struct axs_value *value)
+gen_logical_not (struct agent_expr *ax, struct axs_value *value,
+ struct type *result_type)
{
if (TYPE_CODE (value->type) != TYPE_CODE_INT
&& TYPE_CODE (value->type) != TYPE_CODE_PTR)
- error ("Illegal type of operand to `!'.");
+ error (_("Invalid type of operand to `!'."));
- gen_usual_unary (ax, value);
ax_simple (ax, aop_log_not);
- value->type = builtin_type_int;
+ value->type = result_type;
}
@@ -1074,10 +1188,8 @@ static void
gen_complement (struct agent_expr *ax, struct axs_value *value)
{
if (TYPE_CODE (value->type) != TYPE_CODE_INT)
- error ("Illegal type of operand to `~'.");
+ error (_("Invalid type of operand to `~'."));
- gen_usual_unary (ax, value);
- gen_integral_promotions (ax, value);
ax_simple (ax, aop_bit_not);
gen_extend (ax, value->type);
}
@@ -1088,13 +1200,13 @@ gen_complement (struct agent_expr *ax, struct axs_value *value)
/* Dereference the value on the top of the stack. */
static void
-gen_deref (struct agent_expr *ax, struct axs_value *value)
+gen_deref (struct axs_value *value)
{
/* The caller should check the type, because several operators use
this, and we don't know what error message to generate. */
- if (TYPE_CODE (value->type) != TYPE_CODE_PTR)
+ if (!pointer_type (value->type))
internal_error (__FILE__, __LINE__,
- "gen_deref: expected a pointer");
+ _("gen_deref: expected a pointer"));
/* We've got an rvalue now, which is a pointer. We want to yield an
lvalue, whose address is exactly that pointer. So we don't
@@ -1102,6 +1214,8 @@ gen_deref (struct agent_expr *ax, struct axs_value *value)
T" to "T", and mark the value as an lvalue in memory. Leave it
to the consumer to actually dereference it. */
value->type = check_typedef (TYPE_TARGET_TYPE (value->type));
+ if (TYPE_CODE (value->type) == TYPE_CODE_VOID)
+ error (_("Attempt to dereference a generic pointer."));
value->kind = ((TYPE_CODE (value->type) == TYPE_CODE_FUNC)
? axs_rvalue : axs_lvalue_memory);
}
@@ -1109,7 +1223,7 @@ gen_deref (struct agent_expr *ax, struct axs_value *value)
/* Produce the address of the lvalue on the top of the stack. */
static void
-gen_address_of (struct agent_expr *ax, struct axs_value *value)
+gen_address_of (struct axs_value *value)
{
/* Special case for taking the address of a function. The ANSI
standard describes this as a special case, too, so this
@@ -1122,10 +1236,10 @@ gen_address_of (struct agent_expr *ax, struct axs_value *value)
switch (value->kind)
{
case axs_rvalue:
- error ("Operand of `&' is an rvalue, which has no address.");
+ error (_("Operand of `&' is an rvalue, which has no address."));
case axs_lvalue_register:
- error ("Operand of `&' is in a register, and has no address.");
+ error (_("Operand of `&' is in a register, and has no address."));
case axs_lvalue_memory:
value->kind = axs_rvalue;
@@ -1134,43 +1248,6 @@ gen_address_of (struct agent_expr *ax, struct axs_value *value)
}
}
-
-/* A lot of this stuff will have to change to support C++. But we're
- not going to deal with that at the moment. */
-
-/* Find the field in the structure type TYPE named NAME, and return
- its index in TYPE's field array. */
-static int
-find_field (struct type *type, char *name)
-{
- int i;
-
- CHECK_TYPEDEF (type);
-
- /* Make sure this isn't C++. */
- if (TYPE_N_BASECLASSES (type) != 0)
- internal_error (__FILE__, __LINE__,
- "find_field: derived classes supported");
-
- for (i = 0; i < TYPE_NFIELDS (type); i++)
- {
- char *this_name = TYPE_FIELD_NAME (type, i);
-
- if (this_name && STREQ (name, this_name))
- return i;
-
- if (this_name[0] == '\0')
- internal_error (__FILE__, __LINE__,
- "find_field: anonymous unions not supported");
- }
-
- error ("Couldn't find member named `%s' in struct/union `%s'",
- name, TYPE_TAG_NAME (type));
-
- return 0;
-}
-
-
/* Generate code to push the value of a bitfield of a structure whose
address is on the top of the stack. START and END give the
starting and one-past-ending *bit* numbers of the field within the
@@ -1181,8 +1258,7 @@ gen_bitfield_ref (struct agent_expr *ax, struct axs_value *value,
{
/* Note that ops[i] fetches 8 << i bits. */
static enum agent_op ops[]
- =
- {aop_ref8, aop_ref16, aop_ref32, aop_ref64};
+ = {aop_ref8, aop_ref16, aop_ref32, aop_ref64};
static int num_ops = (sizeof (ops) / sizeof (ops[0]));
/* We don't want to touch any byte that the bitfield doesn't
@@ -1228,13 +1304,13 @@ gen_bitfield_ref (struct agent_expr *ax, struct axs_value *value,
equal to the number of `one' bits in bytesize, but who cares? */
int fragment_count;
- /* Dereference any typedefs. */
+ /* Dereference any typedefs. */
type = check_typedef (type);
/* Can we fetch the number of bits requested at all? */
if ((end - start) > ((1 << num_ops) * 8))
internal_error (__FILE__, __LINE__,
- "gen_bitfield_ref: bitfield too wide");
+ _("gen_bitfield_ref: bitfield too wide"));
/* Note that we know here that we only need to try each opcode once.
That may not be true on machines with weird byte sizes. */
@@ -1260,7 +1336,7 @@ gen_bitfield_ref (struct agent_expr *ax, struct axs_value *value,
/* 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);
@@ -1303,7 +1379,7 @@ gen_bitfield_ref (struct agent_expr *ax, struct axs_value *value,
the sign/zero extension will wipe them out.
- If we're in the interior of the word, then there is no garbage
on either end, because the ref operators zero-extend. */
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+ if (gdbarch_byte_order (ax->gdbarch) == BFD_ENDIAN_BIG)
gen_left_shift (ax, end - (offset + op_size));
else
gen_left_shift (ax, offset - start);
@@ -1330,6 +1406,93 @@ gen_bitfield_ref (struct agent_expr *ax, struct axs_value *value,
value->type = type;
}
+/* Generate bytecodes for field number FIELDNO of type TYPE. OFFSET
+ is an accumulated offset (in bytes), will be nonzero for objects
+ embedded in other objects, like C++ base classes. Behavior should
+ generally follow value_primitive_field. */
+
+static void
+gen_primitive_field (struct agent_expr *ax, struct axs_value *value,
+ int offset, int fieldno, struct type *type)
+{
+ /* Is this a bitfield? */
+ if (TYPE_FIELD_PACKED (type, fieldno))
+ gen_bitfield_ref (ax, value, TYPE_FIELD_TYPE (type, fieldno),
+ (offset * TARGET_CHAR_BIT
+ + TYPE_FIELD_BITPOS (type, fieldno)),
+ (offset * TARGET_CHAR_BIT
+ + TYPE_FIELD_BITPOS (type, fieldno)
+ + TYPE_FIELD_BITSIZE (type, fieldno)));
+ else
+ {
+ gen_offset (ax, offset
+ + TYPE_FIELD_BITPOS (type, fieldno) / TARGET_CHAR_BIT);
+ value->kind = axs_lvalue_memory;
+ value->type = TYPE_FIELD_TYPE (type, fieldno);
+ }
+}
+
+/* Search for the given field in either the given type or one of its
+ base classes. Return 1 if found, 0 if not. */
+
+static int
+gen_struct_ref_recursive (struct agent_expr *ax, struct axs_value *value,
+ const char *field, int offset, struct type *type)
+{
+ int i, rslt;
+ int nbases = TYPE_N_BASECLASSES (type);
+
+ type = check_typedef (type);
+
+ for (i = TYPE_NFIELDS (type) - 1; i >= nbases; i--)
+ {
+ const char *this_name = TYPE_FIELD_NAME (type, i);
+
+ if (this_name)
+ {
+ if (strcmp (field, this_name) == 0)
+ {
+ /* Note that bytecodes for the struct's base (aka
+ "this") will have been generated already, which will
+ be unnecessary but not harmful if the static field is
+ being handled as a global. */
+ if (field_is_static (&TYPE_FIELD (type, i)))
+ {
+ gen_static_field (ax, value, type, i);
+ if (value->optimized_out)
+ error (_("static field `%s' has been "
+ "optimized out, cannot use"),
+ field);
+ return 1;
+ }
+
+ gen_primitive_field (ax, value, offset, i, type);
+ return 1;
+ }
+#if 0 /* is this right? */
+ if (this_name[0] == '\0')
+ internal_error (__FILE__, __LINE__,
+ _("find_field: anonymous unions not supported"));
+#endif
+ }
+ }
+
+ /* Now scan through base classes recursively. */
+ for (i = 0; i < nbases; i++)
+ {
+ struct type *basetype = check_typedef (TYPE_BASECLASS (type, i));
+
+ rslt = gen_struct_ref_recursive (ax, value, field,
+ offset + TYPE_BASECLASS_BITPOS (type, i)
+ / TARGET_CHAR_BIT,
+ basetype);
+ if (rslt)
+ return 1;
+ }
+
+ /* Not found anywhere, flag so caller can complain. */
+ return 0;
+}
/* Generate code to reference the member named FIELD of a structure or
union. The top of the stack, as described by VALUE, should have
@@ -1337,51 +1500,192 @@ gen_bitfield_ref (struct agent_expr *ax, struct axs_value *value,
the operator being compiled, and OPERAND_NAME is the kind of thing
it operates on; we use them in error messages. */
static void
-gen_struct_ref (struct agent_expr *ax, struct axs_value *value, char *field,
- char *operator_name, char *operand_name)
+gen_struct_ref (struct agent_expr *ax, struct axs_value *value,
+ const char *field, const char *operator_name,
+ const char *operand_name)
{
struct type *type;
- int i;
+ int found;
/* Follow pointers until we reach a non-pointer. These aren't the C
semantics, but they're what the normal GDB evaluator does, so we
should at least be consistent. */
- while (TYPE_CODE (value->type) == TYPE_CODE_PTR)
+ while (pointer_type (value->type))
{
- gen_usual_unary (ax, value);
- gen_deref (ax, value);
+ require_rvalue (ax, value);
+ gen_deref (value);
}
type = check_typedef (value->type);
/* This must yield a structure or a union. */
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION)
- error ("The left operand of `%s' is not a %s.",
+ error (_("The left operand of `%s' is not a %s."),
operator_name, operand_name);
/* And it must be in memory; we don't deal with structure rvalues,
or structures living in registers. */
if (value->kind != axs_lvalue_memory)
- error ("Structure does not live in memory.");
+ error (_("Structure does not live in memory."));
+
+ /* Search through fields and base classes recursively. */
+ found = gen_struct_ref_recursive (ax, value, field, 0, type);
+
+ if (!found)
+ error (_("Couldn't find member named `%s' in struct/union/class `%s'"),
+ field, TYPE_NAME (type));
+}
- i = find_field (type, field);
+static int
+gen_namespace_elt (struct agent_expr *ax, struct axs_value *value,
+ const struct type *curtype, char *name);
+static int
+gen_maybe_namespace_elt (struct agent_expr *ax, struct axs_value *value,
+ const struct type *curtype, char *name);
- /* Is this a bitfield? */
- if (TYPE_FIELD_PACKED (type, i))
- gen_bitfield_ref (ax, value, TYPE_FIELD_TYPE (type, i),
- TYPE_FIELD_BITPOS (type, i),
- (TYPE_FIELD_BITPOS (type, i)
- + TYPE_FIELD_BITSIZE (type, i)));
- else
+static void
+gen_static_field (struct agent_expr *ax, struct axs_value *value,
+ struct type *type, int fieldno)
+{
+ if (TYPE_FIELD_LOC_KIND (type, fieldno) == FIELD_LOC_KIND_PHYSADDR)
{
- gen_offset (ax, TYPE_FIELD_BITPOS (type, i) / TARGET_CHAR_BIT);
+ ax_const_l (ax, TYPE_FIELD_STATIC_PHYSADDR (type, fieldno));
value->kind = axs_lvalue_memory;
- value->type = TYPE_FIELD_TYPE (type, i);
+ value->type = TYPE_FIELD_TYPE (type, fieldno);
+ value->optimized_out = 0;
+ }
+ else
+ {
+ const char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno);
+ struct symbol *sym = lookup_symbol (phys_name, 0, VAR_DOMAIN, 0).symbol;
+
+ if (sym)
+ {
+ gen_var_ref (ax, value, sym);
+
+ /* Don't error if the value was optimized out, we may be
+ scanning all static fields and just want to pass over this
+ and continue with the rest. */
+ }
+ else
+ {
+ /* Silently assume this was optimized out; class printing
+ will let the user know why the data is missing. */
+ value->optimized_out = 1;
+ }
}
}
+static int
+gen_struct_elt_for_reference (struct agent_expr *ax, struct axs_value *value,
+ struct type *type, char *fieldname)
+{
+ struct type *t = type;
+ int i;
+
+ if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
+ internal_error (__FILE__, __LINE__,
+ _("non-aggregate type to gen_struct_elt_for_reference"));
+
+ for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--)
+ {
+ const char *t_field_name = TYPE_FIELD_NAME (t, i);
+
+ if (t_field_name && strcmp (t_field_name, fieldname) == 0)
+ {
+ if (field_is_static (&TYPE_FIELD (t, i)))
+ {
+ gen_static_field (ax, value, t, i);
+ if (value->optimized_out)
+ error (_("static field `%s' has been "
+ "optimized out, cannot use"),
+ fieldname);
+ return 1;
+ }
+ if (TYPE_FIELD_PACKED (t, i))
+ error (_("pointers to bitfield members not allowed"));
+
+ /* FIXME we need a way to do "want_address" equivalent */
+
+ error (_("Cannot reference non-static field \"%s\""), fieldname);
+ }
+ }
+
+ /* FIXME add other scoped-reference cases here */
+
+ /* Do a last-ditch lookup. */
+ return gen_maybe_namespace_elt (ax, value, type, fieldname);
+}
+
+/* C++: Return the member NAME of the namespace given by the type
+ CURTYPE. */
+
+static int
+gen_namespace_elt (struct agent_expr *ax, struct axs_value *value,
+ const struct type *curtype, char *name)
+{
+ int found = gen_maybe_namespace_elt (ax, value, curtype, name);
+
+ if (!found)
+ error (_("No symbol \"%s\" in namespace \"%s\"."),
+ name, TYPE_NAME (curtype));
+
+ return found;
+}
+
+/* A helper function used by value_namespace_elt and
+ value_struct_elt_for_reference. It looks up NAME inside the
+ context CURTYPE; this works if CURTYPE is a namespace or if CURTYPE
+ is a class and NAME refers to a type in CURTYPE itself (as opposed
+ to, say, some base class of CURTYPE). */
+
+static int
+gen_maybe_namespace_elt (struct agent_expr *ax, struct axs_value *value,
+ const struct type *curtype, char *name)
+{
+ const char *namespace_name = TYPE_NAME (curtype);
+ struct block_symbol sym;
+
+ sym = cp_lookup_symbol_namespace (namespace_name, name,
+ block_for_pc (ax->scope),
+ VAR_DOMAIN);
-/* Generate code for GDB's magical `repeat' operator.
+ if (sym.symbol == NULL)
+ return 0;
+
+ gen_var_ref (ax, value, sym.symbol);
+
+ if (value->optimized_out)
+ error (_("`%s' has been optimized out, cannot use"),
+ SYMBOL_PRINT_NAME (sym.symbol));
+
+ return 1;
+}
+
+
+static int
+gen_aggregate_elt_ref (struct agent_expr *ax, struct axs_value *value,
+ struct type *type, char *field)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ return gen_struct_elt_for_reference (ax, value, type, field);
+ break;
+ case TYPE_CODE_NAMESPACE:
+ return gen_namespace_elt (ax, value, type, field);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("non-aggregate type in gen_aggregate_elt_ref"));
+ }
+
+ return 0;
+}
+
+/* Generate code for GDB's magical `repeat' operator.
LVALUE @ INT creates an array INT elements long, and whose elements
have the same type as LVALUE, located in memory so that LVALUE is
its first element. For example, argv[0]@argc gives you the array
@@ -1393,15 +1697,16 @@ gen_struct_ref (struct agent_expr *ax, struct axs_value *value, char *field,
stack slots, doing weird things with sizeof, etc. So we require
the right operand to be a constant expression. */
static void
-gen_repeat (union exp_element **pc, struct agent_expr *ax,
- struct axs_value *value)
+gen_repeat (struct expression *exp, union exp_element **pc,
+ struct agent_expr *ax, struct axs_value *value)
{
struct axs_value value1;
+
/* We don't want to turn this into an rvalue, so no conversions
here. */
- gen_expr (pc, ax, &value1);
+ gen_expr (exp, pc, ax, &value1);
if (value1.kind != axs_lvalue_memory)
- error ("Left operand of `@' must be an object in memory.");
+ error (_("Left operand of `@' must be an object in memory."));
/* Evaluate the length; it had better be a constant. */
{
@@ -1409,21 +1714,21 @@ gen_repeat (union exp_element **pc, struct agent_expr *ax,
int length;
if (!v)
- error ("Right operand of `@' must be a constant, in agent expressions.");
- if (TYPE_CODE (v->type) != TYPE_CODE_INT)
- error ("Right operand of `@' must be an integer.");
+ error (_("Right operand of `@' must be a "
+ "constant, in agent expressions."));
+ if (TYPE_CODE (value_type (v)) != TYPE_CODE_INT)
+ error (_("Right operand of `@' must be an integer."));
length = value_as_long (v);
if (length <= 0)
- error ("Right operand of `@' must be positive.");
+ error (_("Right operand of `@' must be positive."));
/* The top of the stack is already the address of the object, so
all we need to do is frob the type of the lvalue. */
{
/* FIXME-type-allocation: need a way to free this type when we are
done with it. */
- struct type *range
- = create_range_type (0, builtin_type_int, 0, length - 1);
- struct type *array = create_array_type (0, value1.type, range);
+ struct type *array
+ = lookup_array_range_type (value1.type, 0, length - 1);
value->kind = axs_lvalue_memory;
value->type = array;
@@ -1436,8 +1741,9 @@ gen_repeat (union exp_element **pc, struct agent_expr *ax,
*PC should point at the start of the operand expression; we advance it
to the first instruction after the operand. */
static void
-gen_sizeof (union exp_element **pc, struct agent_expr *ax,
- struct axs_value *value)
+gen_sizeof (struct expression *exp, union exp_element **pc,
+ struct agent_expr *ax, struct axs_value *value,
+ struct type *size_type)
{
/* We don't care about the value of the operand expression; we only
care about its type. However, in the current arrangement, the
@@ -1445,28 +1751,66 @@ gen_sizeof (union exp_element **pc, struct agent_expr *ax,
So we generate code for the operand, and then throw it away,
replacing it with code that simply pushes its size. */
int start = ax->len;
- gen_expr (pc, ax, value);
+
+ gen_expr (exp, pc, ax, value);
/* Throw away the code we just generated. */
ax->len = start;
ax_const_l (ax, TYPE_LENGTH (value->type));
value->kind = axs_rvalue;
- value->type = builtin_type_int;
+ value->type = size_type;
}
+/* Generate bytecode for a cast to TO_TYPE. Advance *PC over the
+ subexpression. */
+
+static void
+gen_expr_for_cast (struct expression *exp, union exp_element **pc,
+ struct agent_expr *ax, struct axs_value *value,
+ struct type *to_type)
+{
+ enum exp_opcode op = (*pc)[0].opcode;
+
+ /* Don't let symbols be handled with gen_expr because that throws an
+ "unknown type" error for no-debug data symbols. Instead, we want
+ the cast to reinterpret such symbols. */
+ if (op == OP_VAR_MSYM_VALUE || op == OP_VAR_VALUE)
+ {
+ if (op == OP_VAR_VALUE)
+ {
+ gen_var_ref (ax, value, (*pc)[2].symbol);
+
+ if (value->optimized_out)
+ error (_("`%s' has been optimized out, cannot use"),
+ SYMBOL_PRINT_NAME ((*pc)[2].symbol));
+ }
+ else
+ gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
+ if (TYPE_CODE (value->type) == TYPE_CODE_ERROR)
+ value->type = to_type;
+ (*pc) += 4;
+ }
+ else
+ gen_expr (exp, pc, ax, value);
+ gen_cast (ax, value, to_type);
+}
+
/* Generating bytecode from GDB expressions: general recursive thingy */
+/* 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
-gen_expr (union exp_element **pc, struct agent_expr *ax,
- struct axs_value *value)
+void
+gen_expr (struct expression *exp, union exp_element **pc,
+ struct agent_expr *ax, struct axs_value *value)
{
/* Used to hold the descriptions of operand expressions. */
- struct axs_value value1, value2;
- enum exp_opcode op = (*pc)[0].opcode;
+ struct axs_value value1, value2, value3;
+ enum exp_opcode op = (*pc)[0].opcode, op2;
+ int if1, go1, if2, go2, end;
+ struct type *int_type = builtin_type (ax->gdbarch)->builtin_int;
/* If we're looking at a constant expression, just push its value. */
{
@@ -1476,7 +1820,7 @@ gen_expr (union exp_element **pc, struct agent_expr *ax,
{
ax_const_l (ax, value_as_long (v));
value->kind = axs_rvalue;
- value->type = check_typedef (VALUE_TYPE (v));
+ value->type = check_typedef (value_type (v));
return;
}
}
@@ -1490,63 +1834,146 @@ gen_expr (union exp_element **pc, struct agent_expr *ax,
case BINOP_MUL:
case BINOP_DIV:
case BINOP_REM:
+ case BINOP_LSH:
+ case BINOP_RSH:
case BINOP_SUBSCRIPT:
case BINOP_BITWISE_AND:
case BINOP_BITWISE_IOR:
case BINOP_BITWISE_XOR:
+ case BINOP_EQUAL:
+ case BINOP_NOTEQUAL:
+ case BINOP_LESS:
+ case BINOP_GTR:
+ case BINOP_LEQ:
+ case BINOP_GEQ:
+ (*pc)++;
+ gen_expr (exp, pc, ax, &value1);
+ gen_usual_unary (ax, &value1);
+ gen_expr_binop_rest (exp, op, pc, ax, value, &value1, &value2);
+ break;
+
+ case BINOP_LOGICAL_AND:
(*pc)++;
- gen_expr (pc, ax, &value1);
+ /* Generate the obvious sequence of tests and jumps. */
+ gen_expr (exp, pc, ax, &value1);
gen_usual_unary (ax, &value1);
- gen_expr (pc, ax, &value2);
+ if1 = ax_goto (ax, aop_if_goto);
+ go1 = ax_goto (ax, aop_goto);
+ ax_label (ax, if1, ax->len);
+ gen_expr (exp, pc, ax, &value2);
gen_usual_unary (ax, &value2);
- gen_usual_arithmetic (ax, &value1, &value2);
- switch (op)
+ if2 = ax_goto (ax, aop_if_goto);
+ go2 = ax_goto (ax, aop_goto);
+ ax_label (ax, if2, ax->len);
+ ax_const_l (ax, 1);
+ end = ax_goto (ax, aop_goto);
+ ax_label (ax, go1, ax->len);
+ ax_label (ax, go2, ax->len);
+ ax_const_l (ax, 0);
+ ax_label (ax, end, ax->len);
+ value->kind = axs_rvalue;
+ value->type = int_type;
+ break;
+
+ case BINOP_LOGICAL_OR:
+ (*pc)++;
+ /* Generate the obvious sequence of tests and jumps. */
+ gen_expr (exp, pc, ax, &value1);
+ gen_usual_unary (ax, &value1);
+ if1 = ax_goto (ax, aop_if_goto);
+ gen_expr (exp, pc, ax, &value2);
+ gen_usual_unary (ax, &value2);
+ if2 = ax_goto (ax, aop_if_goto);
+ ax_const_l (ax, 0);
+ end = ax_goto (ax, aop_goto);
+ ax_label (ax, if1, ax->len);
+ ax_label (ax, if2, ax->len);
+ ax_const_l (ax, 1);
+ ax_label (ax, end, ax->len);
+ value->kind = axs_rvalue;
+ value->type = int_type;
+ break;
+
+ case TERNOP_COND:
+ (*pc)++;
+ gen_expr (exp, pc, ax, &value1);
+ gen_usual_unary (ax, &value1);
+ /* For (A ? B : C), it's easiest to generate subexpression
+ bytecodes in order, but if_goto jumps on true, so we invert
+ the sense of A. Then we can do B by dropping through, and
+ jump to do C. */
+ gen_logical_not (ax, &value1, int_type);
+ if1 = ax_goto (ax, aop_if_goto);
+ gen_expr (exp, pc, ax, &value2);
+ gen_usual_unary (ax, &value2);
+ end = ax_goto (ax, aop_goto);
+ ax_label (ax, if1, ax->len);
+ gen_expr (exp, pc, ax, &value3);
+ gen_usual_unary (ax, &value3);
+ ax_label (ax, end, ax->len);
+ /* This is arbitary - what if B and C are incompatible types? */
+ value->type = value2.type;
+ value->kind = value2.kind;
+ break;
+
+ case BINOP_ASSIGN:
+ (*pc)++;
+ if ((*pc)[0].opcode == OP_INTERNALVAR)
{
- case BINOP_ADD:
- gen_add (ax, value, &value1, &value2, "addition");
- break;
- case BINOP_SUB:
- gen_sub (ax, value, &value1, &value2);
- break;
- case BINOP_MUL:
- gen_binop (ax, value, &value1, &value2,
- aop_mul, aop_mul, 1, "multiplication");
- break;
- case BINOP_DIV:
- gen_binop (ax, value, &value1, &value2,
- aop_div_signed, aop_div_unsigned, 1, "division");
- break;
- case BINOP_REM:
- gen_binop (ax, value, &value1, &value2,
- aop_rem_signed, aop_rem_unsigned, 1, "remainder");
- break;
- case BINOP_SUBSCRIPT:
- gen_add (ax, value, &value1, &value2, "array subscripting");
- if (TYPE_CODE (value->type) != TYPE_CODE_PTR)
- error ("Illegal combination of types in array subscripting.");
- gen_deref (ax, value);
- break;
- case BINOP_BITWISE_AND:
- gen_binop (ax, value, &value1, &value2,
- aop_bit_and, aop_bit_and, 0, "bitwise and");
- break;
+ char *name = internalvar_name ((*pc)[1].internalvar);
+ struct trace_state_variable *tsv;
- case BINOP_BITWISE_IOR:
- gen_binop (ax, value, &value1, &value2,
- aop_bit_or, aop_bit_or, 0, "bitwise or");
- break;
+ (*pc) += 3;
+ gen_expr (exp, pc, ax, value);
+ tsv = find_trace_state_variable (name);
+ if (tsv)
+ {
+ ax_tsv (ax, aop_setv, tsv->number);
+ if (ax->tracing)
+ ax_tsv (ax, aop_tracev, tsv->number);
+ }
+ else
+ error (_("$%s is not a trace state variable, "
+ "may not assign to it"), name);
+ }
+ else
+ error (_("May only assign to trace state variables"));
+ break;
- case BINOP_BITWISE_XOR:
- gen_binop (ax, value, &value1, &value2,
- aop_bit_xor, aop_bit_xor, 0, "bitwise exclusive-or");
- break;
+ case BINOP_ASSIGN_MODIFY:
+ (*pc)++;
+ op2 = (*pc)[0].opcode;
+ (*pc)++;
+ (*pc)++;
+ if ((*pc)[0].opcode == OP_INTERNALVAR)
+ {
+ char *name = internalvar_name ((*pc)[1].internalvar);
+ struct trace_state_variable *tsv;
- default:
- /* We should only list operators in the outer case statement
- that we actually handle in the inner case statement. */
- internal_error (__FILE__, __LINE__,
- "gen_expr: op case sets don't match");
+ (*pc) += 3;
+ tsv = find_trace_state_variable (name);
+ if (tsv)
+ {
+ /* The tsv will be the left half of the binary operation. */
+ ax_tsv (ax, aop_getv, tsv->number);
+ if (ax->tracing)
+ ax_tsv (ax, aop_tracev, tsv->number);
+ /* Trace state variables are always 64-bit integers. */
+ value1.kind = axs_rvalue;
+ value1.type = builtin_type (ax->gdbarch)->builtin_long_long;
+ /* Now do right half of expression. */
+ 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 (ax->tracing)
+ ax_tsv (ax, aop_tracev, tsv->number);
+ }
+ else
+ error (_("$%s is not a trace state variable, "
+ "may not assign to it"), name);
}
+ else
+ error (_("May only assign to trace state variables"));
break;
/* Note that we need to be a little subtle about generating code
@@ -1557,12 +1984,12 @@ gen_expr (union exp_element **pc, struct agent_expr *ax,
variables it mentions get traced. */
case BINOP_COMMA:
(*pc)++;
- gen_expr (pc, ax, &value1);
+ gen_expr (exp, pc, ax, &value1);
/* Don't just dispose of the left operand. We might be tracing,
in which case we want to emit code to trace it if it's an
lvalue. */
gen_traced_pop (ax, &value1);
- gen_expr (pc, ax, value);
+ gen_expr (exp, pc, ax, value);
/* It's the consumer's responsibility to trace the right operand. */
break;
@@ -1570,6 +1997,7 @@ gen_expr (union exp_element **pc, struct agent_expr *ax,
{
struct type *type = (*pc)[1].type;
LONGEST k = (*pc)[2].longconst;
+
(*pc) += 4;
gen_int_literal (ax, value, k, type);
}
@@ -1577,92 +2005,191 @@ gen_expr (union exp_element **pc, struct agent_expr *ax,
case OP_VAR_VALUE:
gen_var_ref (ax, value, (*pc)[2].symbol);
+
+ if (value->optimized_out)
+ error (_("`%s' has been optimized out, cannot use"),
+ SYMBOL_PRINT_NAME ((*pc)[2].symbol));
+
+ if (TYPE_CODE (value->type) == TYPE_CODE_ERROR)
+ error_unknown_type (SYMBOL_PRINT_NAME ((*pc)[2].symbol));
+
+ (*pc) += 4;
+ break;
+
+ case OP_VAR_MSYM_VALUE:
+ gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
+
+ if (TYPE_CODE (value->type) == TYPE_CODE_ERROR)
+ error_unknown_type (MSYMBOL_PRINT_NAME ((*pc)[2].msymbol));
+
(*pc) += 4;
break;
case OP_REGISTER:
{
- int reg = (int) (*pc)[1].longconst;
- (*pc) += 3;
+ const char *name = &(*pc)[2].string;
+ int reg;
+
+ (*pc) += 4 + BYTES_TO_EXP_ELEM ((*pc)[1].longconst + 1);
+ reg = user_reg_map_name_to_regnum (ax->gdbarch, name, strlen (name));
+ if (reg == -1)
+ internal_error (__FILE__, __LINE__,
+ _("Register $%s not available"), name);
+ /* No support for tracing user registers yet. */
+ if (reg >= gdbarch_num_cooked_regs (ax->gdbarch))
+ error (_("'%s' is a user-register; "
+ "GDB cannot yet trace user-register contents."),
+ name);
value->kind = axs_lvalue_register;
value->u.reg = reg;
- value->type = REGISTER_VIRTUAL_TYPE (reg);
+ value->type = register_type (ax->gdbarch, reg);
}
break;
case OP_INTERNALVAR:
- error ("GDB agent expressions cannot use convenience variables.");
+ {
+ struct internalvar *var = (*pc)[1].internalvar;
+ const char *name = internalvar_name (var);
+ struct trace_state_variable *tsv;
+
+ (*pc) += 3;
+ tsv = find_trace_state_variable (name);
+ if (tsv)
+ {
+ ax_tsv (ax, aop_getv, tsv->number);
+ if (ax->tracing)
+ ax_tsv (ax, aop_tracev, tsv->number);
+ /* Trace state variables are always 64-bit integers. */
+ value->kind = axs_rvalue;
+ value->type = builtin_type (ax->gdbarch)->builtin_long_long;
+ }
+ 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;
/* Weirdo operator: see comments for gen_repeat for details. */
case BINOP_REPEAT:
/* Note that gen_repeat handles its own argument evaluation. */
(*pc)++;
- gen_repeat (pc, ax, value);
+ gen_repeat (exp, pc, ax, value);
break;
case UNOP_CAST:
{
struct type *type = (*pc)[1].type;
+
(*pc) += 3;
- gen_expr (pc, ax, value);
- gen_cast (ax, value, type);
+ gen_expr_for_cast (exp, pc, ax, value, type);
+ }
+ 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_for_cast (exp, pc, ax, value, type);
}
break;
case UNOP_MEMVAL:
{
struct type *type = check_typedef ((*pc)[1].type);
+
(*pc) += 3;
- gen_expr (pc, ax, value);
- /* I'm not sure I understand UNOP_MEMVAL entirely. I think
- it's just a hack for dealing with minsyms; you take some
- integer constant, pretend it's the address of an lvalue of
- the given type, and dereference it. */
- if (value->kind != axs_rvalue)
- /* This would be weird. */
- internal_error (__FILE__, __LINE__,
- "gen_expr: OP_MEMVAL operand isn't an rvalue???");
+ 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_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. */
+ gen_expr (exp, pc, ax, value);
+ gen_usual_unary (ax, value);
+ break;
+
case UNOP_NEG:
(*pc)++;
/* -FOO is equivalent to 0 - FOO. */
- gen_int_literal (ax, &value1, (LONGEST) 0, builtin_type_int);
+ gen_int_literal (ax, &value1, 0,
+ builtin_type (ax->gdbarch)->builtin_int);
gen_usual_unary (ax, &value1); /* shouldn't do much */
- gen_expr (pc, ax, &value2);
+ gen_expr (exp, pc, ax, &value2);
gen_usual_unary (ax, &value2);
gen_usual_arithmetic (ax, &value1, &value2);
- gen_sub (ax, value, &value1, &value2);
+ gen_binop (ax, value, &value1, &value2, aop_sub, aop_sub, 1, "negation");
break;
case UNOP_LOGICAL_NOT:
(*pc)++;
- gen_expr (pc, ax, value);
- gen_logical_not (ax, value);
+ gen_expr (exp, pc, ax, value);
+ gen_usual_unary (ax, value);
+ gen_logical_not (ax, value, int_type);
break;
case UNOP_COMPLEMENT:
(*pc)++;
- gen_expr (pc, ax, value);
+ gen_expr (exp, pc, ax, value);
+ gen_usual_unary (ax, value);
+ gen_integral_promotions (ax, value);
gen_complement (ax, value);
break;
case UNOP_IND:
(*pc)++;
- gen_expr (pc, ax, value);
+ gen_expr (exp, pc, ax, value);
gen_usual_unary (ax, value);
- if (TYPE_CODE (value->type) != TYPE_CODE_PTR)
- error ("Argument of unary `*' is not a pointer.");
- gen_deref (ax, value);
+ if (!pointer_type (value->type))
+ error (_("Argument of unary `*' is not a pointer."));
+ gen_deref (value);
break;
case UNOP_ADDR:
(*pc)++;
- gen_expr (pc, ax, value);
- gen_address_of (ax, value);
+ gen_expr (exp, pc, ax, value);
+ gen_address_of (value);
break;
case UNOP_SIZEOF:
@@ -1670,7 +2197,8 @@ gen_expr (union exp_element **pc, struct agent_expr *ax,
/* Notice that gen_sizeof handles its own operand, unlike most
of the other unary operator functions. This is because we
have to throw away the code we generate. */
- gen_sizeof (pc, ax, value);
+ gen_sizeof (exp, pc, ax, value,
+ builtin_type (ax->gdbarch)->builtin_int);
break;
case STRUCTOP_STRUCT:
@@ -1680,7 +2208,7 @@ gen_expr (union exp_element **pc, struct agent_expr *ax,
char *name = &(*pc)[2].string;
(*pc) += 4 + BYTES_TO_EXP_ELEM (length + 1);
- gen_expr (pc, ax, value);
+ gen_expr (exp, pc, ax, value);
if (op == STRUCTOP_STRUCT)
gen_struct_ref (ax, value, name, ".", "structure or union");
else if (op == STRUCTOP_PTR)
@@ -1690,170 +2218,552 @@ gen_expr (union exp_element **pc, struct agent_expr *ax,
/* If this `if' chain doesn't handle it, then the case list
shouldn't mention it, and we shouldn't be here. */
internal_error (__FILE__, __LINE__,
- "gen_expr: unhandled struct case");
+ _("gen_expr: unhandled struct case"));
+ }
+ break;
+
+ case OP_THIS:
+ {
+ struct symbol *sym, *func;
+ const struct block *b;
+ const struct language_defn *lang;
+
+ b = block_for_pc (ax->scope);
+ func = block_linkage_function (b);
+ lang = language_def (SYMBOL_LANGUAGE (func));
+
+ sym = lookup_language_this (lang, b).symbol;
+ if (!sym)
+ error (_("no `%s' found"), lang->la_name_of_this);
+
+ gen_var_ref (ax, value, sym);
+
+ if (value->optimized_out)
+ error (_("`%s' has been optimized out, cannot use"),
+ SYMBOL_PRINT_NAME (sym));
+
+ (*pc) += 2;
+ }
+ break;
+
+ case OP_SCOPE:
+ {
+ struct type *type = (*pc)[1].type;
+ int length = longest_to_int ((*pc)[2].longconst);
+ char *name = &(*pc)[3].string;
+ int found;
+
+ found = gen_aggregate_elt_ref (ax, value, type, name);
+ if (!found)
+ error (_("There is no field named %s"), name);
+ (*pc) += 5 + BYTES_TO_EXP_ELEM (length + 1);
}
break;
case OP_TYPE:
- error ("Attempt to use a type name as an expression.");
+ case OP_TYPEOF:
+ case OP_DECLTYPE:
+ error (_("Attempt to use a type name as an expression."));
default:
- error ("Unsupported operator in expression.");
+ error (_("Unsupported operator %s (%d) in expression."),
+ op_name (exp, op), op);
}
}
-
-
-/* Generating bytecode from GDB expressions: driver */
+/* This handles the middle-to-right-side of code generation for binary
+ expressions, which is shared between regular binary operations and
+ assign-modify (+= and friends) expressions. */
-/* Given a GDB expression EXPR, produce a string of agent bytecode
- which computes its value. Return the agent expression, and set
- *VALUE to describe its type, and whether it's an lvalue or rvalue. */
-struct agent_expr *
-expr_to_agent (struct expression *expr, 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, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2)
{
- struct cleanup *old_chain = 0;
- struct agent_expr *ax = new_agent_expr (0);
- union exp_element *pc;
+ struct type *int_type = builtin_type (ax->gdbarch)->builtin_int;
- old_chain = make_cleanup_free_agent_expr (ax);
+ gen_expr (exp, pc, ax, value2);
+ gen_usual_unary (ax, value2);
+ gen_usual_arithmetic (ax, value1, value2);
+ switch (op)
+ {
+ case BINOP_ADD:
+ if (TYPE_CODE (value1->type) == TYPE_CODE_INT
+ && pointer_type (value2->type))
+ {
+ /* Swap the values and proceed normally. */
+ ax_simple (ax, aop_swap);
+ gen_ptradd (ax, value, value2, value1);
+ }
+ else if (pointer_type (value1->type)
+ && TYPE_CODE (value2->type) == TYPE_CODE_INT)
+ gen_ptradd (ax, value, value1, value2);
+ else
+ gen_binop (ax, value, value1, value2,
+ aop_add, aop_add, 1, "addition");
+ break;
+ case BINOP_SUB:
+ if (pointer_type (value1->type)
+ && TYPE_CODE (value2->type) == TYPE_CODE_INT)
+ gen_ptrsub (ax,value, value1, value2);
+ else if (pointer_type (value1->type)
+ && pointer_type (value2->type))
+ /* FIXME --- result type should be ptrdiff_t */
+ gen_ptrdiff (ax, value, value1, value2,
+ builtin_type (ax->gdbarch)->builtin_long);
+ else
+ gen_binop (ax, value, value1, value2,
+ aop_sub, aop_sub, 1, "subtraction");
+ break;
+ case BINOP_MUL:
+ gen_binop (ax, value, value1, value2,
+ aop_mul, aop_mul, 1, "multiplication");
+ break;
+ case BINOP_DIV:
+ gen_binop (ax, value, value1, value2,
+ aop_div_signed, aop_div_unsigned, 1, "division");
+ break;
+ case BINOP_REM:
+ gen_binop (ax, value, value1, value2,
+ aop_rem_signed, aop_rem_unsigned, 1, "remainder");
+ break;
+ case BINOP_LSH:
+ gen_binop (ax, value, value1, value2,
+ aop_lsh, aop_lsh, 1, "left shift");
+ break;
+ case BINOP_RSH:
+ gen_binop (ax, value, value1, value2,
+ aop_rsh_signed, aop_rsh_unsigned, 1, "right shift");
+ break;
+ case BINOP_SUBSCRIPT:
+ {
+ struct type *type;
- pc = expr->elts;
- trace_kludge = 0;
- gen_expr (&pc, ax, value);
+ if (binop_types_user_defined_p (op, value1->type, value2->type))
+ {
+ error (_("cannot subscript requested type: "
+ "cannot call user defined functions"));
+ }
+ else
+ {
+ /* If the user attempts to subscript something that is not
+ an array or pointer type (like a plain int variable for
+ example), then report this as an error. */
+ type = check_typedef (value1->type);
+ if (TYPE_CODE (type) != TYPE_CODE_ARRAY
+ && TYPE_CODE (type) != TYPE_CODE_PTR)
+ {
+ if (TYPE_NAME (type))
+ error (_("cannot subscript something of type `%s'"),
+ TYPE_NAME (type));
+ else
+ error (_("cannot subscript requested type"));
+ }
+ }
+
+ if (!is_integral_type (value2->type))
+ error (_("Argument to arithmetic operation "
+ "not a number or boolean."));
+
+ gen_ptradd (ax, value, value1, value2);
+ gen_deref (value);
+ break;
+ }
+ case BINOP_BITWISE_AND:
+ gen_binop (ax, value, value1, value2,
+ aop_bit_and, aop_bit_and, 0, "bitwise and");
+ break;
- /* 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;
-}
+ case BINOP_BITWISE_IOR:
+ gen_binop (ax, value, value1, value2,
+ aop_bit_or, aop_bit_or, 0, "bitwise or");
+ break;
+
+ case BINOP_BITWISE_XOR:
+ gen_binop (ax, value, value1, value2,
+ aop_bit_xor, aop_bit_xor, 0, "bitwise exclusive-or");
+ break;
+ case BINOP_EQUAL:
+ gen_equal (ax, value, value1, value2, int_type);
+ break;
-#if 0 /* not used */
-/* Given a GDB expression EXPR denoting an lvalue in memory, produce a
- string of agent bytecode which will leave its address and size on
- the top of stack. Return the agent expression.
+ case BINOP_NOTEQUAL:
+ gen_equal (ax, value, value1, value2, int_type);
+ gen_logical_not (ax, value, int_type);
+ break;
- Not sure this function is useful at all. */
-struct agent_expr *
-expr_to_address_and_size (struct expression *expr)
+ case BINOP_LESS:
+ gen_less (ax, value, value1, value2, int_type);
+ break;
+
+ case BINOP_GTR:
+ ax_simple (ax, aop_swap);
+ gen_less (ax, value, value1, value2, int_type);
+ break;
+
+ case BINOP_LEQ:
+ ax_simple (ax, aop_swap);
+ gen_less (ax, value, value1, value2, int_type);
+ gen_logical_not (ax, value, int_type);
+ break;
+
+ case BINOP_GEQ:
+ gen_less (ax, value, value1, value2, int_type);
+ gen_logical_not (ax, value, int_type);
+ break;
+
+ default:
+ /* We should only list operators in the outer case statement
+ that we actually handle in the inner case statement. */
+ internal_error (__FILE__, __LINE__,
+ _("gen_expr: op case sets don't match"));
+ }
+}
+
+
+/* Given a single variable and a scope, generate bytecodes to trace
+ its value. This is for use in situations where we have only a
+ variable's name, and no parsed expression; for instance, when the
+ name comes from a list of local variables of a function. */
+
+agent_expr_up
+gen_trace_for_var (CORE_ADDR scope, struct gdbarch *gdbarch,
+ struct symbol *var, int trace_string)
{
+ agent_expr_up ax (new agent_expr (gdbarch, scope));
struct axs_value value;
- struct agent_expr *ax = expr_to_agent (expr, &value);
- /* Complain if the result is not a memory lvalue. */
- if (value.kind != axs_lvalue_memory)
- {
- free_agent_expr (ax);
- error ("Expression does not denote an object in memory.");
- }
+ ax->tracing = 1;
+ ax->trace_string = trace_string;
+ gen_var_ref (ax.get (), &value, var);
- /* Push the object's size on the stack. */
- ax_const_l (ax, TYPE_LENGTH (value.type));
+ /* If there is no actual variable to trace, flag it by returning
+ an empty agent expression. */
+ if (value.optimized_out)
+ return agent_expr_up ();
+
+ /* Make sure we record the final object, and get rid of it. */
+ gen_traced_pop (ax.get (), &value);
+
+ /* Oh, and terminate. */
+ ax_simple (ax.get (), aop_end);
return ax;
}
-#endif
+
+/* Generating bytecode from GDB expressions: driver */
/* Given a GDB expression EXPR, return bytecode to trace its value.
The result will use the `trace' and `trace_quick' bytecodes to
record the value of all memory touched by the expression. The
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)
+
+agent_expr_up
+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 (scope);
+ agent_expr_up ax (new agent_expr (expr->gdbarch, scope));
union exp_element *pc;
struct axs_value value;
- old_chain = make_cleanup_free_agent_expr (ax);
+ pc = expr->elts;
+ ax->tracing = 1;
+ ax->trace_string = trace_string;
+ value.optimized_out = 0;
+ gen_expr (expr, &pc, ax.get (), &value);
+
+ /* Make sure we record the final object, and get rid of it. */
+ gen_traced_pop (ax.get (), &value);
+
+ /* Oh, and terminate. */
+ ax_simple (ax.get (), aop_end);
+
+ return ax;
+}
+
+/* Given a GDB expression EXPR, return a bytecode sequence that will
+ evaluate and return a result. The bytecodes will do a direct
+ evaluation, using the current data on the target, rather than
+ recording blocks of memory and registers for later use, as
+ gen_trace_for_expr does. The generated bytecode sequence leaves
+ the result of expression evaluation on the top of the stack. */
+
+agent_expr_up
+gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
+{
+ agent_expr_up ax (new agent_expr (expr->gdbarch, scope));
+ union exp_element *pc;
+ struct axs_value value;
pc = expr->elts;
- trace_kludge = 1;
- gen_expr (&pc, ax, &value);
+ ax->tracing = 0;
+ value.optimized_out = 0;
+ gen_expr (expr, &pc, ax.get (), &value);
+
+ require_rvalue (ax.get (), &value);
+
+ /* Oh, and terminate. */
+ ax_simple (ax.get (), aop_end);
+
+ return ax;
+}
+
+agent_expr_up
+gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch,
+ int trace_string)
+{
+ agent_expr_up ax (new agent_expr (gdbarch, scope));
+ struct axs_value value;
+
+ ax->tracing = 1;
+ ax->trace_string = trace_string;
+
+ gdbarch_gen_return_address (gdbarch, ax.get (), &value, scope);
/* Make sure we record the final object, and get rid of it. */
- gen_traced_pop (ax, &value);
+ gen_traced_pop (ax.get (), &value);
/* Oh, and terminate. */
- ax_simple (ax, aop_end);
+ ax_simple (ax.get (), 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. */
-/* The "agent" command, for testing: compile and disassemble an expression. */
+agent_expr_up
+gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
+ CORE_ADDR function, LONGEST channel,
+ const char *format, int fmtlen,
+ int nargs, struct expression **exprs)
+{
+ agent_expr_up ax (new agent_expr (gdbarch, scope));
+ union exp_element *pc;
+ struct axs_value value;
+ int tem;
+
+ /* 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.get (), &value);
+ require_rvalue (ax.get (), &value);
+ }
+
+ /* Push function and channel. */
+ ax_const_l (ax.get (), channel);
+ ax_const_l (ax.get (), function);
+
+ /* Issue the printf bytecode proper. */
+ ax_simple (ax.get (), aop_printf);
+ ax_raw_byte (ax.get (), nargs);
+ ax_string (ax.get (), format, fmtlen);
+
+ /* And terminate. */
+ ax_simple (ax.get (), aop_end);
+
+ return ax;
+}
static void
-print_axs_value (struct ui_file *f, struct axs_value *value)
+agent_eval_command_one (const char *exp, int eval, CORE_ADDR pc)
{
- switch (value->kind)
+ const char *arg;
+ int trace_string = 0;
+
+ if (!eval)
{
- case axs_rvalue:
- fputs_filtered ("rvalue", f);
- break;
+ if (*exp == '/')
+ exp = decode_agent_options (exp, &trace_string);
+ }
- case axs_lvalue_memory:
- fputs_filtered ("memory lvalue", f);
- break;
+ agent_expr_up agent;
- case axs_lvalue_register:
- fprintf_filtered (f, "register %d lvalue", value->u.reg);
- break;
+ arg = exp;
+ if (!eval && strcmp (arg, "$_ret") == 0)
+ {
+ agent = gen_trace_for_return_address (pc, get_current_arch (),
+ trace_string);
+ }
+ else
+ {
+ expression_up expr = parse_exp_1 (&arg, pc, block_for_pc (pc), 0);
+
+ if (eval)
+ {
+ gdb_assert (trace_string == 0);
+ agent = gen_eval_for_expr (pc, expr.get ());
+ }
+ else
+ agent = gen_trace_for_expr (pc, expr.get (), trace_string);
+ }
+
+ ax_reqs (agent.get ());
+ ax_print (gdb_stdout, agent.get ());
+
+ /* It would be nice to call ax_reqs here to gather some general info
+ about the expression, and then print out the result. */
+
+ dont_repeat ();
+}
+
+static void
+agent_command_1 (const 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;
+
+ event_location_up location
+ = new_linespec_location (&exp, symbol_name_match_type::WILD);
+ decode_line_full (location.get (), DECODE_LINE_FUNFIRSTLINE, NULL,
+ NULL, 0, &canonical,
+ NULL, NULL);
+ exp = skip_spaces (exp);
+ if (exp[0] == ',')
+ {
+ exp++;
+ exp = skip_spaces (exp);
+ }
+ for (const auto &lsal : canonical.lsals)
+ for (const auto &sal : lsal.sals)
+ agent_eval_command_one (exp, eval, sal.pc);
}
+ else
+ agent_eval_command_one (exp, eval, get_frame_pc (get_current_frame ()));
+
+ dont_repeat ();
+}
+
+static void
+agent_command (const char *exp, int from_tty)
+{
+ agent_command_1 (exp, 0);
+}
- fputs_filtered (" : ", f);
- type_print (value->type, "", f, -1);
+/* Parse the given expression, compile it into an agent expression
+ that does direct evaluation, and display the resulting
+ expression. */
+
+static void
+agent_eval_command (const 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
-agent_command (char *exp, int from_tty)
+maint_agent_printf_command (const char *cmdrest, int from_tty)
{
- struct cleanup *old_chain = 0;
- struct expression *expr;
- struct agent_expr *agent;
struct frame_info *fi = get_current_frame (); /* need current scope */
+ const char *format_start, *format_end;
/* 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.");
+ error (_("GDB can't do agent expression translation with overlays."));
- if (exp == 0)
- error_no_arg ("expression to translate");
+ if (cmdrest == 0)
+ error_no_arg (_("expression to translate"));
+
+ cmdrest = skip_spaces (cmdrest);
+
+ if (*cmdrest++ != '"')
+ error (_("Must start with a format string."));
- expr = parse_expression (exp);
- old_chain = make_cleanup (free_current_contents, &expr);
- agent = gen_trace_for_expr (fi->pc, expr);
- make_cleanup_free_agent_expr (agent);
- ax_print (gdb_stdout, agent);
+ format_start = cmdrest;
+
+ format_pieces fpieces (&cmdrest);
+
+ 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);
+
+ std::vector argvec;
+ while (*cmdrest != '\0')
+ {
+ const char *cmd1;
+
+ cmd1 = cmdrest;
+ expression_up expr = parse_exp_1 (&cmd1, 0, (struct block *) 0, 1);
+ argvec.push_back (expr.release ());
+ cmdrest = cmd1;
+ if (*cmdrest == ',')
+ ++cmdrest;
+ /* else complain? */
+ }
+
+
+ agent_expr_up agent = gen_printf (get_frame_pc (fi), get_current_arch (),
+ 0, 0,
+ format_start, format_end - format_start,
+ argvec.size (), argvec.data ());
+ ax_reqs (agent.get ());
+ ax_print (gdb_stdout, agent.get ());
/* 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 ();
}
-
/* Initialization code. */
-void _initialize_ax_gdb (void);
void
_initialize_ax_gdb (void)
{
add_cmd ("agent", class_maintenance, agent_command,
- "Translate an expression into remote agent bytecode.",
+ _("\
+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 and display the bytecodes."),
&maintenancelist);
}