[RFC] Use compilation unit's address size in dwarf2expr.c and dwarf2loc.c

Kevin Buettner
2008-03-14T22:15:38Z

The patch below is a re-work of a patch that Jim Blandy wrote in 2005
and posted in 2006. Jim's 2006 posting may be found here:

http://sourceware.org/ml/gdb-patches/2006-05/msg00226.html

This patch fixes problems identified by Fred Fish and Michael Snyder.
See:

http://sourceware.org/ml/gdb-patches/2006-05/msg00198.html

and:

http://sourceware.org/ml/gdb-patches/2006-05/msg00484.html

I've tested this patch against i686-pc-linux-gnu (native) and mipsisa64-elf
(cross). I see no regressions for i686-pc-linux. For mipsisa64-elf, the
failure count for gdb.base/*.exp is reduced from 882 to 447.

I've tried to preserve the structure of Jim's ChangeLog comments as
much as possible to make comparisons between this and the original
work easier.

Comments?

Include a pointer to the partial symbol table in the symbol
batons, not to the objfile.
* dwarf2loc.h (sturct dwarf2_locexpr_baton, struct
dwarf2_loclist_baton): New member `psymtab', replacing `objfile'.
* dwarf2loc.c (dwarf2_evaluate_loc_desc): Expect a psymtab, not
an objfile. Store the psymtab's objfile in baton.
(locexpr_read_variable, loclist_read_variable): Pass
baton->psymtab to dwarf2_evaluate_loc_desc, not baton->objfile.
(locexpr_describe_location): Get the file name for thread-local
storage blocks from dlbaton->psymtab->objfile, instead of
dlbaton->objfile.
* dwarf2read.c (dwarf2_symbol_mark_computed): Store the cu's psymtab
in the batons we create for location expressions and location lists.

Allow dwarf2loc.c to find a compilation unit's address size, given
the psymtab for that compilation unit.
* dwarf2loc.h (dwarf_psymtab_address_size): New function.
* dwarf2read.c (struct dwarf2_per_cu_data): Add `address_size'
member.
(load_full_comp_unit): Store the cu's address size in it.
(dwarf_psymtab_address_size): New function.

Use the correct address size when parsing Dwarf 2 location lists,
and evaluation of DW_OP_deref and DW_OP_deref_size opcodes.
* dwarf2loc.h (struct dwarf_expr_context): New member
`address_size'.
(dwarf2_read_address): Adjust prototype; see next change.
* dwarf2expr.c (dwarf2_read_address): Take the address size as an
argument, rather than returning the address size via a reference
parameter.
(unsigned_address_type, signed_address_type): Take an address size
as an argument.
(execute_stack_op): Pass CTX's address size to dwarf2_read_address.
Use it as the pointer size for DW_OP_deref and DW_OP_deref_size.
Pass CTX to pass the address size to unsigned_address_type and
signed_address_type.
* dwarf2loc.h (dwarf_psymtab_address_size): New prototype.
* dwarf2loc.c (find_location_expression): Use baton->psymtab's
address size.
(dwarf2_evaluate_loc_desc): Store PSYMTAB's address size in the
context we're creating.
(dwarf2_loc_desc_needs_frame): Likewise.
(locexpr_read_needs_frame): Pass the psymtab to
dwarf2_loc_desc_needs_frame.
(locexpr_describe_location): Use dlbaton's psymtab's address size
to read DW_OP_GNU_push_tls_address's operand.
* dwarf2-frame.c (size_of_encoded_value): Add forward declaration.
(execute_stack_op, execute_cfa_program): Use
size_of_encoded_value (DW_EH_PE_absptr) as the address size.

Index: dwarf2-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2-frame.c,v
retrieving revision 1.79
diff -u -p -r1.79 dwarf2-frame.c
--- dwarf2-frame.c 1 Jan 2008 22:53:09 -0000 1.79
+++ dwarf2-frame.c 14 Mar 2008 20:56:35 -0000
@@ -227,6 +227,8 @@ dwarf2_frame_state_free (void *p)

/* Helper functions for execute_stack_op. */

