objdump: Handle 32-bit base address in debug_ranges / debug_loc.
authorAndrew Burgess <andrew.burgess@embecosm.com>
Fri, 16 Oct 2015 09:58:02 +0000 (11:58 +0200)
committerAndrew Burgess <andrew.burgess@embecosm.com>
Mon, 30 Nov 2015 13:28:26 +0000 (13:28 +0000)
When the DWARF address size is 32-bit, but the host machine is 64-bit,
objdump fails to spot base addresses specified in the .debug_ranges and
.debug_loc lists.

As an example, here is the output when dumping an example .debug_ranges
section with the pre-patched objdump:

    Contents of the .debug_ranges section:

        Offset   Begin    End
        00000000 ffffffff 00000004 (start > end)
        00000000 00000000 00000004
        00000000 ffffffff 00000008 (start > end)
        00000000 00000000 00000004
        00000000 <End of list>

And this is what the same section looks like when dumped with the
patched version of objdump:

    Contents of the .debug_ranges section:

        Offset   Begin    End
        00000000 ffffffff 00000004 (base address)
        00000000 00000004 00000008
        00000000 ffffffff 00000008 (base address)
        00000000 00000008 0000000c
        00000000 <End of list>

binutils/ChangeLog:

* dwarf.c (is_max_address): New function.
(display_loc_list): Remove out of date comment, use
is_max_address.
(display_debug_ranges): Likewise.

binutils/testsuite/ChangeLog:

* binutils-all/objdump.exp: Add test for .debug_ranges decode.
* binutils-all/dw2-ranges.S: New file.
* binutils-all/dw2-ranges.W: New file.

binutils/ChangeLog
binutils/dwarf.c
binutils/testsuite/ChangeLog
binutils/testsuite/binutils-all/dw2-ranges.S [new file with mode: 0644]
binutils/testsuite/binutils-all/dw2-ranges.W [new file with mode: 0644]
binutils/testsuite/binutils-all/objdump.exp

index b058ead9a6677b1fd879eb9aaba918aa146c0232..73698d9873cdd73c4db3209fd5cfc50b82725237 100644 (file)
@@ -1,3 +1,10 @@
+2015-11-30  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * dwarf.c (is_max_address): New function.
+       (display_loc_list): Remove out of date comment, use
+       is_max_address.
+       (display_debug_ranges): Likewise.
+
 2015-11-28  Cary Coutant  <ccoutant@gmail.com>
 
        * MAINTAINERS: Update my email address.
index 9f1baea831227940575eb286f8a3c7f3466e0ca5..03e01175ccc7cfec7fb9c631070ff9dac66de432 100644 (file)
@@ -4326,6 +4326,16 @@ display_debug_abbrev (struct dwarf_section *section,
   return 1;
 }
 
+/* Return true when ADDR is the maximum address, when addresses are
+   POINTER_SIZE bytes long.  */
+
+static bfd_boolean
+is_max_address (dwarf_vma addr, unsigned int pointer_size)
+{
+  dwarf_vma mask = ~(~(dwarf_vma) 1 << (pointer_size * 8 - 1));
+  return ((addr & mask) == mask);
+}
+
 /* Display a location list from a normal (ie, non-dwo) .debug_loc section.  */
 
 static void
