From mboxrd@z Thu Jan 1 00:00:00 1970 From: Daniel Berlin To: gdb-patches@sources.redhat.com Subject: [RFA]: Symbol evaluation code Date: Tue, 29 May 2001 10:38:00 -0000 Message-id: <87hey4jbsd.fsf@dynamic-addr-83-177.resnet.rochester.edu> X-SW-Source: 2001-05/msg00482.html I'd like approval for this code. I plan on making the push_opcode non-varargs before making anything use it, but i really want to get this stuff out of my tree and into sourceware, before I start having fun with cvs conflicts. Also, one of my HD's is starting to go, and I didn't want to lose it. I've deliberately not included the Makefile.in portion of the patch, so that it is not compiled in yet. I will submit that along with the non-vararging patch, in a few days. 2001-05-29 Daniel Berlin * symtab.h: Add LOC_LOC_EXPR and LOC_LOC_LIST to the location types. Add dynamic_location and loc/frameloc to the symbol structure. (SYMBOL_LOC_EXPR): New macro. (SYMBOL_FRAME_LOC_EXPR): Ditto. Add forward declaration of locexpr struct. * symeval.c: New file. * symeval.def: New file. * symeval.h: New file. Index: symeval.c =================================================================== RCS file: symeval.c diff -N symeval.c *** /dev/null Tue May 5 13:32:27 1998 --- symeval.c Tue May 29 10:34:00 2001 *************** *** 0 **** --- 1,595 ---- + /* Location expression evaluation for the GNU debugger, GDB. + Copyright 2001 + Free Software Foundation, Inc. + + Contributed by Daniel Berlin + + 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. */ + #include "defs.h" + #include "symtab.h" + #include "frame.h" + #include "value.h" + #include "gdbcore.h" + #include "symeval.h" + #include "gdb_assert.h" + + #define MORE_BYTES 0x80 + #define DATA_MASK 0x7f + #define DIGIT_WIDTH 7 + #define SIGN_BIT 0x40 + + /* Decode the unsigned LEB128 constant at BUF into the variable pointed to + by R, and return the new value of BUF. */ + + static unsigned char * + read_uleb128 (unsigned char *buf, ULONGEST *r) + { + unsigned shift = 0; + ULONGEST result = 0; + + while (1) + { + unsigned char byte = *buf++; + result |= (byte & DATA_MASK) << shift; + if ((byte & MORE_BYTES) == 0) + break; + shift += DIGIT_WIDTH; + } + *r = result; + return buf; + } + + /* Decode the signed LEB128 constant at BUF into the variable pointed to + by R, and return the new value of BUF. */ + + static unsigned char * + read_sleb128 (unsigned char *buf, LONGEST *r) + { + unsigned shift = 0; + LONGEST result = 0; + unsigned char byte; + + while (1) + { + byte = *buf++; + result |= (byte & DATA_MASK) << shift; + shift += DIGIT_WIDTH; + if ((byte & MORE_BYTES) == 0) + break; + } + if (shift < (sizeof (*r) * 8) && (byte & SIGN_BIT) != 0) + result |= - (1 << shift); + + *r = result; + return buf; + } + + struct locexpr + { + unsigned int size; + unsigned char *data; + }; + + struct locexpr_cookie + { + struct locexpr *expr; + unsigned int position; + enum locexpr_opcode lastopcode; + unsigned char operands_left; + }; + static int + sizeof_uleb128 (ULONGEST value) + { + int size =0, byte; + do + { + byte = value & DATA_MASK; + value >>= DIGIT_WIDTH; + size++; + } while (value != 0); + return size; + } + + static int + sizeof_sleb128 (LONGEST value) + { + int size =0, byte; + do + { + byte = value & DATA_MASK; + value >>= DIGIT_WIDTH; + size++; + } while (!(( value == 0 && (byte & SIGN_BIT) == 0) || (value == -1 && (byte & SIGN_BIT) != 0))); + return size; + } + + + /* Encode the value into ULEB128 into the expr->data */ + + static void + encode_uleb128 (struct locexpr *expr, ULONGEST value) + { + char *place; + int size = sizeof_uleb128(value); + expr->data = xrealloc (expr->data, expr->size + size); + place = expr->data + expr->size; + expr->size += size; + do + { + unsigned char uc; + uc = value & DATA_MASK; + value >>= DIGIT_WIDTH; + if (value != 0) + uc |= MORE_BYTES; + *place = uc; + place++; + } while (value); + + } + /* Encode the value into SLEB128 into the expr->data */ + + static void + encode_sleb128 (struct locexpr *expr, LONGEST value) + { + char *place; + int size = sizeof_sleb128(value); + int sign = - (value < 0); + int more = 1; + expr->data = xrealloc (expr->data, expr->size + size); + place = expr->data + expr->size; + expr->size += size; + do + { + unsigned char uc = value & DATA_MASK; + value >>= DIGIT_WIDTH; + if (value == sign && ((uc & SIGN_BIT) == (sign & SIGN_BIT))) + more = 0; + else + uc |= MORE_BYTES; + *place = uc; + place++; + } while (more); + } + + static void + encode_uchar (struct locexpr *expr, unsigned char value) + { + expr->data = xrealloc (expr->data, expr->size+1); + *(expr->data + expr->size) = value; + expr->size++; + } + + void + init_locexpr(struct locexpr **expr) + { + *expr = xmalloc(sizeof (struct locexpr)); + } + void + destroy_locexpr (struct locexpr **expr) + { + xfree ((*expr)->data); + xfree (*expr); + + } + #define DEFINE_LOCEXPR_OPCODE(opcode, desc, numargs, argtypes) numargs, + static const int locexpr_opcount[] = { + #include "symeval.def" + }; + #undef DEFINE_LOCEXPR_OPCODE + #define DEFINE_LOCEXPR_OPCODE(opcode, desc, numargs, argtypes) argtypes, + static const char *locexpr_opfmt[] = { + #include "symeval.def" + }; + #undef DEFINE_LOCEXPR_OPCODE + #define DEFINE_LOCEXPR_OPCODE(opcode, desc, numargs, argtypes) #opcode, + static const char *locexpr_opstring[] = { + #include "symeval.def" + } + ; + #undef DEFINE_LOCEXPR_OPCODE + void + locexpr_push_op (struct locexpr *expr, enum locexpr_opcode operation, const char *fmt, ...) + { + va_list ap; + LONGEST sval; + ULONGEST uval; + unsigned char ucval; + expr->data = xrealloc (expr->data, expr->size + 1); + expr->data[expr->size] = operation; + expr->size++; + if (strcmp (fmt, locexpr_opfmt[operation])) + { + internal_error (__FILE__, __LINE__, + "You passed a format string of %s for opcode %s, and its format string is %s\n", + fmt, locexpr_opstring[operation], locexpr_opfmt[operation]); + } + va_start (ap, fmt); + while (*fmt) + { + switch (*fmt++) + { + case 'u': + uval = (ULONGEST) va_arg (ap, unsigned long); + encode_uleb128 (expr, uval); + break; + case 's': + sval = (LONGEST) va_arg (ap, signed long); + encode_sleb128 (expr, sval); + break; + case 'c': + ucval = (unsigned char) va_arg (ap, unsigned int); + encode_uchar (expr, ucval); + break; + } + } + va_end (ap); + } + + void + locexpr_get_op (struct locexpr *expr, struct locexpr_cookie *cookie, enum locexpr_opcode *op) + { + struct locexpr *realexpr; + unsigned int position = 0; + gdb_assert (!(expr == NULL && (cookie == NULL || cookie->expr == NULL))); + gdb_assert (op != NULL); + gdb_assert (cookie == NULL || (cookie->operands_left == 0)); + if (cookie->expr != NULL) + { + realexpr = cookie->expr; + position = cookie->position; + } + else + { + realexpr = expr; + position = 0; + } + *op = realexpr->data[position]; + cookie->lastopcode = *op; + cookie->operands_left = locexpr_opcount[*op]; + cookie->expr = realexpr; + cookie->position++; + + } + void + locexpr_get_longest (struct locexpr_cookie *cookie, LONGEST *value) + { + unsigned char *newdata; + gdb_assert (cookie != NULL && cookie->expr != NULL); + gdb_assert (cookie->operands_left > 0); + + newdata = read_sleb128 (cookie->expr->data + cookie->position, value); + cookie->position = newdata - (unsigned char *)cookie->expr->data; + cookie->operands_left--; + + } + void + locexpr_get_ulongest (struct locexpr_cookie *cookie, ULONGEST *value) + { + unsigned char *newdata; + gdb_assert (cookie != NULL && cookie->expr != NULL); + gdb_assert (cookie->operands_left > 0); + + newdata = read_uleb128 (cookie->expr->data + cookie->position, value); + cookie->position = newdata - (unsigned char *)cookie->expr->data; + cookie->operands_left--; + + } + void + locexpr_get_uchar (struct locexpr_cookie *cookie, unsigned char *value) + { + gdb_assert (cookie != NULL && cookie->expr != NULL); + gdb_assert (cookie->operands_left > 0); + + *value = (unsigned char)*(cookie->expr->data + cookie->position); + cookie->position++; + cookie->operands_left--; + } + + + static CORE_ADDR + execute_stack_op (struct symbol *var, unsigned char *op_ptr, unsigned char *op_end, + struct frame_info *frame, CORE_ADDR initial, value_ptr *currval) + { + CORE_ADDR stack[64]; /* ??? Assume this is enough. */ + int stack_elt; + stack[0] = initial; + stack_elt = 1; + while (op_ptr < op_end) + { + enum locexpr_opcode op = *op_ptr++; + ULONGEST result, reg; + LONGEST offset; + switch (op) + { + case GLO_addr: + result = (CORE_ADDR) extract_unsigned_integer (op_ptr, TARGET_PTR_BIT / TARGET_CHAR_BIT); + op_ptr += TARGET_PTR_BIT / TARGET_CHAR_BIT; + break; + + case GLO_constu: + op_ptr = read_uleb128 (op_ptr, &result); + break; + case GLO_consts: + op_ptr = read_sleb128 (op_ptr, &offset); + result = offset; + break; + + case GLO_regx: + { + char *buf = (char*) alloca (MAX_REGISTER_RAW_SIZE); + + op_ptr = read_uleb128 (op_ptr, ®); + get_saved_register (buf, NULL, NULL, frame, reg, NULL); + result = extract_address (buf, REGISTER_RAW_SIZE (reg)); + if (currval != NULL) + { + store_typed_address (VALUE_CONTENTS_RAW (*currval), SYMBOL_TYPE (var), result); + VALUE_LVAL (*currval) = not_lval; + } + } + break; + case GLO_fbreg: + { + struct symbol *framefunc; + unsigned char *datastart; + unsigned char *dataend; + struct locexpr *theblock; + + framefunc = get_frame_function (frame); + op_ptr = read_sleb128 (op_ptr, &offset); + theblock = SYMBOL_FRAME_LOC_EXPR (framefunc); + datastart = theblock->data; + dataend = theblock->data + theblock->size; + result = execute_stack_op (var, datastart, dataend, frame, 0, NULL) + offset; + } + break; + case GLO_dup: + if (stack_elt < 1) + abort (); + result = stack[stack_elt - 1]; + break; + + case GLO_drop: + if (--stack_elt < 0) + abort (); + goto no_push; + + case GLO_pick: + offset = *op_ptr++; + if (offset >= stack_elt - 1) + abort (); + result = stack[stack_elt - 1 - offset]; + break; + + case GLO_over: + if (stack_elt < 2) + abort (); + result = stack[stack_elt - 2]; + break; + + case GLO_rot: + { + CORE_ADDR t1, t2, t3; + + if (stack_elt < 3) + abort (); + t1 = stack[stack_elt - 1]; + t2 = stack[stack_elt - 2]; + t3 = stack[stack_elt - 3]; + stack[stack_elt - 1] = t2; + stack[stack_elt - 2] = t3; + stack[stack_elt - 3] = t1; + goto no_push; + } + + case GLO_deref: + case GLO_abs: + case GLO_neg: + case GLO_not: + /* Unary operations. */ + if (--stack_elt < 0) + abort (); + result = stack[stack_elt]; + + switch (op) + { + case GLO_deref: + { + switch (*op_ptr++) + { + case 1: + result = read_memory_unsigned_integer (result, 1); + break; + case 2: + result = read_memory_unsigned_integer (result, 2); + break; + case 4: + result = read_memory_unsigned_integer (result, 4); + break; + case 8: + result = read_memory_unsigned_integer (result, 8); + break; + default: + abort (); + } + } + break; + + case GLO_abs: + if ((signed int) result < 0) + result = -result; + break; + case GLO_neg: + result = -result; + break; + case GLO_not: + result = ~result; + break; + } + break; + + case GLO_and: + case GLO_div: + case GLO_minus: + case GLO_mod: + case GLO_mul: + case GLO_or: + case GLO_plus: + case GLO_le: + case GLO_ge: + case GLO_eq: + case GLO_lt: + case GLO_gt: + case GLO_ne: + { + /* Binary operations. */ + CORE_ADDR first, second; + if ((stack_elt -= 2) < 0) + abort (); + second = stack[stack_elt]; + first = stack[stack_elt + 1]; + + switch (op) + { + case GLO_and: + result = second & first; + break; + case GLO_div: + result = (LONGEST)second / (LONGEST)first; + break; + case GLO_minus: + result = second - first; + break; + case GLO_mod: + result = (LONGEST)second % (LONGEST)first; + break; + case GLO_mul: + result = second * first; + break; + case GLO_or: + result = second | first; + break; + case GLO_plus: + result = second + first; + break; + case GLO_shl: + result = second << first; + break; + case GLO_shr: + result = second >> first; + break; + case GLO_shra: + result = (LONGEST)second >> first; + break; + case GLO_xor: + result = second ^ first; + break; + case GLO_le: + result = (LONGEST)first <= (LONGEST)second; + break; + case GLO_ge: + result = (LONGEST)first >= (LONGEST)second; + break; + case GLO_eq: + result = (LONGEST)first == (LONGEST)second; + break; + case GLO_lt: + result = (LONGEST)first < (LONGEST)second; + break; + case GLO_gt: + result = (LONGEST)first > (LONGEST)second; + break; + case GLO_ne: + result = (LONGEST)first != (LONGEST)second; + break; + } + } + break; + + case GLO_skip: + op_ptr = read_sleb128 (op_ptr, &offset); + op_ptr += offset; + goto no_push; + + case GLO_bra: + if (--stack_elt < 0) + abort (); + op_ptr = read_sleb128 (op_ptr, &offset); + if (stack[stack_elt] != 0) + op_ptr += offset; + goto no_push; + + case GLO_nop: + goto no_push; + + default: + abort (); + } + + /* Most things push a result value. */ + if ((size_t) stack_elt >= sizeof(stack)/sizeof(*stack)) + abort (); + stack[++stack_elt] = result; + no_push:; + } + + /* We were executing this program to get a value. It should be + at top of stack. */ + if (stack_elt-1 < 0) + abort (); + return stack[stack_elt]; + } + + /* Evaluate a dwarf2 location description, given in THEBLOCK, in the + context of frame FRAME. */ + value_ptr + evaluate_loc_expr (struct symbol *var, struct frame_info *frame, + struct locexpr *theblock, struct type *type) + { + CORE_ADDR result; + value_ptr retval; + retval = allocate_value(type); + VALUE_LVAL (retval) = lval_memory; + VALUE_BFD_SECTION (retval) = SYMBOL_BFD_SECTION (var); + result = execute_stack_op (var, theblock->data, theblock->data+theblock->size, frame, 0, &retval); + if (VALUE_LVAL (retval) == lval_memory) + { + VALUE_LAZY (retval) = 1; + VALUE_ADDRESS (retval) = result; + } + return retval; + } + void + _initialize_symeval (void) + { + struct locexpr *test; + struct locexpr_cookie temp3; + LONGEST temp; + ULONGEST temp2; + enum locexpr_opcode opcode; + memset (&temp3, 0, sizeof (temp3)); + + init_locexpr (&test); + locexpr_push_op (test, GLO_consts, "s", -100000); + locexpr_push_op (test, GLO_constu, "u", 100000); + locexpr_get_op (test, &temp3, &opcode); + locexpr_get_longest (&temp3, &temp); + locexpr_get_op (NULL, &temp3, &opcode); + locexpr_get_ulongest (&temp3, &temp2); + destroy_locexpr (&test); + } Index: symeval.def =================================================================== RCS file: symeval.def diff -N symeval.def *** /dev/null Tue May 5 13:32:27 1998 --- symeval.def Tue May 29 10:34:00 2001 *************** *** 0 **** --- 1,38 ---- + /* DEFINE_LOCEXPR_OPCODE (opcode, description, numargs, argtypes) */ + DEFINE_LOCEXPR_OPCODE (GLO_addr, "Address", 1, "u") + DEFINE_LOCEXPR_OPCODE (GLO_constu, "Unsigned constant", 1, "u") + DEFINE_LOCEXPR_OPCODE (GLO_consts, "Signed constant", 1, "s") + DEFINE_LOCEXPR_OPCODE (GLO_dup, "Duplicate top of stack", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_drop, "Pop top of stack", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_over, "Push second entry of stack onto top of stack", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_pick, "Push a stack entry onto top of stack", 1, "c") + DEFINE_LOCEXPR_OPCODE (GLO_swap, "Swap top two stack entries", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_rot, "Rotate first three stack entries", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_xderef, "Extended dereference of top of stack", 1, "c") + DEFINE_LOCEXPR_OPCODE (GLO_deref, "Dereference top of stack", 1, "c") + DEFINE_LOCEXPR_OPCODE (GLO_abs, "Absolute value", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_and, "Bitwise AND", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_div, "Signed division", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_minus, "Subtraction", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_mod, "Modulo", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_mul, "Multiply", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_neg, "Negate", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_not, "Bitwise NOT", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_or, "Bitwise OR", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_plus, "Addition", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_shl, "Logical bitshift left", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_shr, "Logical bitshift right", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_shra, "Arithmetic bitshift right", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_xor, "Bitwise XOR", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_bra, "Conditional branch", 1, "s") + DEFINE_LOCEXPR_OPCODE (GLO_eq, "==", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_ge, ">=", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_gt, ">", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_le, "<=", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_lt, "<", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_ne, "!=", 0, "") + DEFINE_LOCEXPR_OPCODE (GLO_skip, "Unconditional branch", 1, "s") + DEFINE_LOCEXPR_OPCODE (GLO_regx, "Get register value", 1, "u") + DEFINE_LOCEXPR_OPCODE (GLO_fbreg, "Frame based value", 1, "s") + DEFINE_LOCEXPR_OPCODE (GLO_piece, "Piece of object", 1, "u") + DEFINE_LOCEXPR_OPCODE (GLO_nop, "No operation", 0, "") \ No newline at end of file Index: symeval.h =================================================================== RCS file: symeval.h diff -N symeval.h *** /dev/null Tue May 5 13:32:27 1998 --- symeval.h Tue May 29 10:34:00 2001 *************** *** 0 **** --- 1,20 ---- + #ifndef SYMEVAL_H + #define SYMEVAL_H + /* Make up the enum from the list of opcodes */ + #define DEFINE_LOCEXPR_OPCODE(opcode, desc, numargs, argtypes) opcode, + enum locexpr_opcode + { + #include "symeval.def" + }; + #undef DEFINE_LOCEXPR_OPCODE + struct locexpr_cookie; + struct locexpr; + void init_locexpr (struct locexpr **); + void destroy_locexpr (struct locexpr **); + void locexpr_push_op (struct locexpr *, enum locexpr_opcode, const char *, ...); + void locexpr_get_op (struct locexpr *, struct locexpr_cookie *, enum locexpr_opcode *); + void locexpr_get_longest (struct locexpr_cookie *, LONGEST *); + void locexpr_get_ulongest (struct locexpr_cookie *, ULONGEST *); + void locexpr_get_uchar (struct locexpr_cookie *, unsigned char *); + value_ptr evaluate_loc_expr (struct symbol *, struct frame_info *, struct locexpr *, struct type *); + #endif Index: symtab.h =================================================================== RCS file: /cvs/src/src/gdb/symtab.h,v retrieving revision 1.21 diff -c -3 -p -w -B -b -r1.21 symtab.h *** symtab.h 2001/04/27 00:19:09 1.21 --- symtab.h 2001/05/29 17:34:08 *************** enum address_class *** 653,660 **** * than the one where the global was allocated are done * with a level of indirection. */ ! LOC_INDIRECT }; --- 642,654 ---- * than the one where the global was allocated are done * with a level of indirection. */ + + LOC_INDIRECT, ! /* Location is a location expression */ ! LOC_LOC_EXPR, ! /* Location is a location list (ranges + location expressions) */ ! LOC_LOC_LIST }; *************** struct symbol *** 713,718 **** --- 711,721 ---- short basereg; } aux_value; + struct + { + struct locexpr *loc; + struct locexpr *frameloc; + } dynamic_location; /* Link to a list of aliases for this symbol. *************** struct symbol *** 730,735 **** --- 736,743 ---- #define SYMBOL_TYPE(symbol) (symbol)->type #define SYMBOL_LINE(symbol) (symbol)->line #define SYMBOL_BASEREG(symbol) (symbol)->aux_value.basereg + #define SYMBOL_LOC_EXPR(symbol) (symbol)->dynamic_location.loc + #define SYMBOL_FRAME_LOC_EXPR(symbol) (symbol)->dynamic_location.frameloc #define SYMBOL_ALIASES(symbol) (symbol)->aliases #define SYMBOL_RANGES(symbol) (symbol)->ranges *************** struct linetable *** 805,810 **** --- 813,819 ---- struct linetable_entry item[1]; }; + struct locexpr; /* All the information on one source file. */ struct source -- "Yesterday I parked my car in a tow-away zone... When I came back the entire area was missing. "-Steven Wright