+static unsigned int size_of_encoded_value (gdb_byte encoding);
+
static CORE_ADDR
read_reg (void *baton, int reg)
{
@@ -312,6 +314,11 @@ execute_stack_op (gdb_byte *exp, ULONGES
ctx->get_frame_base = no_get_frame_base;
ctx->get_tls_address = no_get_tls_address;

+ /* This isn't really right, but the Dwarf spec doesn't say what
+ address size is correct to use for CFI, so this is a reasonable
+ guess. */
+ ctx->address_size = size_of_encoded_value (DW_EH_PE_absptr);
+
dwarf_expr_push (ctx, initial);
dwarf_expr_eval (ctx, exp, len);
result = dwarf_expr_fetch (ctx, 0);
@@ -331,7 +338,6 @@ execute_cfa_program (gdb_byte *insn_ptr,
struct dwarf2_frame_state *fs, int eh_frame_p)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
- int bytes_read;
struct gdbarch *gdbarch = get_frame_arch (next_frame);

while (insn_ptr < insn_end && fs->pc <= pc)
@@ -362,8 +368,14 @@ execute_cfa_program (gdb_byte *insn_ptr,
switch (insn)
{
case DW_CFA_set_loc:
- fs->pc = dwarf2_read_address (insn_ptr, insn_end, &bytes_read);
- insn_ptr += bytes_read;
+ /* This isn't really the right address size to use, but
+ the Dwarf spec doesn't say what address size is
+ correct to use for CFI, so this is a reasonable
+ guess. */
+ fs->pc =
+ dwarf2_read_address (insn_ptr, insn_end,
+ size_of_encoded_value (DW_EH_PE_absptr));
+ insn_ptr += size_of_encoded_value (DW_EH_PE_absptr);
break;

case DW_CFA_advance_loc1:
Index: dwarf2expr.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2expr.c,v
retrieving revision 1.24
diff -u -p -r1.24 dwarf2expr.c
--- dwarf2expr.c 1 Jan 2008 22:53:09 -0000 1.24
+++ dwarf2expr.c 14 Mar 2008 20:56:35 -0000
@@ -32,7 +32,7 @@

static void execute_stack_op (struct dwarf_expr_context *,
gdb_byte *, gdb_byte *);
-static struct type *unsigned_address_type (void);
+static struct type *unsigned_address_type (CORE_ADDR address_size);

/* Create a new context for the expression evaluator. */

@@ -192,20 +192,17 @@ read_sleb128 (gdb_byte *buf, gdb_byte *b
return buf;
}

-/* Read an address from BUF, and verify that it doesn't extend past
- BUF_END. The address is returned, and *BYTES_READ is set to the
- number of bytes read from BUF. */
+/* Read and return an ADDRESS_SIZE-byte address from BUF, and verify
+ that it doesn't extend past BUF_END. */

CORE_ADDR
-dwarf2_read_address (gdb_byte *buf, gdb_byte *buf_end, int *bytes_read)
+dwarf2_read_address (gdb_byte *buf, gdb_byte *buf_end, CORE_ADDR address_size)
{
CORE_ADDR result;

- if (buf_end - buf < gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT)
+ if (buf_end - buf < address_size)
error (_("dwarf2_read_address: Corrupted DWARF expression."));

- *bytes_read = gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT;
-
/* For most architectures, calling extract_unsigned_integer() alone
is sufficient for extracting an address. However, some
architectures (e.g. MIPS) use signed addresses and using
@@ -229,11 +226,9 @@ dwarf2_read_address (gdb_byte *buf, gdb_
address being returned. */

result = value_as_address (value_from_longest
- (unsigned_address_type (),
+ (unsigned_address_type (address_size),
extract_unsigned_integer
- (buf,
- gdbarch_addr_bit (current_gdbarch)
- / TARGET_CHAR_BIT)));
+ (buf, address_size)));

return result;
}
@@ -241,9 +236,9 @@ dwarf2_read_address (gdb_byte *buf, gdb_
/* Return the type of an address, for unsigned arithmetic. */

static struct type *
-unsigned_address_type (void)
+unsigned_address_type (CORE_ADDR address_size)
{
- switch (gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT)
+ switch (address_size)
{
case 2:
return builtin_type_uint16;
@@ -260,9 +255,9 @@ unsigned_address_type (void)
/* Return the type of an address, for signed arithmetic. */

static struct type *
-signed_address_type (void)
+signed_address_type (CORE_ADDR address_size)
{
- switch (gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT)
+ switch (address_size)
{
case 2:
return builtin_type_int16;
@@ -332,8 +327,8 @@ execute_stack_op (struct dwarf_expr_cont
break;

case DW_OP_addr:
- result = dwarf2_read_address (op_ptr, op_end, &bytes_read);
- op_ptr += bytes_read;
+ result = dwarf2_read_address (op_ptr, op_end, ctx->address_size);
+ op_ptr += ctx->address_size;
break;

case DW_OP_const1u:
@@ -550,34 +545,23 @@ execute_stack_op (struct dwarf_expr_cont
{
case DW_OP_deref:
{
- gdb_byte *buf = alloca (gdbarch_addr_bit (current_gdbarch)
- / TARGET_CHAR_BIT);
- int bytes_read;
+ gdb_byte *buf = alloca (ctx->address_size);

- (ctx->read_mem) (ctx->baton, buf, result,
- gdbarch_addr_bit (current_gdbarch)
- / TARGET_CHAR_BIT);
- result = dwarf2_read_address (buf,
- buf + (gdbarch_addr_bit
- (current_gdbarch)
- / TARGET_CHAR_BIT),
- &bytes_read);
+ (ctx->read_mem) (ctx->baton, buf, result, ctx->address_size);
+ result = dwarf2_read_address (buf, buf + ctx->address_size,
+ ctx->address_size);
}
break;

case DW_OP_deref_size:
{
gdb_byte *buf
- = alloca (gdbarch_addr_bit (current_gdbarch)
- / TARGET_CHAR_BIT);
+ = alloca (ctx->address_size);
int bytes_read;

(ctx->read_mem) (ctx->baton, buf, result, *op_ptr++);
- result = dwarf2_read_address (buf,
- buf + (gdbarch_addr_bit
- (current_gdbarch)
- / TARGET_CHAR_BIT),
- &bytes_read);
+ result = dwarf2_read_address (buf, buf + ctx->address_size,
+ ctx->address_size);
}
break;

@@ -628,8 +612,8 @@ execute_stack_op (struct dwarf_expr_cont
first = dwarf_expr_fetch (ctx, 0);
dwarf_expr_pop (ctx);

- val1 = value_from_longest (unsigned_address_type (), first);
- val2 = value_from_longest (unsigned_address_type (), second);
+ val1 = value_from_longest (unsigned_address_type (ctx->address_size), first);
+ val2 = value_from_longest (unsigned_address_type (ctx->address_size), second);

switch (op)
{
@@ -662,7 +646,7 @@ execute_stack_op (struct dwarf_expr_cont
break;
case DW_OP_shra:
binop = BINOP_RSH;
- val1 = value_from_longest (signed_address_type (), first);
+ val1 = value_from_longest (signed_address_type (ctx->address_size), first);
break;
case DW_OP_xor:
binop = BINOP_BITWISE_XOR;
Index: dwarf2expr.h
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2expr.h,v
retrieving revision 1.12
diff -u -p -r1.12 dwarf2expr.h
--- dwarf2expr.h 1 Jan 2008 22:53:09 -0000 1.12
+++ dwarf2expr.h 14 Mar 2008 20:56:35 -0000
@@ -34,6 +34,11 @@ struct dwarf_expr_context
number of elements allocated to the stack. */
int stack_len, stack_allocated;

+ /* The size of an address, in bytes. For use with operations like
+ DW_OP_addr and DW_OP_deref, and for properly masking arguments to
+ division-like operators. */
+ CORE_ADDR address_size;
+
/* An opaque argument provided by the caller, which will be passed
to all of the callback functions. */
void *baton;
@@ -136,6 +141,6 @@ CORE_ADDR dwarf_expr_fetch (struct dwarf
gdb_byte *read_uleb128 (gdb_byte *buf, gdb_byte *buf_end, ULONGEST * r);
gdb_byte *read_sleb128 (gdb_byte *buf, gdb_byte *buf_end, LONGEST * r);
CORE_ADDR dwarf2_read_address (gdb_byte *buf, gdb_byte *buf_end,
- int *bytes_read);
+ CORE_ADDR address_size);

#endif /* dwarf2expr.h */
Index: dwarf2loc.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2loc.c,v
retrieving revision 1.48
diff -u -p -r1.48 dwarf2loc.c
--- dwarf2loc.c 1 Jan 2008 22:53:09 -0000 1.48
+++ dwarf2loc.c 14 Mar 2008 20:56:35 -0000
@@ -54,11 +54,11 @@ find_location_expression (struct dwarf2_
CORE_ADDR low, high;
gdb_byte *loc_ptr, *buf_end;
int length;
- unsigned int addr_size = gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT;
+ unsigned int addr_size = dwarf_psymtab_address_size (baton->psymtab);
CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1));
/* Adjust base_address for relocatable objects. */
- CORE_ADDR base_offset = ANOFFSET (baton->objfile->section_offsets,
- SECT_OFF_TEXT (baton->objfile));
+ CORE_ADDR base_offset = ANOFFSET (baton->psymtab->objfile->section_offsets,
+ SECT_OFF_TEXT (baton->psymtab->objfile));
CORE_ADDR base_address = baton->base_address + base_offset;

loc_ptr = baton->data;
@@ -66,10 +66,10 @@ find_location_expression (struct dwarf2_

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;
+ low = dwarf2_read_address (loc_ptr, buf_end, addr_size);
+ loc_ptr += addr_size;
+ high = dwarf2_read_address (loc_ptr, buf_end, addr_size);
+ loc_ptr += addr_size;

/* An end-of-list entry. */
if (low == 0 && high == 0)
@@ -185,11 +185,12 @@ dwarf_expr_tls_address (void *baton, COR

/* Evaluate a location description, starting at DATA and with length
SIZE, to find the current location of variable VAR in the context
- of FRAME. */
+ of FRAME. PSYMTAB is the partial symtab for the compilation unit
+ defining VAR. */
static struct value *
dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
gdb_byte *data, unsigned short size,
- struct objfile *objfile)
+ struct partial_symtab *psymtab)
{
struct gdbarch *arch = get_frame_arch (frame);
struct value *retval;
@@ -205,9 +206,10 @@ dwarf2_evaluate_loc_desc (struct symbol
}

baton.frame = frame;
- baton.objfile = objfile;
+ baton.objfile = psymtab->objfile;

ctx = new_dwarf_expr_context ();
+ ctx->address_size = dwarf_psymtab_address_size (psymtab);
ctx->baton = &baton;
ctx->read_reg = dwarf_expr_read_reg;
ctx->read_mem = dwarf_expr_read_mem;
@@ -318,7 +320,8 @@ needs_frame_tls_address (void *baton, CO
requires a frame to evaluate. */

static int
-dwarf2_loc_desc_needs_frame (gdb_byte *data, unsigned short size)
+dwarf2_loc_desc_needs_frame (gdb_byte *data, unsigned short size,
+ struct partial_symtab *psymtab)
{
struct needs_frame_baton baton;
struct dwarf_expr_context *ctx;
@@ -327,6 +330,7 @@ dwarf2_loc_desc_needs_frame (gdb_byte *d
baton.needs_frame = 0;

ctx = new_dwarf_expr_context ();
+ ctx->address_size = dwarf_psymtab_address_size (psymtab);
ctx->baton = &baton;
ctx->read_reg = needs_frame_read_reg;
ctx->read_mem = needs_frame_read_mem;
@@ -429,7 +433,7 @@ locexpr_read_variable (struct symbol *sy
struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
struct value *val;
val = dwarf2_evaluate_loc_desc (symbol, frame, dlbaton->data, dlbaton->size,
- dlbaton->objfile);
+ dlbaton->psymtab);

return val;
}
@@ -439,7 +443,8 @@ static int
locexpr_read_needs_frame (struct symbol *symbol)
{
struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
- return dwarf2_loc_desc_needs_frame (dlbaton->data, dlbaton->size);
+ return dwarf2_loc_desc_needs_frame (dlbaton->data, dlbaton->size,
+ dlbaton->psymtab);
}

/* Print a natural-language description of SYMBOL to STREAM. */
@@ -477,14 +482,14 @@ locexpr_describe_location (struct symbol
&& dlbaton->data[dlbaton->size - 1] == DW_OP_GNU_push_tls_address)
if (dlbaton->data[0] == DW_OP_addr)
{
- int bytes_read;
+ int address_size = dwarf_psymtab_address_size (dlbaton->psymtab);
CORE_ADDR offset = dwarf2_read_address (&dlbaton->data[1],
&dlbaton->data[dlbaton->size - 1],
- &bytes_read);
+ address_size);
fprintf_filtered (stream,
"a thread-local variable at offset %s in the "
"thread-local storage for `%s'",
- paddr_nz (offset), dlbaton->objfile->name);
+ paddr_nz (offset), dlbaton->psymtab->objfile->name);
return 1;
}

@@ -546,7 +551,7 @@ loclist_read_variable (struct symbol *sy
}
else
val = dwarf2_evaluate_loc_desc (symbol, frame, data, size,
- dlbaton->objfile);
+ dlbaton->psymtab);

return val;
}
Index: dwarf2loc.h
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2loc.h,v
retrieving revision 1.10
diff -u -p -r1.10 dwarf2loc.h
--- dwarf2loc.h 1 Jan 2008 22:53:09 -0000 1.10
+++ dwarf2loc.h 14 Mar 2008 20:56:35 -0000
@@ -25,6 +25,10 @@ struct symbol_ops;
/* This header is private to the DWARF-2 reader. It is shared between
dwarf2read.c and dwarf2loc.c. */

+/* Return the address size given in the compilation unit header for
+ PSYMTAB. */
+CORE_ADDR dwarf_psymtab_address_size (struct partial_symtab *psymtab);
+
/* 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
@@ -39,8 +43,12 @@ struct dwarf2_locexpr_baton
/* Length of the location expression. */
unsigned long size;

- /* The objfile containing the symbol whose location we're computing. */
- struct objfile *objfile;
+ /* The partial symtab structure for the compilation unit containing
+ the symbol whose location we're computing. Passing the psymtab
+ instead of the objfile gives us access to compilation-unit-
+ specific information like Dwarf address size, and the psymtab
+ also points to the objfile. */
+ struct partial_symtab *psymtab;
};

struct dwarf2_loclist_baton
@@ -55,12 +63,12 @@ struct dwarf2_loclist_baton
/* Length of the location list. */
unsigned long size;

- /* The objfile containing the symbol whose location we're computing. */
- /* Used (only???) by thread local variables. The objfile in which
- this symbol is defined. To find a thread-local variable (e.g., a
- variable declared with the `__thread' storage class), we may need
- to know which object file it's in. */
- struct objfile *objfile;
+ /* The partial symtab structure for the compilation unit containing
+ the symbol whose location we're computing. Passing the psymtab
+ instead of the objfile gives us access to compilation-unit-
+ specific information like Dwarf address size, and the psymtab
+ also points to the objfile. */
+ struct partial_symtab *psymtab;
};

extern const struct symbol_ops dwarf2_locexpr_funcs;
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.252
diff -u -p -r1.252 dwarf2read.c
--- dwarf2read.c 10 Mar 2008 14:01:56 -0000 1.252
+++ dwarf2read.c 14 Mar 2008 20:56:36 -0000
@@ -378,6 +378,10 @@ struct dwarf2_per_cu_data
or NULL for partial units (which do not have an associated
symtab). */
struct partial_symtab *psymtab;
+
+ /* Size of the addresses in this compilation unit -- from the
+ compilation unit header. */
+ CORE_ADDR address_size;
};

/* The line number information for a compilation unit (found in the
@@ -2548,6 +2552,9 @@ load_full_comp_unit (struct dwarf2_per_c

/* read in the comp_unit header */
info_ptr = read_comp_unit_head (&cu->header, info_ptr, abfd);
+
+ /* Save the address size in the per-cu data. */
+ per_cu->address_size = cu->header.addr_size;

/* Read the abbrevs for this compilation unit */
dwarf2_read_abbrevs (abfd, cu);
@@ -2657,6 +2664,14 @@ process_full_comp_unit (struct dwarf2_pe
do_cleanups (back_to);
}

+CORE_ADDR
+dwarf_psymtab_address_size (struct partial_symtab *psymtab)
+{
+ struct dwarf2_per_cu_data *this_cu
+ = (struct dwarf2_per_cu_data *) psymtab->read_symtab_private;
+ return this_cu->address_size;
+}
+
/* Process a die and its children. */

static void
@@ -9835,7 +9850,7 @@ dwarf2_symbol_mark_computed (struct attr

baton = obstack_alloc (&cu->objfile->objfile_obstack,
sizeof (struct dwarf2_loclist_baton));
- baton->objfile = objfile;
+ baton->psymtab = cu->per_cu->psymtab;

/* We don't know how long the location list is, but make sure we
don't run off the edge of the section. */
@@ -9855,7 +9870,7 @@ dwarf2_symbol_mark_computed (struct attr

baton = obstack_alloc (&cu->objfile->objfile_obstack,
sizeof (struct dwarf2_locexpr_baton));
- baton->objfile = objfile;
+ baton->psymtab = cu->per_cu->psymtab;

if (attr_form_is_block (attr))
{