@@ -4380,10 +4390,6 @@ display_loc_list (struct dwarf_section *section,
 
       printf ("    %8.8lx ", off);
 
-      /* Note: we use sign extension here in order to be sure that we can detect
-        the -1 escape value.  Sign extension into the top 32 bits of a 32-bit
-        address will not affect the values that we display since we always show
-        hex values, and always the bottom 32-bits.  */
       SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
       SAFE_BYTE_GET_AND_INC (end, start, pointer_size, section_end);
 
@@ -4404,7 +4410,8 @@ display_loc_list (struct dwarf_section *section,
        }
 
       /* Check base address specifiers.  */
-      if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1)
+      if (is_max_address (begin, pointer_size)
+          && !is_max_address (end, pointer_size))
        {
          base_address = end;
          print_dwarf_vma (begin, pointer_size);
@@ -5202,11 +5209,6 @@ display_debug_ranges (struct dwarf_section *section,
          dwarf_vma begin;
          dwarf_vma end;
 
-         /* Note: we use sign extension here in order to be sure that
-            we can detect the -1 escape value.  Sign extension into the
-            top 32 bits of a 32-bit address will not affect the values
-            that we display since we always show hex values, and always
-            the bottom 32-bits.  */
          SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, finish);
          if (start >= finish)
            break;
@@ -5221,7 +5223,8 @@ display_debug_ranges (struct dwarf_section *section,
            }
 
          /* Check base address specifiers.  */
-         if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1)
+          if (is_max_address (begin, pointer_size)
+              && !is_max_address (end, pointer_size))
            {
              base_address = end;
              print_dwarf_vma (begin, pointer_size);
index 64348e6c1cf85a59c8eb4099887c62d84db529b9..57d9b89240bc8f5580f28f1fe770693436a4c7ee 100644 (file)
@@ -1,3 +1,9 @@
+2015-11-30  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * binutils-all/objdump.exp: Add test for .debug_ranges decode.
+       * binutils-all/dw2-ranges.S: New file.
+       * binutils-all/dw2-ranges.W: New file.
+
 2015-10-22  Alan Modra  <amodra@gmail.com>
 
        * binutils-all/add-symbol.d: Run test on mips.  Support either
diff --git a/binutils/testsuite/binutils-all/dw2-ranges.S b/binutils/testsuite/binutils-all/dw2-ranges.S
new file mode 100644 (file)
index 0000000..74d7287
--- /dev/null
@@ -0,0 +1,140 @@
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* This tests makes use of the .debug_ranges section, especially,
+   making sure that the base address encoding scheme is used.  */
+
+/* Dummy function to provide debug information for.  */
+
+       .text
+       .globl _start
+_start:
+       .4byte 0
+.Lbegin_text1:
+       .globl func_cu1
+       .type func_cu1, %function
+func_cu1:
+.Lbegin_func_cu1:
+       .4byte 0
+.Lend_func_cu1:
+       .size func_cu1, .-func_cu1
+.Lend_text1:
+
+.Lbegin_text2:
+       .globl func_cu2
+       .type func_cu2, %function
+func_cu2:
+.Lbegin_func_cu2:
+       .4byte 0
+.Lend_func_cu2:
+       .size func_cu2, .-func_cu2
+.Lend_text2:
+
+/* Debug information */
+
+       .section .debug_info
+.Lcu1_begin:
+       /* CU header */
+       .4byte  .Lcu1_end - .Lcu1_start         /* Length of Compilation Unit */
+.Lcu1_start:
+       .2byte  2                               /* DWARF Version */
+       .4byte  .Labbrev1_begin                 /* Offset into abbrev section */
+       .byte   4                               /* Pointer size */
+
+       /* CU die */
+       .uleb128 1                              /* Abbrev: DW_TAG_compile_unit */
+        .4byte  .Lrange1_begin
+       .ascii  "file1.c\0"                     /* DW_AT_name */
+       .byte   1                               /* DW_AT_language (C) */
+
+       /* func_cu1 */
+       .uleb128        2                       /* Abbrev: DW_TAG_subprogram */
+       .ascii          "func_cu1\0"            /* DW_AT_name */
+       .4byte          .Ltype_int-.Lcu1_begin  /* DW_AT_type */
+       .4byte          .Lbegin_func_cu1        /* DW_AT_low_pc */
+       .4byte          .Lend_func_cu1          /* DW_AT_high_pc */
+
+       /* func_cu1 */
+       .uleb128        2                       /* Abbrev: DW_TAG_subprogram */
+       .ascii          "func_cu2\0"            /* DW_AT_name */
+       .4byte          .Ltype_int-.Lcu1_begin  /* DW_AT_type */
+       .4byte          .Lbegin_func_cu2        /* DW_AT_low_pc */
+       .4byte          .Lend_func_cu2          /* DW_AT_high_pc */
+
+.Ltype_int:
+       .uleb128        3                       /* Abbrev: DW_TAG_base_type */
+       .ascii          "int\0"                 /* DW_AT_name */
+       .byte           4                       /* DW_AT_byte_size */
+       .byte           5                       /* DW_AT_encoding */
+
+       .byte           0                       /* End of children of CU */
+
+.Lcu1_end:
+
+        .section .debug_ranges
+.Lrange1_begin:
+        .4byte  0xffffffff                      /* base address marker */
+       .4byte  .Lbegin_text1                   /* base address */
+        .4byte  0                               /* start offset */
+       .4byte  .Lend_text1 - .Lbegin_text1     /* end offset */
+        .4byte  0xffffffff                      /* base address marker */
+       .4byte  .Lbegin_text2                   /* base address */
+        .4byte  0                               /* start offset */
+       .4byte  .Lend_text2 - .Lbegin_text2     /* end offset */
+        .4byte  0                               /* End marker (Part 1) */
+        .4byte  0                               /* End marker (Part 2) */
+
+       .section .debug_abbrev
+.Labbrev1_begin:
+       .uleb128        1                       /* Abbrev code */
+       .uleb128        0x11                    /* DW_TAG_compile_unit */
+       .byte           1                       /* has_children */
+        .uleb128       0x55                    /* DW_AT_ranges */
+       .uleb128        0x17                    /* DW_FORM_sec_offset */
+       .uleb128        0x3                     /* DW_AT_name */
+       .uleb128        0x8                     /* DW_FORM_string */
+       .uleb128        0x13                    /* DW_AT_language */
+       .uleb128        0xb                     /* DW_FORM_data1 */
+       .byte           0x0                     /* Terminator */
+       .byte           0x0                     /* Terminator */
+
+       .uleb128        2                       /* Abbrev code */
+       .uleb128        0x2e                    /* DW_TAG_subprogram */
+       .byte           0                       /* has_children */
+       .uleb128        0x3                     /* DW_AT_name */
+       .uleb128        0x8                     /* DW_FORM_string */
+       .uleb128        0x49                    /* DW_AT_type */
+       .uleb128        0x13                    /* DW_FORM_ref4 */
+       .uleb128        0x11                    /* DW_AT_low_pc */
+       .uleb128        0x1                     /* DW_FORM_addr */
+       .uleb128        0x12                    /* DW_AT_high_pc */
+       .uleb128        0x1                     /* DW_FORM_addr */
+       .byte           0x0                     /* Terminator */
+       .byte           0x0                     /* Terminator */
+
+       .uleb128        3                       /* Abbrev code */
+       .uleb128        0x24                    /* DW_TAG_base_type */
+       .byte           0                       /* has_children */
+       .uleb128        0x3                     /* DW_AT_name */
+       .uleb128        0x8                     /* DW_FORM_string */
+       .uleb128        0xb                     /* DW_AT_byte_size */
+       .uleb128        0xb                     /* DW_FORM_data1 */
+       .uleb128        0x3e                    /* DW_AT_encoding */
+       .uleb128        0xb                     /* DW_FORM_data1 */
+       .byte           0x0                     /* Terminator */
+       .byte           0x0                     /* Terminator */
+
+       .byte           0x0                     /* Terminator */
+       .byte           0x0                     /* Terminator */
diff --git a/binutils/testsuite/binutils-all/dw2-ranges.W b/binutils/testsuite/binutils-all/dw2-ranges.W
new file mode 100644 (file)
index 0000000..4dfd248
--- /dev/null
@@ -0,0 +1,11 @@
+
+.*:     file format .*
+
+Contents of the \.debug_ranges section:
+
+    Offset   Begin    End
+    00000000 ffffffff 00000004 \(base address\)
+    00000000 00000004 00000008 
+    00000000 ffffffff 00000008 \(base address\)
+    00000000 00000008 0000000c 
+    00000000 <End of list>
index c3cbb13adc230260ed702b989e28ed202111300e..66b27e37d6075f23fa1cb24da3a4e715e61a6f13 100644 (file)
@@ -244,6 +244,35 @@ if { ![is_elf_format]
     }
 }
 
