This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFA: LOC_COMPUTED support


On Wed, Feb 05, 2003 at 12:24:34AM -0500, Jim Blandy wrote:
> 
> Daniel Jacobowitz <drow@mvista.com> writes:
> > Here we go again.  I've been staring at this patch for a couple of days, so
> > my description of it may be slightly incoherent.  Let me know if I miss
> > anything major.
> > 
> > First, overview, pretty much unchanged from when Daniel Berlin posted it:
> > we add two new address classes, LOC_COMPUTED and LOC_COMPUTED_ARG, whose
> > address must be determined by calling some set of runtime functions provided
> > by the symbol reader.
> > 
> > There are a lot of little structural changes from Daniel's patch; for
> > instance, I moved some code from dwarf2read.c out into a new file, because
> > the idea of including things like "target.h" and "inferior.h" in a debug
> > reader bothered me a little.  I also shrunk the size of the batons a bit.
> > 
> > Two things that Jim commented on as problems with the original patch are
> > still here, because on reflection I thought it was better this way: the use
> > of get_frame_function and the function's aux_value union to hold the frame
> > base
> 
> What's weird about this is that the LOC_BLOCK symbol's aux_value is
> never used by the core GDB code at all --- it's used strictly by
> Dwarf-specific code.  When you say, "and [used] by LOC_BLOCK to locate
> the function's base register", you're referring to something that
> doesn't exist in core GDB.
> 
> The comment needs to come clean about this:
> 
>   /* For a LOC_COMPUTED symbol, this is the baton and location_funcs
>      structure to find its value.  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 Dwarf location description that computes frame
>      base for that function.  */
> 
> Maybe I'm going too far, but that is at least more honest about how
> messy this is.  I'm still not sure I'm cool with this.

I've adapted your comment.  I'd like to leave this for another time, to
be honest... after we kill some of the current excess memory usage in
symbols, like the dead aliases/ranges code which this is obsoleting.

Another way we could do this would be to make the frame base a magic
symbol in the function's block, and look it up.  That's probably a
safer approach; more memory per-function but that doesn't bother me as
much as per-symbol does.  And easier to look up, too.

> > and the use of pointers directly into the .debug_info (eventually
> > .debug_loc) data.  The former is for memory reasons, among others; Jim's
> > suggestion of each symbol having a pointer to the frame base would increase
> > the per-symbol memory for all LOC_COMPUTED* symbols, since we can't easily
> > tell which symbols will need the frame base and which won't.  The latter is
> > because we never get rid of it anyway, so why duplicate the data?  When
> > someone tackles cleanups in the reader to let us free the sections, then we
> > can talk about alternate memory management.
> 
> Right, that was what I was worried about.  The relocation patch makes
> this harder, too, since BFD doesn't have any interface to relocate
> only a portion of a section.  But I think you're right --- at this
> point it's best to get out of the way for other improvements.
> 
> The documentation for dwarf2_locexpr_baton should explain that it's
> pointing into dwarf_info_buffer, and should explain exactly which
> objfile's dwarf_info_buffer that is.

I've been thinking about an interface for BFD that would allow us to
read parts of a section arbitrarily, with relocation.  It's hard
because in the general case we aren't guaranteed that relocations are
sorted by ascending VMA.  We might be able to check that they are and
be more memory efficient in that case, or something.

That's BFD work for another day.  Comments updated.

> I may be missing something, but I think your TLS stuff is broken.
> Suppose the symbol S's location is computed by a Dwarf location
> expression that uses DW_OP_GNU_push_tls_address.  SYMBOL_CLASS (S) is
> LOC_COMPUTED.  Therefore S->aux_value holds a baton and a struct
> location_funcs.  Its struct location_funcs read_variable is
> locexpr_read_variable, which calls dwarf2_evaluate_loc_desc on S, a
> frame, and the locexpr.  dwarf2_evaluate_loc_desc calls
> dwarf_expr_eval with a struct dwarf_expr_baton whose 'var' is S.  The
> case for DW_OP_GNU_push_tls_address calls the context's
> get_tls_address, which is dwarf_expr_tls_address, passing the baton
> and the offset.  That then tries to access SYMBOL_OBJFILE (S) --- but
> that is S->aux_value.objfile, when S->aux_value is actually the
> LOC_COMPUTED baton and location_funcs.

Blech.  You're right; and somewhere out there, so is Daniel Berlin, who
half-warned me about that.  I'm not set up to test the thread-local
stuff, and I don't think it's in the testsuite either, so I was mostly
guessing.

To get this right I either need to add the objfile to the baton (and
all LOC_COMPUTED functions) or to the symbol (and all symbols).  By the
time we get to read_var_value we no longer know what objfile the symbol
came from.  I'll go for baton for now.

> But I'm not sure I have anything really helpful or substantial to say.
> Some other nits:
> 
> The results of DW_OP_shr, DW_OP_shra, and the comparison operators can
> depend on CORE_ADDR bits that may be above the current architecture's
> address size.  All of those operators need to use the
> value_from_pointer trick that DW_OP_div uses now, I'm afraid.

