Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* RFA: Location list support for DWARF-2
@ 2003-03-10 16:06 Daniel Jacobowitz
  2003-03-12 21:40 ` Jim Blandy
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Jacobowitz @ 2003-03-10 16:06 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andreas Jaeger, Josef Zlomek, jimb, Michal Ludvig

Here's initial support for location lists.  I'd like to take a moment
to thank Jim Blandy and Daniel Berlin for hashing out the interface to
LOC_COMPUTED so thoroughly; it turned out that I didn't need to do
anything at all to the interface or to its clients in order to make
this work.

To test this, you'll need a GCC CVS checkout from the "rtlopt-branch"
branch tag.  This patch has no effect if location lists aren't used,
and is a strict improvement if they are, since otherwise we won't find
things at all.  However, debug output from that branch is still a
little immature.  One problem I've noticed so far is that we emit
incomplete location lists for global variables; see my post on the gcc@
list for more details.  So sometimes we can't find globals, which is a
regression in the debug info.

This patch also does not support multiple overlapping location lists;
it simply uses the first match.  The rest of GDB isn't ready for
multiple locations yet; that's down the list after DW_OP_piece I think.

I had to add the CU base address to each symbol's baton.  Long term we
can get rid of it by making sure we can go from symbol to symtab and
storing it in the symtab; I think that's a good idea but it's a patch
for another day.

Jim, is this OK?  I'd appreciate another set of eyes on it.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2003-03-10  Daniel Jacobowitz  <drow@mvista.com>

	* dwarf2expr.c (dwarf2_read_address): Renamed from read_address;
	made non-static.
	(execute_stack_op): All callers updated.
	* dwarf2expr.h: Add prototype for dwarf2_read_address.
	* dwarf2loc.c (find_location_expression): New function.
	(dwarf_expr_frame_base, locexpr_read_variable): Call it.
	(locexpr_tracepoint_var_ref): Likewise.
	(locexpr_read_needs_frame, locexpr_describe_location): Handle
	location lists.
	* dwarf2loc.c (struct dwarf2_locexpr_baton): Add is_list and
	base_address.
	* dwarf2read.c (struct comp_unit_head): Remove DIE member, add
	base_address and base_known.
	(dwarf_loc_buffer): New variable.
	(struct dwarf2_pinfo): Add dwarf_loc_buffer and dwarf_loc_size.
	(DWARF_LOC_BUFFER, DWARF_LOC_SIZE): New macros.
	(dwarf2_has_info): Initialize dwarf_loc_offset.
	(dwarf2_build_psymtabs): Read in .debug_loc.
	(dwarf2_build_psymtabs_hard): Use DWARF_LOC_BUFFER and
	DWARF_LOC_SIZE.
	(psymtab_to_symtab_1): Likewise.  Move base address calculation
	here, from...
	(dwarf2_get_pc_bounds): ... here.  Use the base address from
	cu_header.
	(dump_die): Handle DW_FORM_ref8.
	(dwarf2_symbol_mark_computed): Handle location lists.

Index: dwarf2expr.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2expr.c,v
retrieving revision 1.3
diff -u -p -r1.3 dwarf2expr.c
--- dwarf2expr.c	5 Mar 2003 18:00:02 -0000	1.3
+++ dwarf2expr.c	10 Mar 2003 00:30:18 -0000
@@ -170,13 +170,13 @@ read_sleb128 (unsigned char *buf, unsign
    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
+dwarf2_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.");
+    error ("dwarf2_read_address: Corrupted DWARF expression.");
 
   *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
   result = extract_address (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT);
@@ -277,7 +277,7 @@ execute_stack_op (struct dwarf_expr_cont
 	  break;
 
 	case DW_OP_addr:
-	  result = read_address (op_ptr, op_end, &bytes_read);
+	  result = dwarf2_read_address (op_ptr, op_end, &bytes_read);
 	  op_ptr += bytes_read;
 	  break;
 
@@ -464,9 +464,10 @@ execute_stack_op (struct dwarf_expr_cont
 
 		(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 = dwarf2_read_address (buf,
+					      buf + (TARGET_ADDR_BIT
+						     / TARGET_CHAR_BIT),
+					      &bytes_read);
 	      }
 	    result = result + offset;
 	    ctx->stack_len = before_stack_len;
@@ -525,9 +526,10 @@ execute_stack_op (struct dwarf_expr_cont
 
 		(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 = dwarf2_read_address (buf,
+					      buf + (TARGET_ADDR_BIT
+						     / TARGET_CHAR_BIT),
+					      &bytes_read);
 	      }
 	      break;
 
@@ -537,9 +539,10 @@ execute_stack_op (struct dwarf_expr_cont
 		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);
+		result = dwarf2_read_address (buf,
+					      buf + (TARGET_ADDR_BIT
+						     / TARGET_CHAR_BIT),
+					      &bytes_read);
 	      }
 	      break;
 
Index: dwarf2expr.h
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2expr.h,v
retrieving revision 1.2
diff -u -p -r1.2 dwarf2expr.h
--- dwarf2expr.h	28 Feb 2003 20:03:18 -0000	1.2
+++ dwarf2expr.h	10 Mar 2003 00:30:37 -0000
@@ -99,5 +99,7 @@ unsigned char *read_uleb128 (unsigned ch
 			     ULONGEST * r);
 unsigned char *read_sleb128 (unsigned char *buf, unsigned char *buf_end,
 			     LONGEST * r);
+CORE_ADDR dwarf2_read_address (unsigned char *buf, unsigned char *buf_end,
+			       int *bytes_read);
 
 #endif
Index: dwarf2loc.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2loc.c,v
retrieving revision 1.3
diff -u -p -r1.3 dwarf2loc.c
--- dwarf2loc.c	5 Mar 2003 18:00:02 -0000	1.3
+++ dwarf2loc.c	10 Mar 2003 15:22:17 -0000
@@ -40,6 +40,68 @@
 #define DWARF2_REG_TO_REGNUM(REG) (REG)
 #endif
 
+
+/* A helper function for dealing with location lists.  Given a
+   symbol baton (BATON) and a pc value (PC), find the appropriate
+   location expression, set *LOCEXPR_LENGTH, and return a pointer
+   to the beginning of the expression.  Returns NULL on failure.
+
+   For now, only return the first matching location expression; there
+   can be more than one in the list.  */
+
+static char *
+find_location_expression (struct dwarf2_locexpr_baton *baton,
+			  int *locexpr_length, CORE_ADDR pc)
+{
+  CORE_ADDR base_address = baton->base_address;
+  CORE_ADDR low, high;
+  char *loc_ptr;
+  unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT, length;
+  CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
+
+  if (! baton->is_list)
+    {
+      *locexpr_length = baton->size;
+      return baton->data;
+    }
+
+  loc_ptr = baton->data;
+
+  while (1)
+    {
+      low = dwarf2_read_address (loc_ptr, loc_ptr + addr_size, &length);
+      loc_ptr += length;
+      high = dwarf2_read_address (loc_ptr, loc_ptr + addr_size, &length);
+      loc_ptr += length;
+
+      /* An end-of-list entry.  */
+      if (low == 0 && high == 0)
+	return NULL;
+
+      /* A base-address-selection entry.  */
+      if ((low & base_mask) == base_mask)
+	{
+	  base_address = high;
+	  continue;
+	}
+
+      /* Otherwise, a location expression entry.  */
+      low += base_address;
+      high += base_address;
+
+      length = extract_unsigned_integer (loc_ptr, 2);
+      loc_ptr += 2;
+
+      if (pc >= low && pc < high)
+	{
+	  *locexpr_length = length;
+	  return loc_ptr;
+	}
+
+      loc_ptr += length;
+    }
+}
+
 /* This is the baton used when performing dwarf2 expression
    evaluation.  */
 struct dwarf_expr_baton
@@ -90,10 +152,14 @@ dwarf_expr_frame_base (void *baton, unsi
   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;
+  *start = find_location_expression (symbaton, length,
+				     get_frame_pc (debaton->frame));
+  if (*start == NULL)
+    error ("Could not find the frame base for \"%s\".",
+	   SYMBOL_NATURAL_NAME (framefunc));
 }
 
 /* Using the objfile specified in BATON, find the address for the
@@ -248,8 +314,15 @@ locexpr_read_variable (struct symbol *sy
 {
   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);
+  unsigned char *data;
+  int size;
+
+  data = find_location_expression (dlbaton, &size,
+				   frame ? get_frame_pc (frame) : 0);
+  if (data == NULL)
+    error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
+
+  val = dwarf2_evaluate_loc_desc (symbol, frame, data, size, dlbaton->objfile);
 
   return val;
 }
@@ -259,6 +332,12 @@ static int
 locexpr_read_needs_frame (struct symbol *symbol)
 {
   struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+
+  /* If there's a location list, then assume we need to have a frame
+     to choose the appropriate location expression.  */
+  if (dlbaton->is_list)
+    return 1;
+
   return dwarf2_loc_desc_needs_frame (dlbaton->data, dlbaton->size);
 }
 
@@ -269,6 +348,12 @@ locexpr_describe_location (struct symbol
   /* FIXME: be more extensive.  */
   struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
 
+  if (dlbaton->is_list)
+    {
+      fprintf_filtered (stream, "a variable with multiple locations");
+      return 1;
+    }
+
   if (dlbaton->size == 1
       && dlbaton->data[0] >= DW_OP_reg0
       && dlbaton->data[0] <= DW_OP_reg31)
@@ -298,27 +383,32 @@ locexpr_tracepoint_var_ref (struct symbo
 			    struct axs_value * value)
 {
   struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+  unsigned char *data;
+  int size;
+
+  data = find_location_expression (dlbaton, &size, ax->scope);
+  if (data == NULL)
+    error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
 
-  if (dlbaton->size == 0)
+  if (size == 0)
     error ("Symbol \"%s\" has been optimized out.",
 	   SYMBOL_PRINT_NAME (symbol));
 
-  if (dlbaton->size == 1
-      && dlbaton->data[0] >= DW_OP_reg0
-      && dlbaton->data[0] <= DW_OP_reg31)
+  if (size == 1
+      && data[0] >= DW_OP_reg0
+      && data[0] <= DW_OP_reg31)
     {
       value->kind = axs_lvalue_register;
-      value->u.reg = dlbaton->data[0] - DW_OP_reg0;
+      value->u.reg = data[0] - DW_OP_reg0;
     }
-  else if (dlbaton->data[0] == DW_OP_regx)
+  else if (data[0] == DW_OP_regx)
     {
       ULONGEST reg;
-      read_uleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
-		    &reg);
+      read_uleb128 (data + 1, data + size, &reg);
       value->kind = axs_lvalue_register;
       value->u.reg = reg;
     }
-  else if (dlbaton->data[0] == DW_OP_fbreg)
+  else if (data[0] == DW_OP_fbreg)
     {
       /* And this is worse than just minimal; we should honor the frame base
 	 as above.  */
@@ -326,9 +416,8 @@ locexpr_tracepoint_var_ref (struct symbo
       LONGEST frame_offset;
       unsigned char *buf_end;
 
-      buf_end = read_sleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
-			      &frame_offset);
-      if (buf_end != dlbaton->data + dlbaton->size)
+      buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
+      if (buf_end != data + size)
 	error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
 	       SYMBOL_PRINT_NAME (symbol));
 
Index: dwarf2loc.h
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2loc.h,v
retrieving revision 1.1
diff -u -p -r1.1 dwarf2loc.h
--- dwarf2loc.h	21 Feb 2003 15:24:17 -0000	1.1
+++ dwarf2loc.h	8 Mar 2003 18:26:15 -0000
@@ -31,6 +31,8 @@ struct dwarf2_locexpr_baton
 {
   unsigned char *data;
   unsigned short size;
+  unsigned char is_list;
+  CORE_ADDR base_address;
   struct objfile *objfile;
 };
 
Index: dwarf2read.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2read.c,v
retrieving revision 1.88
diff -u -p -r1.88 dwarf2read.c
--- dwarf2read.c	25 Feb 2003 21:36:17 -0000	1.88
+++ dwarf2read.c	10 Mar 2003 05:01:11 -0000
@@ -220,9 +220,13 @@ struct comp_unit_head
 
     struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
 
-    /* Pointer to the DIE associated with the compilation unit.  */
+    /* Base address of this compilation unit.  */
 
-    struct die_info *die;
+    CORE_ADDR base_address;
+
+    /* Flag representing whether base_address is accurate.  */
+
+    int base_known;
   };
 
 /* The line number information for a compilation unit (found in the
@@ -395,6 +399,7 @@ static char *dwarf_line_buffer;
 static char *dwarf_str_buffer;
 static char *dwarf_macinfo_buffer;
 static char *dwarf_ranges_buffer;
+static char *dwarf_loc_buffer;
 
 /* A zeroed version of a partial die for initialization purposes.  */
 static struct partial_die_info zeroed_partial_die;
@@ -511,6 +516,13 @@ struct dwarf2_pinfo
 
     unsigned int dwarf_ranges_size;
 
+    /* Pointer to start of dwarf locations buffer for the objfile.  */
+
+    char *dwarf_loc_buffer;
+
+    /* Size of dwarf locations buffer for the objfile.  */
+
+    unsigned int dwarf_loc_size;
   };
 
 #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
@@ -526,6 +538,8 @@ struct dwarf2_pinfo
 #define DWARF_MACINFO_SIZE(p)   (PST_PRIVATE(p)->dwarf_macinfo_size)
 #define DWARF_RANGES_BUFFER(p)  (PST_PRIVATE(p)->dwarf_ranges_buffer)
 #define DWARF_RANGES_SIZE(p)    (PST_PRIVATE(p)->dwarf_ranges_size)
+#define DWARF_LOC_BUFFER(p)     (PST_PRIVATE(p)->dwarf_loc_buffer)
+#define DWARF_LOC_SIZE(p)       (PST_PRIVATE(p)->dwarf_loc_size)
 
 /* Maintain an array of referenced fundamental types for the current
    compilation unit being read.  For DWARF version 1, we have to construct
@@ -926,6 +940,7 @@ dwarf2_has_info (bfd *abfd)
   dwarf_frame_offset = 0;
   dwarf_eh_frame_offset = 0;
   dwarf_ranges_offset = 0;
+  dwarf_loc_offset = 0;
   
   bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
   if (dwarf_info_offset && dwarf_abbrev_offset)
@@ -1062,6 +1077,14 @@ dwarf2_build_psymtabs (struct objfile *o
   else
     dwarf_ranges_buffer = NULL;
 
+  if (dwarf_loc_offset)
+    dwarf_loc_buffer = dwarf2_read_section (objfile,
+					    dwarf_loc_offset,
+					    dwarf_loc_size,
+					    dwarf_loc_section);
+  else
+    dwarf_loc_buffer = NULL;
+
   if (mainline
       || (objfile->global_psymbols.size == 0
 	  && objfile->static_psymbols.size == 0))
@@ -1283,6 +1306,8 @@ dwarf2_build_psymtabs_hard (struct objfi
       DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
       DWARF_RANGES_BUFFER (pst) = dwarf_ranges_buffer;
       DWARF_RANGES_SIZE (pst) = dwarf_ranges_size;
+      DWARF_LOC_BUFFER (pst) = dwarf_loc_buffer;
+      DWARF_LOC_SIZE (pst) = dwarf_loc_size;
       baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
       /* Store the function that reads in the rest of the symbol table */
@@ -1607,6 +1632,7 @@ psymtab_to_symtab_1 (struct partial_symt
   char *info_ptr;
   struct symtab *symtab;
   struct cleanup *back_to;
+  struct attribute *attr;
 
   /* Set local variables from the partial symbol table info.  */
   offset = DWARF_INFO_OFFSET (pst);
@@ -1621,6 +1647,8 @@ psymtab_to_symtab_1 (struct partial_symt
   dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
   dwarf_ranges_buffer = DWARF_RANGES_BUFFER (pst);
   dwarf_ranges_size = DWARF_RANGES_SIZE (pst);
+  dwarf_loc_buffer = DWARF_LOC_BUFFER (pst);
+  dwarf_loc_size = DWARF_LOC_SIZE (pst);
   baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
   cu_header_offset = offset;
   info_ptr = dwarf_info_buffer + offset;
@@ -1642,8 +1670,32 @@ psymtab_to_symtab_1 (struct partial_symt
 
   make_cleanup_free_die_list (dies);
 
+  /* Find the base address of the compilation unit for range lists and
+     location lists.  It will normally be specified by DW_AT_low_pc.
+     In DWARF-3 draft 4, the base address could be overridden by
+     DW_AT_entry_pc.  It's been removed, but GCC still uses this for
+     compilation units with discontinuous ranges.  */
+
+  cu_header.base_known = 0;
+  cu_header.base_address = 0;
+
+  attr = dwarf_attr (dies, DW_AT_entry_pc);
+  if (attr)
+    {
+      cu_header.base_address = DW_ADDR (attr);
+      cu_header.base_known = 0;
+    }
+  else
+    {
+      attr = dwarf_attr (dies, DW_AT_low_pc);
+      if (attr)
+	{
+	  cu_header.base_address = DW_ADDR (attr);
+	  cu_header.base_known = 1;
+	}
+    }
+
   /* Do line number decoding in read_file_scope () */
-  cu_header.die = dies;
   process_die (dies, objfile, &cu_header);
 
   if (!dwarf2_get_pc_bounds (dies, &lowpc, &highpc, objfile, &cu_header))
@@ -2122,40 +2174,18 @@ dwarf2_get_pc_bounds (struct die_info *d
 	     .debug_renges section.  */
 	  unsigned int offset = DW_UNSND (attr);
 	  /* Base address selection entry.  */
-	  CORE_ADDR base = 0;
-	  int found_base = 0;
+	  CORE_ADDR base;
+	  int found_base;
 	  int dummy;
 	  unsigned int i;
 	  char *buffer;
 	  CORE_ADDR marker;
 	  int low_set;
  
-	  /* The applicable base address is determined by (1) the closest
-	     preceding base address selection entry in the range list or
-	     (2) the DW_AT_low_pc of the compilation unit.  */
-
-	  /* ??? Was in dwarf3 draft4, and has since been removed.
-	     GCC still uses it though.  */
-	  attr = dwarf_attr (cu_header->die, DW_AT_entry_pc);
-	  if (attr)
-	    {
-	      base = DW_ADDR (attr);
-	      found_base = 1;
-	    }
-
-	  if (!found_base)
-	    {
-	      attr = dwarf_attr (cu_header->die, DW_AT_low_pc);
-	      if (attr)
-		{
-		  base = DW_ADDR (attr);
-		  found_base = 1;
-		}
-	    }
-
+	  found_base = cu_header->base_known;
+	  base = cu_header->base_address;
 	  buffer = dwarf_ranges_buffer + offset;
 
-
 	  /* Read in the largest possible address.  */
 	  marker = read_address (obfd, buffer, cu_header, &dummy);
 	  if ((marker & mask) == mask)
@@ -6481,6 +6511,7 @@ dump_die (struct die_info *die)
 	case DW_FORM_ref1:
 	case DW_FORM_ref2:
 	case DW_FORM_ref4:
+	case DW_FORM_ref8:
 	case DW_FORM_udata:
 	case DW_FORM_sdata:
 	  fprintf_unfiltered (gdb_stderr, "constant: %ld", DW_UNSND (&die->attrs[i]));
@@ -7330,23 +7361,39 @@ dwarf2_symbol_mark_computed (struct attr
 {
   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;
+  /* When support for location lists is added, this will go away.  */
+  if (attr_form_is_block (attr))
+    {
+      /* 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;
+      baton->is_list = 0;
+    }
+  else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
+    {
+      baton->size = 0;
+      baton->data = dwarf_loc_buffer + DW_UNSND (attr);
+      baton->is_list = 1;
+      baton->base_address = cu_header->base_address;
+      if (cu_header->base_known == 0)
+	complain (&symfile_complaints,
+		  "Location list used without specifying the CU base address.");
+    }
+  else
+    {
+      dwarf2_invalid_attrib_class_complaint ("location description",
+					     SYMBOL_NATURAL_NAME (sym));
+      baton->size = 0;
+      baton->data = NULL;
+      baton->is_list = 0;
+    }
 
   SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs;
   SYMBOL_LOCATION_BATON (sym) = baton;


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: RFA: Location list support for DWARF-2
  2003-03-10 16:06 RFA: Location list support for DWARF-2 Daniel Jacobowitz
@ 2003-03-12 21:40 ` Jim Blandy
  2003-03-12 22:42   ` Daniel Jacobowitz
  0 siblings, 1 reply; 6+ messages in thread
From: Jim Blandy @ 2003-03-12 21:40 UTC (permalink / raw)
  To: Daniel Jacobowitz
  Cc: gdb-patches, Andreas Jaeger, Josef Zlomek, Michal Ludvig


Daniel Jacobowitz <drow@mvista.com> writes:
> Here's initial support for location lists.  I'd like to take a moment
> to thank Jim Blandy and Daniel Berlin for hashing out the interface to
> LOC_COMPUTED so thoroughly; it turned out that I didn't need to do
> anything at all to the interface or to its clients in order to make
> this work.
> 
> To test this, you'll need a GCC CVS checkout from the "rtlopt-branch"
> branch tag.  This patch has no effect if location lists aren't used,
> and is a strict improvement if they are, since otherwise we won't find
> things at all.  However, debug output from that branch is still a
> little immature.  One problem I've noticed so far is that we emit
> incomplete location lists for global variables; see my post on the gcc@
> list for more details.  So sometimes we can't find globals, which is a
> regression in the debug info.
> 
> This patch also does not support multiple overlapping location lists;
> it simply uses the first match.  The rest of GDB isn't ready for
> multiple locations yet; that's down the list after DW_OP_piece I
> think.
> 
> I had to add the CU base address to each symbol's baton.  Long term we
> can get rid of it by making sure we can go from symbol to symtab and
> storing it in the symtab; I think that's a good idea but it's a patch
> for another day.
> 
> Jim, is this OK?  I'd appreciate another set of eyes on it.

Rather than putting 'if (foo->is_list)' everywhere, why not just
introduce a separate 'struct location_funcs' for location lists?
Aside from just being cleaner, you'll save a word in each baton.

> Index: dwarf2loc.c
> ===================================================================
> RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2loc.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 dwarf2loc.c
> --- dwarf2loc.c	5 Mar 2003 18:00:02 -0000	1.3
> +++ dwarf2loc.c	10 Mar 2003 15:22:17 -0000
> @@ -40,6 +40,68 @@
>  #define DWARF2_REG_TO_REGNUM(REG) (REG)
>  #endif
>  
> +
> +/* A helper function for dealing with location lists.  Given a
> +   symbol baton (BATON) and a pc value (PC), find the appropriate
> +   location expression, set *LOCEXPR_LENGTH, and return a pointer
> +   to the beginning of the expression.  Returns NULL on failure.
> +
> +   For now, only return the first matching location expression; there
> +   can be more than one in the list.  */
> +
> +static char *
> +find_location_expression (struct dwarf2_locexpr_baton *baton,
> +			  int *locexpr_length, CORE_ADDR pc)
> +{
> +  CORE_ADDR base_address = baton->base_address;
> +  CORE_ADDR low, high;
> +  char *loc_ptr;
> +  unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT, length;
> +  CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));

Why not just ~(~(CORE_ADDR)0 << (addr_size * 8))?

> +
> +  if (! baton->is_list)
> +    {
> +      *locexpr_length = baton->size;
> +      return baton->data;
> +    }
> +
> +  loc_ptr = baton->data;
> +
> +  while (1)
> +    {
> +      low = dwarf2_read_address (loc_ptr, loc_ptr + addr_size, &length);
> +      loc_ptr += length;
> +      high = dwarf2_read_address (loc_ptr, loc_ptr + addr_size, &length);
> +      loc_ptr += length;

Shouldn't you pass baton->data + baton_size as the 'buf_end' argument?
You're defeating the range-checking that function performs.

> Index: dwarf2read.c
> ===================================================================
> RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2read.c,v
> retrieving revision 1.88
> diff -u -p -r1.88 dwarf2read.c
> --- dwarf2read.c	25 Feb 2003 21:36:17 -0000	1.88
> +++ dwarf2read.c	10 Mar 2003 05:01:11 -0000
> @@ -220,9 +220,13 @@ struct comp_unit_head
>  
>      struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
>  
> -    /* Pointer to the DIE associated with the compilation unit.  */
> +    /* Base address of this compilation unit.  */
>  
> -    struct die_info *die;
> +    CORE_ADDR base_address;
> +
> +    /* Flag representing whether base_address is accurate.  */

You can be more concrete: "Non-zero if base_address has been set."

> @@ -1642,8 +1670,32 @@ psymtab_to_symtab_1 (struct partial_symt
>  
>    make_cleanup_free_die_list (dies);
>  
> +  /* Find the base address of the compilation unit for range lists and
> +     location lists.  It will normally be specified by DW_AT_low_pc.
> +     In DWARF-3 draft 4, the base address could be overridden by
> +     DW_AT_entry_pc.  It's been removed, but GCC still uses this for
> +     compilation units with discontinuous ranges.  */
> +
> +  cu_header.base_known = 0;
> +  cu_header.base_address = 0;
> +
> +  attr = dwarf_attr (dies, DW_AT_entry_pc);
> +  if (attr)
> +    {
> +      cu_header.base_address = DW_ADDR (attr);
> +      cu_header.base_known = 0;

Shouldn't this set it to 1, not zero?

> @@ -6481,6 +6511,7 @@ dump_die (struct die_info *die)
>  	case DW_FORM_ref1:
>  	case DW_FORM_ref2:
>  	case DW_FORM_ref4:
> +	case DW_FORM_ref8:
>  	case DW_FORM_udata:
>  	case DW_FORM_sdata:
>  	  fprintf_unfiltered (gdb_stderr, "constant: %ld", DW_UNSND (&die->attrs[i]));

This should be a separate patch (which you are welcome to commit).

> @@ -7330,23 +7361,39 @@ dwarf2_symbol_mark_computed (struct attr
>  {
>    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;
> +  /* When support for location lists is added, this will go away.  */

This comment should go away, shouldn't it?

> +  if (attr_form_is_block (attr))
> +    {
> +      /* 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;
> +      baton->is_list = 0;
> +    }
> +  else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
> +    {
> +      baton->size = 0;

We don't have good information about the range list's extent
available, but you should set this to 'dwarf_loc_size - DW_UNSND
(attr)' or something like that.

> +      baton->data = dwarf_loc_buffer + DW_UNSND (attr);
> +      baton->is_list = 1;
> +      baton->base_address = cu_header->base_address;
> +      if (cu_header->base_known == 0)
> +	complain (&symfile_complaints,
> +		  "Location list used without specifying the CU base address.");
'complain' has been gone for a month and a half now.  You'd probably
better check this patch against more recent sources.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: RFA: Location list support for DWARF-2
  2003-03-12 21:40 ` Jim Blandy