+# Test objdump -W on a file containing debug_ranges information.
+
+if { ![is_elf_format] } then {
+    unsupported "objdump debug_ranges test"
+} elseif { ![binutils_assemble $srcdir/$subdir/dw2-ranges.S tmpdir/dw2-ranges.o] } then {
+    fail "objdump debug_ranges test"
+} else {
+    if [is_remote host] {
+       set ranges_testfile [remote_download host tmpdir/dw2-ranges.o]
+    } else {
+       set ranges_testfile tmpdir/dw2-ranges.o
+    }
+
+    set got [remote_exec host "$OBJDUMP $OBJDUMPFLAGS --dwarf=Ranges $ranges_testfile" "" "/dev/null" "objdump.out"]
+
+    if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+       fail "objdump -W for debug_ranges (reason: unexpected output)"
+       send_log $got
+       send_log "\n"
+    }
+
+    if { [regexp_diff objdump.out $srcdir/$subdir/dw2-ranges.W] } then {
+       fail "objdump -W for debug_ranges"
+    } else {
+       pass "objdump -W for debug_ranges"
+    }
+}
+
+
 # Options which are not tested: -a -d -D -R -T -x -l --stabs
 # I don't see any generic way to test any of these other than -a.
 # Tests could be written for specific targets, and that should be done