From 4c2df51b5ace4f5c0a1f8a76cdf536ac4432dd14 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Fri, 21 Feb 2003 15:24:18 +0000 Subject: [PATCH] Based on a patch from Daniel Berlin (dberlin@dberlin.org). * symtab.h: Add opaque declarations of struct axs_value and struct agent_expr. (enum address_class): Add LOC_COMPUTED and LOC_COMPUTED_ARG. (struct location_funcs): New type. (struct symbol): Add "loc" to aux_value. (SYMBOL_LOCATION_BATON, SYMBOL_LOCATION_FUNCS): New macros. * dwarf2read.c: Include "dwarf2expr.h". (dwarf2_symbol_mark_computed): New function. (read_func_scope): Use it. (var_decode_location): New function. (new_symbol): Use it. * dwarf2expr.c, dwarf2expr.h, dwarf2loc.c, dwarf2loc.h: New files. * Makefile.in (SFILES): Add dwarf2loc.c and dwarf2expr.c. (dwarf2expr_h, dwarf2loc_h): New variables. (COMMON_OBS): Add dwarf2expr.o and dwarf2loc.o. (dwarf2expr.o, dwarf2loc.o): New rules. (dwarf2read.o): Add $(dwarf2expr_h) and $(dwarf2loc_h). * buildsym.c (finish_block): Handle LOC_COMPUTED and LOC_COMPUTED_ARG. * findvar.c (symbol_read_needs_frame, read_var_value): Likewise. * m2-exp.y (yylex): Likewise. * printcmd.c (address_info, print_frame_args): Likewise. * stack.c (print_block_frame_locals, print_frame_arg_vars): Likewise. * symmisc.c (print_symbol, print_partial_symbols): Likewise. * ada-lang.c (ada_resolve_subexp, symtab_for_sym) (ada_add_block_symbols, fill_in_ada_prototype): Likewise. * symtab.c (lookup_block_symbol): Likewise. --- gdb/ChangeLog | 32 +++ gdb/Makefile.in | 14 +- gdb/ada-lang.c | 8 + gdb/buildsym.c | 4 + gdb/dwarf2expr.c | 687 +++++++++++++++++++++++++++++++++++++++++++++++ gdb/dwarf2expr.h | 97 +++++++ gdb/dwarf2loc.c | 287 ++++++++++++++++++++ gdb/dwarf2loc.h | 39 +++ gdb/dwarf2read.c | 200 +++++++------- gdb/findvar.c | 20 ++ gdb/m2-exp.y | 2 + gdb/printcmd.c | 6 + gdb/stack.c | 2 + gdb/symmisc.c | 9 + gdb/symtab.c | 3 +- gdb/symtab.h | 72 ++++- 16 files changed, 1379 insertions(+), 103 deletions(-) create mode 100644 gdb/dwarf2expr.c create mode 100644 gdb/dwarf2expr.h create mode 100644 gdb/dwarf2loc.c create mode 100644 gdb/dwarf2loc.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3020fe35a29..b69364a6f65 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,35 @@ +2003-02-21 Daniel Jacobowitz + + Based on a patch from Daniel Berlin (dberlin@dberlin.org). + * symtab.h: Add opaque declarations of struct axs_value and + struct agent_expr. + (enum address_class): Add LOC_COMPUTED and LOC_COMPUTED_ARG. + (struct location_funcs): New type. + (struct symbol): Add "loc" to aux_value. + (SYMBOL_LOCATION_BATON, SYMBOL_LOCATION_FUNCS): New macros. + * dwarf2read.c: Include "dwarf2expr.h". + (dwarf2_symbol_mark_computed): New function. + (read_func_scope): Use it. + (var_decode_location): New function. + (new_symbol): Use it. + * dwarf2expr.c, dwarf2expr.h, dwarf2loc.c, dwarf2loc.h: New files. + + * Makefile.in (SFILES): Add dwarf2loc.c and dwarf2expr.c. + (dwarf2expr_h, dwarf2loc_h): New variables. + (COMMON_OBS): Add dwarf2expr.o and dwarf2loc.o. + (dwarf2expr.o, dwarf2loc.o): New rules. + (dwarf2read.o): Add $(dwarf2expr_h) and $(dwarf2loc_h). + * buildsym.c (finish_block): Handle LOC_COMPUTED and + LOC_COMPUTED_ARG. + * findvar.c (symbol_read_needs_frame, read_var_value): Likewise. + * m2-exp.y (yylex): Likewise. + * printcmd.c (address_info, print_frame_args): Likewise. + * stack.c (print_block_frame_locals, print_frame_arg_vars): Likewise. + * symmisc.c (print_symbol, print_partial_symbols): Likewise. + * ada-lang.c (ada_resolve_subexp, symtab_for_sym) + (ada_add_block_symbols, fill_in_ada_prototype): Likewise. + * symtab.c (lookup_block_symbol): Likewise. + 2003-02-20 Adam Fedor * symtab.h: Remove objc_specific struct diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5e39e12aa27..2158d25d9f0 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -513,7 +513,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ complaints.c completer.c corefile.c \ cp-abi.c cp-support.c cp-valprint.c \ dbxread.c demangle.c disasm.c doublest.c \ - dummy-frame.c dwarfread.c dwarf2read.c \ + dummy-frame.c dwarfread.c dwarf2expr.c dwarf2loc.c dwarf2read.c \ elfread.c environ.c eval.c event-loop.c event-top.c expprint.c \ f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c frame.c \ frame-unwind.c \ @@ -628,6 +628,8 @@ doublest_h = doublest.h $(floatformat_h) dst_h = dst.h dummy_frame_h = dummy-frame.h dwarf2cfi_h = dwarf2cfi.h +dwarf2expr_h = dwarf2expr.h +dwarf2loc_h = dwarf2loc.h environ_h = environ.h event_loop_h = event-loop.h event_top_h = event-top.h @@ -837,6 +839,7 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \ exec.o bcache.o objfiles.o minsyms.o maint.o demangle.o \ dbxread.o coffread.o coff-pe-read.o elfread.o \ dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \ + dwarf2expr.o dwarf2loc.o \ c-lang.o f-lang.o \ ui-out.o cli-out.o \ varobj.o wrapper.o \ @@ -1632,11 +1635,16 @@ dve3900-rom.o: dve3900-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \ dwarf2cfi.o: dwarf2cfi.c $(defs_h) $(gdbcore_h) $(symtab_h) $(symfile_h) \ $(objfiles_h) $(target_h) $(elf_dwarf2_h) $(inferior_h) \ $(regcache_h) $(dwarf2cfi_h) $(gdb_assert_h) +dwarf2expr.o: dwarf2expr.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(value_h) \ + $(gdbcore_h) $(dwarf2expr_h) +dwarf2loc.o: dwarf2loc.c $(defs_h) $(ui_out_h) $(value_h) $(frame_h) \ + $(gdbcore_h) $(target_h) $(inferior_h) $(dwarf2expr_h) \ + $(dwarf2loc_h) $(gdb_string_h) dwarf2read.o: dwarf2read.c $(defs_h) $(bfd_h) $(symtab_h) $(gdbtypes_h) \ $(symfile_h) $(objfiles_h) $(elf_dwarf2_h) $(buildsym_h) \ $(demangle_h) $(expression_h) $(filenames_h) $(macrotab_h) \ - $(language_h) $(complaints_h) $(bcache_h) $(gdb_string_h) \ - $(gdb_assert_h) + $(language_h) $(complaints_h) $(bcache_h) $(dwarf2expr_h) \ + $(dwarf2loc_h) $(gdb_string_h) $(gdb_assert_h) dwarfread.o: dwarfread.c $(defs_h) $(symtab_h) $(gdbtypes_h) $(symfile_h) \ $(objfiles_h) $(elf_dwarf_h) $(buildsym_h) $(demangle_h) \ $(expression_h) $(language_h) $(complaints_h) $(gdb_string_h) diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c index d5323a145e8..83d1090bf8c 100644 --- a/gdb/ada-lang.c +++ b/gdb/ada-lang.c @@ -2172,6 +2172,8 @@ ada_resolve_subexp (struct expression **expp, int *pos, int deprocedure_p, case LOC_LOCAL_ARG: case LOC_BASEREG: case LOC_BASEREG_ARG: + case LOC_COMPUTED: + case LOC_COMPUTED_ARG: goto FoundNonType; default: break; @@ -3466,6 +3468,8 @@ symtab_for_sym (struct symbol *sym) case LOC_LOCAL_ARG: case LOC_BASEREG: case LOC_BASEREG_ARG: + case LOC_COMPUTED: + case LOC_COMPUTED_ARG: for (j = FIRST_LOCAL_BLOCK; j < BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)); j += 1) { @@ -3970,6 +3974,7 @@ ada_add_block_symbols (struct block *block, const char *name, case LOC_REGPARM: case LOC_REGPARM_ADDR: case LOC_BASEREG_ARG: + case LOC_COMPUTED_ARG: arg_sym = sym; break; case LOC_UNRESOLVED: @@ -4033,6 +4038,7 @@ ada_add_block_symbols (struct block *block, const char *name, case LOC_REGPARM: case LOC_REGPARM_ADDR: case LOC_BASEREG_ARG: + case LOC_COMPUTED_ARG: arg_sym = sym; break; case LOC_UNRESOLVED: @@ -4117,6 +4123,7 @@ ada_add_block_symbols (struct block *block, const char *name, case LOC_REGPARM: case LOC_REGPARM_ADDR: case LOC_BASEREG_ARG: + case LOC_COMPUTED_ARG: arg_sym = sym; break; case LOC_UNRESOLVED: @@ -4201,6 +4208,7 @@ fill_in_ada_prototype (struct symbol *func) case LOC_REGPARM: case LOC_LOCAL_ARG: case LOC_BASEREG_ARG: + case LOC_COMPUTED_ARG: TYPE_FIELD_BITPOS (ftype, nargs) = nargs; TYPE_FIELD_BITSIZE (ftype, nargs) = 0; TYPE_FIELD_STATIC_KIND (ftype, nargs) = 0; diff --git a/gdb/buildsym.c b/gdb/buildsym.c index 15a59a039f5..3cc9e8ee0a4 100644 --- a/gdb/buildsym.c +++ b/gdb/buildsym.c @@ -309,6 +309,7 @@ finish_block (struct symbol *symbol, struct pending **listhead, case LOC_REGPARM_ADDR: case LOC_BASEREG_ARG: case LOC_LOCAL_ARG: + case LOC_COMPUTED_ARG: nparams++; break; case LOC_UNDEF: @@ -324,6 +325,7 @@ finish_block (struct symbol *symbol, struct pending **listhead, case LOC_BASEREG: case LOC_UNRESOLVED: case LOC_OPTIMIZED_OUT: + case LOC_COMPUTED: default: break; } @@ -345,6 +347,7 @@ finish_block (struct symbol *symbol, struct pending **listhead, case LOC_REGPARM_ADDR: case LOC_BASEREG_ARG: case LOC_LOCAL_ARG: + case LOC_COMPUTED_ARG: TYPE_FIELD_TYPE (ftype, iparams) = SYMBOL_TYPE (sym); TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0; iparams++; @@ -362,6 +365,7 @@ finish_block (struct symbol *symbol, struct pending **listhead, case LOC_BASEREG: case LOC_UNRESOLVED: case LOC_OPTIMIZED_OUT: + case LOC_COMPUTED: default: break; } diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c new file mode 100644 index 00000000000..02e246f6d58 --- /dev/null +++ b/gdb/dwarf2expr.c @@ -0,0 +1,687 @@ +/* Dwarf2 Expression Evaluator + Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Daniel Berlin (dan@dberlin.org) + + 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 "gdbtypes.h" +#include "value.h" +#include "gdbcore.h" +#include "elf/dwarf2.h" +#include "dwarf2expr.h" + +/* Local prototypes. */ + +static void execute_stack_op (struct dwarf_expr_context *, + unsigned char *, unsigned char *); + +/* Create a new context for the expression evaluator. */ + +struct dwarf_expr_context * +new_dwarf_expr_context () +{ + struct dwarf_expr_context *retval; + retval = xcalloc (1, sizeof (struct dwarf_expr_context)); + retval->stack_len = 10; + retval->stack = xmalloc (10 * sizeof (CORE_ADDR)); + return retval; +} + +/* Release the memory allocated to CTX. */ + +void +free_dwarf_expr_context (struct dwarf_expr_context *ctx) +{ + xfree (ctx->stack); + xfree (ctx); +} + +/* Expand the memory allocated to CTX's stack to contain at least + NEED more elements than are currently used. */ + +static void +dwarf_expr_grow_stack (struct dwarf_expr_context *ctx, size_t need) +{ + if (ctx->stack_len + need > ctx->stack_allocated) + { + size_t templen = ctx->stack_len * 2; + while (templen < (ctx->stack_len + need)) + templen *= 2; + ctx->stack = xrealloc (ctx->stack, + templen * sizeof (CORE_ADDR)); + ctx->stack_allocated = templen; + } +} + +/* Push VALUE onto CTX's stack. */ + +void +dwarf_expr_push (struct dwarf_expr_context *ctx, CORE_ADDR value) +{ + dwarf_expr_grow_stack (ctx, 1); + ctx->stack[ctx->stack_len++] = value; +} + +/* Pop the top item off of CTX's stack. */ + +void +dwarf_expr_pop (struct dwarf_expr_context *ctx) +{ + if (ctx->stack_len <= 0) + error ("dwarf expression stack underflow"); + ctx->stack_len--; +} + +/* Retrieve the N'th item on CTX's stack. */ + +CORE_ADDR +dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n) +{ + if (ctx->stack_len < n) + error ("Asked for position %d of stack, stack only has %d elements on it\n", + n, ctx->stack_len); + return ctx->stack[ctx->stack_len - (1 + n)]; + +} + +/* Evaluate the expression at ADDR (LEN bytes long) using the context + CTX. */ + +void +dwarf_expr_eval (struct dwarf_expr_context *ctx, unsigned char *addr, + size_t len) +{ + execute_stack_op (ctx, addr, addr + len); +} + +/* Decode the unsigned LEB128 constant at BUF into the variable pointed to + by R, and return the new value of BUF. Verify that it doesn't extend + past BUF_END. */ + +static unsigned char * +read_uleb128 (unsigned char *buf, unsigned char *buf_end, ULONGEST * r) +{ + unsigned shift = 0; + ULONGEST result = 0; + unsigned char byte; + + while (1) + { + if (buf >= buf_end) + error ("read_uleb128: Corrupted DWARF expression."); + + byte = *buf++; + result |= (byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + *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. Verify that it doesn't extend + past BUF_END. */ + +static unsigned char * +read_sleb128 (unsigned char *buf, unsigned char *buf_end, LONGEST * r) +{ + unsigned shift = 0; + LONGEST result = 0; + unsigned char byte; + + while (1) + { + if (buf >= buf_end) + error ("read_sleb128: Corrupted DWARF expression."); + + byte = *buf++; + result |= (byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) + break; + } + if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0) + result |= -(1 << shift); + + *r = result; + return buf; +} + +/* Read an address from BUF, and verify that it doesn't extend past + BUF_END. The address is returned, and *BYTES_READ is set to the + number of bytes read from BUF. */ + +static CORE_ADDR +read_address (unsigned char *buf, unsigned char *buf_end, int *bytes_read) +{ + CORE_ADDR result; + + if (buf_end - buf < TARGET_ADDR_BIT / TARGET_CHAR_BIT) + error ("read_address: Corrupted DWARF expression."); + + *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT; + result = extract_address (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT); + return result; +} + +/* Return the type of an address, for unsigned arithmetic. */ + +static struct type * +unsigned_address_type (void) +{ + switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT) + { + case 2: + return builtin_type_uint16; + case 4: + return builtin_type_uint32; + case 8: + return builtin_type_uint64; + default: + internal_error (__FILE__, __LINE__, + "Unsupported address size.\n"); + } +} + +/* Return the type of an address, for signed arithmetic. */ + +static struct type * +signed_address_type (void) +{ + switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT) + { + case 2: + return builtin_type_int16; + case 4: + return builtin_type_int32; + case 8: + return builtin_type_int64; + default: + internal_error (__FILE__, __LINE__, + "Unsupported address size.\n"); + } +} + +/* The engine for the expression evaluator. Using the context in CTX, + evaluate the expression between OP_PTR and OP_END. */ + +static void +execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr, + unsigned char *op_end) +{ + while (op_ptr < op_end) + { + enum dwarf_location_atom op = *op_ptr++; + CORE_ADDR result, memaddr; + ULONGEST uoffset, reg; + LONGEST offset; + int bytes_read; + enum lval_type expr_lval; + + ctx->in_reg = 0; + + switch (op) + { + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + result = op - DW_OP_lit0; + break; + + case DW_OP_addr: + result = read_address (op_ptr, op_end, &bytes_read); + op_ptr += bytes_read; + break; + + case DW_OP_const1u: + result = extract_unsigned_integer (op_ptr, 1); + op_ptr += 1; + break; + case DW_OP_const1s: + result = extract_signed_integer (op_ptr, 1); + op_ptr += 1; + break; + case DW_OP_const2u: + result = extract_unsigned_integer (op_ptr, 2); + op_ptr += 2; + break; + case DW_OP_const2s: + result = extract_signed_integer (op_ptr, 2); + op_ptr += 2; + break; + case DW_OP_const4u: + result = extract_unsigned_integer (op_ptr, 4); + op_ptr += 4; + break; + case DW_OP_const4s: + result = extract_signed_integer (op_ptr, 4); + op_ptr += 4; + break; + case DW_OP_const8u: + result = extract_unsigned_integer (op_ptr, 8); + op_ptr += 8; + break; + case DW_OP_const8s: + result = extract_signed_integer (op_ptr, 8); + op_ptr += 8; + break; + case DW_OP_constu: + op_ptr = read_uleb128 (op_ptr, op_end, &uoffset); + result = uoffset; + break; + case DW_OP_consts: + op_ptr = read_sleb128 (op_ptr, op_end, &offset); + result = offset; + break; + + /* The DW_OP_reg operations are required to occur alone in + location expressions. */ + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + /* NOTE: in the presence of DW_OP_piece this check is incorrect. */ + if (op_ptr != op_end) + error ("DWARF-2 expression error: DW_OP_reg operations must be " + "used alone."); + + /* FIXME drow/2003-02-21: This call to read_reg could be pushed + into the evaluator's caller by changing the semantics for in_reg. + Then we wouldn't need to return an lval_type and a memaddr. */ + result = (ctx->read_reg) (ctx->baton, op - DW_OP_reg0, &expr_lval, + &memaddr); + + if (expr_lval == lval_register) + { + ctx->regnum = op - DW_OP_reg0; + ctx->in_reg = 1; + } + else + result = memaddr; + + break; + + case DW_OP_regx: + op_ptr = read_uleb128 (op_ptr, op_end, ®); + if (op_ptr != op_end) + error ("DWARF-2 expression error: DW_OP_reg operations must be " + "used alone."); + + result = (ctx->read_reg) (ctx->baton, reg, &expr_lval, &memaddr); + + if (expr_lval == lval_register) + { + ctx->regnum = reg; + ctx->in_reg = 1; + } + else + result = memaddr; + + break; + + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + { + op_ptr = read_sleb128 (op_ptr, op_end, &offset); + result = (ctx->read_reg) (ctx->baton, op - DW_OP_breg0, + &expr_lval, &memaddr); + result += offset; + } + break; + case DW_OP_bregx: + { + op_ptr = read_uleb128 (op_ptr, op_end, ®); + op_ptr = read_sleb128 (op_ptr, op_end, &offset); + result = (ctx->read_reg) (ctx->baton, reg, &expr_lval, &memaddr); + result += offset; + } + break; + case DW_OP_fbreg: + { + unsigned char *datastart; + size_t datalen; + unsigned int before_stack_len; + + op_ptr = read_sleb128 (op_ptr, op_end, &offset); + /* Rather than create a whole new context, we simply + record the stack length before execution, then reset it + afterwards, effectively erasing whatever the recursive + call put there. */ + before_stack_len = ctx->stack_len; + (ctx->get_frame_base) (ctx->baton, &datastart, &datalen); + dwarf_expr_eval (ctx, datastart, datalen); + result = dwarf_expr_fetch (ctx, 0); + if (! ctx->in_reg) + { + char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT); + int bytes_read; + + (ctx->read_mem) (ctx->baton, buf, result, + TARGET_ADDR_BIT / TARGET_CHAR_BIT); + result = read_address (buf, + buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT, + &bytes_read); + } + result = result + offset; + ctx->stack_len = before_stack_len; + ctx->in_reg = 0; + } + break; + case DW_OP_dup: + result = dwarf_expr_fetch (ctx, 0); + break; + + case DW_OP_drop: + dwarf_expr_pop (ctx); + goto no_push; + + case DW_OP_pick: + offset = *op_ptr++; + result = dwarf_expr_fetch (ctx, offset); + break; + + case DW_OP_over: + result = dwarf_expr_fetch (ctx, 1); + break; + + case DW_OP_rot: + { + CORE_ADDR t1, t2, t3; + + if (ctx->stack_len < 3) + error ("Not enough elements for DW_OP_rot. Need 3, have %d\n", + ctx->stack_len); + t1 = ctx->stack[ctx->stack_len - 1]; + t2 = ctx->stack[ctx->stack_len - 2]; + t3 = ctx->stack[ctx->stack_len - 3]; + ctx->stack[ctx->stack_len - 1] = t2; + ctx->stack[ctx->stack_len - 2] = t3; + ctx->stack[ctx->stack_len - 3] = t1; + goto no_push; + } + + case DW_OP_deref: + case DW_OP_deref_size: + case DW_OP_abs: + case DW_OP_neg: + case DW_OP_not: + case DW_OP_plus_uconst: + /* Unary operations. */ + result = dwarf_expr_fetch (ctx, 0); + dwarf_expr_pop (ctx); + + switch (op) + { + case DW_OP_deref: + { + char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT); + int bytes_read; + + (ctx->read_mem) (ctx->baton, buf, result, + TARGET_ADDR_BIT / TARGET_CHAR_BIT); + result = read_address (buf, + buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT, + &bytes_read); + } + break; + + case DW_OP_deref_size: + { + char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT); + int bytes_read; + + (ctx->read_mem) (ctx->baton, buf, result, *op_ptr++); + result = read_address (buf, + buf + TARGET_ADDR_BIT / TARGET_CHAR_BIT, + &bytes_read); + } + break; + + case DW_OP_abs: + if ((signed int) result < 0) + result = -result; + break; + case DW_OP_neg: + result = -result; + break; + case DW_OP_not: + result = ~result; + break; + case DW_OP_plus_uconst: + op_ptr = read_uleb128 (op_ptr, op_end, ®); + result += reg; + break; + } + break; + + case DW_OP_and: + case DW_OP_div: + case DW_OP_minus: + case DW_OP_mod: + case DW_OP_mul: + case DW_OP_or: + case DW_OP_plus: + case DW_OP_shl: + case DW_OP_shr: + case DW_OP_shra: + case DW_OP_xor: + case DW_OP_le: + case DW_OP_ge: + case DW_OP_eq: + case DW_OP_lt: + case DW_OP_gt: + case DW_OP_ne: + { + /* Binary operations. Use the value engine to do computations in + the right width. */ + CORE_ADDR first, second; + enum exp_opcode binop; + struct value *val1, *val2; + + second = dwarf_expr_fetch (ctx, 0); + dwarf_expr_pop (ctx); + + first = dwarf_expr_fetch (ctx, 1); + dwarf_expr_pop (ctx); + + val1 = value_from_longest (unsigned_address_type (), first); + val2 = value_from_longest (unsigned_address_type (), second); + + switch (op) + { + case DW_OP_and: + binop = BINOP_BITWISE_AND; + break; + case DW_OP_div: + binop = BINOP_DIV; + case DW_OP_minus: + binop = BINOP_SUB; + break; + case DW_OP_mod: + binop = BINOP_MOD; + break; + case DW_OP_mul: + binop = BINOP_MUL; + break; + case DW_OP_or: + binop = BINOP_BITWISE_IOR; + break; + case DW_OP_plus: + binop = BINOP_ADD; + break; + case DW_OP_shl: + binop = BINOP_LSH; + break; + case DW_OP_shr: + binop = BINOP_RSH; + case DW_OP_shra: + binop = BINOP_RSH; + val1 = value_from_longest (signed_address_type (), first); + break; + case DW_OP_xor: + binop = BINOP_BITWISE_XOR; + break; + case DW_OP_le: + binop = BINOP_LEQ; + break; + case DW_OP_ge: + binop = BINOP_GEQ; + break; + case DW_OP_eq: + binop = BINOP_EQUAL; + break; + case DW_OP_lt: + binop = BINOP_LESS; + break; + case DW_OP_gt: + binop = BINOP_GTR; + break; + case DW_OP_ne: + binop = BINOP_NOTEQUAL; + break; + default: + internal_error (__FILE__, __LINE__, + "Can't be reached."); + } + result = value_as_long (value_binop (val1, val2, binop)); + } + break; + + case DW_OP_GNU_push_tls_address: + result = dwarf_expr_fetch (ctx, 0); + dwarf_expr_pop (ctx); + result = (ctx->get_tls_address) (ctx->baton, result); + break; + + case DW_OP_skip: + offset = extract_signed_integer (op_ptr, 2); + op_ptr += 2; + op_ptr += offset; + goto no_push; + + case DW_OP_bra: + offset = extract_signed_integer (op_ptr, 2); + op_ptr += 2; + if (dwarf_expr_fetch (ctx, 0) != 0) + op_ptr += offset; + dwarf_expr_pop (ctx); + goto no_push; + + case DW_OP_nop: + goto no_push; + + default: + error ("Unhandled dwarf expression opcode"); + } + + /* Most things push a result value. */ + dwarf_expr_push (ctx, result); + no_push:; + } +} diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h new file mode 100644 index 00000000000..e8cc489dcf6 --- /dev/null +++ b/gdb/dwarf2expr.h @@ -0,0 +1,97 @@ +/* Dwarf2 Expression Evaluator + Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Daniel Berlin (dan@dberlin.org) + 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. */ + +#if !defined (DWARF2EXPR_H) +#define DWARF2EXPR_H + +/* The expression evaluator works with a dwarf_expr_context, describing + its current state and its callbacks. */ +struct dwarf_expr_context +{ + /* The stack of values, allocated with xmalloc. */ + CORE_ADDR *stack; + + /* The number of values currently pushed on the stack, and the + number of elements allocated to the stack. */ + int stack_len, stack_allocated; + + /* An opaque argument provided by the caller, which will be passed + to all of the callback functions. */ + void *baton; + + /* Return the value of register number REGNUM. LVALP will be set + to the kind of lval this register is (generally lval_register + for the current frame's registers or lval_memory for a register + saved to the stack). For lval_memory ADDRP will be set to the + saved location of the register. */ + CORE_ADDR (*read_reg) (void *baton, int regnum, enum lval_type *lvalp, + CORE_ADDR *addrp); + + /* Read LENGTH bytes at ADDR into BUF. */ + void (*read_mem) (void *baton, char *buf, CORE_ADDR addr, + size_t length); + + /* Return the location expression for the frame base attribute, in + START and LENGTH. The result must be live until the current + expression evaluation is complete. */ + void (*get_frame_base) (void *baton, unsigned char **start, + size_t *length); + + /* Return the thread-local storage address for + DW_OP_GNU_push_tls_address. */ + CORE_ADDR (*get_tls_address) (void *baton, CORE_ADDR offset); + +#if 0 + /* Not yet implemented. */ + + /* Return the location expression for the dwarf expression + subroutine in the die at OFFSET in the current compilation unit. + The result must be live until the current expression evaluation + is complete. */ + unsigned char *(*get_subr) (void *baton, off_t offset, size_t *length); + + /* Return the `object address' for DW_OP_push_object_address. */ + CORE_ADDR (*get_object_address) (void *baton); +#endif + + /* The current depth of dwarf expression recursion, via DW_OP_call*, + DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum + depth we'll tolerate before raising an error. */ + int recursion_depth, max_recursion_depth; + + /* Non-zero if the result is in a register. The register number + will be in REGNUM, and the result will be the contents of the + register. */ + int in_reg; + + /* If the result is in a register, the register number. */ + int regnum; +}; + +struct dwarf_expr_context *new_dwarf_expr_context (); +void free_dwarf_expr_context (struct dwarf_expr_context *ctx); + +void dwarf_expr_push (struct dwarf_expr_context *ctx, CORE_ADDR value); +void dwarf_expr_pop (struct dwarf_expr_context *ctx); +void dwarf_expr_eval (struct dwarf_expr_context *ctx, unsigned char *addr, + size_t len); +CORE_ADDR dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n); + +#endif diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c new file mode 100644 index 00000000000..330765d556a --- /dev/null +++ b/gdb/dwarf2loc.c @@ -0,0 +1,287 @@ +/* DWARF 2 location expression support for GDB. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Daniel Jacobowitz, MontaVista Software, 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. */ + +#include "defs.h" +#include "ui-out.h" +#include "value.h" +#include "frame.h" +#include "gdbcore.h" +#include "target.h" +#include "inferior.h" + +#include "elf/dwarf2.h" +#include "dwarf2expr.h" +#include "dwarf2loc.h" + +#include "gdb_string.h" + +#ifndef DWARF2_REG_TO_REGNUM +#define DWARF2_REG_TO_REGNUM(REG) (REG) +#endif + +/* This is the baton used when performing dwarf2 expression + evaluation. */ +struct dwarf_expr_baton +{ + struct frame_info *frame; + struct objfile *objfile; +}; + +/* Helper functions for dwarf2_evaluate_loc_desc. */ + +/* Using the frame specified in BATON, read register REGNUM. The lval + type will be returned in LVALP, and for lval_memory the register + save address will be returned in ADDRP. */ +static CORE_ADDR +dwarf_expr_read_reg (void *baton, int regnum, enum lval_type *lvalp, + CORE_ADDR *addrp) +{ + CORE_ADDR result; + struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; + char *buf = (char *) alloca (MAX_REGISTER_RAW_SIZE); + int optimized, realnum; + + frame_register (debaton->frame, DWARF2_REG_TO_REGNUM (regnum), + &optimized, lvalp, addrp, &realnum, buf); + result = extract_address (buf, REGISTER_RAW_SIZE (regnum)); + + return result; +} + +/* Read memory at ADDR (length LEN) into BUF. */ + +static void +dwarf_expr_read_mem (void *baton, char *buf, CORE_ADDR addr, size_t len) +{ + read_memory (addr, buf, len); +} + +/* Using the frame specified in BATON, find the location expression + describing the frame base. Return a pointer to it in START and + its length in LENGTH. */ +static void +dwarf_expr_frame_base (void *baton, unsigned char **start, size_t * length) +{ + struct symbol *framefunc; + struct dwarf2_locexpr_baton *symbaton; + struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; + framefunc = get_frame_function (debaton->frame); + symbaton = SYMBOL_LOCATION_BATON (framefunc); + *start = symbaton->data; + *length = symbaton->size; +} + +/* Using the objfile specified in BATON, find the address for the + current thread's thread-local storage with offset OFFSET. */ +static CORE_ADDR +dwarf_expr_tls_address (void *baton, CORE_ADDR offset) +{ + struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; + CORE_ADDR addr; + + if (target_get_thread_local_address_p ()) + addr = target_get_thread_local_address (inferior_ptid, + debaton->objfile, + offset); + else + error ("Cannot find thread-local variables on this target"); + + return addr; +} + +/* Evaluate a location description, starting at DATA and with length + SIZE, to find the current location of variable VAR in the context + of FRAME. */ +static struct value * +dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, + unsigned char *data, unsigned short size, + struct objfile *objfile) +{ + CORE_ADDR result; + struct value *retval; + struct dwarf_expr_baton baton; + struct dwarf_expr_context *ctx; + + baton.frame = frame; + baton.objfile = objfile; + + ctx = new_dwarf_expr_context (); + ctx->baton = &baton; + ctx->read_reg = dwarf_expr_read_reg; + ctx->read_mem = dwarf_expr_read_mem; + ctx->get_frame_base = dwarf_expr_frame_base; + ctx->get_tls_address = dwarf_expr_tls_address; + + dwarf_expr_eval (ctx, data, size); + + retval = allocate_value (SYMBOL_TYPE (var)); + VALUE_BFD_SECTION (retval) = SYMBOL_BFD_SECTION (var); + + if (ctx->in_reg) + { + store_unsigned_integer (VALUE_CONTENTS_RAW (retval), + TYPE_LENGTH (SYMBOL_TYPE (var)), + dwarf_expr_fetch (ctx, 0)); + VALUE_LVAL (retval) = lval_register; + VALUE_REGNO (retval) = ctx->regnum; + } + else + { + result = dwarf_expr_fetch (ctx, 0); + VALUE_LVAL (retval) = lval_memory; + VALUE_LAZY (retval) = 1; + VALUE_ADDRESS (retval) = result; + } + + free_dwarf_expr_context (ctx); + + return retval; +} + + + + + +/* Helper functions and baton for dwarf2_loc_desc_needs_frame. */ + +struct needs_frame_baton +{ + int needs_frame; +}; + +/* Reads from registers do require a frame. */ +static CORE_ADDR +needs_frame_read_reg (void *baton, int regnum, enum lval_type *lvalp, + CORE_ADDR *addrp) +{ + struct needs_frame_baton *nf_baton = baton; + nf_baton->needs_frame = 1; + return 1; +} + +/* Reads from memory do not require a frame. */ +static void +needs_frame_read_mem (void *baton, char *buf, CORE_ADDR addr, size_t len) +{ + memset (buf, 0, len); +} + +/* Frame-relative accesses do require a frame. */ +static void +needs_frame_frame_base (void *baton, unsigned char **start, size_t * length) +{ + static char lit0 = DW_OP_lit0; + struct needs_frame_baton *nf_baton = baton; + + *start = &lit0; + *length = 1; + + nf_baton->needs_frame = 1; +} + +/* Thread-local accesses do require a frame. */ +static CORE_ADDR +needs_frame_tls_address (void *baton, CORE_ADDR offset) +{ + struct needs_frame_baton *nf_baton = baton; + nf_baton->needs_frame = 1; + return 1; +} + +/* Return non-zero iff the location expression at DATA (length SIZE) + requires a frame to evaluate. */ + +static int +dwarf2_loc_desc_needs_frame (unsigned char *data, unsigned short size) +{ + struct needs_frame_baton baton; + struct dwarf_expr_context *ctx; + + baton.needs_frame = 0; + + ctx = new_dwarf_expr_context (); + ctx->baton = &baton; + ctx->read_reg = needs_frame_read_reg; + ctx->read_mem = needs_frame_read_mem; + ctx->get_frame_base = needs_frame_frame_base; + ctx->get_tls_address = needs_frame_tls_address; + + dwarf_expr_eval (ctx, data, size); + + free_dwarf_expr_context (ctx); + + return baton.needs_frame; +} + + + + +/* Return the value of SYMBOL in FRAME using the DWARF-2 expression + evaluator to calculate the location. */ +static struct value * +locexpr_read_variable (struct symbol *symbol, struct frame_info *frame) +{ + struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); + struct value *val; + val = dwarf2_evaluate_loc_desc (symbol, frame, dlbaton->data, dlbaton->size, + dlbaton->objfile); + + return val; +} + +/* Return non-zero iff we need a frame to evaluate SYMBOL. */ +static int +locexpr_read_needs_frame (struct symbol *symbol) +{ + struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); + return dwarf2_loc_desc_needs_frame (dlbaton->data, dlbaton->size); +} + +/* Print a natural-language description of SYMBOL to STREAM. */ +static int +locexpr_describe_location (struct symbol *symbol, struct ui_file *stream) +{ + /* FIXME: be more extensive. */ + struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); + + if (dlbaton->size == 1 + && dlbaton->data[0] >= DW_OP_reg0 + && dlbaton->data[0] <= DW_OP_reg31) + { + int regno = DWARF2_REG_TO_REGNUM (dlbaton->data[0] - DW_OP_reg0); + fprintf_filtered (stream, + "a variable in register %s", REGISTER_NAME (regno)); + return 1; + } + + fprintf_filtered (stream, + "a variable with complex or multiple locations (DWARF2)"); + return 1; +} + +/* The set of location functions used with the DWARF-2 expression + evaluator. */ +struct location_funcs dwarf2_locexpr_funcs = { + locexpr_read_variable, + locexpr_read_needs_frame, + locexpr_describe_location, + NULL +}; diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h new file mode 100644 index 00000000000..fde132922ac --- /dev/null +++ b/gdb/dwarf2loc.h @@ -0,0 +1,39 @@ +/* Dwarf2 location expression support for GDB. + Copyright 2003 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. */ + +#if !defined (DWARF2LOC_H) +#define DWARF2LOC_H + +/* This header is private to the DWARF-2 reader. It is shared between + dwarf2read.c and dwarf2loc.c. */ + +/* The symbol location baton type used by the DWARF-2 reader (i.e. + SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol). */ + +struct dwarf2_locexpr_baton +{ + unsigned char *data; + unsigned short size; + struct objfile *objfile; +}; + +extern struct location_funcs dwarf2_locexpr_funcs; + +#endif diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 3b067d5464d..8f1afd099f6 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -38,10 +38,12 @@ #include "expression.h" #include "filenames.h" /* for DOSish file names */ #include "macrotab.h" - #include "language.h" #include "complaints.h" #include "bcache.h" +#include "dwarf2expr.h" +#include "dwarf2loc.h" + #include #include "gdb_string.h" #include "gdb_assert.h" @@ -905,6 +907,11 @@ static void dwarf_decode_macros (struct line_header *, unsigned int, static int attr_form_is_block (struct attribute *); +static void +dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, + const struct comp_unit_head *, + struct objfile *objfile); + /* Try to locate the sections we need for DWARF 2 debugging information and return true if we have enough to do something. */ @@ -1998,6 +2005,13 @@ read_func_scope (struct die_info *die, struct objfile *objfile, new = push_context (0, lowpc); new->name = new_symbol (die, die->type, objfile, cu_header); + + /* If there was a location expression for DW_AT_frame_base above, + record it. We still need to decode it above because not all + symbols use location expressions exclusively. */ + if (attr) + dwarf2_symbol_mark_computed (attr, new->name, cu_header, objfile); + list_in_scope = &local_symbols; if (die->has_children) @@ -4930,6 +4944,61 @@ dwarf2_start_subfile (char *filename, char *dirname) start_subfile (filename, dirname); } +static void +var_decode_location (struct attribute *attr, struct symbol *sym, + struct objfile *objfile, + const struct comp_unit_head *cu_header) +{ + /* NOTE drow/2003-01-30: There used to be a comment and some special + code here to turn a symbol with DW_AT_external and a + SYMBOL_VALUE_ADDRESS of 0 into a LOC_UNRESOLVED symbol. This was + necessary for platforms (maybe Alpha, certainly PowerPC GNU/Linux + with some versions of binutils) where shared libraries could have + relocations against symbols in their debug information - the + minimal symbol would have the right address, but the debug info + would not. It's no longer necessary, because we will explicitly + apply relocations when we read in the debug information now. */ + + /* A DW_AT_location attribute with no contents indicates that a + variable has been optimized away. */ + if (attr_form_is_block (attr) && DW_BLOCK (attr)->size == 0) + { + SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT; + return; + } + + /* Handle one degenerate form of location expression specially, to + preserve GDB's previous behavior when section offsets are + specified. If this is just a DW_OP_addr then mark this symbol + as LOC_STATIC. */ + + if (attr_form_is_block (attr) + && DW_BLOCK (attr)->size == 1 + cu_header->addr_size + && DW_BLOCK (attr)->data[0] == DW_OP_addr) + { + int dummy; + + SYMBOL_VALUE_ADDRESS (sym) = + read_address (objfile->obfd, DW_BLOCK (attr)->data + 1, cu_header, + &dummy); + fixup_symbol_section (sym, objfile); + SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (objfile->section_offsets, + SYMBOL_SECTION (sym)); + SYMBOL_CLASS (sym) = LOC_STATIC; + return; + } + + /* NOTE drow/2002-01-30: It might be worthwhile to have a static + expression evaluator, and use LOC_COMPUTED only when necessary + (i.e. when the value of a register or memory location is + referenced, or a thread-local block, etc.). Then again, it might + not be worthwhile. I'm assuming that it isn't unless performance + or memory numbers show me otherwise. */ + + dwarf2_symbol_mark_computed (attr, sym, cu_header, objfile); + SYMBOL_CLASS (sym) = LOC_COMPUTED; +} + /* Given a pointer to a DWARF information entry, figure out if we need to make a symbol table entry for it, and if so, create a new entry and return a pointer to it. @@ -5018,106 +5087,12 @@ new_symbol (struct die_info *die, struct type *type, struct objfile *objfile, attr = dwarf_attr (die, DW_AT_location); if (attr) { + var_decode_location (attr, sym, objfile, cu_header); attr2 = dwarf_attr (die, DW_AT_external); if (attr2 && (DW_UNSND (attr2) != 0)) - { - /* Support the .debug_loc offsets */ - if (attr_form_is_block (attr)) - { - SYMBOL_VALUE_ADDRESS (sym) = - decode_locdesc (DW_BLOCK (attr), objfile, cu_header); - } - else if (attr->form == DW_FORM_data4 - || attr->form == DW_FORM_data8) - { - dwarf2_complex_location_expr_complaint (); - } - else - { - dwarf2_invalid_attrib_class_complaint ("DW_AT_location", - "external variable"); - } - add_symbol_to_list (sym, &global_symbols); - if (is_thread_local) - { - /* SYMBOL_VALUE_ADDRESS contains at this point the - offset of the variable within the thread local - storage. */ - SYMBOL_CLASS (sym) = LOC_THREAD_LOCAL_STATIC; - SYMBOL_OBJFILE (sym) = objfile; - } - - /* In shared libraries the address of the variable - in the location descriptor might still be relocatable, - so its value could be zero. - Enter the symbol as a LOC_UNRESOLVED symbol, if its - value is zero, the address of the variable will then - be determined from the minimal symbol table whenever - the variable is referenced. */ - else if (SYMBOL_VALUE_ADDRESS (sym)) - { - fixup_symbol_section (sym, objfile); - SYMBOL_VALUE_ADDRESS (sym) += - ANOFFSET (objfile->section_offsets, - SYMBOL_SECTION (sym)); - SYMBOL_CLASS (sym) = LOC_STATIC; - } - else - SYMBOL_CLASS (sym) = LOC_UNRESOLVED; - } + add_symbol_to_list (sym, &global_symbols); else - { - /* Support the .debug_loc offsets */ - if (attr_form_is_block (attr)) - { - SYMBOL_VALUE (sym) = addr = - decode_locdesc (DW_BLOCK (attr), objfile, cu_header); - } - else if (attr->form == DW_FORM_data4 - || attr->form == DW_FORM_data8) - { - dwarf2_complex_location_expr_complaint (); - } - else - { - dwarf2_invalid_attrib_class_complaint ("DW_AT_location", - "external variable"); - addr = 0; - } - add_symbol_to_list (sym, list_in_scope); - if (optimized_out) - { - SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT; - } - else if (isreg) - { - SYMBOL_CLASS (sym) = LOC_REGISTER; - SYMBOL_VALUE (sym) = - DWARF2_REG_TO_REGNUM (SYMBOL_VALUE (sym)); - } - else if (offreg) - { - SYMBOL_CLASS (sym) = LOC_BASEREG; - SYMBOL_BASEREG (sym) = DWARF2_REG_TO_REGNUM (basereg); - } - else if (islocal) - { - SYMBOL_CLASS (sym) = LOC_LOCAL; - } - else if (is_thread_local) - { - SYMBOL_CLASS (sym) = LOC_THREAD_LOCAL_STATIC; - SYMBOL_OBJFILE (sym) = objfile; - } - else - { - fixup_symbol_section (sym, objfile); - SYMBOL_VALUE_ADDRESS (sym) = - addr + ANOFFSET (objfile->section_offsets, - SYMBOL_SECTION (sym)); - SYMBOL_CLASS (sym) = LOC_STATIC; - } - } + add_symbol_to_list (sym, list_in_scope); } else { @@ -7347,3 +7322,32 @@ attr_form_is_block (struct attribute *attr) || attr->form == DW_FORM_block4 || attr->form == DW_FORM_block); } + +static void +dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, + const struct comp_unit_head *cu_header, + struct objfile *objfile) +{ + struct dwarf2_locexpr_baton *baton; + + /* When support for location lists is added, this will go away. */ + if (!attr_form_is_block (attr)) + { + dwarf2_complex_location_expr_complaint (); + return; + } + + baton = obstack_alloc (&objfile->symbol_obstack, + sizeof (struct dwarf2_locexpr_baton)); + baton->objfile = objfile; + + /* Note that we're just copying the block's data pointer here, not + the actual data. We're still pointing into the dwarf_info_buffer + for SYM's objfile; right now we never release that buffer, but + when we do clean up properly this may need to change. */ + baton->size = DW_BLOCK (attr)->size; + baton->data = DW_BLOCK (attr)->data; + + SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs; + SYMBOL_LOCATION_BATON (sym) = baton; +} diff --git a/gdb/findvar.c b/gdb/findvar.c index 740d8d6ba8d..d2a3025b3d1 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -384,6 +384,14 @@ symbol_read_needs_frame (struct symbol *sym) { /* All cases listed explicitly so that gcc -Wall will detect it if we failed to consider one. */ + case LOC_COMPUTED: + case LOC_COMPUTED_ARG: + { + struct location_funcs *symfuncs = SYMBOL_LOCATION_FUNCS (sym); + return (symfuncs->read_needs_frame) (sym); + } + break; + case LOC_REGISTER: case LOC_ARG: case LOC_REF_ARG: @@ -605,6 +613,18 @@ addresses have not been bound by the dynamic loader. Try again when executable i } break; + case LOC_COMPUTED: + case LOC_COMPUTED_ARG: + { + struct location_funcs *funcs = SYMBOL_LOCATION_FUNCS (var); + + if (frame == 0 && (funcs->read_needs_frame) (var)) + return 0; + return (funcs->read_variable) (var, frame); + + } + break; + case LOC_UNRESOLVED: { struct minimal_symbol *msym; diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y index cf0846c667d..b318bcc7915 100644 --- a/gdb/m2-exp.y +++ b/gdb/m2-exp.y @@ -1041,6 +1041,8 @@ yylex () case LOC_CONST: case LOC_CONST_BYTES: case LOC_OPTIMIZED_OUT: + case LOC_COMPUTED: + case LOC_COMPUTED_ARG: return NAME; case LOC_TYPEDEF: diff --git a/gdb/printcmd.c b/gdb/printcmd.c index 9b0c641c4ca..96d987a19e2 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -1149,6 +1149,11 @@ address_info (char *exp, int from_tty) } break; + case LOC_COMPUTED: + case LOC_COMPUTED_ARG: + (SYMBOL_LOCATION_FUNCS (sym)->describe_location) (sym, gdb_stdout); + break; + case LOC_REGISTER: printf_filtered ("a variable in register %s", REGISTER_NAME (val)); break; @@ -1814,6 +1819,7 @@ print_frame_args (struct symbol *func, struct frame_info *fi, int num, case LOC_REGPARM_ADDR: case LOC_LOCAL_ARG: case LOC_BASEREG_ARG: + case LOC_COMPUTED_ARG: break; /* Other types of symbols we just skip over. */ diff --git a/gdb/stack.c b/gdb/stack.c index f4e79da8f9f..1263ed9d95c 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1083,6 +1083,7 @@ print_block_frame_locals (struct block *b, register struct frame_info *fi, case LOC_REGISTER: case LOC_STATIC: case LOC_BASEREG: + case LOC_COMPUTED: values_printed = 1; for (j = 0; j < num_tabs; j++) fputs_filtered ("\t", stream); @@ -1309,6 +1310,7 @@ print_frame_arg_vars (register struct frame_info *fi, case LOC_REGPARM: case LOC_REGPARM_ADDR: case LOC_BASEREG_ARG: + case LOC_COMPUTED_ARG: values_printed = 1; fputs_filtered (SYMBOL_PRINT_NAME (sym), stream); fputs_filtered (" = ", stream); diff --git a/gdb/symmisc.c b/gdb/symmisc.c index 8c4902542ce..24f8f58b3ff 100644 --- a/gdb/symmisc.c +++ b/gdb/symmisc.c @@ -752,6 +752,11 @@ print_symbol (void *args) SYMBOL_BFD_SECTION (symbol))); break; + case LOC_COMPUTED: + case LOC_COMPUTED_ARG: + fprintf_filtered (outfile, "computed at runtime"); + break; + case LOC_UNRESOLVED: fprintf_filtered (outfile, "unresolved"); break; @@ -903,6 +908,10 @@ print_partial_symbols (struct partial_symbol **p, int count, char *what, case LOC_OPTIMIZED_OUT: fputs_filtered ("optimized out", outfile); break; + case LOC_COMPUTED: + case LOC_COMPUTED_ARG: + fputs_filtered ("computed at runtime", outfile); + break; default: fputs_filtered ("", outfile); break; diff --git a/gdb/symtab.c b/gdb/symtab.c index cc31beb3f9a..1a123fb4684 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -1739,7 +1739,8 @@ lookup_block_symbol (register const struct block *block, const char *name, SYMBOL_CLASS (sym) != LOC_REF_ARG && SYMBOL_CLASS (sym) != LOC_REGPARM && SYMBOL_CLASS (sym) != LOC_REGPARM_ADDR && - SYMBOL_CLASS (sym) != LOC_BASEREG_ARG) + SYMBOL_CLASS (sym) != LOC_BASEREG_ARG && + SYMBOL_CLASS (sym) != LOC_COMPUTED_ARG) { break; } diff --git a/gdb/symtab.h b/gdb/symtab.h index 3bde09f0f81..0d1b41cdd4e 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -30,6 +30,8 @@ struct obstack; struct objfile; struct block; struct blockvector; +struct axs_value; +struct agent_expr; /* Don't do this; it means that if some .o's are compiled with GNU C and some are not (easy to do accidentally the way we configure @@ -474,7 +476,58 @@ enum address_class * with a level of indirection. */ - LOC_INDIRECT + LOC_INDIRECT, + + /* The variable's address is computed by a set of location + functions (see "struct location_funcs" below). */ + LOC_COMPUTED, + + /* Same as LOC_COMPUTED, but for function arguments. */ + LOC_COMPUTED_ARG +}; + +/* A structure of function pointers describing the location of a + variable, structure member, or structure base class. + + These functions' BATON arguments are generic data pointers, holding + whatever data the functions need --- the code which provides this + structure also provides the actual contents of the baton, and + decides its form. However, there may be other rules about where + the baton data must be allocated; whoever is pointing to this + `struct location_funcs' object will know the rules. For example, + when a symbol S's location is LOC_COMPUTED, then + SYMBOL_LOCATION_FUNCS(S) is pointing to a location_funcs structure, + and SYMBOL_LOCATION_BATON(S) is the baton, which must be allocated + on the same obstack as the symbol itself. */ + +struct location_funcs +{ + + /* Return the value of the variable SYMBOL, relative to the stack + frame FRAME. If the variable has been optimized out, return + zero. + + Iff `read_needs_frame (SYMBOL)' is zero, then FRAME may be zero. */ + + struct value *(*read_variable) (struct symbol * symbol, + struct frame_info * frame); + + /* Return non-zero if we need a frame to find the value of the SYMBOL. */ + int (*read_needs_frame) (struct symbol * symbol); + + /* Write to STREAM a natural-language description of the location of + SYMBOL. */ + int (*describe_location) (struct symbol * symbol, struct ui_file * stream); + + /* Tracepoint support. Append bytecodes to the tracepoint agent + expression AX that push the address of the object SYMBOL. Set + VALUE appropriately. Note --- for objects in registers, this + needn't emit any code; as long as it sets VALUE properly, then + the caller will generate the right code in the process of + treating this as an lvalue or rvalue. */ + + void (*tracepoint_var_ref) (struct symbol * symbol, struct agent_expr * ax, + struct axs_value * value); }; /* Linked list of symbol's live ranges. */ @@ -536,6 +589,21 @@ struct symbol variable declared with the `__thread' storage class), we may need to know which object file it's in. */ struct objfile *objfile; + + /* For a LOC_COMPUTED or LOC_COMPUTED_ARG symbol, this is the + baton and location_funcs structure to find its location. For a + LOC_BLOCK symbol for a function in a compilation unit compiled + with DWARF 2 information, this is information used internally + by the DWARF 2 code --- specifically, the location expression + for the frame base for this function. */ + /* FIXME drow/2003-02-21: For the LOC_BLOCK case, it might be better + to add a magic symbol to the block containing this information, + or to have a generic debug info annotation slot for symbols. */ + struct + { + void *baton; + struct location_funcs *funcs; + } loc; } aux_value; @@ -560,6 +628,8 @@ struct symbol #define SYMBOL_OBJFILE(symbol) (symbol)->aux_value.objfile #define SYMBOL_ALIASES(symbol) (symbol)->aliases #define SYMBOL_RANGES(symbol) (symbol)->ranges +#define SYMBOL_LOCATION_BATON(symbol) (symbol)->aux_value.loc.baton +#define SYMBOL_LOCATION_FUNCS(symbol) (symbol)->aux_value.loc.funcs /* A partial_symbol records the name, namespace, and address class of symbols whose types we have not parsed yet. For functions, it also -- 2.30.2