@ 2003-03-12 22:42   ` Daniel Jacobowitz
  2003-04-08 16:46     ` Daniel Jacobowitz
  2003-04-09  5:05     ` Jim Blandy
  0 siblings, 2 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2003-03-12 22:42 UTC (permalink / raw)
  To: Jim Blandy; +Cc: gdb-patches

On Wed, Mar 12, 2003 at 04:37:20PM -0500, Jim Blandy wrote:
> 
> Daniel Jacobowitz <drow@mvista.com> writes:
> > Here's initial support for location lists.  I'd like to take a moment
> > to thank Jim Blandy and Daniel Berlin for hashing out the interface to
> > LOC_COMPUTED so thoroughly; it turned out that I didn't need to do
> > anything at all to the interface or to its clients in order to make
> > this work.
> > 
> > To test this, you'll need a GCC CVS checkout from the "rtlopt-branch"
> > branch tag.  This patch has no effect if location lists aren't used,
> > and is a strict improvement if they are, since otherwise we won't find
> > things at all.  However, debug output from that branch is still a
> > little immature.  One problem I've noticed so far is that we emit
> > incomplete location lists for global variables; see my post on the gcc@
> > list for more details.  So sometimes we can't find globals, which is a
> > regression in the debug info.
> > 
> > This patch also does not support multiple overlapping location lists;
> > it simply uses the first match.  The rest of GDB isn't ready for
> > multiple locations yet; that's down the list after DW_OP_piece I
> > think.
> > 
> > I had to add the CU base address to each symbol's baton.  Long term we
> > can get rid of it by making sure we can go from symbol to symtab and
> > storing it in the symtab; I think that's a good idea but it's a patch
> > for another day.
> > 
> > Jim, is this OK?  I'd appreciate another set of eyes on it.
> 
> Rather than putting 'if (foo->is_list)' everywhere, why not just
> introduce a separate 'struct location_funcs' for location lists?
> Aside from just being cleaner, you'll save a word in each baton.

Actually, it won't save any space to remove is_list: it goes into the
padding between size and the following CORE_ADDR/pointer.  It does save
space for non-location-list variables though, because of the base
address, so I think it's a good idea.  It requires introducing one
annoying hack in dwarf_expr_frame_base but I'm not terribly upset by
it.

> 
> > Index: dwarf2loc.c
> > ===================================================================
> > RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2loc.c,v
> > retrieving revision 1.3
> > diff -u -p -r1.3 dwarf2loc.c
> > --- dwarf2loc.c	5 Mar 2003 18:00:02 -0000	1.3
> > +++ dwarf2loc.c	10 Mar 2003 15:22:17 -0000
> > @@ -40,6 +40,68 @@
> >  #define DWARF2_REG_TO_REGNUM(REG) (REG)
> >  #endif
> >  
> > +
> > +/* A helper function for dealing with location lists.  Given a
> > +   symbol baton (BATON) and a pc value (PC), find the appropriate
> > +   location expression, set *LOCEXPR_LENGTH, and return a pointer
> > +   to the beginning of the expression.  Returns NULL on failure.
> > +
> > +   For now, only return the first matching location expression; there
> > +   can be more than one in the list.  */
> > +
> > +static char *
> > +find_location_expression (struct dwarf2_locexpr_baton *baton,
> > +			  int *locexpr_length, CORE_ADDR pc)
> > +{
> > +  CORE_ADDR base_address = baton->base_address;
> > +  CORE_ADDR low, high;
> > +  char *loc_ptr;
> > +  unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT, length;
> > +  CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
> 
> Why not just ~(~(CORE_ADDR)0 << (addr_size * 8))?

Suppose that sizeof(CORE_ADDR) == 4 and addr_size == 4.  That's a
left-shift by 32; very bad C mojo.

By the way, Richard Henderson originally wrote this (although every
copy of it in GDB has my name on it, he submitted the original
DW_AT_ranges patch).  So he gets credit for getting this right.  I
always get it wrong :)

> > +  if (! baton->is_list)
> > +    {
> > +      *locexpr_length = baton->size;
> > +      return baton->data;
> > +    }
> > +
> > +  loc_ptr = baton->data;
> > +
> > +  while (1)
> > +    {
> > +      low = dwarf2_read_address (loc_ptr, loc_ptr + addr_size, &length);
> > +      loc_ptr += length;
> > +      high = dwarf2_read_address (loc_ptr, loc_ptr + addr_size, &length);
> > +      loc_ptr += length;
> 
> Shouldn't you pass baton->data + baton_size as the 'buf_end' argument?
> You're defeating the range-checking that function performs.

Oops, this brings up a wart that I forgot to document.  The size value
can't be trusted.  You suggested a fix for this below; I like it, so
I'll use it :)

> 
> > Index: dwarf2read.c
> > ===================================================================
> > RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2read.c,v
> > retrieving revision 1.88
> > diff -u -p -r1.88 dwarf2read.c
> > --- dwarf2read.c	25 Feb 2003 21:36:17 -0000	1.88
> > +++ dwarf2read.c	10 Mar 2003 05:01:11 -0000
> > @@ -220,9 +220,13 @@ struct comp_unit_head
> >  
> >      struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
> >  
> > -    /* Pointer to the DIE associated with the compilation unit.  */
> > +    /* Base address of this compilation unit.  */
> >  
> > -    struct die_info *die;
> > +    CORE_ADDR base_address;
> > +
> > +    /* Flag representing whether base_address is accurate.  */
> 
> You can be more concrete: "Non-zero if base_address has been set."

Thanks.


> 
> > @@ -1642,8 +1670,32 @@ psymtab_to_symtab_1 (struct partial_symt
> >  
> >    make_cleanup_free_die_list (dies);
> >  
> > +  /* Find the base address of the compilation unit for range lists and
> > +     location lists.  It will normally be specified by DW_AT_low_pc.
> > +     In DWARF-3 draft 4, the base address could be overridden by
> > +     DW_AT_entry_pc.  It's been removed, but GCC still uses this for
> > +     compilation units with discontinuous ranges.  */
> > +
> > +  cu_header.base_known = 0;
> > +  cu_header.base_address = 0;
> > +
> > +  attr = dwarf_attr (dies, DW_AT_entry_pc);
> > +  if (attr)
> > +    {
> > +      cu_header.base_address = DW_ADDR (attr);
> > +      cu_header.base_known = 0;
> 
> Shouldn't this set it to 1, not zero?

Uh, er, yes.  Told you I needed more eyes.  My tests all must have had
a low_pc.

> 
> > @@ -6481,6 +6511,7 @@ dump_die (struct die_info *die)
> >  	case DW_FORM_ref1:
> >  	case DW_FORM_ref2:
> >  	case DW_FORM_ref4:
> > +	case DW_FORM_ref8:
> >  	case DW_FORM_udata:
> >  	case DW_FORM_sdata:
> >  	  fprintf_unfiltered (gdb_stderr, "constant: %ld", DW_UNSND (&die->attrs[i]));
> 
> This should be a separate patch (which you are welcome to commit).

OK.

> 
> > @@ -7330,23 +7361,39 @@ dwarf2_symbol_mark_computed (struct attr
> >  {
> >    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;
> > +  /* When support for location lists is added, this will go away.  */
> 
> This comment should go away, shouldn't it?

Thought it had.  Oopsie.

> 
> > +  if (attr_form_is_block (attr))
> > +    {
> > +      /* 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;
> > +      baton->is_list = 0;
> > +    }
> > +  else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
> > +    {
> > +      baton->size = 0;
> 
> We don't have good information about the range list's extent
> available, but you should set this to 'dwarf_loc_size - DW_UNSND
> (attr)' or something like that.

As above, sure.

> > +      baton->data = dwarf_loc_buffer + DW_UNSND (attr);
> > +      baton->is_list = 1;
> > +      baton->base_address = cu_header->base_address;
> > +      if (cu_header->base_known == 0)
> > +	complain (&symfile_complaints,
> > +		  "Location list used without specifying the CU base address.");
> 'complain' has been gone for a month and a half now.  You'd probably
> better check this patch against more recent sources.

Uhm... I was using the current development sources.  My changelog
includes the deletion of complain.  I apparently managed to change that
to a complain() without recompiling.  I was shooting for complaint().
Sorry 'bout that.

Here's a revision.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2003-03-10  Daniel Jacobowitz  <drow@mvista.com>

	* dwarf2expr.c (dwarf2_read_address): Renamed from read_address;
	made non-static.
	(execute_stack_op): All callers updated.
	* dwarf2expr.h: Add prototype for dwarf2_read_address.
	* dwarf2loc.c (find_location_expression): New function.
	(dwarf_expr_frame_base): Call it.
	(dwarf2_tracepoint_var_ref): New function, broken out from
	locexpr_tracepoint_var_ref.
	(locexpr_tracepoint_var_ref): Call dwarf2_tracepoint_var_ref.
	Make static.
	(loclist_read_variable, loclist_read_needs_frame): New functions.
	(loclist_describe_location, loclist_tracepoint_var_ref): New
	functions.
	(dwarf2_loclist_funcs): New struct location_funcs.
	* dwarf2loc.h (struct dwarf2_loclist_baton): New.
	(dwarf2_loclist_funcs): New extern.
	* dwarf2read.c (struct comp_unit_head): Remove DIE member, add
	base_address and base_known.
	(dwarf_loc_buffer): New variable.
	(struct dwarf2_pinfo): Add dwarf_loc_buffer and dwarf_loc_size.
	(DWARF_LOC_BUFFER, DWARF_LOC_SIZE): New macros.
	(dwarf2_has_info): Initialize dwarf_loc_offset.
	(dwarf2_build_psymtabs): Read in .debug_loc.
	(dwarf2_build_psymtabs_hard): Use DWARF_LOC_BUFFER and
	DWARF_LOC_SIZE.
	(psymtab_to_symtab_1): Likewise.  Move base address calculation
	here, from...
	(dwarf2_get_pc_bounds): ... here.  Use the base address from
	cu_header.
	(dwarf2_symbol_mark_computed): Handle location lists.

Index: dwarf2expr.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2expr.c,v
retrieving revision 1.3
diff -u -p -r1.3 dwarf2expr.c
--- dwarf2expr.c	5 Mar 2003 18:00:02 -0000	1.3
+++ dwarf2expr.c	10 Mar 2003 00:30:18 -0000
@@ -170,13 +170,13 @@ read_sleb128 (unsigned char *buf, unsign
    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
+dwarf2_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.");
+    error ("dwarf2_read_address: Corrupted DWARF expression.");
 
   *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
   result = extract_address (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT);
@@ -277,7 +277,7 @@ execute_stack_op (struct dwarf_expr_cont
 	  break;
 
 	case DW_OP_addr:
-	  result = read_address (op_ptr, op_end, &bytes_read);
+	  result = dwarf2_read_address (op_ptr, op_end, &bytes_read);
 	  op_ptr += bytes_read;
 	  break;
 
@@ -464,9 +464,10 @@ execute_stack_op (struct dwarf_expr_cont
 
 		(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 = dwarf2_read_address (buf,
+					      buf + (TARGET_ADDR_BIT
+						     / TARGET_CHAR_BIT),
+					      &bytes_read);
 	      }
 	    result = result + offset;
 	    ctx->stack_len = before_stack_len;
@@ -525,9 +526,10 @@ execute_stack_op (struct dwarf_expr_cont
 
 		(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 = dwarf2_read_address (buf,
+					      buf + (TARGET_ADDR_BIT
+						     / TARGET_CHAR_BIT),
+					      &bytes_read);
 	      }
 	      break;
 
@@ -537,9 +539,10 @@ execute_stack_op (struct dwarf_expr_cont
 		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);
+		result = dwarf2_read_address (buf,
+					      buf + (TARGET_ADDR_BIT
+						     / TARGET_CHAR_BIT),
+					      &bytes_read);
 	      }
 	      break;
 
Index: dwarf2expr.h
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2expr.h,v
retrieving revision 1.2
diff -u -p -r1.2 dwarf2expr.h
--- dwarf2expr.h	28 Feb 2003 20:03:18 -0000	1.2
+++ dwarf2expr.h	10 Mar 2003 00:30:37 -0000
@@ -99,5 +99,7 @@ unsigned char *read_uleb128 (unsigned ch
 			     ULONGEST * r);
 unsigned char *read_sleb128 (unsigned char *buf, unsigned char *buf_end,
 			     LONGEST * r);
+CORE_ADDR dwarf2_read_address (unsigned char *buf, unsigned char *buf_end,
+			       int *bytes_read);
 
 #endif
Index: dwarf2loc.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2loc.c,v
retrieving revision 1.3
diff -u -p -r1.3 dwarf2loc.c
--- dwarf2loc.c	5 Mar 2003 18:00:02 -0000	1.3
+++ dwarf2loc.c	12 Mar 2003 22:37:23 -0000
@@ -40,6 +40,62 @@
 #define DWARF2_REG_TO_REGNUM(REG) (REG)
 #endif
 
+/* A helper function for dealing with location lists.  Given a
+   symbol baton (BATON) and a pc value (PC), find the appropriate
+   location expression, set *LOCEXPR_LENGTH, and return a pointer
+   to the beginning of the expression.  Returns NULL on failure.
+
+   For now, only return the first matching location expression; there
+   can be more than one in the list.  */
+
+static char *
+find_location_expression (struct dwarf2_loclist_baton *baton,
+			  int *locexpr_length, CORE_ADDR pc)
+{
+  CORE_ADDR base_address = baton->base_address;
+  CORE_ADDR low, high;
+  char *loc_ptr, *buf_end;
+  unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT, length;
+  CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
+
+  loc_ptr = baton->data;
+  buf_end = baton->data + baton->size;
+
+  while (1)
+    {
+      low = dwarf2_read_address (loc_ptr, buf_end, &length);
+      loc_ptr += length;
+      high = dwarf2_read_address (loc_ptr, buf_end, &length);
+      loc_ptr += length;
+
+      /* An end-of-list entry.  */
+      if (low == 0 && high == 0)
+	return NULL;
+
+      /* A base-address-selection entry.  */
+      if ((low & base_mask) == base_mask)
+	{
+	  base_address = high;
+	  continue;
+	}
+
+      /* Otherwise, a location expression entry.  */
+      low += base_address;
+      high += base_address;
+
+      length = extract_unsigned_integer (loc_ptr, 2);
+      loc_ptr += 2;
+
+      if (pc >= low && pc < high)
+	{
+	  *locexpr_length = length;
+	  return loc_ptr;
+	}
+
+      loc_ptr += length;
+    }
+}
+
 /* This is the baton used when performing dwarf2 expression
    evaluation.  */
 struct dwarf_expr_baton
@@ -88,12 +144,28 @@ 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;
+
+  if (SYMBOL_LOCATION_FUNCS (framefunc) == &dwarf2_loclist_funcs)
+    {
+      struct dwarf2_loclist_baton *symbaton;
+      symbaton = SYMBOL_LOCATION_BATON (framefunc);
+      *start = find_location_expression (symbaton, length,
+					 get_frame_pc (debaton->frame));
+    }
+  else
+    {
+      struct dwarf2_locexpr_baton *symbaton;
+      symbaton = SYMBOL_LOCATION_BATON (framefunc);
+      *length = symbaton->size;
+      *start = symbaton->data;
+    }
+
+  if (*start == NULL)
+    error ("Could not find the frame base for \"%s\".",
+	   SYMBOL_NATURAL_NAME (framefunc));
 }
 
 /* Using the objfile specified in BATON, find the address for the
@@ -238,8 +310,55 @@ dwarf2_loc_desc_needs_frame (unsigned ch
   return baton.needs_frame;
 }
 
+static void
+dwarf2_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
+			   struct axs_value * value, unsigned char *data,
+			   int size)
+{
+  if (size == 0)
+    error ("Symbol \"%s\" has been optimized out.",
+	   SYMBOL_PRINT_NAME (symbol));
 
+  if (size == 1
+      && data[0] >= DW_OP_reg0
+      && data[0] <= DW_OP_reg31)
+    {
+      value->kind = axs_lvalue_register;
+      value->u.reg = data[0] - DW_OP_reg0;
+    }
+  else if (data[0] == DW_OP_regx)
+    {
+      ULONGEST reg;
+      read_uleb128 (data + 1, data + size, &reg);
+      value->kind = axs_lvalue_register;
+      value->u.reg = reg;
+    }
+  else if (data[0] == DW_OP_fbreg)
+    {
+      /* And this is worse than just minimal; we should honor the frame base
+	 as above.  */
+      int frame_reg;
+      LONGEST frame_offset;
+      unsigned char *buf_end;
+
+      buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
+      if (buf_end != data + size)
+	error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
+	       SYMBOL_PRINT_NAME (symbol));
 
+      TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
+      ax_reg (ax, frame_reg);
+      ax_const_l (ax, frame_offset);
+      ax_simple (ax, aop_add);
+
+      ax_const_l (ax, frame_offset);
+      ax_simple (ax, aop_add);
+      value->kind = axs_lvalue_memory;
+    }
+  else
+    error ("Unsupported DWARF opcode in the location of \"%s\".",
+	   SYMBOL_PRINT_NAME (symbol));
+}
 \f
 /* Return the value of SYMBOL in FRAME using the DWARF-2 expression
    evaluator to calculate the location.  */
@@ -293,57 +412,13 @@ locexpr_describe_location (struct symbol
    publicly available stub with tracepoint support for me to test
    against.  When there is one this function should be revisited.  */
 
-void
+static void
 locexpr_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
 			    struct axs_value * value)
 {
   struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
 
-  if (dlbaton->size == 0)
-    error ("Symbol \"%s\" has been optimized out.",
-	   SYMBOL_PRINT_NAME (symbol));
-
-  if (dlbaton->size == 1
-      && dlbaton->data[0] >= DW_OP_reg0
-      && dlbaton->data[0] <= DW_OP_reg31)
-    {
-      value->kind = axs_lvalue_register;
-      value->u.reg = dlbaton->data[0] - DW_OP_reg0;
-    }
-  else if (dlbaton->data[0] == DW_OP_regx)
-    {
-      ULONGEST reg;
-      read_uleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
-		    &reg);
-      value->kind = axs_lvalue_register;
-      value->u.reg = reg;
-    }
-  else if (dlbaton->data[0] == DW_OP_fbreg)
-    {
-      /* And this is worse than just minimal; we should honor the frame base
-	 as above.  */
-      int frame_reg;
-      LONGEST frame_offset;
-      unsigned char *buf_end;
-
-      buf_end = read_sleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
-			      &frame_offset);
-      if (buf_end != dlbaton->data + dlbaton->size)
-	error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
-	       SYMBOL_PRINT_NAME (symbol));
-
-      TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
-      ax_reg (ax, frame_reg);
-      ax_const_l (ax, frame_offset);
-      ax_simple (ax, aop_add);
-
-      ax_const_l (ax, frame_offset);
-      ax_simple (ax, aop_add);
-      value->kind = axs_lvalue_memory;
-    }
-  else
-    error ("Unsupported DWARF opcode in the location of \"%s\".",
-	   SYMBOL_PRINT_NAME (symbol));
+  dwarf2_tracepoint_var_ref (symbol, ax, value, dlbaton->data, dlbaton->size);
 }
 
 /* The set of location functions used with the DWARF-2 expression
@@ -353,4 +428,76 @@ struct location_funcs dwarf2_locexpr_fun
   locexpr_read_needs_frame,
   locexpr_describe_location,
   locexpr_tracepoint_var_ref
+};
+
+
+/* Wrapper functions for location lists.  These generally find
+   the appropriate location expression and call something above.  */
+
+/* Return the value of SYMBOL in FRAME using the DWARF-2 expression
+   evaluator to calculate the location.  */
+static struct value *
+loclist_read_variable (struct symbol *symbol, struct frame_info *frame)
+{
+  struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+  struct value *val;
+  unsigned char *data;
+  int size;
+
+  data = find_location_expression (dlbaton, &size,
+				   frame ? get_frame_pc (frame) : 0);
+  if (data == NULL)
+    error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
+
+  val = dwarf2_evaluate_loc_desc (symbol, frame, data, size, dlbaton->objfile);
+
+  return val;
+}
+
+/* Return non-zero iff we need a frame to evaluate SYMBOL.  */
+static int
+loclist_read_needs_frame (struct symbol *symbol)
+{
+  /* If there's a location list, then assume we need to have a frame
+     to choose the appropriate location expression.  With tracking of
+     global variables this is not necessarily true, but such tracking
+     is disabled in GCC at the moment until we figure out how to
+     represent it.  */
+
+  return 1;
+}
+
+/* Print a natural-language description of SYMBOL to STREAM.  */
+static int
+loclist_describe_location (struct symbol *symbol, struct ui_file *stream)
+{
+  /* FIXME: Could print the entire list of locations.  */
+  fprintf_filtered (stream, "a variable with multiple locations");
+  return 1;
+}
+
+/* Describe the location of SYMBOL as an agent value in VALUE, generating
+   any necessary bytecode in AX.  */
+static void
+loclist_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
+			    struct axs_value * value)
+{
+  struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+  unsigned char *data;
+  int size;
+
+  data = find_location_expression (dlbaton, &size, ax->scope);
+  if (data == NULL)
+    error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
+
+  dwarf2_tracepoint_var_ref (symbol, ax, value, data, size);
+}
+
+/* The set of location functions used with the DWARF-2 expression
+   evaluator and location lists.  */
+struct location_funcs dwarf2_loclist_funcs = {
+  loclist_read_variable,
+  loclist_read_needs_frame,
+  loclist_describe_location,
+  loclist_tracepoint_var_ref
 };
Index: dwarf2loc.h
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2loc.h,v
retrieving revision 1.1
diff -u -p -r1.1 dwarf2loc.h
--- dwarf2loc.h	21 Feb 2003 15:24:17 -0000	1.1
+++ dwarf2loc.h	12 Mar 2003 22:03:18 -0000
@@ -24,8 +24,11 @@
 /* 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).  */
+/* The symbol location baton types used by the DWARF-2 reader (i.e.
+   SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol).  "struct
+   dwarf2_locexpr_baton" is for a symbol with a single location
+   expression; "struct dwarf2_loclist_baton" is for a symbol with a
+   location list.  */
 
 struct dwarf2_locexpr_baton
 {
@@ -34,6 +37,15 @@ struct dwarf2_locexpr_baton
   struct objfile *objfile;
 };
 
+struct dwarf2_loclist_baton
+{
+  CORE_ADDR base_address;
+  unsigned char *data;
+  unsigned short size;
+  struct objfile *objfile;
+};
+
 extern struct location_funcs dwarf2_locexpr_funcs;
+extern struct location_funcs dwarf2_loclist_funcs;
 
 #endif
Index: dwarf2read.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2read.c,v
retrieving revision 1.88
diff -u -p -r1.88 dwarf2read.c
--- dwarf2read.c	25 Feb 2003 21:36:17 -0000	1.88
+++ dwarf2read.c	12 Mar 2003 22:26:18 -0000
@@ -220,9 +220,13 @@ struct comp_unit_head
 
     struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
 
-    /* Pointer to the DIE associated with the compilation unit.  */
+    /* Base address of this compilation unit.  */
 
-    struct die_info *die;
+    CORE_ADDR base_address;
+
+    /* Non-zero if base_address has been set.  */
+
+    int base_known;
   };
 
 /* The line number information for a compilation unit (found in the
@@ -395,6 +399,7 @@ static char *dwarf_line_buffer;
 static char *dwarf_str_buffer;
 static char *dwarf_macinfo_buffer;
 static char *dwarf_ranges_buffer;
+static char *dwarf_loc_buffer;
 
 /* A zeroed version of a partial die for initialization purposes.  */
 static struct partial_die_info zeroed_partial_die;
@@ -511,6 +516,13 @@ struct dwarf2_pinfo
 
     unsigned int dwarf_ranges_size;
 
+    /* Pointer to start of dwarf locations buffer for the objfile.  */
+
+    char *dwarf_loc_buffer;
+
+    /* Size of dwarf locations buffer for the objfile.  */
+
+    unsigned int dwarf_loc_size;
   };
 
 #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
@@ -526,6 +538,8 @@ struct dwarf2_pinfo
 #define DWARF_MACINFO_SIZE(p)   (PST_PRIVATE(p)->dwarf_macinfo_size)
 #define DWARF_RANGES_BUFFER(p)  (PST_PRIVATE(p)->dwarf_ranges_buffer)
 #define DWARF_RANGES_SIZE(p)    (PST_PRIVATE(p)->dwarf_ranges_size)
+#define DWARF_LOC_BUFFER(p)     (PST_PRIVATE(p)->dwarf_loc_buffer)
+#define DWARF_LOC_SIZE(p)       (PST_PRIVATE(p)->dwarf_loc_size)
 
 /* Maintain an array of referenced fundamental types for the current
    compilation unit being read.  For DWARF version 1, we have to construct
@@ -926,6 +940,7 @@ dwarf2_has_info (bfd *abfd)
   dwarf_frame_offset = 0;
   dwarf_eh_frame_offset = 0;
   dwarf_ranges_offset = 0;
+  dwarf_loc_offset = 0;
   
   bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
   if (dwarf_info_offset && dwarf_abbrev_offset)
@@ -1062,6 +1077,14 @@ dwarf2_build_psymtabs (struct objfile *o
   else
     dwarf_ranges_buffer = NULL;
 
+  if (dwarf_loc_offset)
+    dwarf_loc_buffer = dwarf2_read_section (objfile,
+					    dwarf_loc_offset,
+					    dwarf_loc_size,
+					    dwarf_loc_section);
+  else
+    dwarf_loc_buffer = NULL;
+
   if (mainline
       || (objfile->global_psymbols.size == 0
 	  && objfile->static_psymbols.size == 0))
@@ -1283,6 +1306,8 @@ dwarf2_build_psymtabs_hard (struct objfi
       DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
       DWARF_RANGES_BUFFER (pst) = dwarf_ranges_buffer;
       DWARF_RANGES_SIZE (pst) = dwarf_ranges_size;
+      DWARF_LOC_BUFFER (pst) = dwarf_loc_buffer;
+      DWARF_LOC_SIZE (pst) = dwarf_loc_size;
       baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
       /* Store the function that reads in the rest of the symbol table */
@@ -1607,6 +1632,7 @@ psymtab_to_symtab_1 (struct partial_symt
   char *info_ptr;
   struct symtab *symtab;
   struct cleanup *back_to;
+  struct attribute *attr;
 
   /* Set local variables from the partial symbol table info.  */
   offset = DWARF_INFO_OFFSET (pst);
@@ -1621,6 +1647,8 @@ psymtab_to_symtab_1 (struct partial_symt
   dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
   dwarf_ranges_buffer = DWARF_RANGES_BUFFER (pst);
   dwarf_ranges_size = DWARF_RANGES_SIZE (pst);
+  dwarf_loc_buffer = DWARF_LOC_BUFFER (pst);
+  dwarf_loc_size = DWARF_LOC_SIZE (pst);
   baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
   cu_header_offset = offset;
   info_ptr = dwarf_info_buffer + offset;
@@ -1642,8 +1670,32 @@ psymtab_to_symtab_1 (struct partial_symt
 
   make_cleanup_free_die_list (dies);
 
+  /* Find the base address of the compilation unit for range lists and
+     location lists.  It will normally be specified by DW_AT_low_pc.
+     In DWARF-3 draft 4, the base address could be overridden by
+     DW_AT_entry_pc.  It's been removed, but GCC still uses this for
+     compilation units with discontinuous ranges.  */
+
+  cu_header.base_known = 0;
+  cu_header.base_address = 0;
+
+  attr = dwarf_attr (dies, DW_AT_entry_pc);
+  if (attr)
+    {
+      cu_header.base_address = DW_ADDR (attr);
+      cu_header.base_known = 1;
+    }
+  else
+    {
+      attr = dwarf_attr (dies, DW_AT_low_pc);
+      if (attr)
+	{
+	  cu_header.base_address = DW_ADDR (attr);
+	  cu_header.base_known = 1;
+	}
+    }
+
   /* Do line number decoding in read_file_scope () */
-  cu_header.die = dies;
   process_die (dies, objfile, &cu_header);
 
   if (!dwarf2_get_pc_bounds (dies, &lowpc, &highpc, objfile, &cu_header))
@@ -2122,40 +2174,18 @@ dwarf2_get_pc_bounds (struct die_info *d
 	     .debug_renges section.  */
 	  unsigned int offset = DW_UNSND (attr);
 	  /* Base address selection entry.  */
-	  CORE_ADDR base = 0;
-	  int found_base = 0;
+	  CORE_ADDR base;
+	  int found_base;
 	  int dummy;
 	  unsigned int i;
 	  char *buffer;
 	  CORE_ADDR marker;
 	  int low_set;
  
-	  /* The applicable base address is determined by (1) the closest
-	     preceding base address selection entry in the range list or
-	     (2) the DW_AT_low_pc of the compilation unit.  */
-
-	  /* ??? Was in dwarf3 draft4, and has since been removed.
-	     GCC still uses it though.  */
-	  attr = dwarf_attr (cu_header->die, DW_AT_entry_pc);
-	  if (attr)
-	    {
-	      base = DW_ADDR (attr);
-	      found_base = 1;
-	    }
-
-	  if (!found_base)
-	    {
-	      attr = dwarf_attr (cu_header->die, DW_AT_low_pc);
-	      if (attr)
-		{
-		  base = DW_ADDR (attr);
-		  found_base = 1;
-		}
-	    }
-
+	  found_base = cu_header->base_known;
+	  base = cu_header->base_address;
 	  buffer = dwarf_ranges_buffer + offset;
 
-
 	  /* Read in the largest possible address.  */
 	  marker = read_address (obfd, buffer, cu_header, &dummy);
 	  if ((marker & mask) == mask)
@@ -7328,26 +7358,53 @@ dwarf2_symbol_mark_computed (struct attr
 			     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))
+  if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
     {
-      dwarf2_complex_location_expr_complaint ();
-      return;
+      struct dwarf2_loclist_baton *baton;
+
+      baton = obstack_alloc (&objfile->symbol_obstack,
+			     sizeof (struct dwarf2_loclist_baton));
+      baton->objfile = objfile;
+
+      /* We don't know how long the location list is, but make sure we
+	 don't run off the edge of the section.  */
+      baton->size = dwarf_loc_size - DW_UNSND (attr);
+      baton->data = dwarf_loc_buffer + DW_UNSND (attr);
+      baton->base_address = cu_header->base_address;
+      if (cu_header->base_known == 0)
+	complaint (&symfile_complaints,
+		   "Location list used without specifying the CU base address.");
+
+      SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_loclist_funcs;
+      SYMBOL_LOCATION_BATON (sym) = baton;
     }
+  else
+    {
+      struct dwarf2_locexpr_baton *baton;
 
-  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;
+      baton = obstack_alloc (&objfile->symbol_obstack,
+			     sizeof (struct dwarf2_locexpr_baton));
+      baton->objfile = objfile;
 
-  SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs;
-  SYMBOL_LOCATION_BATON (sym) = baton;
+      if (attr_form_is_block (attr))
+	{
+	  /* 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;
+	}
+      else
+	{
+	  dwarf2_invalid_attrib_class_complaint ("location description",
+						 SYMBOL_NATURAL_NAME (sym));
+	  baton->size = 0;
+	  baton->data = NULL;
+	}
+      
+      SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs;
+      SYMBOL_LOCATION_BATON (sym) = baton;
+    }
 }


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: RFA: Location list support for DWARF-2
  2003-03-12 22:42   ` Daniel Jacobowitz
