aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2003-02-21 15:24:18 +0000
committerDaniel Jacobowitz <drow@false.org>2003-02-21 15:24:18 +0000
commit4c2df51b5ace4f5c0a1f8a76cdf536ac4432dd14 (patch)
tree598c2097c2499be7ad8123ff91575ab6085f08f6
parent4cf623b60bb41ce141aa47d27e6d119324cb5ed1 (diff)
downloadgdb-4c2df51b5ace4f5c0a1f8a76cdf536ac4432dd14.zip
gdb-4c2df51b5ace4f5c0a1f8a76cdf536ac4432dd14.tar.gz
gdb-4c2df51b5ace4f5c0a1f8a76cdf536ac4432dd14.tar.bz2
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.
-rw-r--r--gdb/ChangeLog32
-rw-r--r--gdb/Makefile.in14
-rw-r--r--gdb/ada-lang.c8
-rw-r--r--gdb/buildsym.c4
-rw-r--r--gdb/dwarf2expr.c687
-rw-r--r--gdb/dwarf2expr.h97
-rw-r--r--gdb/dwarf2loc.c287
-rw-r--r--gdb/dwarf2loc.h39
-rw-r--r--gdb/dwarf2read.c200
-rw-r--r--gdb/findvar.c20
-rw-r--r--gdb/m2-exp.y2
-rw-r--r--gdb/printcmd.c6
-rw-r--r--gdb/stack.c2
-rw-r--r--gdb/symmisc.c9
-rw-r--r--gdb/symtab.c3
-rw-r--r--gdb/symtab.h72
16 files changed, 1379 insertions, 103 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 3020fe3..b69364a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,35 @@
+2003-02-21 Daniel Jacobowitz <drow@mvista.com>
+
+ 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 <fedor@gnu.org>
* symtab.h: Remove objc_specific struct
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5e39e12..2158d25 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 d5323a1..83d1090 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 15a59a0..3cc9e8e 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 0000000..02e246f
--- /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, &reg);
+ 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, &reg);
+ 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, &reg);
+ 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 0000000..e8cc489
--- /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 0000000..330765d
--- /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 0000000..fde1329
--- /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 3b067d5..8f1afd0 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 <fcntl.h>
#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 740d8d6..d2a3025 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 cf0846c..b318bcc 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 9b0c641..96d987a 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 f4e79da..1263ed9 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 8c49025..24f8f58 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 ("<invalid location>", outfile);
break;
diff --git a/gdb/symtab.c b/gdb/symtab.c
index cc31beb..1a123fb 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 3bde09f..0d1b41c 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