diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/ax-gdb.c | 1928 |
2 files changed, 1933 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d7f31a1..49150fd 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +Tue Aug 25 13:21:58 1998 Michael Snyder <msnyder@cleaver.cygnus.com> + + * ax-gdb.c (gen_var_ref): Allow for typedef types. + (gen_cast, gen_bitfield_ref, gen_expr): ditto. + Mon Aug 24 18:29:03 1998 Michael Snyder <msnyder@cleaver.cygnus.com> * tracepoint.c (collect_symbol): Handle register doubles that diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c new file mode 100644 index 0000000..a55df32 --- /dev/null +++ b/gdb/ax-gdb.c @@ -0,0 +1,1928 @@ +/* GDB-specific functions for operating on agent expressions + Copyright 1998 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 +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +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. */ + +/* $Id$ */ + +#include "defs.h" +#include "symtab.h" +#include "symfile.h" +#include "gdbtypes.h" +#include "value.h" +#include "expression.h" +#include "command.h" +#include "gdbcmd.h" +#include "ax.h" +#include "ax-gdb.h" + +/* Probably the best way to read this file is to start with the types + and enums in ax-gdb.h, and then look at gen_expr, towards the + bottom; that's the main function that looks at the GDB expressions + and calls everything else to generate code. + + I'm beginning to wonder whether it wouldn't be nicer to internally + generate trees, with types, and then spit out the bytecode in + linear form afterwards; we could generate fewer `swap', `ext', and + `zero_ext' bytecodes that way; it would make good constant folding + easier, too. But at the moment, I think we should be willing to + pay for the simplicity of this code with less-than-optimal bytecode + strings. + + Remember, "GBD" stands for "Great Britain, Dammit!" So be careful. */ + + + +/* Static forward declarations */ + +/* There's a standard order to the arguments of these functions: + union exp_element ** --- pointer into expression + struct agent_expr * --- agent expression buffer to generate code into + struct axs_value * --- describes value left on top of stack */ + +static struct value *const_var_ref PARAMS ((struct symbol *var)); +static struct value *const_expr PARAMS ((union exp_element **pc)); +static struct value *maybe_const_expr PARAMS ((union exp_element **pc)); + +static void gen_traced_pop PARAMS ((struct agent_expr *, struct axs_value *)); + +static void gen_sign_extend PARAMS ((struct agent_expr *, struct type *)); +static void gen_extend PARAMS ((struct agent_expr *, struct type *)); +static void gen_fetch PARAMS ((struct agent_expr *, struct type *)); +static void gen_left_shift PARAMS ((struct agent_expr *, int)); + + +static void gen_frame_args_address PARAMS ((struct agent_expr *)); +static void gen_frame_locals_address PARAMS ((struct agent_expr *)); +static void gen_offset PARAMS ((struct agent_expr *ax, int offset)); +static void gen_sym_offset PARAMS ((struct agent_expr *, struct symbol *)); +static void gen_var_ref PARAMS ((struct agent_expr *ax, + struct axs_value *value, + struct symbol *var)); + + +static void gen_int_literal PARAMS ((struct agent_expr *ax, + struct axs_value *value, + LONGEST k, struct type *type)); + + +static void require_rvalue PARAMS ((struct agent_expr *ax, + struct axs_value *value)); +static void gen_usual_unary PARAMS ((struct agent_expr *ax, + struct axs_value *value)); +static int type_wider_than PARAMS ((struct type *type1, + struct type *type2)); +static struct type *max_type PARAMS ((struct type *type1, + struct type *type2)); +static void gen_conversion PARAMS ((struct agent_expr *ax, + struct type *from, + struct type *to)); +static int is_nontrivial_conversion PARAMS ((struct type *from, + struct type *to)); +static void gen_usual_arithmetic PARAMS ((struct agent_expr *ax, + struct axs_value *value1, + struct axs_value *value2)); +static void gen_integral_promotions PARAMS ((struct agent_expr *ax, + struct axs_value *value)); +static void gen_cast PARAMS ((struct agent_expr *ax, + struct axs_value *value, + struct type *type)); +static void gen_scale PARAMS ((struct agent_expr *ax, + enum agent_op op, + struct type *type)); +static void gen_add PARAMS ((struct agent_expr *ax, + struct axs_value *value, + struct axs_value *value1, + struct axs_value *value2, + char *name)); +static void gen_sub PARAMS ((struct agent_expr *ax, + struct axs_value *value, + struct axs_value *value1, + struct axs_value *value2)); +static void gen_binop PARAMS ((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 PARAMS ((struct agent_expr *ax, + struct axs_value *value)); +static void gen_complement PARAMS ((struct agent_expr *ax, + struct axs_value *value)); +static void gen_deref PARAMS ((struct agent_expr *, struct axs_value *)); +static void gen_address_of PARAMS ((struct agent_expr *, struct axs_value *)); +static int find_field PARAMS ((struct type *type, char *name)); +static void gen_bitfield_ref PARAMS ((struct agent_expr *ax, + struct axs_value *value, + struct type *type, + int start, int end)); +static void gen_struct_ref PARAMS ((struct agent_expr *ax, + struct axs_value *value, + char *field, + char *operator_name, + char *operand_name)); +static void gen_repeat PARAMS ((union exp_element **pc, + struct agent_expr *ax, + struct axs_value *value)); +static void gen_sizeof PARAMS ((union exp_element **pc, + struct agent_expr *ax, + struct axs_value *value)); +static void gen_expr PARAMS ((union exp_element **pc, + struct agent_expr *ax, + struct axs_value *value)); +static void print_axs_value PARAMS ((GDB_FILE *f, struct axs_value *value)); +static void agent_command PARAMS ((char *exp, int from_tty)); + + +/* Detecting constant expressions. */ + +/* If the variable reference at *PC is a constant, return its value. + Otherwise, return zero. + + Hey, Wally! How can a variable reference be a constant? + + Well, Beav, this function really handles the OP_VAR_VALUE operator, + not specifically variable references. GDB uses OP_VAR_VALUE to + refer to any kind of symbolic reference: function names, enum + elements, and goto labels are all handled through the OP_VAR_VALUE + operator, even though they're constants. It makes sense given the + situation. + + Gee, Wally, don'cha wonder sometimes if data representations that + subvert commonly accepted definitions of terms in favor of heavily + context-specific interpretations are really just a tool of the + programming hegemony to preserve their power and exclude the + proletariat? */ + +static struct value * +const_var_ref (var) + struct symbol *var; +{ + struct type *type = SYMBOL_TYPE (var); + + switch (SYMBOL_CLASS (var)) + { + case LOC_CONST: + return value_from_longest (type, (LONGEST) SYMBOL_VALUE (var)); + + case LOC_LABEL: + return value_from_longest (type, (LONGEST) SYMBOL_VALUE_ADDRESS (var)); + + default: + return 0; + } +} + + +/* If the expression starting at *PC has a constant value, return it. + Otherwise, return zero. If we return a value, then *PC will be + advanced to the end of it. If we return zero, *PC could be + anywhere. */ +static struct value * +const_expr (pc) + union exp_element **pc; +{ + enum exp_opcode op = (*pc)->opcode; + struct value *v1; + + switch (op) + { + case OP_LONG: + { + struct type *type = (*pc)[1].type; + LONGEST k = (*pc)[2].longconst; + (*pc) += 4; + return value_from_longest (type, k); + } + + case OP_VAR_VALUE: + { + struct value *v = const_var_ref ((*pc)[2].symbol); + (*pc) += 4; + return v; + } + + /* We could add more operators in here. */ + + case UNOP_NEG: + (*pc)++; + v1 = const_expr (pc); + if (v1) + return value_neg (v1); + else + return 0; + + default: + return 0; + } +} + + +/* Like const_expr, but guarantee also that *PC is undisturbed if the + expression is not constant. */ +static struct value * +maybe_const_expr (pc) + union exp_element **pc; +{ + union exp_element *tentative_pc = *pc; + struct value *v = const_expr (&tentative_pc); + + /* If we got a value, then update the real PC. */ + if (v) + *pc = tentative_pc; + + return v; +} + + +/* Generating bytecode from GDB expressions: general assumptions */ + +/* Here are a few general assumptions made throughout the code; if you + want to make a change that contradicts one of these, then you'd + better scan things pretty thoroughly. + + - We assume that all values occupy one stack element. For example, + sometimes we'll swap to get at the left argument to a binary + operator. If we decide that void values should occupy no stack + elements, or that synthetic arrays (whose size is determined at + run time, created by the `@' operator) should occupy two stack + elements (address and length), then this will cause trouble. + + - We assume the stack elements are infinitely wide, and that we + don't have to worry what happens if the user requests an + operation that is wider than the actual interpreter's stack. + That is, it's up to the interpreter to handle directly all the + integer widths the user has access to. (Woe betide the language + with bignums!) + + - We don't support side effects. Thus, we don't have to worry about + GCC's generalized lvalues, function calls, etc. + + - We don't support floating point. Many places where we switch on + some type don't bother to include cases for floating point; there + may be even more subtle ways this assumption exists. For + example, the arguments to % must be integers. + + - We assume all subexpressions have a static, unchanging type. If + we tried to support convenience variables, this would be a + problem. + + - All values on the stack should always be fully zero- or + sign-extended. + + (I wasn't sure whether to choose this or its opposite --- that + only addresses are assumed extended --- but it turns out that + neither convention completely eliminates spurious extend + operations (if everything is always extended, then you have to + extend after add, because it could overflow; if nothing is + extended, then you end up producing extends whenever you change + sizes), and this is simpler.) */ + + +/* Generating bytecode from GDB expressions: the `trace' kludge */ + +/* The compiler in this file is a general-purpose mechanism for + translating GDB expressions into bytecode. One ought to be able to + find a million and one uses for it. + + However, at the moment it is HOPELESSLY BRAIN-DAMAGED for the sake + of expediency. Let he who is without sin cast the first stone. + + For the data tracing facility, we need to insert `trace' bytecodes + before each data fetch; this records all the memory that the + expression touches in the course of evaluation, so that memory will + be available when the user later tries to evaluate the expression + in GDB. + + This should be done (I think) in a post-processing pass, that walks + an arbitrary agent expression and inserts `trace' operations at the + appropriate points. But it's much faster to just hack them + directly into the code. And since we're in a crunch, that's what + I've done. + + Setting the flag trace_kludge to non-zero enables the code that + emits the trace bytecodes at the appropriate points. */ +static int trace_kludge; + +/* 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 + an expression being used for tracing. */ +static void +gen_traced_pop (ax, value) + struct agent_expr *ax; + struct axs_value *value; +{ + if (trace_kludge) + switch (value->kind) + { + case axs_rvalue: + /* We don't trace rvalues, just the lvalues necessary to + produce them. So just dispose of this value. */ + ax_simple (ax, aop_pop); + 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); + } + 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); + break; + } + else + /* If we're not tracing, just pop the value. */ + ax_simple (ax, aop_pop); +} + + + +/* Generating bytecode from GDB expressions: helper functions */ + +/* Assume that the lower bits of the top of the stack is a value of + type TYPE, and the upper bits are zero. Sign-extend if necessary. */ +static void +gen_sign_extend (ax, type) + struct agent_expr *ax; + struct type *type; +{ + /* Do we need to sign-extend this? */ + if (! TYPE_UNSIGNED (type)) + ax_ext (ax, type->length * TARGET_CHAR_BIT); +} + + +/* Assume the lower bits of the top of the stack hold a value of type + TYPE, and the upper bits are garbage. Sign-extend or truncate as + needed. */ +static void +gen_extend (ax, type) + struct agent_expr *ax; + struct type *type; +{ + int bits = type->length * TARGET_CHAR_BIT; + /* I just had to. */ + ((TYPE_UNSIGNED (type) ? ax_zero_ext : ax_ext) (ax, bits)); +} + + +/* Assume that the top of the stack contains a value of type "pointer + to TYPE"; generate code to fetch its value. Note that TYPE is the + target type, not the pointer type. */ +static void +gen_fetch (ax, type) + struct agent_expr *ax; + struct type *type; +{ + if (trace_kludge) + { + /* Record the area of memory we're about to fetch. */ + ax_trace_quick (ax, TYPE_LENGTH (type)); + } + + switch (type->code) + { + case TYPE_CODE_PTR: + case TYPE_CODE_ENUM: + case TYPE_CODE_INT: + case TYPE_CODE_CHAR: + /* It's a scalar value, so we know how to dereference it. How + many bytes long is it? */ + switch (type->length) + { + case 8 / TARGET_CHAR_BIT: ax_simple (ax, aop_ref8 ); break; + case 16 / TARGET_CHAR_BIT: ax_simple (ax, aop_ref16); break; + case 32 / TARGET_CHAR_BIT: ax_simple (ax, aop_ref32); break; + case 64 / TARGET_CHAR_BIT: ax_simple (ax, aop_ref64); break; + + /* 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. */ + default: + error ("GDB bug: ax-gdb.c (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. */ + error ("GDB bug: ax-gdb.c (gen_fetch): bad type code"); + } +} + + +/* Generate code to left shift the top of the stack by DISTANCE bits, or + right shift it by -DISTANCE bits if DISTANCE < 0. This generates + unsigned (logical) right shifts. */ +static void +gen_left_shift (ax, distance) + struct agent_expr *ax; + int distance; +{ + if (distance > 0) + { + ax_const_l (ax, distance); + ax_simple (ax, aop_lsh); + } + else if (distance < 0) + { + ax_const_l (ax, -distance); + ax_simple (ax, aop_rsh_unsigned); + } +} + + + +/* Generating bytecode from GDB expressions: symbol references */ + +/* Generate code to push the base address of the argument portion of + the top stack frame. */ +static void +gen_frame_args_address (ax) + struct agent_expr *ax; +{ + /* FIXME: I'm sure this is wrong for processors other than the 68k. */ + ax_reg (ax, FP_REGNUM); +} + + +/* Generate code to push the base address of the locals portion of the + top stack frame. */ +static void +gen_frame_locals_address (ax) + struct agent_expr *ax; +{ + /* FIXME: I'm sure this is wrong for processors other than the 68k. */ + ax_reg (ax, FP_REGNUM); +} + + +/* Generate code to add OFFSET to the top of the stack. Try to + generate short and readable code. We use this for getting to + variables on the stack, and structure members. If we were + programming in ML, it would be clearer why these are the same + thing. */ +static void +gen_offset (ax, offset) + struct agent_expr *ax; + int offset; +{ + /* It would suffice to simply push the offset and add it, but this + makes it easier to read positive and negative offsets in the + bytecode. */ + if (offset > 0) + { + ax_const_l (ax, offset); + ax_simple (ax, aop_add); + } + else if (offset < 0) + { + ax_const_l (ax, -offset); + ax_simple (ax, aop_sub); + } +} + + +/* In many cases, a symbol's value is the offset from some other + address (stack frame, base register, etc.) Generate code to add + VAR's value to the top of the stack. */ +static void +gen_sym_offset (ax, var) + struct agent_expr *ax; + struct symbol *var; +{ + gen_offset (ax, SYMBOL_VALUE (var)); +} + + +/* Generate code for a variable reference to AX. The variable is the + symbol VAR. Set VALUE to describe the result. */ + +static void +gen_var_ref (ax, value, var) + struct agent_expr *ax; + struct axs_value *value; + struct symbol *var; +{ + /* Dereference any typedefs. */ + value->type = check_typedef (SYMBOL_TYPE (var)); + + /* I'm imitating the code in read_var_value. */ + switch (SYMBOL_CLASS (var)) + { + case LOC_CONST: /* A constant, like an enum value. */ + ax_const_l (ax, (LONGEST) SYMBOL_VALUE (var)); + value->kind = axs_rvalue; + break; + + case LOC_LABEL: /* A goto label, being used as a value. */ + ax_const_l (ax, (LONGEST) SYMBOL_VALUE_ADDRESS (var)); + value->kind = axs_rvalue; + break; + + case LOC_CONST_BYTES: + error ("GDB bug: ax-gdb.c (gen_var_ref): LOC_CONST_BYTES symbols are not supported"); + + /* Variable at a fixed location in memory. Easy. */ + case LOC_STATIC: + /* Push the address of the variable. */ + ax_const_l (ax, SYMBOL_VALUE_ADDRESS (var)); + value->kind = axs_lvalue_memory; + break; + + case LOC_ARG: /* var lives in argument area of frame */ + gen_frame_args_address (ax); + gen_sym_offset (ax, var); + value->kind = axs_lvalue_memory; + break; + + case LOC_REF_ARG: /* As above, but the frame slot really + holds the address of the variable. */ + 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)); + 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)); + break; + + case LOC_BLOCK: + ax_const_l (ax, BLOCK_START (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); + 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. */ + case LOC_REGPARM_ADDR: + ax_reg (ax, SYMBOL_VALUE (var)); + 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)); + + /* Push the address of the variable. */ + ax_const_l (ax, SYMBOL_VALUE_ADDRESS (msym)); + value->kind = axs_lvalue_memory; + } + break; + + case LOC_OPTIMIZED_OUT: + error ("The variable `%s' has been optimized out.", + SYMBOL_SOURCE_NAME (var)); + break; + + default: + error ("Cannot find value of botched symbol `%s'.", + SYMBOL_SOURCE_NAME (var)); + break; + } +} + + + +/* Generating bytecode from GDB expressions: literals */ + +static void +gen_int_literal (ax, value, k, type) + struct agent_expr *ax; + struct axs_value *value; + LONGEST k; + struct type *type; +{ + ax_const_l (ax, k); + value->kind = axs_rvalue; + value->type = type; +} + + + +/* Generating bytecode from GDB expressions: unary conversions, casts */ + +/* 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 +require_rvalue (ax, value) + struct agent_expr *ax; + struct axs_value *value; +{ + switch (value->kind) + { + case axs_rvalue: + /* It's already an rvalue. */ + break; + + case axs_lvalue_memory: + /* The top of stack is the address of the object. Dereference. */ + gen_fetch (ax, value->type); + break; + + case axs_lvalue_register: + /* There's nothing on the stack, but value->u.reg is the + register number containing the value. + + When we add floating-point support, this is going to have to + change. What about SPARC register pairs, for example? */ + ax_reg (ax, value->u.reg); + gen_extend (ax, value->type); + break; + } + + value->kind = axs_rvalue; +} + + +/* Assume the top of the stack is described by VALUE, and perform the + usual unary conversions. This is motivated by ANSI 6.2.2, but of + course GDB expressions are not ANSI; they're the mishmash union of + a bunch of languages. Rah. + + NOTE! This function promises to produce an rvalue only when the + incoming value is of an appropriate type. In other words, the + consumer of the value this function produces may assume the value + is an rvalue only after checking its type. + + The immediate issue is that if the user tries to use a structure or + union as an operand of, say, the `+' operator, we don't want to try + to convert that structure to an rvalue; require_rvalue will bomb on + structs and unions. Rather, we want to simply pass the struct + lvalue through unchanged, and let `+' raise an error. */ + +static void +gen_usual_unary (ax, value) + struct agent_expr *ax; + struct axs_value *value; +{ + /* We don't have to generate any code for the usual integral + conversions, since values are always represented as full-width on + the stack. Should we tweak the type? */ + + /* Some types require special handling. */ + switch (value->type->code) + { + /* Functions get converted to a pointer to the function. */ + case TYPE_CODE_FUNC: + value->type = lookup_pointer_type (value->type); + value->kind = axs_rvalue; /* Should always be true, but just in case. */ + break; + + /* Arrays get converted to a pointer to their first element, and + are no longer an lvalue. */ + 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 + is also the address of its first element. */ + } + break; + + /* Don't try to convert structures and unions to rvalues. Let the + consumer signal an error. */ + 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. */ + require_rvalue (ax, value); +} + + +/* Return non-zero iff the type TYPE1 is considered "wider" than the + type TYPE2, according to the rules described in gen_usual_arithmetic. */ +static int +type_wider_than (type1, type2) + struct type *type1, *type2; +{ + return (TYPE_LENGTH (type1) > TYPE_LENGTH (type2) + || (TYPE_LENGTH (type1) == TYPE_LENGTH (type2) + && TYPE_UNSIGNED (type1) + && ! TYPE_UNSIGNED (type2))); +} + + +/* Return the "wider" of the two types TYPE1 and TYPE2. */ +static struct type * +max_type (type1, type2) + struct type *type1, *type2; +{ + return type_wider_than (type1, type2) ? type1 : type2; +} + + +/* Generate code to convert a scalar value of type FROM to type TO. */ +static void +gen_conversion (ax, from, to) + struct agent_expr *ax; + struct type *from, *to; +{ + /* Perhaps there is a more graceful way to state these rules. */ + + /* 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); + + /* If the two values have equal width, but different signednesses, + then we need to extend. */ + else if (TYPE_LENGTH (to) == TYPE_LENGTH (from)) + { + if (TYPE_UNSIGNED (from) != TYPE_UNSIGNED (to)) + gen_extend (ax, to); + } + + /* If we're converting to a wider type, and becoming unsigned, then + we need to zero out any possible sign bits. */ + else if (TYPE_LENGTH (to) > TYPE_LENGTH (from)) + { + if (TYPE_UNSIGNED (to)) + gen_extend (ax, to); + } +} + + +/* Return non-zero iff the type FROM will require any bytecodes to be + emitted to be converted to the type TO. */ +static int +is_nontrivial_conversion (from, to) + struct type *from, *to; +{ + struct agent_expr *ax = new_agent_expr (); + int nontrivial; + + /* Actually generate the code, and see if anything came out. At the + moment, it would be trivial to replicate the code in + gen_conversion here, but in the future, when we're supporting + 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); + nontrivial = ax->len > 0; + free_agent_expr (ax); + return nontrivial; +} + + +/* Generate code to perform the "usual arithmetic conversions" (ANSI C + 6.2.1.5) for the two operands of an arithmetic operator. This + effectively finds a "least upper bound" type for the two arguments, + and promotes each argument to that type. *VALUE1 and *VALUE2 + describe the values as they are passed in, and as they are left. */ +static void +gen_usual_arithmetic (ax, value1, value2) + struct agent_expr *ax; + struct axs_value *value1, *value2; +{ + /* Do the usual binary conversions. */ + if (TYPE_CODE (value1->type) == TYPE_CODE_INT + && TYPE_CODE (value2->type) == TYPE_CODE_INT) + { + /* The ANSI integral promotions seem to work this way: Order the + integer types by size, and then by signedness: an n-bit + 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, + max_type (value1->type, value2->type)); + + /* Deal with value2, on the top of the stack. */ + gen_conversion (ax, value2->type, target); + + /* Deal with value1, not on the top of the stack. Don't + generate the `swap' instructions if we're not actually going + to do anything. */ + if (is_nontrivial_conversion (value1->type, target)) + { + ax_simple (ax, aop_swap); + gen_conversion (ax, value1->type, target); + ax_simple (ax, aop_swap); + } + + value1->type = value2->type = target; + } +} + + +/* Generate code to perform the integral promotions (ANSI 6.2.1.1) on + the value on the top of the stack, as described by VALUE. Assume + the value has integral type. */ +static void +gen_integral_promotions (ax, value) + struct agent_expr *ax; + struct axs_value *value; +{ + if (! type_wider_than (value->type, builtin_type_int)) + { + gen_conversion (ax, value->type, builtin_type_int); + value->type = builtin_type_int; + } + else if (! type_wider_than (value->type, builtin_type_unsigned_int)) + { + gen_conversion (ax, value->type, builtin_type_unsigned_int); + value->type = builtin_type_unsigned_int; + } +} + + +/* Generate code for a cast to TYPE. */ +static void +gen_cast (ax, value, type) + 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. */ + type = check_typedef (type); + + switch (type->code) + { + case TYPE_CODE_PTR: + /* It's implementation-defined, and I'll bet this is what GCC + does. */ + break; + + case TYPE_CODE_ARRAY: + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + case TYPE_CODE_FUNC: + error ("Illegal type cast: intended type must be scalar."); + + case TYPE_CODE_ENUM: + /* 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; + break; + + case TYPE_CODE_INT: + gen_conversion (ax, value->type, type); + break; + + case TYPE_CODE_VOID: + /* We could pop the value, and rely on everyone else to check + the type and notice that this value doesn't occupy a stack + slot. But for now, leave the value on the stack, and + preserve the "value == stack element" assumption. */ + break; + + default: + error ("Casts to requested type are not yet implemented."); + } + + value->type = type; +} + + + +/* Generating bytecode from GDB expressions: arithmetic */ + +/* Scale the integer on the top of the stack by the size of the target + of the pointer type TYPE. */ +static void +gen_scale (ax, op, type) + struct agent_expr *ax; + enum agent_op op; + struct type *type; +{ + struct type *element = TYPE_TARGET_TYPE (type); + + if (element->length != 1) + { + ax_const_l (ax, element->length); + ax_simple (ax, op); + } +} + + +/* 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. */ +static void +gen_add (ax, value, value1, value2, name) + struct agent_expr *ax; + struct axs_value *value, *value1, *value2; + char *name; +{ + /* Is it INT+PTR? */ + if (value1->type->code == TYPE_CODE_INT + && value2->type->code == 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; + } + + /* Is it PTR+INT? */ + else if (value1->type->code == TYPE_CODE_PTR + && value2->type->code == 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; + } + + /* Must be number + number; the usual binary conversions will have + brought them both to the same width. */ + else if (value1->type->code == TYPE_CODE_INT + && value2->type->code == 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); + + 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. */ +static void +gen_sub (ax, value, value1, value2) + struct agent_expr *ax; + struct axs_value *value, *value1, *value2; +{ + struct type *element; + + if (value1->type->code == TYPE_CODE_PTR) + { + /* Is it PTR - INT? */ + if (value2->type->code == 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; + } + + /* Is it PTR - PTR? Strictly speaking, the types ought to + match, but this is what the normal GDB expression evaluator + tests for. */ + else if (value2->type->code == 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 ("\ +First argument of `-' is a pointer, but second argument is neither\n\ +an integer nor a pointer of the same type."); + } + + /* Must be number + number. */ + else if (value1->type->code == TYPE_CODE_INT + && value2->type->code == TYPE_CODE_INT) + { + ax_simple (ax, aop_sub); + gen_extend (ax, value1->type); /* Catch overflow. */ + value->type = value1->type; + } + + else + error ("Illegal combination of types in subtraction."); + + value->kind = axs_rvalue; +} + +/* Generate code for a binary operator that doesn't do pointer magic. + 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. MAY_CARRY should be non-zero iff the + result needs to be extended. NAME is the English name of the + operator, used in error messages */ +static void +gen_binop (ax, value, value1, value2, op, op_unsigned, may_carry, name) + struct agent_expr *ax; + struct axs_value *value, *value1, *value2; + enum agent_op op, op_unsigned; + int may_carry; + char *name; +{ + /* We only handle INT op INT. */ + if ((value1->type->code != TYPE_CODE_INT) + || (value2->type->code != TYPE_CODE_INT)) + error ("Illegal combination of types in %s.", name); + + ax_simple (ax, + TYPE_UNSIGNED (value1->type) ? op_unsigned : op); + if (may_carry) + gen_extend (ax, value1->type); /* catch overflow */ + value->type = value1->type; + value->kind = axs_rvalue; +} + + +static void +gen_logical_not (ax, value) + struct agent_expr *ax; + struct axs_value *value; +{ + if (TYPE_CODE (value->type) != TYPE_CODE_INT + && TYPE_CODE (value->type) != TYPE_CODE_PTR) + error ("Illegal type of operand to `!'."); + + gen_usual_unary (ax, value); + ax_simple (ax, aop_log_not); + value->type = builtin_type_int; +} + + +static void +gen_complement (ax, value) + struct agent_expr *ax; + struct axs_value *value; +{ + if (TYPE_CODE (value->type) != TYPE_CODE_INT) + error ("Illegal 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); +} + + + +/* Generating bytecode from GDB expressions: * & . -> @ sizeof */ + +/* Dereference the value on the top of the stack. */ +static void +gen_deref (ax, value) + struct agent_expr *ax; + 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 (value->type->code != TYPE_CODE_PTR) + error ("GDB bug: ax-gdb.c (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 + actually emit any code; we just change the type from "Pointer to + T" to "T", and mark the value as an lvalue in memory. Leave it + to the consumer to actually dereference it. */ + value->type = TYPE_TARGET_TYPE (value->type); + value->kind = ((value->type->code == TYPE_CODE_FUNC) + ? axs_rvalue : axs_lvalue_memory); +} + + +/* Produce the address of the lvalue on the top of the stack. */ +static void +gen_address_of (ax, value) + struct agent_expr *ax; + 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 + arrangement is not without motivation. */ + if (value->type->code == TYPE_CODE_FUNC) + /* The value's already an rvalue on the stack, so we just need to + change the type. */ + value->type = lookup_pointer_type (value->type); + else + switch (value->kind) + { + case axs_rvalue: + 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."); + + case axs_lvalue_memory: + value->kind = axs_rvalue; + value->type = lookup_pointer_type (value->type); + break; + } +} + + +/* 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 (type, name) + struct type *type; + char *name; +{ + int i; + + CHECK_TYPEDEF (type); + + /* Make sure this isn't C++. */ + if (TYPE_N_BASECLASSES (type) != 0) + error ("GDB bug: ax-gdb.c (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') + error ("GDB bug: ax-gdb.c (find_field): anonymous unions not supported"); + } + + error ("Couldn't find member named `%s' in struct/union `%s'", + name, type->tag_name); + + 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 + structure. */ +static void +gen_bitfield_ref (ax, value, type, start, end) + struct agent_expr *ax; + struct axs_value *value; + struct type *type; + int start, end; +{ + /* Note that ops[i] fetches 8 << i bits. */ + static enum agent_op ops[] + = { 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 + actually occupy; we shouldn't make any accesses we're not + explicitly permitted to. We rely here on the fact that the + bytecode `ref' operators work on unaligned addresses. + + It takes some fancy footwork to get the stack to work the way + we'd like. Say we're retrieving a bitfield that requires three + fetches. Initially, the stack just contains the address: + addr + For the first fetch, we duplicate the address + addr addr + then add the byte offset, do the fetch, and shift and mask as + needed, yielding a fragment of the value, properly aligned for + the final bitwise or: + addr frag1 + then we swap, and repeat the process: + frag1 addr --- address on top + frag1 addr addr --- duplicate it + frag1 addr frag2 --- get second fragment + frag1 frag2 addr --- swap again + frag1 frag2 frag3 --- get third fragment + Notice that, since the third fragment is the last one, we don't + bother duplicating the address this time. Now we have all the + fragments on the stack, and we can simply `or' them together, + yielding the final value of the bitfield. */ + + /* The first and one-after-last bits in the field, but rounded down + and up to byte boundaries. */ + int bound_start = (start / TARGET_CHAR_BIT) * TARGET_CHAR_BIT; + int bound_end = (((end + TARGET_CHAR_BIT - 1) + / TARGET_CHAR_BIT) + * TARGET_CHAR_BIT); + + /* current bit offset within the structure */ + int offset; + + /* The index in ops of the opcode we're considering. */ + int op; + + /* The number of fragments we generated in the process. Probably + equal to the number of `one' bits in bytesize, but who cares? */ + int fragment_count; + + /* Dereference any typedefs. */ + type = check_typedef (type); + + /* Can we fetch the number of bits requested at all? */ + if ((end - start) > ((1 << num_ops) * 8)) + error ("GDB bug: ax-gdb.c (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. */ + offset = bound_start; + fragment_count = 0; + for (op = num_ops - 1; op >= 0; op--) + { + /* number of bits that ops[op] would fetch */ + int op_size = 8 << op; + + /* The stack at this point, from bottom to top, contains zero or + more fragments, then the address. */ + + /* Does this fetch fit within the bitfield? */ + if (offset + op_size <= bound_end) + { + /* Is this the last fragment? */ + int last_frag = (offset + op_size == bound_end); + + if (! last_frag) + ax_simple (ax, aop_dup); /* keep a copy of the address */ + + /* Add the offset. */ + gen_offset (ax, offset / TARGET_CHAR_BIT); + + if (trace_kludge) + { + /* Record the area of memory we're about to fetch. */ + ax_trace_quick (ax, op_size / TARGET_CHAR_BIT); + } + + /* Perform the fetch. */ + ax_simple (ax, ops[op]); + + /* Shift the bits we have to their proper position. + gen_left_shift will generate right shifts when the operand + is negative. + + A big-endian field diagram to ponder: + byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 byte 7 + +------++------++------++------++------++------++------++------+ + xxxxAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCxxxxxxxxxxx + ^ ^ ^ ^ + bit number 16 32 48 53 + These are bit numbers as supplied by GDB. Note that the + bit numbers run from right to left once you've fetched the + value! + + A little-endian field diagram to ponder: + byte 7 byte 6 byte 5 byte 4 byte 3 byte 2 byte 1 byte 0 + +------++------++------++------++------++------++------++------+ + xxxxxxxxxxxAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCxxxx + ^ ^ ^ ^ ^ + bit number 48 32 16 4 0 + + In both cases, the most significant end is on the left + (i.e. normal numeric writing order), which means that you + don't go crazy thinking about `left' and `right' shifts. + + We don't have to worry about masking yet: + - If they contain garbage off the least significant end, then we + must be looking at the low end of the field, and the right + shift will wipe them out. + - If they contain garbage off the most significant end, then we + must be looking at the most significant end of the word, and + 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 == BIG_ENDIAN) + gen_left_shift (ax, end - (offset + op_size)); + else + gen_left_shift (ax, offset - start); + + if (! last_frag) + /* Bring the copy of the address up to the top. */ + ax_simple (ax, aop_swap); + + offset += op_size; + fragment_count++; + } + } + + /* Generate enough bitwise `or' operations to combine all the + fragments we left on the stack. */ + while (fragment_count-- > 1) + ax_simple (ax, aop_bit_or); + + /* Sign- or zero-extend the value as appropriate. */ + ((TYPE_UNSIGNED (type) ? ax_zero_ext : ax_ext) (ax, end - start)); + + /* This is *not* an lvalue. Ugh. */ + value->kind = axs_rvalue; + value->type = type; +} + + +/* Generate code to reference the member named FIELD of a structure or + union. The top of the stack, as described by VALUE, should have + type (pointer to a)* struct/union. OPERATOR_NAME is the name of + 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 (ax, value, field, operator_name, operand_name) + struct agent_expr *ax; + struct axs_value *value; + char *field; + char *operator_name; + char *operand_name; +{ + struct type *type; + int i; + + /* 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 (value->type->code == TYPE_CODE_PTR) + { + gen_usual_unary (ax, value); + gen_deref (ax, value); + } + type = 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.", + 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."); + + i = find_field (type, field); + + /* 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 + { + gen_offset (ax, TYPE_FIELD_BITPOS (type, i) / TARGET_CHAR_BIT); + value->kind = axs_lvalue_memory; + value->type = TYPE_FIELD_TYPE (type, i); + } +} + + +/* 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 + of command-line arguments. + + Unfortunately, because we have to know the types before we actually + have a value for the expression, we can't implement this perfectly + without changing the type system, having values that occupy two + stack slots, doing weird things with sizeof, etc. So we require + the right operand to be a constant expression. */ +static void +gen_repeat (pc, ax, value) + 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); + if (value1.kind != axs_lvalue_memory) + error ("Left operand of `@' must be an object in memory."); + + /* Evaluate the length; it had better be a constant. */ + { + struct value *v = const_expr (pc); + int length; + + if (! v) + error ("Right operand of `@' must be a constant, in agent expressions."); + if (v->type->code != 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."); + + /* 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); + + value->kind = axs_lvalue_memory; + value->type = array; + } + } +} + + +/* Emit code for the `sizeof' operator. + *PC should point at the start of the operand expression; we advance it + to the first instruction after the operand. */ +static void +gen_sizeof (pc, ax, value) + union exp_element **pc; + struct agent_expr *ax; + struct axs_value *value; +{ + /* We don't care about the value of the operand expression; we only + care about its type. However, in the current arrangement, the + only way to find an expression's type is to generate code for it. + 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); + + /* 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; +} + + +/* Generating bytecode from GDB expressions: general recursive thingy */ + +/* 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 (pc, ax, value) + 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; + + /* If we're looking at a constant expression, just push its value. */ + { + struct value *v = maybe_const_expr (pc); + + if (v) + { + ax_const_l (ax, value_as_long (v)); + value->kind = axs_rvalue; + value->type = check_typedef (VALUE_TYPE (v)); + return; + } + } + + /* Otherwise, go ahead and generate code for it. */ + switch (op) + { + /* Binary arithmetic operators. */ + case BINOP_ADD: + case BINOP_SUB: + case BINOP_MUL: + case BINOP_DIV: + case BINOP_REM: + case BINOP_SUBSCRIPT: + case BINOP_BITWISE_AND: + case BINOP_BITWISE_IOR: + case BINOP_BITWISE_XOR: + (*pc)++; + gen_expr (pc, ax, &value1); + gen_usual_unary (ax, &value1); + gen_expr (pc, ax, &value2); + gen_usual_unary (ax, &value2); + gen_usual_arithmetic (ax, &value1, &value2); + switch (op) + { + 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; + + 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; + + default: + /* We should only list operators in the outer case statement + that we actually handle in the inner case statement. */ + error ("GDB bug: ax-gdb.c (gen_expr): op case sets don't match"); + } + break; + + /* Note that we need to be a little subtle about generating code + for comma. In C, we can do some optimizations here because + we know the left operand is only being evaluated for effect. + However, if the tracing kludge is in effect, then we always + need to evaluate the left hand side fully, so that all the + variables it mentions get traced. */ + case BINOP_COMMA: + (*pc)++; + gen_expr (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); + /* It's the consumer's responsibility to trace the right operand. */ + break; + + case OP_LONG: /* some integer constant */ + { + struct type *type = (*pc)[1].type; + LONGEST k = (*pc)[2].longconst; + (*pc) += 4; + gen_int_literal (ax, value, k, type); + } + break; + + case OP_VAR_VALUE: + gen_var_ref (ax, value, (*pc)[2].symbol); + (*pc) += 4; + break; + + case OP_REGISTER: + { + int reg = (int) (*pc)[1].longconst; + (*pc) += 3; + value->kind = axs_lvalue_register; + value->u.reg = reg; + value->type = REGISTER_VIRTUAL_TYPE (reg); + } + break; + + case OP_INTERNALVAR: + error ("GDB agent expressions cannot use convenience variables."); + + /* 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); + break; + + case UNOP_CAST: + { + struct type *type = (*pc)[1].type; + (*pc) += 3; + gen_expr (pc, ax, value); + gen_cast (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. */ + error ("GDB bug: ax-gdb.c (gen_expr): OP_MEMVAL operand isn't an rvalue???"); + value->type = type; + value->kind = axs_lvalue_memory; + } + break; + + case UNOP_NEG: + (*pc)++; + /* -FOO is equivalent to 0 - FOO. */ + gen_int_literal (ax, &value1, (LONGEST) 0, builtin_type_int); + gen_usual_unary (ax, &value1); /* shouldn't do much */ + gen_expr (pc, ax, &value2); + gen_usual_unary (ax, &value2); + gen_usual_arithmetic (ax, &value1, &value2); + gen_sub (ax, value, &value1, &value2); + break; + + case UNOP_LOGICAL_NOT: + (*pc)++; + gen_expr (pc, ax, value); + gen_logical_not (ax, value); + break; + + case UNOP_COMPLEMENT: + (*pc)++; + gen_expr (pc, ax, value); + gen_complement (ax, value); + break; + + case UNOP_IND: + (*pc)++; + gen_expr (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); + break; + + case UNOP_ADDR: + (*pc)++; + gen_expr (pc, ax, value); + gen_address_of (ax, value); + break; + + case UNOP_SIZEOF: + (*pc)++; + /* 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); + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + { + int length = (*pc)[1].longconst; + char *name = &(*pc)[2].string; + + (*pc) += 4 + BYTES_TO_EXP_ELEM (length + 1); + gen_expr (pc, ax, value); + if (op == STRUCTOP_STRUCT) + gen_struct_ref (ax, value, name, ".", "structure or union"); + else if (op == STRUCTOP_PTR) + gen_struct_ref (ax, value, name, "->", + "pointer to a structure or union"); + else + /* If this `if' chain doesn't handle it, then the case list + shouldn't mention it, and we shouldn't be here. */ + error ("GDB bug: ax-gdb.c (gen_expr): unhandled struct case"); + } + break; + + case OP_TYPE: + error ("Attempt to use a type name as an expression."); + + default: + error ("Unsupported operator in expression."); + } +} + + + +/* Generating bytecode from GDB expressions: driver */ + +/* 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 (expr, value) + struct expression *expr; + struct axs_value *value; +{ + struct cleanup *old_chain = 0; + struct agent_expr *ax = new_agent_expr (); + union exp_element *pc; + + old_chain = make_cleanup (free_agent_expr, ax); + + pc = expr->elts; + trace_kludge = 0; + gen_expr (&pc, ax, value); + + /* 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 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. + + Not sure this function is useful at all. */ +struct agent_expr * +expr_to_address_and_size (expr) + struct expression *expr; +{ + 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."); + } + + /* Push the object's size on the stack. */ + ax_const_l (ax, TYPE_LENGTH (value.type)); + + return ax; +} + + +/* 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 (expr) + struct expression *expr; +{ + struct cleanup *old_chain = 0; + struct agent_expr *ax = new_agent_expr (); + union exp_element *pc; + struct axs_value value; + + old_chain = make_cleanup (free_agent_expr, ax); + + pc = expr->elts; + trace_kludge = 1; + gen_expr (&pc, ax, &value); + + /* Make sure we record the final object, and get rid of it. */ + gen_traced_pop (ax, &value); + + /* Oh, and terminate. */ + ax_simple (ax, aop_end); + + /* We have successfully built the agent expr, so cancel the cleanup + request. If we add more cleanups that we always want done, this + will have to get more complicated. */ + discard_cleanups (old_chain); + return ax; +} + + + +/* The "agent" command, for testing: compile and disassemble an expression. */ + +static void +print_axs_value (f, value) + GDB_FILE *f; + struct axs_value *value; +{ + switch (value->kind) + { + case axs_rvalue: + fputs_filtered ("rvalue", f); + break; + + case axs_lvalue_memory: + fputs_filtered ("memory lvalue", f); + break; + + case axs_lvalue_register: + fprintf_filtered (f, "register %d lvalue", value->u.reg); + break; + } + + fputs_filtered (" : ", f); + type_print (value->type, "", f, -1); +} + + +static void +agent_command (exp, from_tty) + char *exp; + int from_tty; +{ + struct cleanup *old_chain = 0; + struct expression *expr; + struct agent_expr *agent; + struct agent_reqs reqs; + + /* 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"); + + expr = parse_expression (exp); + old_chain = make_cleanup (free_current_contents, &expr); + agent = gen_trace_for_expr (expr); + make_cleanup (free_agent_expr, agent); + ax_print (gdb_stdout, agent); + ax_reqs (agent, &reqs); + + do_cleanups (old_chain); + dont_repeat (); +} + + +/* Initialization code. */ + +_initialize_ax_gdb () +{ + struct cmd_list_element *c; + + add_cmd ("agent", class_maintenance, agent_command, + "Translate an expression into remote agent bytecode.", + &maintenancelist); +} |