Fix printing of .debug_addr

Message ID 20210212193242.GA17627@delia
State New
Headers show
Series
  • Fix printing of .debug_addr
Related show

Commit Message

Tom de Vries Feb. 12, 2021, 7:32 p.m.
Hi,

Consider this exec:
...
$ clang -gdwarf-5 ./src/gdb/testsuite/gdb.dwarf2/fission-mix*.c
...

When trying to print the dwarf, we run into unsupported forms:
- 37 (0x25, DW_FORM_strx1) and
- 27 (0x1b, DW_FORM_addrx)
like this:
...
$ readelf -w a.out> READELF
readelf: Warning: Unrecognized form: 37
  ...
readelf: Warning: Unrecognized form: 27
  ...
readelf: Warning: Unable to load/parse the .debug_info section, so cannot \
  interpret the .debug_addr section.
...

With an enablement patch that adds support for:
- DW_FORM_strx* alongside DW_FORM_GNU_str_index
- DW_FORM_addrx* alongside DW_FORM_GNU_addr_index
- DW_AT_addr_base alongside DW_AT_GNU_addr_base
we are able to interpret the .debug_addr section, and get:
...
Contents of the .debug_addr section:

  For compilation unit at offset 0xc7:
        Index   Address
        0:      000000000060102c
        1:      00000000004004a0
        2:      000800050000001c
  For compilation unit at offset 0x118:
        Index   Address
        0:      0000000000601030
        1:      00000000004004c0
        2:      00000000004004d0
...

The entry with index 2 in the first CU (000800050000001c) is actually not an
entry, but the header of the next CU, which we can see with f.i.
llvm-dwarfdump:
...
Addr Section: \
  length = 0x0000001c, version = 0x0005, addr_size = 0x08, seg_size = 0x00
...

Fix this in display_debug_addr, and add support for DW_AT_addr_base.

OK for trunk?

Thanks,
- Tom

[binutils] Fix printing of .debug_addr

binutils/ChangeLog:

2021-02-12  Tom de Vries  <tdevries@suse.de>

	* dwarf.c (read_and_display_attr_value): Handle DW_AT_addr_base.
	(display_debug_addr): Handle dwarf-5 .debug_addr bits.

---
 binutils/dwarf.c | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

Patch

diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index e55a7daa8fe..d682bac35f9 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -2844,6 +2844,7 @@  read_and_display_attr_value (unsigned long           attribute,
 	  break;
 
 	case DW_AT_GNU_addr_base:
+	case DW_AT_addr_base:
 	  debug_info_p->addr_base = uvalue;
 	  break;
 
@@ -7308,6 +7309,7 @@  display_debug_addr (struct dwarf_section *section,
   debug_addr_info [count]->addr_base = section->size;
   qsort (debug_addr_info, count, sizeof (debug_info *), comp_addr_base);
 
+  unsigned char *header = section->start;
   for (i = 0; i < count; i++)
     {
       unsigned int idx;
@@ -7318,7 +7320,34 @@  display_debug_addr (struct dwarf_section *section,
 
       printf (_("\tIndex\tAddress\n"));
       entry = section->start + debug_addr_info [i]->addr_base;
-      end = section->start + debug_addr_info [i + 1]->addr_base;
+      if (debug_addr_info [i]->dwarf_version >= 5)
+	{
+	  size_t header_size = entry - header;
+	  if (header_size != 8 && header_size != 16)
+	    return 0;
+
+	  unsigned char *curr_header = header;
+
+	  dwarf_vma length;
+	  SAFE_BYTE_GET_AND_INC (length, curr_header, 4, entry);
+	  if (length == 0xffffffff)
+	    SAFE_BYTE_GET (length, curr_header, 8, entry);
+	  end = curr_header + length;
+
+	  int version;
+	  SAFE_BYTE_GET_AND_INC (version, curr_header, 2, entry);
+	  if (version != 5)
+	    warn (_("Unexpected version number in .debug_addr header: %#x\n"), version);
+
+	  SAFE_BYTE_GET_AND_INC (address_size, curr_header, 1, entry);
+
+	  int segment_selector_size;
+	  SAFE_BYTE_GET_AND_INC (segment_selector_size, curr_header, 1, entry);
+	  address_size += segment_selector_size;
+	}
+      else
+	end = section->start + debug_addr_info [i + 1]->addr_base;
+      header = end;
       idx = 0;
       while (entry < end)
 	{