Based on a patch from Daniel Berlin (dberlin@dberlin.org).
authorDaniel Jacobowitz <drow@false.org>
Fri, 21 Feb 2003 15:24:18 +0000 (15:24 +0000)
committerDaniel Jacobowitz <drow@false.org>
Fri, 21 Feb 2003 15:24:18 +0000 (15:24 +0000)
* 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.

16 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/ada-lang.c
gdb/buildsym.c
gdb/dwarf2expr.c [new file with mode: 0644]
gdb/dwarf2expr.h [new file with mode: 0644]
gdb/dwarf2loc.c [new file with mode: 0644]
gdb/dwarf2loc.h [new file with mode: 0644]
gdb/dwarf2read.c
gdb/findvar.c
gdb/m2-exp.y
gdb/printcmd.c
gdb/stack.c
gdb/symmisc.c
gdb/symtab.c
gdb/symtab.h

index 3020fe35a2960396b69ec422dd98142f0ca983c1..b69364a6f65d245e0ec3e65eeea33a4ac9fe2d2b 100644 (file)
@@ -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
index 5e39e12aa27e3e7a07f907d7d32d7b739209577a..2158d25d9f01ac622e58da8a1b66d12a057fe65c 100644 (file)
@@ -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)
index d5323a145e880390bd64baf200d6e9f64ae06363..83d1090bf8cc5d71745f54e2f094a9c290902b63 100644 (file)
@@ -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;
index 15a59a039f55bf6ea370042631d1639759573cf6..3cc9e8ee0a4dd8140b1894a400cdea970b52cae2 100644 (file)
@@ -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 (file)
index 0000000..02e246f
--- /dev/null
@@ -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");
+    }
+}
+\f
+/* 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 (file)
index 0000000..e8cc489
--- /dev/null
@@ -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 (file)
index 0000000..330765d
--- /dev/null
@@ -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;
+}
+
+
+
+
+\f
+/* 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;
+}
+
+
+
+\f
+/* 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 (file)
index 0000000..fde1329
--- /dev/null
@@ -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
index 3b067d5464d785dfd95780098743267283895753..8f1afd099f6f5951226a664ebd34426d63f178e0 100644 (file)
 #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;
+}
index 740d8d6ba8de6f522f7805b96a4716e32ab855f7..d2a3025b3d100c233cd6f9f072edf46c2b711e9a 100644 (file)
@@ -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;
index cf0846c667d1ea3e9e3f2d5707494c11a7c708f3..b318bcc791566209bbf6391bc3ab4af5f10ba87a 100644 (file)
@@ -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:
index 9b0c641c4ca2bb5abdde505a36a17a3ad5a0769e..96d987a19e27c130e494d2ce64d08db9bf4a2423 100644 (file)
@@ -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.  */
index f4e79da8f9f0a9ebdd36ac3a83834eddc8a5f781..1263ed9d95c1938e9e34e43da0d9f03c53d6f981 100644 (file)
@@ -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);
index 8c4902542ce7194110343b9a26949f9000748144..24f8f58b3ff28ea074e41c13a685e3e50811b3c2 100644 (file)
@@ -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;
index cc31beb3f9a7c765fd6b41013fc17a88ce47c15e..1a123fb4684ae0cdff18651cd6fcc1e86e892771 100644 (file)
@@ -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;
                }
index 3bde09f0f81efcc26d4448891f8bf099477529b5..0d1b41cdd4eb018a9f3aa25479d1e2161dbc09a2 100644 (file)
@@ -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
 \f
 /* A partial_symbol records the name, namespace, and address class of
    symbols whose types we have not parsed yet.  For functions, it also