@ 2003-04-08 16:46     ` Daniel Jacobowitz
  2003-04-09  5:05     ` Jim Blandy
  1 sibling, 0 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2003-04-08 16:46 UTC (permalink / raw)
  To: gdb-patches; +Cc: Jim Blandy

Ping?  I never got any feedback on the updated patch.

On Wed, Mar 12, 2003 at 05:40:44PM -0500, Daniel Jacobowitz wrote:
> On Wed, Mar 12, 2003 at 04:37:20PM -0500, Jim Blandy wrote:
> > 
> > Daniel Jacobowitz <drow@mvista.com> writes:
> > > Here's initial support for location lists.  I'd like to take a moment
> > > to thank Jim Blandy and Daniel Berlin for hashing out the interface to
> > > LOC_COMPUTED so thoroughly; it turned out that I didn't need to do
> > > anything at all to the interface or to its clients in order to make
> > > this work.
> > > 
> > > To test this, you'll need a GCC CVS checkout from the "rtlopt-branch"
> > > branch tag.  This patch has no effect if location lists aren't used,
> > > and is a strict improvement if they are, since otherwise we won't find
> > > things at all.  However, debug output from that branch is still a
> > > little immature.  One problem I've noticed so far is that we emit
> > > incomplete location lists for global variables; see my post on the gcc@
> > > list for more details.  So sometimes we can't find globals, which is a
> > > regression in the debug info.
> > > 
> > > This patch also does not support multiple overlapping location lists;
> > > it simply uses the first match.  The rest of GDB isn't ready for
> > > multiple locations yet; that's down the list after DW_OP_piece I
> > > think.
> > > 
> > > I had to add the CU base address to each symbol's baton.  Long term we
> > > can get rid of it by making sure we can go from symbol to symtab and
> > > storing it in the symtab; I think that's a good idea but it's a patch
> > > for another day.
> > > 
> > > Jim, is this OK?  I'd appreciate another set of eyes on it.
> > 
> > Rather than putting 'if (foo->is_list)' everywhere, why not just
> > introduce a separate 'struct location_funcs' for location lists?
> > Aside from just being cleaner, you'll save a word in each baton.
> 
> Actually, it won't save any space to remove is_list: it goes into the
> padding between size and the following CORE_ADDR/pointer.  It does save
> space for non-location-list variables though, because of the base
> address, so I think it's a good idea.  It requires introducing one
> annoying hack in dwarf_expr_frame_base but I'm not terribly upset by
> it.
> 
> > 
> > > Index: dwarf2loc.c
> > > ===================================================================
> > > RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2loc.c,v
> > > retrieving revision 1.3
> > > diff -u -p -r1.3 dwarf2loc.c
> > > --- dwarf2loc.c	5 Mar 2003 18:00:02 -0000	1.3
> > > +++ dwarf2loc.c	10 Mar 2003 15:22:17 -0000
> > > @@ -40,6 +40,68 @@
> > >  #define DWARF2_REG_TO_REGNUM(REG) (REG)
> > >  #endif
> > >  
> > > +
> > > +/* A helper function for dealing with location lists.  Given a
> > > +   symbol baton (BATON) and a pc value (PC), find the appropriate
> > > +   location expression, set *LOCEXPR_LENGTH, and return a pointer
> > > +   to the beginning of the expression.  Returns NULL on failure.
> > > +
> > > +   For now, only return the first matching location expression; there
> > > +   can be more than one in the list.  */
> > > +
> > > +static char *
> > > +find_location_expression (struct dwarf2_locexpr_baton *baton,
> > > +			  int *locexpr_length, CORE_ADDR pc)
> > > +{
> > > +  CORE_ADDR base_address = baton->base_address;
> > > +  CORE_ADDR low, high;
> > > +  char *loc_ptr;
> > > +  unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT, length;
> > > +  CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
> > 
> > Why not just ~(~(CORE_ADDR)0 << (addr_size * 8))?
> 
> Suppose that sizeof(CORE_ADDR) == 4 and addr_size == 4.  That's a
> left-shift by 32; very bad C mojo.
> 
> By the way, Richard Henderson originally wrote this (although every
> copy of it in GDB has my name on it, he submitted the original
> DW_AT_ranges patch).  So he gets credit for getting this right.  I
> always get it wrong :)
> 
> > > +  if (! baton->is_list)
> > > +    {
> > > +      *locexpr_length = baton->size;
> > > +      return baton->data;
> > > +    }
> > > +
> > > +  loc_ptr = baton->data;
> > > +
> > > +  while (1)
> > > +    {
> > > +      low = dwarf2_read_address (loc_ptr, loc_ptr + addr_size, &length);
> > > +      loc_ptr += length;
> > > +      high = dwarf2_read_address (loc_ptr, loc_ptr + addr_size, &length);
> > > +      loc_ptr += length;
> > 
> > Shouldn't you pass baton->data + baton_size as the 'buf_end' argument?
> > You're defeating the range-checking that function performs.
> 
> Oops, this brings up a wart that I forgot to document.  The size value
> can't be trusted.  You suggested a fix for this below; I like it, so
> I'll use it :)
> 
> > 
> > > Index: dwarf2read.c
> > > ===================================================================
> > > RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2read.c,v
> > > retrieving revision 1.88
> > > diff -u -p -r1.88 dwarf2read.c
> > > --- dwarf2read.c	25 Feb 2003 21:36:17 -0000	1.88
> > > +++ dwarf2read.c	10 Mar 2003 05:01:11 -0000
> > > @@ -220,9 +220,13 @@ struct comp_unit_head
> > >  
> > >      struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
> > >  
> > > -    /* Pointer to the DIE associated with the compilation unit.  */
> > > +    /* Base address of this compilation unit.  */
> > >  
> > > -    struct die_info *die;
> > > +    CORE_ADDR base_address;
> > > +
> > > +    /* Flag representing whether base_address is accurate.  */
> > 
> > You can be more concrete: "Non-zero if base_address has been set."
> 
> Thanks.
> 
> 
> > 
> > > @@ -1642,8 +1670,32 @@ psymtab_to_symtab_1 (struct partial_symt
> > >  
> > >    make_cleanup_free_die_list (dies);
> > >  
> > > +  /* Find the base address of the compilation unit for range lists and
> > > +     location lists.  It will normally be specified by DW_AT_low_pc.
> > > +     In DWARF-3 draft 4, the base address could be overridden by
> > > +     DW_AT_entry_pc.  It's been removed, but GCC still uses this for
> > > +     compilation units with discontinuous ranges.  */
> > > +
> > > +  cu_header.base_known = 0;
> > > +  cu_header.base_address = 0;
> > > +
> > > +  attr = dwarf_attr (dies, DW_AT_entry_pc);
> > > +  if (attr)
> > > +    {
> > > +      cu_header.base_address = DW_ADDR (attr);
> > > +      cu_header.base_known = 0;
> > 
> > Shouldn't this set it to 1, not zero?
> 
> Uh, er, yes.  Told you I needed more eyes.  My tests all must have had
> a low_pc.
> 
> > 
> > > @@ -6481,6 +6511,7 @@ dump_die (struct die_info *die)
> > >  	case DW_FORM_ref1:
> > >  	case DW_FORM_ref2:
> > >  	case DW_FORM_ref4:
> > > +	case DW_FORM_ref8:
> > >  	case DW_FORM_udata:
> > >  	case DW_FORM_sdata:
> > >  	  fprintf_unfiltered (gdb_stderr, "constant: %ld", DW_UNSND (&die->attrs[i]));
> > 
> > This should be a separate patch (which you are welcome to commit).
> 
> OK.
> 
> > 
> > > @@ -7330,23 +7361,39 @@ dwarf2_symbol_mark_computed (struct attr
> > >  {
> > >    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;
> > > +  /* When support for location lists is added, this will go away.  */
> > 
> > This comment should go away, shouldn't it?
> 
> Thought it had.  Oopsie.
> 
> > 
> > > +  if (attr_form_is_block (attr))
> > > +    {
> > > +      /* 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;
> > > +      baton->is_list = 0;
> > > +    }
> > > +  else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
> > > +    {
> > > +      baton->size = 0;
> > 
> > We don't have good information about the range list's extent
> > available, but you should set this to 'dwarf_loc_size - DW_UNSND
> > (attr)' or something like that.
> 
> As above, sure.
> 
> > > +      baton->data = dwarf_loc_buffer + DW_UNSND (attr);
> > > +      baton->is_list = 1;
> > > +      baton->base_address = cu_header->base_address;
> > > +      if (cu_header->base_known == 0)
> > > +	complain (&symfile_complaints,
> > > +		  "Location list used without specifying the CU base address.");
> > 'complain' has been gone for a month and a half now.  You'd probably
> > better check this patch against more recent sources.
> 
> Uhm... I was using the current development sources.  My changelog
> includes the deletion of complain.  I apparently managed to change that
> to a complain() without recompiling.  I was shooting for complaint().
> Sorry 'bout that.
> 
> Here's a revision.
> 
> -- 
> Daniel Jacobowitz
> MontaVista Software                         Debian GNU/Linux Developer
> 
> 2003-03-10  Daniel Jacobowitz  <drow@mvista.com>
> 
> 	* dwarf2expr.c (dwarf2_read_address): Renamed from read_address;
> 	made non-static.
> 	(execute_stack_op): All callers updated.
> 	* dwarf2expr.h: Add prototype for dwarf2_read_address.
> 	* dwarf2loc.c (find_location_expression): New function.
> 	(dwarf_expr_frame_base): Call it.
> 	(dwarf2_tracepoint_var_ref): New function, broken out from
> 	locexpr_tracepoint_var_ref.
> 	(locexpr_tracepoint_var_ref): Call dwarf2_tracepoint_var_ref.
> 	Make static.
> 	(loclist_read_variable, loclist_read_needs_frame): New functions.
> 	(loclist_describe_location, loclist_tracepoint_var_ref): New
> 	functions.
> 	(dwarf2_loclist_funcs): New struct location_funcs.
> 	* dwarf2loc.h (struct dwarf2_loclist_baton): New.
> 	(dwarf2_loclist_funcs): New extern.
> 	* dwarf2read.c (struct comp_unit_head): Remove DIE member, add
> 	base_address and base_known.
> 	(dwarf_loc_buffer): New variable.
> 	(struct dwarf2_pinfo): Add dwarf_loc_buffer and dwarf_loc_size.
> 	(DWARF_LOC_BUFFER, DWARF_LOC_SIZE): New macros.
> 	(dwarf2_has_info): Initialize dwarf_loc_offset.
> 	(dwarf2_build_psymtabs): Read in .debug_loc.
> 	(dwarf2_build_psymtabs_hard): Use DWARF_LOC_BUFFER and
> 	DWARF_LOC_SIZE.
> 	(psymtab_to_symtab_1): Likewise.  Move base address calculation
> 	here, from...
> 	(dwarf2_get_pc_bounds): ... here.  Use the base address from
> 	cu_header.
> 	(dwarf2_symbol_mark_computed): Handle location lists.
> 
> Index: dwarf2expr.c
> ===================================================================
> RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2expr.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 dwarf2expr.c
> --- dwarf2expr.c	5 Mar 2003 18:00:02 -0000	1.3
> +++ dwarf2expr.c	10 Mar 2003 00:30:18 -0000
> @@ -170,13 +170,13 @@ read_sleb128 (unsigned char *buf, unsign
>     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
> +dwarf2_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.");
> +    error ("dwarf2_read_address: Corrupted DWARF expression.");
>  
>    *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
>    result = extract_address (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT);
> @@ -277,7 +277,7 @@ execute_stack_op (struct dwarf_expr_cont
>  	  break;
>  
>  	case DW_OP_addr:
> -	  result = read_address (op_ptr, op_end, &bytes_read);
> +	  result = dwarf2_read_address (op_ptr, op_end, &bytes_read);
>  	  op_ptr += bytes_read;
>  	  break;
>  
> @@ -464,9 +464,10 @@ execute_stack_op (struct dwarf_expr_cont
>  
>  		(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 = dwarf2_read_address (buf,
> +					      buf + (TARGET_ADDR_BIT
> +						     / TARGET_CHAR_BIT),
> +					      &bytes_read);
>  	      }
>  	    result = result + offset;
>  	    ctx->stack_len = before_stack_len;
> @@ -525,9 +526,10 @@ execute_stack_op (struct dwarf_expr_cont
>  
>  		(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 = dwarf2_read_address (buf,
> +					      buf + (TARGET_ADDR_BIT
> +						     / TARGET_CHAR_BIT),
> +					      &bytes_read);
>  	      }
>  	      break;
>  
> @@ -537,9 +539,10 @@ execute_stack_op (struct dwarf_expr_cont
>  		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);
> +		result = dwarf2_read_address (buf,
> +					      buf + (TARGET_ADDR_BIT
> +						     / TARGET_CHAR_BIT),
> +					      &bytes_read);
>  	      }
>  	      break;
>  
> Index: dwarf2expr.h
> ===================================================================
> RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2expr.h,v
> retrieving revision 1.2
> diff -u -p -r1.2 dwarf2expr.h
> --- dwarf2expr.h	28 Feb 2003 20:03:18 -0000	1.2
> +++ dwarf2expr.h	10 Mar 2003 00:30:37 -0000
> @@ -99,5 +99,7 @@ unsigned char *read_uleb128 (unsigned ch
>  			     ULONGEST * r);
>  unsigned char *read_sleb128 (unsigned char *buf, unsigned char *buf_end,
>  			     LONGEST * r);
> +CORE_ADDR dwarf2_read_address (unsigned char *buf, unsigned char *buf_end,
> +			       int *bytes_read);
>  
>  #endif
> Index: dwarf2loc.c
> ===================================================================
> RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2loc.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 dwarf2loc.c
> --- dwarf2loc.c	5 Mar 2003 18:00:02 -0000	1.3
> +++ dwarf2loc.c	12 Mar 2003 22:37:23 -0000
> @@ -40,6 +40,62 @@
>  #define DWARF2_REG_TO_REGNUM(REG) (REG)
>  #endif
>  
> +/* A helper function for dealing with location lists.  Given a
> +   symbol baton (BATON) and a pc value (PC), find the appropriate
> +   location expression, set *LOCEXPR_LENGTH, and return a pointer
> +   to the beginning of the expression.  Returns NULL on failure.
> +
> +   For now, only return the first matching location expression; there
> +   can be more than one in the list.  */
> +
> +static char *
> +find_location_expression (struct dwarf2_loclist_baton *baton,
> +			  int *locexpr_length, CORE_ADDR pc)
> +{
> +  CORE_ADDR base_address = baton->base_address;
> +  CORE_ADDR low, high;
> +  char *loc_ptr, *buf_end;
> +  unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT, length;
> +  CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
> +
> +  loc_ptr = baton->data;
> +  buf_end = baton->data + baton->size;
> +
> +  while (1)
> +    {
> +      low = dwarf2_read_address (loc_ptr, buf_end, &length);
> +      loc_ptr += length;
> +      high = dwarf2_read_address (loc_ptr, buf_end, &length);
> +      loc_ptr += length;
> +
> +      /* An end-of-list entry.  */
> +      if (low == 0 && high == 0)
> +	return NULL;
> +
> +      /* A base-address-selection entry.  */
> +      if ((low & base_mask) == base_mask)
> +	{
> +	  base_address = high;
> +	  continue;
> +	}
> +
> +      /* Otherwise, a location expression entry.  */
> +      low += base_address;
> +      high += base_address;
> +
> +      length = extract_unsigned_integer (loc_ptr, 2);
> +      loc_ptr += 2;
> +
> +      if (pc >= low && pc < high)
> +	{
> +	  *locexpr_length = length;
> +	  return loc_ptr;
> +	}
> +
> +      loc_ptr += length;
> +    }
> +}
> +
>  /* This is the baton used when performing dwarf2 expression
>     evaluation.  */
>  struct dwarf_expr_baton
> @@ -88,12 +144,28 @@ 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;
> +
> +  if (SYMBOL_LOCATION_FUNCS (framefunc) == &dwarf2_loclist_funcs)
> +    {
> +      struct dwarf2_loclist_baton *symbaton;
> +      symbaton = SYMBOL_LOCATION_BATON (framefunc);
> +      *start = find_location_expression (symbaton, length,
> +					 get_frame_pc (debaton->frame));
> +    }
> +  else
> +    {
> +      struct dwarf2_locexpr_baton *symbaton;
> +      symbaton = SYMBOL_LOCATION_BATON (framefunc);
> +      *length = symbaton->size;
> +      *start = symbaton->data;
> +    }
> +
> +  if (*start == NULL)
> +    error ("Could not find the frame base for \"%s\".",
> +	   SYMBOL_NATURAL_NAME (framefunc));
>  }
>  
>  /* Using the objfile specified in BATON, find the address for the
> @@ -238,8 +310,55 @@ dwarf2_loc_desc_needs_frame (unsigned ch
>    return baton.needs_frame;
>  }
>  
> +static void
> +dwarf2_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
> +			   struct axs_value * value, unsigned char *data,
> +			   int size)
> +{
> +  if (size == 0)
> +    error ("Symbol \"%s\" has been optimized out.",
> +	   SYMBOL_PRINT_NAME (symbol));
>  
> +  if (size == 1
> +      && data[0] >= DW_OP_reg0
> +      && data[0] <= DW_OP_reg31)
> +    {
> +      value->kind = axs_lvalue_register;
> +      value->u.reg = data[0] - DW_OP_reg0;
> +    }
> +  else if (data[0] == DW_OP_regx)
> +    {
> +      ULONGEST reg;
> +      read_uleb128 (data + 1, data + size, &reg);
> +      value->kind = axs_lvalue_register;
> +      value->u.reg = reg;
> +    }
> +  else if (data[0] == DW_OP_fbreg)
> +    {
> +      /* And this is worse than just minimal; we should honor the frame base
> +	 as above.  */
> +      int frame_reg;
> +      LONGEST frame_offset;
> +      unsigned char *buf_end;
> +
> +      buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
> +      if (buf_end != data + size)
> +	error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
> +	       SYMBOL_PRINT_NAME (symbol));
>  
> +      TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
> +      ax_reg (ax, frame_reg);
> +      ax_const_l (ax, frame_offset);
> +      ax_simple (ax, aop_add);
> +
> +      ax_const_l (ax, frame_offset);
> +      ax_simple (ax, aop_add);
> +      value->kind = axs_lvalue_memory;
> +    }
> +  else
> +    error ("Unsupported DWARF opcode in the location of \"%s\".",
> +	   SYMBOL_PRINT_NAME (symbol));
> +}
>  \f
>  /* Return the value of SYMBOL in FRAME using the DWARF-2 expression
>     evaluator to calculate the location.  */
> @@ -293,57 +412,13 @@ locexpr_describe_location (struct symbol
>     publicly available stub with tracepoint support for me to test
>     against.  When there is one this function should be revisited.  */
>  
> -void
> +static void
>  locexpr_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
>  			    struct axs_value * value)
>  {
>    struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
>  
> -  if (dlbaton->size == 0)
> -    error ("Symbol \"%s\" has been optimized out.",
> -	   SYMBOL_PRINT_NAME (symbol));
> -
> -  if (dlbaton->size == 1
> -      && dlbaton->data[0] >= DW_OP_reg0
> -      && dlbaton->data[0] <= DW_OP_reg31)
> -    {
> -      value->kind = axs_lvalue_register;
> -      value->u.reg = dlbaton->data[0] - DW_OP_reg0;
> -    }
> -  else if (dlbaton->data[0] == DW_OP_regx)
> -    {
> -      ULONGEST reg;
> -      read_uleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
> -		    &reg);
> -      value->kind = axs_lvalue_register;
> -      value->u.reg = reg;
> -    }
> -  else if (dlbaton->data[0] == DW_OP_fbreg)
> -    {
> -      /* And this is worse than just minimal; we should honor the frame base
> -	 as above.  */
> -      int frame_reg;
> -      LONGEST frame_offset;
> -      unsigned char *buf_end;
> -
> -      buf_end = read_sleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
> -			      &frame_offset);
> -      if (buf_end != dlbaton->data + dlbaton->size)
> -	error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
> -	       SYMBOL_PRINT_NAME (symbol));
> -
> -      TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
> -      ax_reg (ax, frame_reg);
> -      ax_const_l (ax, frame_offset);
> -      ax_simple (ax, aop_add);
> -
> -      ax_const_l (ax, frame_offset);
> -      ax_simple (ax, aop_add);
> -      value->kind = axs_lvalue_memory;
> -    }
> -  else
> -    error ("Unsupported DWARF opcode in the location of \"%s\".",
> -	   SYMBOL_PRINT_NAME (symbol));
> +  dwarf2_tracepoint_var_ref (symbol, ax, value, dlbaton->data, dlbaton->size);
>  }
>  
>  /* The set of location functions used with the DWARF-2 expression
> @@ -353,4 +428,76 @@ struct location_funcs dwarf2_locexpr_fun
>    locexpr_read_needs_frame,
>    locexpr_describe_location,
>    locexpr_tracepoint_var_ref
> +};
> +
> +
> +/* Wrapper functions for location lists.  These generally find
> +   the appropriate location expression and call something above.  */
> +
> +/* Return the value of SYMBOL in FRAME using the DWARF-2 expression
> +   evaluator to calculate the location.  */
> +static struct value *
> +loclist_read_variable (struct symbol *symbol, struct frame_info *frame)
> +{
> +  struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
> +  struct value *val;
> +  unsigned char *data;
> +  int size;
> +
> +  data = find_location_expression (dlbaton, &size,
> +				   frame ? get_frame_pc (frame) : 0);
> +  if (data == NULL)
> +    error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
> +
> +  val = dwarf2_evaluate_loc_desc (symbol, frame, data, size, dlbaton->objfile);
> +
> +  return val;
> +}
> +
> +/* Return non-zero iff we need a frame to evaluate SYMBOL.  */
> +static int
> +loclist_read_needs_frame (struct symbol *symbol)
> +{
> +  /* If there's a location list, then assume we need to have a frame
> +     to choose the appropriate location expression.  With tracking of
> +     global variables this is not necessarily true, but such tracking
> +     is disabled in GCC at the moment until we figure out how to
> +     represent it.  */
> +
> +  return 1;
> +}
> +
> +/* Print a natural-language description of SYMBOL to STREAM.  */
> +static int
> +loclist_describe_location (struct symbol *symbol, struct ui_file *stream)
> +{
> +  /* FIXME: Could print the entire list of locations.  */
> +  fprintf_filtered (stream, "a variable with multiple locations");
> +  return 1;
> +}
> +
> +/* Describe the location of SYMBOL as an agent value in VALUE, generating
> +   any necessary bytecode in AX.  */
> +static void
> +loclist_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
> +			    struct axs_value * value)
> +{
> +  struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
> +  unsigned char *data;
> +  int size;
> +
> +  data = find_location_expression (dlbaton, &size, ax->scope);
> +  if (data == NULL)
> +    error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
> +
> +  dwarf2_tracepoint_var_ref (symbol, ax, value, data, size);
> +}
> +
> +/* The set of location functions used with the DWARF-2 expression
> +   evaluator and location lists.  */
> +struct location_funcs dwarf2_loclist_funcs = {
> +  loclist_read_variable,
> +  loclist_read_needs_frame,
> +  loclist_describe_location,
> +  loclist_tracepoint_var_ref
>  };
> Index: dwarf2loc.h
> ===================================================================
> RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2loc.h,v
> retrieving revision 1.1
> diff -u -p -r1.1 dwarf2loc.h
> --- dwarf2loc.h	21 Feb 2003 15:24:17 -0000	1.1
> +++ dwarf2loc.h	12 Mar 2003 22:03:18 -0000
> @@ -24,8 +24,11 @@
>  /* 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).  */
> +/* The symbol location baton types used by the DWARF-2 reader (i.e.
> +   SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol).  "struct
> +   dwarf2_locexpr_baton" is for a symbol with a single location
> +   expression; "struct dwarf2_loclist_baton" is for a symbol with a
> +   location list.  */
>  
>  struct dwarf2_locexpr_baton
>  {
> @@ -34,6 +37,15 @@ struct dwarf2_locexpr_baton
>    struct objfile *objfile;
>  };
>  
> +struct dwarf2_loclist_baton
> +{
> +  CORE_ADDR base_address;
> +  unsigned char *data;
> +  unsigned short size;
> +  struct objfile *objfile;
> +};
> +
>  extern struct location_funcs dwarf2_locexpr_funcs;
> +extern struct location_funcs dwarf2_loclist_funcs;
>  
>  #endif
> Index: dwarf2read.c
> ===================================================================
> RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2read.c,v
> retrieving revision 1.88
> diff -u -p -r1.88 dwarf2read.c
> --- dwarf2read.c	25 Feb 2003 21:36:17 -0000	1.88
> +++ dwarf2read.c	12 Mar 2003 22:26:18 -0000
> @@ -220,9 +220,13 @@ struct comp_unit_head
>  
>      struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
>  
> -    /* Pointer to the DIE associated with the compilation unit.  */
> +    /* Base address of this compilation unit.  */
>  
> -    struct die_info *die;
> +    CORE_ADDR base_address;
> +
> +    /* Non-zero if base_address has been set.  */
> +
> +    int base_known;
>    };
>  
>  /* The line number information for a compilation unit (found in the
> @@ -395,6 +399,7 @@ static char *dwarf_line_buffer;
>  static char *dwarf_str_buffer;
>  static char *dwarf_macinfo_buffer;
>  static char *dwarf_ranges_buffer;
> +static char *dwarf_loc_buffer;
>  
>  /* A zeroed version of a partial die for initialization purposes.  */
>  static struct partial_die_info zeroed_partial_die;
> @@ -511,6 +516,13 @@ struct dwarf2_pinfo
>  
>      unsigned int dwarf_ranges_size;
>  
> +    /* Pointer to start of dwarf locations buffer for the objfile.  */
> +
> +    char *dwarf_loc_buffer;
> +
> +    /* Size of dwarf locations buffer for the objfile.  */
> +
> +    unsigned int dwarf_loc_size;
>    };
>  
>  #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
> @@ -526,6 +538,8 @@ struct dwarf2_pinfo
>  #define DWARF_MACINFO_SIZE(p)   (PST_PRIVATE(p)->dwarf_macinfo_size)
>  #define DWARF_RANGES_BUFFER(p)  (PST_PRIVATE(p)->dwarf_ranges_buffer)
>  #define DWARF_RANGES_SIZE(p)    (PST_PRIVATE(p)->dwarf_ranges_size)
> +#define DWARF_LOC_BUFFER(p)     (PST_PRIVATE(p)->dwarf_loc_buffer)
> +#define DWARF_LOC_SIZE(p)       (PST_PRIVATE(p)->dwarf_loc_size)
>  
>  /* Maintain an array of referenced fundamental types for the current
>     compilation unit being read.  For DWARF version 1, we have to construct
> @@ -926,6 +940,7 @@ dwarf2_has_info (bfd *abfd)
>    dwarf_frame_offset = 0;
>    dwarf_eh_frame_offset = 0;
>    dwarf_ranges_offset = 0;
> +  dwarf_loc_offset = 0;
>    
>    bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
>    if (dwarf_info_offset && dwarf_abbrev_offset)
> @@ -1062,6 +1077,14 @@ dwarf2_build_psymtabs (struct objfile *o
>    else
>      dwarf_ranges_buffer = NULL;
>  
> +  if (dwarf_loc_offset)
> +    dwarf_loc_buffer = dwarf2_read_section (objfile,
> +					    dwarf_loc_offset,
> +					    dwarf_loc_size,
> +					    dwarf_loc_section);
> +  else
> +    dwarf_loc_buffer = NULL;
> +
>    if (mainline
>        || (objfile->global_psymbols.size == 0
>  	  && objfile->static_psymbols.size == 0))
> @@ -1283,6 +1306,8 @@ dwarf2_build_psymtabs_hard (struct objfi
>        DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
>        DWARF_RANGES_BUFFER (pst) = dwarf_ranges_buffer;
>        DWARF_RANGES_SIZE (pst) = dwarf_ranges_size;
> +      DWARF_LOC_BUFFER (pst) = dwarf_loc_buffer;
> +      DWARF_LOC_SIZE (pst) = dwarf_loc_size;
>        baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
>  
>        /* Store the function that reads in the rest of the symbol table */
> @@ -1607,6 +1632,7 @@ psymtab_to_symtab_1 (struct partial_symt
>    char *info_ptr;
>    struct symtab *symtab;
>    struct cleanup *back_to;
> +  struct attribute *attr;
>  
>    /* Set local variables from the partial symbol table info.  */
>    offset = DWARF_INFO_OFFSET (pst);
> @@ -1621,6 +1647,8 @@ psymtab_to_symtab_1 (struct partial_symt
>    dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
>    dwarf_ranges_buffer = DWARF_RANGES_BUFFER (pst);
>    dwarf_ranges_size = DWARF_RANGES_SIZE (pst);
> +  dwarf_loc_buffer = DWARF_LOC_BUFFER (pst);
> +  dwarf_loc_size = DWARF_LOC_SIZE (pst);
>    baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
>    cu_header_offset = offset;
>    info_ptr = dwarf_info_buffer + offset;
> @@ -1642,8 +1670,32 @@ psymtab_to_symtab_1 (struct partial_symt
>  
>    make_cleanup_free_die_list (dies);
>  
> +  /* Find the base address of the compilation unit for range lists and
> +     location lists.  It will normally be specified by DW_AT_low_pc.
> +     In DWARF-3 draft 4, the base address could be overridden by
> +     DW_AT_entry_pc.  It's been removed, but GCC still uses this for
> +     compilation units with discontinuous ranges.  */
> +
> +  cu_header.base_known = 0;
> +  cu_header.base_address = 0;
> +
> +  attr = dwarf_attr (dies, DW_AT_entry_pc);
> +  if (attr)
> +    {
> +      cu_header.base_address = DW_ADDR (attr);
> +      cu_header.base_known = 1;
> +    }
> +  else
> +    {
> +      attr = dwarf_attr (dies, DW_AT_low_pc);
> +      if (attr)
> +	{
> +	  cu_header.base_address = DW_ADDR (attr);
> +	  cu_header.base_known = 1;
> +	}
> +    }
> +
>    /* Do line number decoding in read_file_scope () */
> -  cu_header.die = dies;
>    process_die (dies, objfile, &cu_header);
>  
>    if (!dwarf2_get_pc_bounds (dies, &lowpc, &highpc, objfile, &cu_header))
> @@ -2122,40 +2174,18 @@ dwarf2_get_pc_bounds (struct die_info *d
>  	     .debug_renges section.  */
>  	  unsigned int offset = DW_UNSND (attr);
>  	  /* Base address selection entry.  */
> -	  CORE_ADDR base = 0;
> -	  int found_base = 0;
> +	  CORE_ADDR base;
> +	  int found_base;
>  	  int dummy;
>  	  unsigned int i;
>  	  char *buffer;
>  	  CORE_ADDR marker;
>  	  int low_set;
>   
> -	  /* The applicable base address is determined by (1) the closest
> -	     preceding base address selection entry in the range list or
> -	     (2) the DW_AT_low_pc of the compilation unit.  */
> -
> -	  /* ??? Was in dwarf3 draft4, and has since been removed.
> -	     GCC still uses it though.  */
> -	  attr = dwarf_attr (cu_header->die, DW_AT_entry_pc);
> -	  if (attr)
> -	    {
> -	      base = DW_ADDR (attr);
> -	      found_base = 1;
> -	    }
> -
> -	  if (!found_base)
> -	    {
> -	      attr = dwarf_attr (cu_header->die, DW_AT_low_pc);
> -	      if (attr)
> -		{
> -		  base = DW_ADDR (attr);
> -		  found_base = 1;
> -		}
> -	    }
> -
> +	  found_base = cu_header->base_known;
> +	  base = cu_header->base_address;
>  	  buffer = dwarf_ranges_buffer + offset;
>  
> -
>  	  /* Read in the largest possible address.  */
>  	  marker = read_address (obfd, buffer, cu_header, &dummy);
>  	  if ((marker & mask) == mask)
> @@ -7328,26 +7358,53 @@ dwarf2_symbol_mark_computed (struct attr
>  			     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))
> +  if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
>      {
> -      dwarf2_complex_location_expr_complaint ();
> -      return;
> +      struct dwarf2_loclist_baton *baton;
> +
> +      baton = obstack_alloc (&objfile->symbol_obstack,
> +			     sizeof (struct dwarf2_loclist_baton));
> +      baton->objfile = objfile;
> +
> +      /* We don't know how long the location list is, but make sure we
> +	 don't run off the edge of the section.  */
> +      baton->size = dwarf_loc_size - DW_UNSND (attr);
> +      baton->data = dwarf_loc_buffer + DW_UNSND (attr);
> +      baton->base_address = cu_header->base_address;
> +      if (cu_header->base_known == 0)
> +	complaint (&symfile_complaints,
> +		   "Location list used without specifying the CU base address.");
> +
> +      SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_loclist_funcs;
> +      SYMBOL_LOCATION_BATON (sym) = baton;
>      }
> +  else
> +    {
> +      struct dwarf2_locexpr_baton *baton;
>  
> -  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;
> +      baton = obstack_alloc (&objfile->symbol_obstack,
> +			     sizeof (struct dwarf2_locexpr_baton));
> +      baton->objfile = objfile;
>  
> -  SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs;
> -  SYMBOL_LOCATION_BATON (sym) = baton;
> +      if (attr_form_is_block (attr))
> +	{
> +	  /* 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;
> +	}
> +      else
> +	{
> +	  dwarf2_invalid_attrib_class_complaint ("location description",
> +						 SYMBOL_NATURAL_NAME (sym));
> +	  baton->size = 0;
> +	  baton->data = NULL;
> +	}
> +      
> +      SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs;
> +      SYMBOL_LOCATION_BATON (sym) = baton;
> +    }
>  }
> 

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: RFA: Location list support for DWARF-2
  2003-03-12 22:42   ` Daniel Jacobowitz
  2003-04-08 16:46     ` Daniel Jacobowitz
@ 2003-04-09  5:05     ` Jim Blandy
  2003-04-13 15:43       ` Daniel Jacobowitz
  1 sibling, 1 reply; 6+ messages in thread
From: Jim Blandy @ 2003-04-09  5:05 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches


This looks good to me --- please commit it, once you've addressed the
minor things I mention here.

(Yay!)

Daniel Jacobowitz <drow@mvista.com> writes:
> > Rather than putting 'if (foo->is_list)' everywhere, why not just
> > introduce a separate 'struct location_funcs' for location lists?
> > Aside from just being cleaner, you'll save a word in each baton.
> 
> Actually, it won't save any space to remove is_list: it goes into the
> padding between size and the following CORE_ADDR/pointer.  It does save
> space for non-location-list variables though, because of the base
> address, so I think it's a good idea.

Okay, I think that's a big improvement.

> It requires introducing one annoying hack in dwarf_expr_frame_base
> but I'm not terribly upset by it.

I can think of a nice solution in C++, but it would lose so much in
the translation to C that it's not worth it.


> +struct dwarf2_loclist_baton
> +{
> +  CORE_ADDR base_address;
> +  unsigned char *data;
> +  unsigned short size;
> +  struct objfile *objfile;
> +};

The fields of this structure need to be documented, as do those of
dwarf2_locexpr_baton.


> +	{
> +	  dwarf2_invalid_attrib_class_complaint ("location description",
> +						 SYMBOL_NATURAL_NAME (sym));
> +	  baton->size = 0;
> +	  baton->data = NULL;
> +	}

dwarf2_evaluate_loc_desc isn't prepared to handle this; it'll get an
error when it tries to fetch the top value off the stack after
evaluating no location instructions, won't it?  It should probably
return a value with its "optimized_out" flag set.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: RFA: Location list support for DWARF-2
  2003-04-09  5:05     ` Jim Blandy
@ 2003-04-13 15:43       ` Daniel Jacobowitz
  0 siblings, 0 replies; 6+ messages in thread
From: Daniel Jacobowitz @ 2003-04-13 15:43 UTC (permalink / raw)
  To: Jim Blandy; +Cc: gdb-patches

On Wed, Apr 09, 2003 at 12:06:37AM -0500, Jim Blandy wrote:
> 
> This looks good to me --- please commit it, once you've addressed the
> minor things I mention here.
> 
> (Yay!)
> 
> Daniel Jacobowitz <drow@mvista.com> writes:
> > > Rather than putting 'if (foo->is_list)' everywhere, why not just
> > > introduce a separate 'struct location_funcs' for location lists?
> > > Aside from just being cleaner, you'll save a word in each baton.
> > 
> > Actually, it won't save any space to remove is_list: it goes into the
> > padding between size and the following CORE_ADDR/pointer.  It does save
> > space for non-location-list variables though, because of the base
> > address, so I think it's a good idea.
> 
> Okay, I think that's a big improvement.
> 
> > It requires introducing one annoying hack in dwarf_expr_frame_base
> > but I'm not terribly upset by it.
> 
> I can think of a nice solution in C++, but it would lose so much in
> the translation to C that it's not worth it.
> 
> 
> > +struct dwarf2_loclist_baton
> > +{
> > +  CORE_ADDR base_address;
> > +  unsigned char *data;
> > +  unsigned short size;
> > +  struct objfile *objfile;
> > +};
> 
> The fields of this structure need to be documented, as do those of
> dwarf2_locexpr_baton.

Fixed.

> > +	{
> > +	  dwarf2_invalid_attrib_class_complaint ("location description",
> > +						 SYMBOL_NATURAL_NAME (sym));
> > +	  baton->size = 0;
> > +	  baton->data = NULL;
> > +	}
> 
> dwarf2_evaluate_loc_desc isn't prepared to handle this; it'll get an
> error when it tries to fetch the top value off the stack after
> evaluating no location instructions, won't it?  It should probably
> return a value with its "optimized_out" flag set.

Sure, sounds good to me.  Here's the updated patch I checked in.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2003-04-13  Daniel Jacobowitz  <drow@mvista.com>

	* dwarf2expr.c (dwarf2_read_address): Renamed from read_address;
	made non-static.
	(execute_stack_op): All callers updated.
	* dwarf2expr.h: Add prototype for dwarf2_read_address.
	* dwarf2loc.c (find_location_expression): New function.
	(dwarf_expr_frame_base): Call it.
	(dwarf2_evaluate_loc_desc): Handle 0-length location expressions.
	(dwarf2_tracepoint_var_ref): New function, broken out from
	locexpr_tracepoint_var_ref.
	(locexpr_tracepoint_var_ref): Call dwarf2_tracepoint_var_ref.
	Make static.
	(loclist_read_variable, loclist_read_needs_frame): New functions.
	(loclist_describe_location, loclist_tracepoint_var_ref): New
	functions.
	(dwarf2_loclist_funcs): New struct location_funcs.
	* dwarf2loc.h (struct dwarf2_loclist_baton): New type.
	(struct dwarf2_locexpr_baton): Add comments.
	(dwarf2_loclist_funcs): New extern.
	* dwarf2read.c (struct comp_unit_head): Remove DIE member, add
	base_address and base_known.
	(dwarf_loc_buffer): New variable.
	(struct dwarf2_pinfo): Add dwarf_loc_buffer and dwarf_loc_size.
	(DWARF_LOC_BUFFER, DWARF_LOC_SIZE): New macros.
	(dwarf2_has_info): Initialize dwarf_loc_offset.
	(dwarf2_build_psymtabs): Read in .debug_loc.
	(dwarf2_build_psymtabs_hard): Use DWARF_LOC_BUFFER and
	DWARF_LOC_SIZE.
	(psymtab_to_symtab_1): Likewise.  Move base address calculation
	here, from...
	(dwarf2_get_pc_bounds): ... here.  Use the base address from
	cu_header.
	(dwarf2_symbol_mark_computed): Handle location lists.

Index: gdb/dwarf2expr.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2expr.c,v
retrieving revision 1.4
diff -u -p -r1.4 dwarf2expr.c
--- gdb/dwarf2expr.c	1 Apr 2003 19:11:01 -0000	1.4
+++ gdb/dwarf2expr.c	13 Apr 2003 15:41:31 -0000
@@ -170,13 +170,13 @@ read_sleb128 (unsigned char *buf, unsign
    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
+dwarf2_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.");
+    error ("dwarf2_read_address: Corrupted DWARF expression.");
 
   *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
   result = extract_address (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT);
@@ -277,7 +277,7 @@ execute_stack_op (struct dwarf_expr_cont
 	  break;
 
 	case DW_OP_addr:
-	  result = read_address (op_ptr, op_end, &bytes_read);
+	  result = dwarf2_read_address (op_ptr, op_end, &bytes_read);
 	  op_ptr += bytes_read;
 	  break;
 
@@ -467,9 +467,10 @@ execute_stack_op (struct dwarf_expr_cont
 
 		(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 = dwarf2_read_address (buf,
+					      buf + (TARGET_ADDR_BIT
+						     / TARGET_CHAR_BIT),
+					      &bytes_read);
 	      }
 	    result = result + offset;
 	    ctx->stack_len = before_stack_len;
@@ -528,9 +529,10 @@ execute_stack_op (struct dwarf_expr_cont
 
 		(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 = dwarf2_read_address (buf,
+					      buf + (TARGET_ADDR_BIT
+						     / TARGET_CHAR_BIT),
+					      &bytes_read);
 	      }
 	      break;
 
@@ -540,9 +542,10 @@ execute_stack_op (struct dwarf_expr_cont
 		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);
+		result = dwarf2_read_address (buf,
+					      buf + (TARGET_ADDR_BIT
+						     / TARGET_CHAR_BIT),
+					      &bytes_read);
 	      }
 	      break;
 
Index: gdb/dwarf2expr.h
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2expr.h,v
retrieving revision 1.2
diff -u -p -r1.2 dwarf2expr.h
--- gdb/dwarf2expr.h	28 Feb 2003 20:03:18 -0000	1.2
+++ gdb/dwarf2expr.h	13 Apr 2003 15:41:31 -0000
@@ -99,5 +99,7 @@ unsigned char *read_uleb128 (unsigned ch
 			     ULONGEST * r);
 unsigned char *read_sleb128 (unsigned char *buf, unsigned char *buf_end,
 			     LONGEST * r);
+CORE_ADDR dwarf2_read_address (unsigned char *buf, unsigned char *buf_end,
+			       int *bytes_read);
 
 #endif
Index: gdb/dwarf2loc.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2loc.c,v
retrieving revision 1.4
diff -u -p -r1.4 dwarf2loc.c
--- gdb/dwarf2loc.c	1 Apr 2003 19:11:01 -0000	1.4
+++ gdb/dwarf2loc.c	13 Apr 2003 15:41:32 -0000
@@ -40,6 +40,62 @@
 #define DWARF2_REG_TO_REGNUM(REG) (REG)
 #endif
 
+/* A helper function for dealing with location lists.  Given a
+   symbol baton (BATON) and a pc value (PC), find the appropriate
+   location expression, set *LOCEXPR_LENGTH, and return a pointer
+   to the beginning of the expression.  Returns NULL on failure.
+
+   For now, only return the first matching location expression; there
+   can be more than one in the list.  */
+
+static char *
+find_location_expression (struct dwarf2_loclist_baton *baton,
+			  int *locexpr_length, CORE_ADDR pc)
+{
+  CORE_ADDR base_address = baton->base_address;
+  CORE_ADDR low, high;
+  char *loc_ptr, *buf_end;
+  unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT, length;
+  CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
+
+  loc_ptr = baton->data;
+  buf_end = baton->data + baton->size;
+
+  while (1)
+    {
+      low = dwarf2_read_address (loc_ptr, buf_end, &length);
+      loc_ptr += length;
+      high = dwarf2_read_address (loc_ptr, buf_end, &length);
+      loc_ptr += length;
+
+      /* An end-of-list entry.  */
+      if (low == 0 && high == 0)
+	return NULL;
+
+      /* A base-address-selection entry.  */
+      if ((low & base_mask) == base_mask)
+	{
+	  base_address = high;
+	  continue;
+	}
+
+      /* Otherwise, a location expression entry.  */
+      low += base_address;
+      high += base_address;
+
+      length = extract_unsigned_integer (loc_ptr, 2);
+      loc_ptr += 2;
+
+      if (pc >= low && pc < high)
+	{
+	  *locexpr_length = length;
+	  return loc_ptr;
+	}
+
+      loc_ptr += length;
+    }
+}
+
 /* This is the baton used when performing dwarf2 expression
    evaluation.  */
 struct dwarf_expr_baton
@@ -91,12 +147,28 @@ dwarf_expr_frame_base (void *baton, unsi
      get_frame_base_address(), and then implement a dwarf2 specific
      this_base method.  */
   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;
+
+  if (SYMBOL_LOCATION_FUNCS (framefunc) == &dwarf2_loclist_funcs)
+    {
+      struct dwarf2_loclist_baton *symbaton;
+      symbaton = SYMBOL_LOCATION_BATON (framefunc);
+      *start = find_location_expression (symbaton, length,
+					 get_frame_pc (debaton->frame));
+    }
+  else
+    {
+      struct dwarf2_locexpr_baton *symbaton;
+      symbaton = SYMBOL_LOCATION_BATON (framefunc);
+      *length = symbaton->size;
+      *start = symbaton->data;
+    }
+
+  if (*start == NULL)
+    error ("Could not find the frame base for \"%s\".",
+	   SYMBOL_NATURAL_NAME (framefunc));
 }
 
 /* Using the objfile specified in BATON, find the address for the
@@ -130,6 +202,13 @@ dwarf2_evaluate_loc_desc (struct symbol 
   struct dwarf_expr_baton baton;
   struct dwarf_expr_context *ctx;
 
+  if (size == 0)
+    {
+      retval = allocate_value (SYMBOL_TYPE (var));
+      VALUE_LVAL (retval) = not_lval;
+      VALUE_OPTIMIZED_OUT (retval) = 1;
+    }
+
   baton.frame = frame;
   baton.objfile = objfile;
 
@@ -241,8 +320,55 @@ dwarf2_loc_desc_needs_frame (unsigned ch
   return baton.needs_frame;
 }
 
+static void
+dwarf2_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
+			   struct axs_value * value, unsigned char *data,
+			   int size)
+{
+  if (size == 0)
+    error ("Symbol \"%s\" has been optimized out.",
+	   SYMBOL_PRINT_NAME (symbol));
 
+  if (size == 1
+      && data[0] >= DW_OP_reg0
+      && data[0] <= DW_OP_reg31)
+    {
+      value->kind = axs_lvalue_register;
+      value->u.reg = data[0] - DW_OP_reg0;
+    }
+  else if (data[0] == DW_OP_regx)
+    {
+      ULONGEST reg;
+      read_uleb128 (data + 1, data + size, &reg);
+      value->kind = axs_lvalue_register;
+      value->u.reg = reg;
+    }
+  else if (data[0] == DW_OP_fbreg)
+    {
+      /* And this is worse than just minimal; we should honor the frame base
+	 as above.  */
+      int frame_reg;
+      LONGEST frame_offset;
+      unsigned char *buf_end;
+
+      buf_end = read_sleb128 (data + 1, data + size, &frame_offset);
+      if (buf_end != data + size)
+	error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
+	       SYMBOL_PRINT_NAME (symbol));
+
+      TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
+      ax_reg (ax, frame_reg);
+      ax_const_l (ax, frame_offset);
+      ax_simple (ax, aop_add);
 
+      ax_const_l (ax, frame_offset);
+      ax_simple (ax, aop_add);
+      value->kind = axs_lvalue_memory;
+    }
+  else
+    error ("Unsupported DWARF opcode in the location of \"%s\".",
+	   SYMBOL_PRINT_NAME (symbol));
+}
 \f
 /* Return the value of SYMBOL in FRAME using the DWARF-2 expression
    evaluator to calculate the location.  */
@@ -296,57 +422,13 @@ locexpr_describe_location (struct symbol
    publicly available stub with tracepoint support for me to test
    against.  When there is one this function should be revisited.  */
 
-void
+static void
 locexpr_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
 			    struct axs_value * value)
 {
   struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
 
-  if (dlbaton->size == 0)
-    error ("Symbol \"%s\" has been optimized out.",
-	   SYMBOL_PRINT_NAME (symbol));
-
-  if (dlbaton->size == 1
-      && dlbaton->data[0] >= DW_OP_reg0
-      && dlbaton->data[0] <= DW_OP_reg31)
-    {
-      value->kind = axs_lvalue_register;
-      value->u.reg = dlbaton->data[0] - DW_OP_reg0;
-    }
-  else if (dlbaton->data[0] == DW_OP_regx)
-    {
-      ULONGEST reg;
-      read_uleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
-		    &reg);
-      value->kind = axs_lvalue_register;
-      value->u.reg = reg;
-    }
-  else if (dlbaton->data[0] == DW_OP_fbreg)
-    {
-      /* And this is worse than just minimal; we should honor the frame base
-	 as above.  */
-      int frame_reg;
-      LONGEST frame_offset;
-      unsigned char *buf_end;
-
-      buf_end = read_sleb128 (dlbaton->data + 1, dlbaton->data + dlbaton->size,
-			      &frame_offset);
-      if (buf_end != dlbaton->data + dlbaton->size)
-	error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".",
-	       SYMBOL_PRINT_NAME (symbol));
-
-      TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset);
-      ax_reg (ax, frame_reg);
-      ax_const_l (ax, frame_offset);
-      ax_simple (ax, aop_add);
-
-      ax_const_l (ax, frame_offset);
-      ax_simple (ax, aop_add);
-      value->kind = axs_lvalue_memory;
-    }
-  else
-    error ("Unsupported DWARF opcode in the location of \"%s\".",
-	   SYMBOL_PRINT_NAME (symbol));
+  dwarf2_tracepoint_var_ref (symbol, ax, value, dlbaton->data, dlbaton->size);
 }
 
 /* The set of location functions used with the DWARF-2 expression
@@ -356,4 +438,76 @@ struct location_funcs dwarf2_locexpr_fun
   locexpr_read_needs_frame,
   locexpr_describe_location,
   locexpr_tracepoint_var_ref
+};
+
+
+/* Wrapper functions for location lists.  These generally find
+   the appropriate location expression and call something above.  */
+
+/* Return the value of SYMBOL in FRAME using the DWARF-2 expression
+   evaluator to calculate the location.  */
+static struct value *
+loclist_read_variable (struct symbol *symbol, struct frame_info *frame)
+{
+  struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+  struct value *val;
+  unsigned char *data;
+  int size;
+
+  data = find_location_expression (dlbaton, &size,
+				   frame ? get_frame_pc (frame) : 0);
+  if (data == NULL)
+    error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
+
+  val = dwarf2_evaluate_loc_desc (symbol, frame, data, size, dlbaton->objfile);
+
+  return val;
+}
+
+/* Return non-zero iff we need a frame to evaluate SYMBOL.  */
+static int
+loclist_read_needs_frame (struct symbol *symbol)
+{
+  /* If there's a location list, then assume we need to have a frame
+     to choose the appropriate location expression.  With tracking of
+     global variables this is not necessarily true, but such tracking
+     is disabled in GCC at the moment until we figure out how to
+     represent it.  */
+
+  return 1;
+}
+
+/* Print a natural-language description of SYMBOL to STREAM.  */
+static int
+loclist_describe_location (struct symbol *symbol, struct ui_file *stream)
+{
+  /* FIXME: Could print the entire list of locations.  */
+  fprintf_filtered (stream, "a variable with multiple locations");
+  return 1;
+}
+
+/* Describe the location of SYMBOL as an agent value in VALUE, generating
+   any necessary bytecode in AX.  */
+static void
+loclist_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
+			    struct axs_value * value)
+{
+  struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+  unsigned char *data;
+  int size;
+
+  data = find_location_expression (dlbaton, &size, ax->scope);
+  if (data == NULL)
+    error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol));
+
+  dwarf2_tracepoint_var_ref (symbol, ax, value, data, size);
+}
+
+/* The set of location functions used with the DWARF-2 expression
+   evaluator and location lists.  */
+struct location_funcs dwarf2_loclist_funcs = {
+  loclist_read_variable,
+  loclist_read_needs_frame,
+  loclist_describe_location,
+  loclist_tracepoint_var_ref
 };