This required playing some tricks with types.  I overhauled the section
on binary ops.  I'm not sure if it will make a difference, but the
DWARF 3 standard specifies _unsigned_ type arithmetic; so I used
unsigned arithmetic instead of CORE_ADDR-signed arithmetic.

I also caught a nasty here.  We had first and second switched for the
binary ops.  DW_OP_shr shifts first by second, not the other way round.

> Could you move 'struct dwarf2_locexpr_baton' and
> 'dwarf2_locexpr_funcs' into a new header, dwarf2loc.h?

Sure.

> dwarf2_loc_desc_needs_frame should either have an extern declaration
> somewhere, or be static to dwarf2loc.c.  The various needs_frame_*
> callbacks should all be static.

Should all be static, yes.  Thanks.

> +/* Expand the memory allocated to CTX's stack to contain at least
> +   NEED elements.  */
> +
> 
> This comment isn't accurate: it makes sure that CTX's stack has room
> to hold at least NEED more elements than it holds now.

Oops.

> Could read_uleb128, read_sleb128, and read_address take a pointer to
> the end of the buffer, and detect misformed constants?

There's lots of other places this isn't robust against malformed
content, but those three are worth fixing.  I did those but didn't go
over the rest of the evaluator for similar problems.

> +static struct value *
> +dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
> +			  unsigned char *data, unsigned short size)
> +{
> +  CORE_ADDR result;
> +  struct value *retval;
> +  struct dwarf_expr_baton *baton = xmalloc (sizeof (struct dwarf_expr_baton));
> +  struct dwarf_expr_context *ctx;
> +
> 
> You could just allocate the dwarf_expr_baton on the stack directly.

Thought I had - thanks for noticing.  Oh, I fixed only needs_frame.

> > Particularly notable bits are the comments in var_decode_location.  I've
> > verified that I got both the LOC_STATIC and relocated symbols bits correct;
> > it would be nice to kill the LOC_STATIC hack but that requires cleaning up
> > the ways we handle section offsets, and that's way too murky for me right
> > now.
> 
> I don't really understand what LOC_UNRESOLVED was supposed to do, but
> I'm going to take your word that you've handled it here; having
> LOC_COMPUTED is worth the risk that you're wrong about LOC_UNRESOLVED
> and we need to go back and fix something.  Elena may know more about
> this than I do.
> 
> Could we also detect the DW_OP_reg* and produce LOC_REGISTER
> variables?  As it stands, this patch is going to make "info address
> VAR" pretty useless when Dwarf 2 is in use.  It'll save memory, too,
> won't it?  :)

I'd rather implement describe_location instead.  I only did the thing
for LOC_STATIC because it was necessary for our confusing section
offsets handing.  This patch implements it for DW_OP_regNUMBER; not for
DW_OP_fbreg, because read_sleb128 is constant right now, but that can
be easily changed later.  So we get back:

(gdb) i addr sumval
Symbol "sumval" is a variable in register eax.

But without optimization:
(gdb) i addr sumval
Symbol "sumval" is a variable with complex or multiple locations (DWARF2).


With the exception of the LOC_BLOCK wart, I've addressed all your
comments, I think.  Here's an update.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2003-02-05  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: 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.

Index: Makefile.in
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/Makefile.in,v
retrieving revision 1.323
diff -u -p -r1.323 Makefile.in
--- Makefile.in	31 Jan 2003 20:43:53 -0000	1.323
+++ Makefile.in	5 Feb 2003 16:57:44 -0000
@@ -510,7 +510,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
 	charset.c cli-out.c coffread.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 \
@@ -622,6 +622,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
@@ -827,6 +829,7 @@ COMMON_OBS = version.o blockframe.o brea
 	exec.o bcache.o objfiles.o minsyms.o maint.o demangle.o \
 	dbxread.o coffread.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 \
@@ -1618,11 +1621,16 @@ dve3900-rom.o: dve3900-rom.c $(defs_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: buildsym.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/buildsym.c,v
retrieving revision 1.27
diff -u -p -r1.27 buildsym.c
--- buildsym.c	14 Jan 2003 00:15:05 -0000	1.27
+++ buildsym.c	3 Feb 2003 16:24:14 -0000
@@ -308,6 +308,7 @@ finish_block (struct symbol *symbol, str
 		case LOC_REGPARM_ADDR:
 		case LOC_BASEREG_ARG:
 		case LOC_LOCAL_ARG:
+		case LOC_COMPUTED_ARG:
 		  nparams++;
 		  break;
 		case LOC_UNDEF:
@@ -323,6 +324,7 @@ finish_block (struct symbol *symbol, str
 		case LOC_BASEREG:
 		case LOC_UNRESOLVED:
 		case LOC_OPTIMIZED_OUT:
+		case LOC_COMPUTED:
 		default:
 		  break;
 		}
@@ -344,6 +346,7 @@ finish_block (struct symbol *symbol, str
 		    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++;
@@ -361,6 +364,7 @@ finish_block (struct symbol *symbol, str
 		    case LOC_BASEREG:
 		    case LOC_UNRESOLVED:
 		    case LOC_OPTIMIZED_OUT:
+		    case LOC_COMPUTED:
 		    default:
 		      break;
 		    }
Index: dwarf2expr.c
===================================================================
RCS file: dwarf2expr.c
diff -N dwarf2expr.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dwarf2expr.c	5 Feb 2003 16:59:31 -0000
@@ -0,0 +1,679 @@
+/* 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 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 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:
+	  if (op_ptr != op_end)
+	    error ("DWARF-2 expression error: DW_OP_reg operations must be "
+		   "used alone.");
+
+	  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:;
+    }
+}
Index: dwarf2expr.h
===================================================================
RCS file: dwarf2expr.h
diff -N dwarf2expr.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dwarf2expr.h	5 Feb 2003 16:59:56 -0000
@@ -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
Index: dwarf2loc.c
===================================================================
RCS file: dwarf2loc.c
diff -N dwarf2loc.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dwarf2loc.c	5 Feb 2003 17:00:37 -0000
@@ -0,0 +1,289 @@
+/* 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 symbol *var;
+  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,
+					    SYMBOL_OBJFILE (debaton->var),
+					    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.var = var;
+  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
+};
Index: dwarf2loc.h
===================================================================
RCS file: dwarf2loc.h
diff -N dwarf2loc.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dwarf2loc.h	5 Feb 2003 17:00:46 -0000
@@ -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: dwarf2read.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2read.c,v
retrieving revision 1.85
diff -u -p -r1.85 dwarf2read.c
--- dwarf2read.c	4 Feb 2003 20:17:02 -0000	1.85
+++ dwarf2read.c	5 Feb 2003 17:01:35 -0000
@@ -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 
 
 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, s
 
   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)
@@ -4927,6 +4941,61 @@ dwarf2_start_subfile (char *filename, ch
   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.
@@ -5015,106 +5084,12 @@ new_symbol (struct die_info *die, struct
 	  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
 	    {
@@ -7343,4 +7318,33 @@ attr_form_is_block (struct attribute *at
       || attr->form == DW_FORM_block2
       || 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: findvar.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/findvar.c,v
retrieving revision 1.45
diff -u -p -r1.45 findvar.c
--- findvar.c	4 Feb 2003 22:04:08 -0000	1.45
+++ findvar.c	5 Feb 2003 16:54:38 -0000
@@ -383,6 +383,14 @@ symbol_read_needs_frame (struct symbol *
     {
       /* 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:
@@ -601,6 +609,18 @@ addresses have not been bound by the dyn
 	      error ("Value of register variable not available.");
 	    return regval;
 	  }
+      }
+      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;
 
Index: m2-exp.y
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/m2-exp.y,v
retrieving revision 1.7
diff -u -p -r1.7 m2-exp.y
--- m2-exp.y	6 Nov 2002 22:48:25 -0000	1.7
+++ m2-exp.y	3 Feb 2003 16:24:14 -0000
@@ -1040,6 +1040,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: printcmd.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/printcmd.c,v
retrieving revision 1.51
diff -u -p -r1.51 printcmd.c
--- printcmd.c	4 Feb 2003 21:37:03 -0000	1.51
+++ printcmd.c	5 Feb 2003 16:54:38 -0000
@@ -1148,6 +1148,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;
@@ -1811,6 +1816,7 @@ print_frame_args (struct symbol *func, s
 	    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: stack.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/stack.c,v
retrieving revision 1.65
diff -u -p -r1.65 stack.c
--- stack.c	2 Feb 2003 18:30:56 -0000	1.65
+++ stack.c	3 Feb 2003 16:24:14 -0000
@@ -1082,6 +1082,7 @@ print_block_frame_locals (struct block *
 	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);
@@ -1308,6 +1309,7 @@ print_frame_arg_vars (register struct fr
 	case LOC_REGPARM:
 	case LOC_REGPARM_ADDR:
 	case LOC_BASEREG_ARG:
+	case LOC_COMPUTED_ARG:
 	  values_printed = 1;
 	  fputs_filtered (SYMBOL_SOURCE_NAME (sym), stream);
 	  fputs_filtered (" = ", stream);
Index: symmisc.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/symmisc.c,v
retrieving revision 1.14
diff -u -p -r1.14 symmisc.c
--- symmisc.c	18 Jan 2003 15:55:53 -0000	1.14
+++ symmisc.c	3 Feb 2003 16:24:14 -0000
@@ -726,6 +726,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;
@@ -876,6 +881,10 @@ print_partial_symbols (struct partial_sy
 	  break;
 	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);
Index: symtab.h
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/symtab.h,v
retrieving revision 1.57
diff -u -p -r1.57 symtab.h
--- symtab.h	4 Feb 2003 21:37:03 -0000	1.57
+++ symtab.h	5 Feb 2003 17:03:11 -0000
@@ -26,6 +26,8 @@
 
 /* Opaque declarations.  */
 struct obstack;
+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
@@ -616,7 +618,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. */
@@ -678,6 +731,18 @@ 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.  */
+    struct
+    {
+      void *baton;
+      struct location_funcs *funcs;
+    } loc;
   }
   aux_value;
 
@@ -702,6 +767,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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]