[RFC] DWARF 2 address size != pointer size

Fred Fish
2006-05-10T18:24:14Z

For at least one target, MIPS using the o64 ABI with -mlong64, the
target DWARF2 address size used in the DWARF info (32 bit) is not the
same as the target pointer size (64 bit). For example, below are some
fragments from dumping the DWARF info for a simple test case:

Compilation Unit @ 0:
Length: 175
Version: 2
Abbrev Offset: 0
Pointer Size: 4
<1><91>: Abbrev Number: 3 (DW_TAG_base_type)
DW_AT_name : long int
DW_AT_byte_size : 8
<1><b0>: Abbrev Number: 4 (DW_TAG_pointer_type)
DW_AT_byte_size : 8

Note that the header records the address size as 4, which is the
number of bytes written to the DWARF info when writing addresses, but
that the target pointer size is 8.

Currently gdb computes the DWARF info address size as:

TARGET_ADDR_BIT / TARGET_CHAR_BIT

Given that the address size is actually recorded in the compilation
unit header, I believe the best solution would be to use that recorded
value somehow. I spent a couple days looking for an easy way to tie
the address size to DWARF expressions that were recorded for later
evaluation, but didn't come up with anything clean enough to submit.

Another way to divorce the DWARF address size from the TARGET_ADDR_BIT
is to add another gdbarch paramter, accessed as TARGET_DWARF_ADDR_BIT.
I've attached a patch that does that. It's simple, but not my first
choice for solving the problem.

Comments?

-Fred

============================================================================

2006-05-10 Fred Fish <fnf@specifix.com>

* gdbarch.sh: Add and document TARGET_DWARF_ADDR_BIT.
* gdbarch.c: Regenerated.
* gdbarch.h: Regenerated.
* mips-tdep.c (mips_find_long_section): New function.
(mips_find_pointer_section): New function.
(mips_find_float_section): New function.
(mips_gdbarch_init): Add long_bit and ptr_bit local variables.
Call bfd_map_over_sections with mips_find_float_section,
mips_find_long section, and mips_find_pointer_section.
Call set_gdbarch_dwarf_addr_bit to get 32 bit DWARF addresses
for MIPS_ABI_O64 and 64 bit DWARF addresses for MIPS_ABI_N64.
* dwarf2expr.c (dwarf2_read_address): Replace TARGET_ADDR_BIT with
TARGET_DWARF_ADDR_BIT.
(unsigned_address_type): Ditto.
(signed_address_type): Ditto.
(execute_stack_op): Ditto.
* dwarf2loc.c (find_location_expression): Replace TARGET_ADDR_BIT with
TARGET_DWARF_ADDR_BIT.
* dwarf2read.c (read_comp_unit_head): Call set_gdbarch_dwarf_addr_bit
with value computed from address size read from header.