Index: gdb/dwarf2loc.h
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2loc.h,v
retrieving revision 1.1
diff -u -p -r1.1 dwarf2loc.h
--- gdb/dwarf2loc.h	21 Feb 2003 15:24:17 -0000	1.1
+++ gdb/dwarf2loc.h	13 Apr 2003 15:41:32 -0000
@@ -24,16 +24,41 @@
 /* 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).  */
+/* The symbol location baton types used by the DWARF-2 reader (i.e.
+   SYMBOL_LOCATION_BATON for a LOC_COMPUTED symbol).  "struct
+   dwarf2_locexpr_baton" is for a symbol with a single location
+   expression; "struct dwarf2_loclist_baton" is for a symbol with a
+   location list.  */
 
 struct dwarf2_locexpr_baton
 {
+  /* Pointer to the start of the location expression.  */
   unsigned char *data;
+
+  /* Length of the location expression.  */
   unsigned short size;
+
+  /* The objfile containing the symbol whose location we're computing.  */
+  struct objfile *objfile;
+};
+
+struct dwarf2_loclist_baton
+{
+  /* The initial base address for the location list, based on the compilation
+     unit.  */
+  CORE_ADDR base_address;
+
+  /* Pointer to the start of the location list.  */
+  unsigned char *data;
+
+  /* Length of the location list.  */
+  unsigned short size;
+
+  /* The objfile containing the symbol whose location we're computing.  */
   struct objfile *objfile;
 };
 
 extern struct location_funcs dwarf2_locexpr_funcs;
