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


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

Re: RFA: Location list support for DWARF-2


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 at mvista dot 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 at mvista dot 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));
> +}
>  
>  /* 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


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