This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: RFA: Location list support for DWARF-2
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, ®);
+ 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,
- ®);
- 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;
+ }
}