+extern struct location_funcs dwarf2_loclist_funcs;
 
 #endif
Index: gdb/dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.88
diff -u -p -r1.88 dwarf2read.c
--- gdb/dwarf2read.c	25 Feb 2003 21:36:17 -0000	1.88
+++ gdb/dwarf2read.c	13 Apr 2003 15:41:33 -0000
@@ -220,9 +220,13 @@ struct comp_unit_head
 
     struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE];
 
-    /* Pointer to the DIE associated with the compilation unit.  */
+    /* Base address of this compilation unit.  */
 
-    struct die_info *die;
+    CORE_ADDR base_address;
+
+    /* Non-zero if base_address has been set.  */
+
+    int base_known;
   };
 
 /* The line number information for a compilation unit (found in the
@@ -395,6 +399,7 @@ static char *dwarf_line_buffer;
 static char *dwarf_str_buffer;
 static char *dwarf_macinfo_buffer;
 static char *dwarf_ranges_buffer;
+static char *dwarf_loc_buffer;
 
 /* A zeroed version of a partial die for initialization purposes.  */
 static struct partial_die_info zeroed_partial_die;
@@ -511,6 +516,13 @@ struct dwarf2_pinfo
 
     unsigned int dwarf_ranges_size;
 
+    /* Pointer to start of dwarf locations buffer for the objfile.  */
+
+    char *dwarf_loc_buffer;
+
+    /* Size of dwarf locations buffer for the objfile.  */
+
+    unsigned int dwarf_loc_size;
   };
 
 #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private)
