Re: RFA: Location list support for DWARF-2

Daniel Jacobowitz
2003-04-08T16:46:39Z

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;
> + }
> }