Index: gdb/gdb/dwarf2expr.c
===================================================================
RCS file: /cvsroots/specifix/gnusense/gdb/gdb/dwarf2expr.c,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 dwarf2expr.c
--- gdb/gdb/dwarf2expr.c 22 Dec 2005 01:56:13 -0000 1.1.1.5
+++ gdb/gdb/dwarf2expr.c 3 May 2006 18:56:10 -0000
@@ -201,13 +201,13 @@ dwarf2_read_address (gdb_byte *buf, gdb_
{
CORE_ADDR result;

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

- *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
+ *bytes_read = TARGET_DWARF_ADDR_BIT / TARGET_CHAR_BIT;
/* NOTE: cagney/2003-05-22: This extract is assuming that a DWARF 2
address is always unsigned. That may or may not be true. */
- result = extract_unsigned_integer (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT);
+ result = extract_unsigned_integer (buf, TARGET_DWARF_ADDR_BIT / TARGET_CHAR_BIT);
return result;
}

@@ -216,7 +216,7 @@ dwarf2_read_address (gdb_byte *buf, gdb_
static struct type *
unsigned_address_type (void)
{
- switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
+ switch (TARGET_DWARF_ADDR_BIT / TARGET_CHAR_BIT)
{
case 2:
return builtin_type_uint16;
@@ -235,7 +235,7 @@ unsigned_address_type (void)
static struct type *
signed_address_type (void)
{
- switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT)
+ switch (TARGET_DWARF_ADDR_BIT / TARGET_CHAR_BIT)
{
case 2:
return builtin_type_int16;
@@ -520,13 +520,13 @@ execute_stack_op (struct dwarf_expr_cont
{
case DW_OP_deref:
{
- gdb_byte *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
+ gdb_byte *buf = alloca (TARGET_DWARF_ADDR_BIT / TARGET_CHAR_BIT);
int bytes_read;

(ctx->read_mem) (ctx->baton, buf, result,
- TARGET_ADDR_BIT / TARGET_CHAR_BIT);
+ TARGET_DWARF_ADDR_BIT / TARGET_CHAR_BIT);
result = dwarf2_read_address (buf,
- buf + (TARGET_ADDR_BIT
+ buf + (TARGET_DWARF_ADDR_BIT
/ TARGET_CHAR_BIT),
&bytes_read);
}
@@ -534,12 +534,12 @@ execute_stack_op (struct dwarf_expr_cont

case DW_OP_deref_size:
{
- gdb_byte *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT);
+ gdb_byte *buf = alloca (TARGET_DWARF_ADDR_BIT / TARGET_CHAR_BIT);
int bytes_read;

(ctx->read_mem) (ctx->baton, buf, result, *op_ptr++);
result = dwarf2_read_address (buf,
- buf + (TARGET_ADDR_BIT
+ buf + (TARGET_DWARF_ADDR_BIT
/ TARGET_CHAR_BIT),
&bytes_read);
}
Index: gdb/gdb/gdbarch.c
===================================================================
RCS file: /cvsroots/specifix/gnusense/gdb/gdb/gdbarch.c,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 gdbarch.c
--- gdb/gdb/gdbarch.c 22 Dec 2005 01:56:27 -0000 1.1.1.5
+++ gdb/gdb/gdbarch.c 3 May 2006 18:35:19 -0000
@@ -142,6 +142,7 @@ struct gdbarch
const struct floatformat * long_double_format;
int ptr_bit;
int addr_bit;
+ int dwarf_addr_bit;
int bfd_vma_bit;
int char_signed;
gdbarch_read_pc_ftype *read_pc;
@@ -268,6 +269,7 @@ struct gdbarch startup_gdbarch =
0, /* long_double_format */
8 * sizeof (void*), /* ptr_bit */
8 * sizeof (void*), /* addr_bit */
+ 8 * sizeof (void*), /* dwarf_addr_bit */
8 * sizeof (void*), /* bfd_vma_bit */
1, /* char_signed */
0, /* read_pc */
@@ -406,6 +408,7 @@ gdbarch_alloc (const struct gdbarch_info
current_gdbarch->double_bit = 8*TARGET_CHAR_BIT;
current_gdbarch->long_double_bit = 8*TARGET_CHAR_BIT;
current_gdbarch->ptr_bit = TARGET_INT_BIT;
+ current_gdbarch->dwarf_addr_bit = TARGET_PTR_BIT;
current_gdbarch->bfd_vma_bit = TARGET_ARCHITECTURE->bits_per_address;
current_gdbarch->char_signed = -1;
current_gdbarch->write_pc = generic_target_write_pc;
@@ -524,6 +527,7 @@ verify_gdbarch (struct gdbarch *current_
/* Skip verify of ptr_bit, invalid_p == 0 */
if (current_gdbarch->addr_bit == 0)
current_gdbarch->addr_bit = TARGET_PTR_BIT;
+ /* Skip verify of dwarf_addr_bit, invalid_p == 0 */
/* Skip verify of bfd_vma_bit, invalid_p == 0 */
if (current_gdbarch->char_signed == -1)
current_gdbarch->char_signed = 1;
@@ -1018,6 +1022,14 @@ gdbarch_dump (struct gdbarch *current_gd
fprintf_unfiltered (file,
"gdbarch_dump: dwarf2_reg_to_regnum = <0x%lx>\n",
(long) current_gdbarch->dwarf2_reg_to_regnum);
+#ifdef TARGET_DWARF_ADDR_BIT
+ fprintf_unfiltered (file,
+ "gdbarch_dump: TARGET_DWARF_ADDR_BIT # %s\n",
+ XSTRING (TARGET_DWARF_ADDR_BIT));
+#endif
+ fprintf_unfiltered (file,
+ "gdbarch_dump: dwarf_addr_bit = %s\n",
+ paddr_d (current_gdbarch->dwarf_addr_bit));
#ifdef DWARF_REG_TO_REGNUM
fprintf_unfiltered (file,
"gdbarch_dump: %s # %s\n",
@@ -1871,6 +1883,23 @@ set_gdbarch_addr_bit (struct gdbarch *gd
}

int
+gdbarch_dwarf_addr_bit (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of dwarf_addr_bit, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_dwarf_addr_bit called\n");
+ return gdbarch->dwarf_addr_bit;
+}
+
+void
+set_gdbarch_dwarf_addr_bit (struct gdbarch *gdbarch,
+ int dwarf_addr_bit)
+{
+ gdbarch->dwarf_addr_bit = dwarf_addr_bit;
+}
+
+int
gdbarch_bfd_vma_bit (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
Index: gdb/gdb/gdbarch.h
===================================================================
RCS file: /cvsroots/specifix/gnusense/gdb/gdb/gdbarch.h,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 gdbarch.h
--- gdb/gdb/gdbarch.h 22 Dec 2005 01:56:16 -0000 1.1.1.5
+++ gdb/gdb/gdbarch.h 3 May 2006 18:53:08 -0000
@@ -200,6 +200,12 @@ extern void set_gdbarch_long_double_form
If TARGET_PTR_BIT and TARGET_ADDR_BIT are different, you'll probably
also need to set POINTER_TO_ADDRESS and ADDRESS_TO_POINTER as well.

+ For at least one system (MIPS) the size of addresses written to the
+ DWARF debug info changes based on the ABI, and may be different than
+ what might be expected by examining TARGET_ADDR_BIT. In particular,
+ using -mlong64, it is possible to get 64 bit pointers while still
+ writing out 32 bit addresses in the DWARF info.
+
ptr_bit is the size of a pointer on the target */

extern int gdbarch_ptr_bit (struct gdbarch *gdbarch);
@@ -222,6 +228,17 @@ extern void set_gdbarch_addr_bit (struct
#define TARGET_ADDR_BIT (gdbarch_addr_bit (current_gdbarch))
#endif

+/* dwarf_addr_bit is the size of a target address as represented in the DWARF debug information */
+
+extern int gdbarch_dwarf_addr_bit (struct gdbarch *gdbarch);
+extern void set_gdbarch_dwarf_addr_bit (struct gdbarch *gdbarch, int dwarf_addr_bit);
+#if !defined (GDB_TM_FILE) && defined (TARGET_DWARF_ADDR_BIT)
+#error "Non multi-arch definition of TARGET_DWARF_ADDR_BIT"
+#endif
+#if !defined (TARGET_DWARF_ADDR_BIT)
+#define TARGET_DWARF_ADDR_BIT (gdbarch_dwarf_addr_bit (current_gdbarch))
+#endif
+
/* Number of bits in a BFD_VMA for the target object file format. */

extern int gdbarch_bfd_vma_bit (struct gdbarch *gdbarch);
Index: gdb/gdb/gdbarch.sh
===================================================================
RCS file: /cvsroots/specifix/gnusense/gdb/gdb/gdbarch.sh,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 gdbarch.sh
--- gdb/gdb/gdbarch.sh 22 Dec 2005 01:56:10 -0000 1.1.1.5
+++ gdb/gdb/gdbarch.sh 3 May 2006 18:52:41 -0000
@@ -404,10 +404,18 @@ v:TARGET_LONG_DOUBLE_FORMAT:const struct
# If TARGET_PTR_BIT and TARGET_ADDR_BIT are different, you'll probably
# also need to set POINTER_TO_ADDRESS and ADDRESS_TO_POINTER as well.
#
+# For at least one system (MIPS) the size of addresses written to the
+# DWARF debug info changes based on the ABI, and may be different than
+# what might be expected by examining TARGET_ADDR_BIT. In particular,
+# using -mlong64, it is possible to get 64 bit pointers while still
+# writing out 32 bit addresses in the DWARF info.
+#
# ptr_bit is the size of a pointer on the target
v:TARGET_PTR_BIT:int:ptr_bit:::8 * sizeof (void*):TARGET_INT_BIT::0
# addr_bit is the size of a target address as represented in gdb
v:TARGET_ADDR_BIT:int:addr_bit:::8 * sizeof (void*):0:TARGET_PTR_BIT:
+# dwarf_addr_bit is the size of a target address as represented in the DWARF debug information
+v:TARGET_DWARF_ADDR_BIT:int:dwarf_addr_bit:::8 * sizeof (void*):TARGET_PTR_BIT::0
# Number of bits in a BFD_VMA for the target object file format.
v:TARGET_BFD_VMA_BIT:int:bfd_vma_bit:::8 * sizeof (void*):TARGET_ARCHITECTURE->bits_per_address::0
#
Index: gdb/gdb/mips-tdep.c
===================================================================
RCS file: /cvsroots/specifix/gnusense/gdb/gdb/mips-tdep.c,v
retrieving revision 1.1.1.5.4.4
diff -u -p -r1.1.1.5.4.4 mips-tdep.c
--- gdb/gdb/mips-tdep.c 2 May 2006 13:15:41 -0000 1.1.1.5.4.4
+++ gdb/gdb/mips-tdep.c 3 May 2006 21:04:04 -0000
@@ -4944,6 +4987,7 @@ mips_gdbarch_init (struct gdbarch_info i
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_ptr_bit (gdbarch, 32);
+ set_gdbarch_dwarf_addr_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
break;
case MIPS_ABI_EABI32:
@@ -4987,6 +5031,7 @@ mips_gdbarch_init (struct gdbarch_info i
tdep->default_mask_address_p = 0;
set_gdbarch_long_bit (gdbarch, 64);
set_gdbarch_ptr_bit (gdbarch, 64);
+ set_gdbarch_dwarf_addr_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_long_double_bit (gdbarch, 128);
set_gdbarch_long_double_format (gdbarch,
Index: dwarf2loc.c
===================================================================
RCS file: /cvsroots/specifix/gnusense/gdb/gdb/dwarf2loc.c,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 dwarf2loc.c
--- dwarf2loc.c 22 Dec 2005 01:56:10 -0000 1.1.1.5
+++ dwarf2loc.c 10 May 2006 15:26:35 -0000
@@ -59,7 +59,7 @@ find_location_expression (struct dwarf2_
CORE_ADDR low, high;
gdb_byte *loc_ptr, *buf_end;
int length;
- unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT;
+ unsigned int addr_size = TARGET_DWARF_ADDR_BIT / TARGET_CHAR_BIT;
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,
Index: dwarf2read.c
===================================================================
RCS file: /cvsroots/specifix/gnusense/gdb/gdb/dwarf2read.c,v
retrieving revision 1.1.1.5
diff -u -p -r1.1.1.5 dwarf2read.c
--- dwarf2read.c 22 Dec 2005 01:56:25 -0000 1.1.1.5
+++ dwarf2read.c 10 May 2006 15:32:55 -0000
@@ -1278,6 +1278,8 @@ read_comp_unit_head (struct comp_unit_he
&bytes_read);
info_ptr += bytes_read;
cu_header->addr_size = read_1_byte (abfd, info_ptr);
+ /* FIXME: This assumes that all compilation units will have the same addr_size */
+ set_gdbarch_dwarf_addr_bit (current_gdbarch, cu_header->addr_size * TARGET_CHAR_BIT);
info_ptr += 1;
signed_addr = bfd_get_sign_extend_vma (abfd);
if (signed_addr < 0)