@@ -526,6 +538,8 @@ struct dwarf2_pinfo
 #define DWARF_MACINFO_SIZE(p)   (PST_PRIVATE(p)->dwarf_macinfo_size)
 #define DWARF_RANGES_BUFFER(p)  (PST_PRIVATE(p)->dwarf_ranges_buffer)
 #define DWARF_RANGES_SIZE(p)    (PST_PRIVATE(p)->dwarf_ranges_size)
+#define DWARF_LOC_BUFFER(p)     (PST_PRIVATE(p)->dwarf_loc_buffer)
+#define DWARF_LOC_SIZE(p)       (PST_PRIVATE(p)->dwarf_loc_size)
 
 /* Maintain an array of referenced fundamental types for the current
    compilation unit being read.  For DWARF version 1, we have to construct
@@ -926,6 +940,7 @@ dwarf2_has_info (bfd *abfd)
   dwarf_frame_offset = 0;
   dwarf_eh_frame_offset = 0;
   dwarf_ranges_offset = 0;
+  dwarf_loc_offset = 0;
   
   bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL);
   if (dwarf_info_offset && dwarf_abbrev_offset)
@@ -1062,6 +1077,14 @@ dwarf2_build_psymtabs (struct objfile *o
   else
     dwarf_ranges_buffer = NULL;
 
+  if (dwarf_loc_offset)
+    dwarf_loc_buffer = dwarf2_read_section (objfile,
+					    dwarf_loc_offset,
+					    dwarf_loc_size,
+					    dwarf_loc_section);
+  else
+    dwarf_loc_buffer = NULL;
+
   if (mainline
       || (objfile->global_psymbols.size == 0
 	  && objfile->static_psymbols.size == 0))
@@ -1283,6 +1306,8 @@ dwarf2_build_psymtabs_hard (struct objfi
       DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size;
       DWARF_RANGES_BUFFER (pst) = dwarf_ranges_buffer;
       DWARF_RANGES_SIZE (pst) = dwarf_ranges_size;
+      DWARF_LOC_BUFFER (pst) = dwarf_loc_buffer;
+      DWARF_LOC_SIZE (pst) = dwarf_loc_size;
       baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
       /* Store the function that reads in the rest of the symbol table */
@@ -1607,6 +1632,7 @@ psymtab_to_symtab_1 (struct partial_symt
   char *info_ptr;
   struct symtab *symtab;
   struct cleanup *back_to;
+  struct attribute *attr;
 
   /* Set local variables from the partial symbol table info.  */
   offset = DWARF_INFO_OFFSET (pst);
@@ -1621,6 +1647,8 @@ psymtab_to_symtab_1 (struct partial_symt
   dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst);
   dwarf_ranges_buffer = DWARF_RANGES_BUFFER (pst);
   dwarf_ranges_size = DWARF_RANGES_SIZE (pst);
+  dwarf_loc_buffer = DWARF_LOC_BUFFER (pst);
+  dwarf_loc_size = DWARF_LOC_SIZE (pst);
   baseaddr = ANOFFSET (pst->section_offsets, SECT_OFF_TEXT (objfile));
   cu_header_offset = offset;
   info_ptr = dwarf_info_buffer + offset;
@@ -1642,8 +1670,32 @@ psymtab_to_symtab_1 (struct partial_symt
 
   make_cleanup_free_die_list (dies);
 
+  /* Find the base address of the compilation unit for range lists and
+     location lists.  It will normally be specified by DW_AT_low_pc.
+     In DWARF-3 draft 4, the base address could be overridden by
+     DW_AT_entry_pc.  It's been removed, but GCC still uses this for
+     compilation units with discontinuous ranges.  */
+
+  cu_header.base_known = 0;
+  cu_header.base_address = 0;
+
+  attr = dwarf_attr (dies, DW_AT_entry_pc);
+  if (attr)
+    {
+      cu_header.base_address = DW_ADDR (attr);
+      cu_header.base_known = 1;
+    }
+  else
+    {
+      attr = dwarf_attr (dies, DW_AT_low_pc);
+      if (attr)
+	{
+	  cu_header.base_address = DW_ADDR (attr);
+	  cu_header.base_known = 1;
+	}
+    }
+
   /* Do line number decoding in read_file_scope () */
-  cu_header.die = dies;
   process_die (dies, objfile, &cu_header);
 
   if (!dwarf2_get_pc_bounds (dies, &lowpc, &highpc, objfile, &cu_header))
@@ -2122,40 +2174,18 @@ dwarf2_get_pc_bounds (struct die_info *d
 	     .debug_renges section.  */
 	  unsigned int offset = DW_UNSND (attr);
 	  /* Base address selection entry.  */
-	  CORE_ADDR base = 0;
-	  int found_base = 0;
+	  CORE_ADDR base;
+	  int found_base;
 	  int dummy;
 	  unsigned int i;
 	  char *buffer;
 	  CORE_ADDR marker;
 	  int low_set;
  
-	  /* The applicable base address is determined by (1) the closest
-	     preceding base address selection entry in the range list or
-	     (2) the DW_AT_low_pc of the compilation unit.  */
-
-	  /* ??? Was in dwarf3 draft4, and has since been removed.
-	     GCC still uses it though.  */
-	  attr = dwarf_attr (cu_header->die, DW_AT_entry_pc);
-	  if (attr)
-	    {
-	      base = DW_ADDR (attr);
-	      found_base = 1;
-	    }
-
-	  if (!found_base)
-	    {
-	      attr = dwarf_attr (cu_header->die, DW_AT_low_pc);
-	      if (attr)
-		{
-		  base = DW_ADDR (attr);
-		  found_base = 1;
-		}
-	    }
-
+	  found_base = cu_header->base_known;
+	  base = cu_header->base_address;
 	  buffer = dwarf_ranges_buffer + offset;
 
-
 	  /* Read in the largest possible address.  */
 	  marker = read_address (obfd, buffer, cu_header, &dummy);
 	  if ((marker & mask) == mask)
@@ -7328,26 +7358,53 @@ dwarf2_symbol_mark_computed (struct attr
 			     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))
+  if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8)
     {
-      dwarf2_complex_location_expr_complaint ();
-      return;
+      struct dwarf2_loclist_baton *baton;
+
+      baton = obstack_alloc (&objfile->symbol_obstack,
+			     sizeof (struct dwarf2_loclist_baton));
+      baton->objfile = objfile;
+
+      /* We don't know how long the location list is, but make sure we
+	 don't run off the edge of the section.  */
+      baton->size = dwarf_loc_size - DW_UNSND (attr);
+      baton->data = dwarf_loc_buffer + DW_UNSND (attr);
+      baton->base_address = cu_header->base_address;
+      if (cu_header->base_known == 0)
+	complaint (&symfile_complaints,
+		   "Location list used without specifying the CU base address.");
+
+      SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_loclist_funcs;
+      SYMBOL_LOCATION_BATON (sym) = baton;
     }
+  else
+    {
+      struct dwarf2_locexpr_baton *baton;
 
-  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;
+      baton = obstack_alloc (&objfile->symbol_obstack,
+			     sizeof (struct dwarf2_locexpr_baton));
+      baton->objfile = objfile;
 
-  SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs;
-  SYMBOL_LOCATION_BATON (sym) = baton;
+      if (attr_form_is_block (attr))
+	{
+	  /* 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;
+	}
+      else
+	{
+	  dwarf2_invalid_attrib_class_complaint ("location description",
+						 SYMBOL_NATURAL_NAME (sym));
+	  baton->size = 0;
+	  baton->data = NULL;
+	}
+      
+      SYMBOL_LOCATION_FUNCS (sym) = &dwarf2_locexpr_funcs;
+      SYMBOL_LOCATION_BATON (sym) = baton;
+    }
 }


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2003-04-13 15:43 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-03-10 16:06 RFA: Location list support for DWARF-2 Daniel Jacobowitz
2003-03-12 21:40 ` Jim Blandy
2003-03-12 22:42   ` Daniel Jacobowitz
2003-04-08 16:46     ` Daniel Jacobowitz
2003-04-09  5:05     ` Jim Blandy
2003-04-13 15:43       ` Daniel Jacobowitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox