gdb: fix issues with handling DWARF v5 rnglists & .dwo files.
authorCaroline Tice <cmtice@google.com>
Wed, 1 Jul 2020 19:39:08 +0000 (12:39 -0700)
committerSimon Marchi <simon.marchi@polymtl.ca>
Thu, 16 Jul 2020 15:37:15 +0000 (11:37 -0400)
While experimenting with GDB on DWARF 5 with split debug (dwo files),
I discovered that GDB was not reading the rnglist index
properly (it needed to be reprocessed in the same way the loclist
index does), and that there was no code for reading rnglists out of
dwo files at all.  Also, the rnglist address reading function
(dwarf2_rnglists_process) was adding the base address to all rnglist
entries, when it's only supposed to add it to the DW_RLE_offset_pair
entries (http://dwarfstd.org/doc/DWARF5.pdf, p. 53), and was not
handling several entry types.

- Added 'reprocessing' for reading rnglist index (as is done for loclist
  index).
- Added code for reading rnglists out of .dwo files.
- Added several missing rnglist forms to dwarf2_rnglists_process.
- Fixed bug that was alwayas adding base address for rnglists (only
  one form needs that).
- Updated dwarf2_rnglists_process to read rnglist out of dwo file when
  appropriate.
- Added new functions cu_debug_rnglist_section & read_rnglist_index.
- Added new testcase, dw5-rnglist-test.{cc,exp}

Special note about the new testcase:

In order for the test case to test anything meaningful, it must be
compiled with clang, not GCC.  The way to do this is as follows:

$ make check RUNTESTFLAGS="CC_FOR_TARGET=/path/to/clang CXX_FOR_TARGET=/path/to/clang++ dw5-rnglist-test.exp"

This following version of clang was used for this testing:

clang version 9.0.1-11
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

Change-Id: I3053c5ddc345720b8ed81e23a88fe537ab38748d

gdb/ChangeLog
gdb/dwarf2/read.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/dw5-rnglist-test.cc [new file with mode: 0644]
gdb/testsuite/gdb.dwarf2/dw5-rnglist-test.exp [new file with mode: 0644]

index f30edafdf92b3c6d134bf9e2695fedb20fd42893..bafb68e35b7c901981b0a6f286546f2999564dd0 100644 (file)
@@ -1,3 +1,46 @@
+2020-07-16  Caroline Tice  <cmtice@google.com>
+
+       * dwarf2/read.c (RNGLIST_HEADER_SIZE32) New constant definition.
+       (RNGLIST_HEADER_SIZE64): New constant definition.
+       (struct dwop_section_names): Add rnglists_dwo.
+       (dwop_section_names): Add .debug_rnglists.dwo, .zdebug_rnglists.dwo.
+       (struct loclist_header): Rename to 'loclists_rnglists_header'.
+       (struct dwo_sections): Add rnglists field.
+       (read_attribut_reprocess): Add tag parameter.
+       (dwarf2_ranges_read): Add tag parameter & remove forward function decl.
+       (cu_debug_rnglists_section): New function (decl & definition).
+       (dwarf2_locate_dwo_sections): Add code to read rnglists_dwo section.
+       (dwarf2_rnglists_process): Add a dwarf_tag parameter, for the kind of
+       die whose range is being checked; get rnglist section from
+       cu_debug_rnglists_section, to get from either objfile or dwo file as
+       appropriate.  Add cases for DW_RLE_base_addressx,
+       DW_RLE_startx_length, DW_RLE_startx_endx.  Also, update to only add
+       the base address to DW_RLE_offset_pairs (not to all ranges), moving
+       test inside if-condition and updating complaint message.
+       (dwarf2_ranges_process): Add dwarf tag parameter and pass it to
+       dwarf2_rnglists_process.
+       (dwarf2_ranges_read): Add dwarf tag parameter and pass it to
+       dwarf2_ranges_process.
+       (dwarf2_get_pc_bounds): Check for DW_FORM_rnglistx when setting
+       need_ranges_base and update comment appropriately.  Also pass die tag
+       to dwarf2_ranges_read.
+       (dwarf2_record_block_ranges): Check for DW_FORM_rnglistx when setting
+       need_ranges_base and update comment appropriately.  Also pass die tag
+       to dwarf2_ranges_process.
+       (read_full_die_1): Add code to read DW_AT_rnglists_base and assign to
+       cu->ranges_base.  Also pass die tag to read_attribute_reprocess.
+       (partial_die_info::read): Check for DW_FORM_rnglistx when setting
+       need_ranges_base and update comment appropriately.  Also pass die tag
+       to read_attribute_reprocess and dwarf2_ranges_read.
+       (read_loclist_header): Rename function to read_loclists_rnglists_header,
+       and update function comment appropriately.
+       (read_loclist_index): Call read_loclists_rnglists_header instead of
+       read_loclist_header.
+       (read_rnglist_index): New function.
+       (read_attribute_reprocess):  Add tag parameter. Add code for
+       DW_FORM_rnglistx, passing tag to read_rnglist_index.
+       (read_attribute_value): Mark DW_FORM_rnglistx with need_reprocess.
+
 2020-07-15  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * f-typeprint.c (f_type_print_base): Allow for dynamic types not
index 558fad74f804180a9969a1415ffa23957a8dcac6..39ed455def5dc7838de4283e52eb6632a83fba7d 100644 (file)
@@ -132,6 +132,12 @@ static int dwarf2_loclist_block_index;
 /* Size of .debug_loclists section header for 64-bit DWARF format.  */
 #define LOCLIST_HEADER_SIZE64 20
 
+/* Size of .debug_rnglists section header for 32-bit DWARF format.  */
+#define RNGLIST_HEADER_SIZE32 12
+
+/* Size of .debug_rnglists section header for 64-bit DWARF format.  */
+#define RNGLIST_HEADER_SIZE64 20
+
 /* An index into a (C++) symbol name component in a symbol name as
    recorded in the mapped_index's symbol table.  For each C++ symbol
    in the symbol table, we record one entry for the start of each
@@ -340,6 +346,7 @@ static const struct dwop_section_names
   struct dwarf2_section_names loclists_dwo;
   struct dwarf2_section_names macinfo_dwo;
   struct dwarf2_section_names macro_dwo;
+  struct dwarf2_section_names rnglists_dwo;
   struct dwarf2_section_names str_dwo;
   struct dwarf2_section_names str_offsets_dwo;
   struct dwarf2_section_names types_dwo;
@@ -355,6 +362,7 @@ dwop_section_names =
   { ".debug_loclists.dwo", ".zdebug_loclists.dwo" },
   { ".debug_macinfo.dwo", ".zdebug_macinfo.dwo" },
   { ".debug_macro.dwo", ".zdebug_macro.dwo" },
+  { ".debug_rnglists.dwo", ".zdebug_rnglists.dwo" },
   { ".debug_str.dwo", ".zdebug_str.dwo" },
   { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo" },
   { ".debug_types.dwo", ".zdebug_types.dwo" },
@@ -364,9 +372,9 @@ dwop_section_names =
 
 /* local data types */
 
-/* The location list section (.debug_loclists) begins with a header,
-   which contains the following information.  */
-struct loclist_header
+/* The location list and range list sections (.debug_loclists & .debug_rnglists)
+   begin with a header,  which contains the following information.  */
+struct loclists_rnglists_header
 {
   /* A 4-byte or 12-byte length containing the length of the
      set of entries for this compilation unit, not including the
@@ -650,6 +658,7 @@ struct dwo_sections
   struct dwarf2_section_info loclists;
   struct dwarf2_section_info macinfo;
   struct dwarf2_section_info macro;
+  struct dwarf2_section_info rnglists;
   struct dwarf2_section_info str;
   struct dwarf2_section_info str_offsets;
   /* In the case of a virtual DWO file, these two are unused.  */
@@ -1274,7 +1283,7 @@ static const gdb_byte *read_attribute (const struct die_reader_specs *,
                                       const gdb_byte *, bool *need_reprocess);
 
 static void read_attribute_reprocess (const struct die_reader_specs *reader,
-                                     struct attribute *attr);
+                                     struct attribute *attr, dwarf_tag tag);
 
 static CORE_ADDR read_addr_index (struct dwarf2_cu *cu, unsigned int addr_index);
 
@@ -1378,12 +1387,13 @@ static void read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu);
 
 static void read_variable (struct die_info *die, struct dwarf2_cu *cu);
 
-static int dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *,
-                              struct dwarf2_cu *, dwarf2_psymtab *);
-
 /* Return the .debug_loclists section to use for cu.  */
 static struct dwarf2_section_info *cu_debug_loc_section (struct dwarf2_cu *cu);
 
+/* Return the .debug_rnglists section to use for cu.  */
+static struct dwarf2_section_info *cu_debug_rnglists_section
+  (struct dwarf2_cu *cu, dwarf_tag tag);
+
 /* How dwarf2_get_pc_bounds constructed its *LOWPC and *HIGHPC return
    values.  Keep the items ordered with increasing constraints compliance.  */
 enum pc_bounds_kind
@@ -12447,6 +12457,11 @@ dwarf2_locate_dwo_sections (bfd *abfd, asection *sectp, void *dwo_sections_ptr)
       dwo_sections->macro.s.section = sectp;
       dwo_sections->macro.size = bfd_section_size (sectp);
     }
+  else if (section_is_p (sectp->name, &names->rnglists_dwo))
+    {
+      dwo_sections->rnglists.s.section = sectp;
+      dwo_sections->rnglists.size = bfd_section_size (sectp);
+    }
   else if (section_is_p (sectp->name, &names->str_dwo))
     {
       dwo_sections->str.s.section = sectp;
@@ -13791,7 +13806,7 @@ read_variable (struct die_info *die, struct dwarf2_cu *cu)
 template <typename Callback>
 static bool
 dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
-                        Callback &&callback)
+                        dwarf_tag tag, Callback &&callback)
 {
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
   struct objfile *objfile = per_objfile->objfile;
@@ -13801,17 +13816,20 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
   const gdb_byte *buffer;
   CORE_ADDR baseaddr;
   bool overflow = false;
+  ULONGEST addr_index;
+  struct dwarf2_section_info *rnglists_section;
 
   base = cu->base_address;
+  rnglists_section = cu_debug_rnglists_section (cu, tag);
+  rnglists_section->read (objfile);
 
-  per_objfile->per_bfd->rnglists.read (objfile);
-  if (offset >= per_objfile->per_bfd->rnglists.size)
+  if (offset >= rnglists_section->size)
     {
       complaint (_("Offset %d out of bounds for DW_AT_ranges attribute"),
                 offset);
       return false;
     }
-  buffer = per_objfile->per_bfd->rnglists.buffer + offset;
+  buffer = rnglists_section->buffer + offset;
 
   baseaddr = objfile->text_section_offset ();
 
@@ -13819,8 +13837,8 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
     {
       /* Initialize it due to a false compiler warning.  */
       CORE_ADDR range_beginning = 0, range_end = 0;
-      const gdb_byte *buf_end = (per_objfile->per_bfd->rnglists.buffer
-                                + per_objfile->per_bfd->rnglists.size);
+      const gdb_byte *buf_end = (rnglists_section->buffer
+                                + rnglists_section->size);
       unsigned int bytes_read;
 
       if (buffer == buf_end)
@@ -13842,6 +13860,11 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
          base = cu->header.read_address (obfd, buffer, &bytes_read);
          buffer += bytes_read;
          break;
+        case DW_RLE_base_addressx:
+          addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
+          buffer += bytes_read;
+          base = read_addr_index (cu, addr_index);
+          break;
        case DW_RLE_start_length:
          if (buffer + cu->header.addr_size > buf_end)
            {
@@ -13860,6 +13883,19 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
              break;
            }
          break;
+       case DW_RLE_startx_length:
+          addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
+          buffer += bytes_read;
+          range_beginning = read_addr_index (cu, addr_index);
+          if (buffer > buf_end)
+            {
+              overflow = true;
+              break;
+            }
+          range_end = (range_beginning
+                       + read_unsigned_leb128 (obfd, buffer, &bytes_read));
+          buffer += bytes_read;
+          break;
        case DW_RLE_offset_pair:
          range_beginning = read_unsigned_leb128 (obfd, buffer, &bytes_read);
          buffer += bytes_read;
@@ -13888,6 +13924,19 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
          range_end = cu->header.read_address (obfd, buffer, &bytes_read);
          buffer += bytes_read;
          break;
+       case DW_RLE_startx_endx:
+          addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
+          buffer += bytes_read;
+          range_beginning = read_addr_index (cu, addr_index);
+          if (buffer > buf_end)
+            {
+              overflow = true;
+              break;
+            }
+          addr_index = read_unsigned_leb128 (obfd, buffer, &bytes_read);
+          buffer += bytes_read;
+          range_end = read_addr_index (cu, addr_index);
+          break;
        default:
          complaint (_("Invalid .debug_rnglists data (no base address)"));
          return false;
@@ -13897,14 +13946,6 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
       if (rlet == DW_RLE_base_address)
        continue;
 
-      if (!base.has_value ())
-       {
-         /* We have no valid base address for the ranges
-            data.  */
-         complaint (_("Invalid .debug_rnglists data (no base address)"));
-         return false;
-       }
-
       if (range_beginning > range_end)
        {
          /* Inverted range entries are invalid.  */
@@ -13916,8 +13957,20 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
       if (range_beginning == range_end)
        continue;
 
-      range_beginning += *base;
-      range_end += *base;
+      /* Only DW_RLE_offset_pair needs the base address added.  */
+      if (rlet == DW_RLE_offset_pair)
+       {
+         if (!base.has_value ())
+           {
+             /* We have no valid base address for the DW_RLE_offset_pair.  */
+             complaint (_("Invalid .debug_rnglists data (no base address for "
+                          "DW_RLE_offset_pair)"));
+             return false;
+           }
+
+         range_beginning += *base;
+         range_end += *base;
+       }
 
       /* A not-uncommon case of bad debug info.
         Don't pollute the addrmap with bad data.  */
@@ -13950,7 +14003,7 @@ dwarf2_rnglists_process (unsigned offset, struct dwarf2_cu *cu,
 
 template <typename Callback>
 static int
-dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu,
+dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu, dwarf_tag tag,
                       Callback &&callback)
 {
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
@@ -13966,7 +14019,7 @@ dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu,
   CORE_ADDR baseaddr;
 
   if (cu_header->version >= 5)
-    return dwarf2_rnglists_process (offset, cu, callback);
+    return dwarf2_rnglists_process (offset, cu, tag, callback);
 
   base = cu->base_address;
 
@@ -14052,7 +14105,7 @@ dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu,
 static int
 dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
                    CORE_ADDR *high_return, struct dwarf2_cu *cu,
-                   dwarf2_psymtab *ranges_pst)
+                   dwarf2_psymtab *ranges_pst, dwarf_tag tag)
 {
   struct objfile *objfile = cu->per_objfile->objfile;
   struct gdbarch *gdbarch = objfile->arch ();
@@ -14062,7 +14115,7 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
   CORE_ADDR high = 0;
   int retval;
 
-  retval = dwarf2_ranges_process (offset, cu,
+  retval = dwarf2_ranges_process (offset, cu, tag,
     [&] (CORE_ADDR range_beginning, CORE_ADDR range_end)
     {
       if (ranges_pst != NULL)
@@ -14154,8 +14207,14 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
        {
          /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
             We take advantage of the fact that DW_AT_ranges does not appear
-            in DW_TAG_compile_unit of DWO files.  */
-         int need_ranges_base = die->tag != DW_TAG_compile_unit;
+            in DW_TAG_compile_unit of DWO files.
+
+            Attributes of the form DW_FORM_rnglistx have already had their
+            value changed by read_rnglist_index and already include
+            DW_AT_rnglists_base, so don't need to add the ranges base,
+            either.  */
+         int need_ranges_base = (die->tag != DW_TAG_compile_unit
+                                 && attr->form != DW_FORM_rnglistx);
          unsigned int ranges_offset = (DW_UNSND (attr)
                                        + (need_ranges_base
                                           ? cu->ranges_base
@@ -14163,7 +14222,8 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
 
          /* Value of the DW_AT_ranges attribute is the offset in the
             .debug_ranges section.  */
-         if (!dwarf2_ranges_read (ranges_offset, &low, &high, cu, pst))
+         if (!dwarf2_ranges_read (ranges_offset, &low, &high, cu, pst,
+                                  die->tag))
            return PC_BOUNDS_INVALID;
          /* Found discontinuous range of addresses.  */
          ret = PC_BOUNDS_RANGES;
@@ -14325,8 +14385,14 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block,
     {
       /* DW_AT_rnglists_base does not apply to DIEs from the DWO skeleton.
         We take advantage of the fact that DW_AT_ranges does not appear
-        in DW_TAG_compile_unit of DWO files.  */
-      int need_ranges_base = die->tag != DW_TAG_compile_unit;
+        in DW_TAG_compile_unit of DWO files.
+
+        Attributes of the form DW_FORM_rnglistx have already had their
+        value changed by read_rnglist_index and already include
+        DW_AT_rnglists_base, so don't need to add the ranges base,
+        either.  */
+      int need_ranges_base = (die->tag != DW_TAG_compile_unit
+                             && attr->form != DW_FORM_rnglistx);
 
       /* The value of the DW_AT_ranges attribute is the offset of the
          address range list in the .debug_ranges section.  */
@@ -14334,7 +14400,7 @@ dwarf2_record_block_ranges (struct die_info *die, struct block *block,
                              + (need_ranges_base ? cu->ranges_base : 0));
 
       std::vector<blockrange> blockvec;
-      dwarf2_ranges_process (offset, cu,
+      dwarf2_ranges_process (offset, cu, die->tag,
        [&] (CORE_ADDR start, CORE_ADDR end)
        {
          start += baseaddr;
@@ -18154,8 +18220,13 @@ read_full_die_1 (const struct die_reader_specs *reader,
   auto maybe_addr_base = die->addr_base ();
   if (maybe_addr_base.has_value ())
     cu->addr_base = *maybe_addr_base;
+
+  attr = die->attr (DW_AT_rnglists_base);
+  if (attr != nullptr)
+    cu->ranges_base = DW_UNSND (attr);
+
   for (int index : indexes_that_need_reprocess)
-    read_attribute_reprocess (reader, &die->attrs[index]);
+    read_attribute_reprocess (reader, &die->attrs[index], die->tag);
   *diep = die;
   return info_ptr;
 }
@@ -18524,7 +18595,7 @@ partial_die_info::read (const struct die_reader_specs *reader,
          already been read at this point, so there is no need to wait until
         the loop terminates to do the reprocessing.  */
       if (need_reprocess)
-       read_attribute_reprocess (reader, &attr);
+       read_attribute_reprocess (reader, &attr, tag);
       /* Store the data if it is of an attribute we want to keep in a
          partial symbol table.  */
       switch (attr.name)
@@ -18670,10 +18741,16 @@ partial_die_info::read (const struct die_reader_specs *reader,
 
        case DW_AT_ranges:
          {
-           /* It would be nice to reuse dwarf2_get_pc_bounds here,
-              but that requires a full DIE, so instead we just
-              reimplement it.  */
-           int need_ranges_base = tag != DW_TAG_compile_unit;
+           /* DW_AT_rnglists_base does not apply to DIEs from the DWO
+              skeleton.  We take advantage of the fact the DW_AT_ranges
+              does not appear in DW_TAG_compile_unit of DWO files.
+
+              Attributes of the form DW_FORM_rnglistx have already had
+               their value changed by read_rnglist_index and already
+              include DW_AT_rnglists_base, so don't need to add the ranges
+              base, either.  */
+           int need_ranges_base = (tag != DW_TAG_compile_unit
+                                   && attr.form != DW_FORM_rnglistx);
            unsigned int ranges_offset = (DW_UNSND (&attr)
                                          + (need_ranges_base
                                             ? cu->ranges_base
@@ -18682,7 +18759,7 @@ partial_die_info::read (const struct die_reader_specs *reader,
            /* Value of the DW_AT_ranges attribute is the offset in the
               .debug_ranges section.  */
            if (dwarf2_ranges_read (ranges_offset, &lowpc, &highpc, cu,
-                                   nullptr))
+                                   nullptr, tag))
              has_pc_info = 1;
          }
          break;
@@ -19006,11 +19083,11 @@ partial_die_info::fixup (struct dwarf2_cu *cu)
   fixup_called = 1;
 }
 
-/* Read the .debug_loclists header contents from the given SECTION in the
-   HEADER.  */
+/* Read the .debug_loclists or .debug_rnglists header (they are the same format)
+   contents from the given SECTION in the HEADER.  */
 static void
-read_loclist_header (struct loclist_header *header,
-                     struct dwarf2_section_info *section)
+read_loclists_rnglists_header (struct loclists_rnglists_header *header,
+                              struct dwarf2_section_info *section)
 {
   unsigned int bytes_read;
   bfd *abfd = section->get_bfd_owner ();
@@ -19063,8 +19140,8 @@ read_loclist_index (struct dwarf2_cu *cu, ULONGEST loclist_index)
   if (section->buffer == NULL)
     complaint (_("DW_FORM_loclistx used without .debug_loclists "
                "section [in module %s]"), objfile_name (objfile));
-  struct loclist_header header;
-  read_loclist_header (&header, section);
+  struct loclists_rnglists_header header;
+  read_loclists_rnglists_header (&header, section);
   if (loclist_index >= header.offset_entry_count)
     complaint (_("DW_FORM_loclistx pointing outside of "
                ".debug_loclists offset array [in module %s]"),
@@ -19083,13 +19160,68 @@ read_loclist_index (struct dwarf2_cu *cu, ULONGEST loclist_index)
     return bfd_get_64 (abfd, info_ptr) + loclist_base;
 }
 
+/* Given a DW_FORM_rnglistx value RNGLIST_INDEX, fetch the offset from the
+   array of offsets in the .debug_rnglists section.  */
+static CORE_ADDR
+read_rnglist_index (struct dwarf2_cu *cu, ULONGEST rnglist_index,
+                   dwarf_tag tag)
+{
+  struct dwarf2_per_objfile *dwarf2_per_objfile = cu->per_objfile;
+  struct objfile *objfile = dwarf2_per_objfile->objfile;
+  bfd *abfd = objfile->obfd;
+  ULONGEST rnglist_header_size =
+    (cu->header.initial_length_size == 4 ? RNGLIST_HEADER_SIZE32
+     : RNGLIST_HEADER_SIZE64);
+  ULONGEST rnglist_base =
+      (cu->dwo_unit != nullptr) ? rnglist_header_size : cu->ranges_base;
+  ULONGEST start_offset =
+    rnglist_base + rnglist_index * cu->header.offset_size;
+
+  /* Get rnglists section.  */
+  struct dwarf2_section_info *section = cu_debug_rnglists_section (cu, tag);
+
+  /* Read the rnglists section content.  */
+  section->read (objfile);
+  if (section->buffer == nullptr)
+    error (_("DW_FORM_rnglistx used without .debug_rnglists section "
+            "[in module %s]"),
+          objfile_name (objfile));
+
+  /* Verify the rnglist index is valid.  */
+  struct loclists_rnglists_header header;
+  read_loclists_rnglists_header (&header, section);
+  if (rnglist_index >= header.offset_entry_count)
+    error (_("DW_FORM_rnglistx index pointing outside of "
+            ".debug_rnglists offset array [in module %s]"),
+          objfile_name (objfile));
+
+  /* Validate that the offset is within the section's range.  */
+  if (start_offset >= section->size)
+    error (_("DW_FORM_rnglistx pointing outside of "
+             ".debug_rnglists section [in module %s]"),
+          objfile_name (objfile));
+
+  /* Validate that reading won't go beyond the end of the section.  */
+  if (start_offset + cu->header.offset_size > rnglist_base + section->size)
+    error (_("Reading DW_FORM_rnglistx index beyond end of"
+            ".debug_rnglists section [in module %s]"),
+          objfile_name (objfile));
+
+  const gdb_byte *info_ptr = section->buffer + start_offset;
+
+  if (cu->header.offset_size == 4)
+    return read_4_bytes (abfd, info_ptr) + rnglist_base;
+  else
+    return read_8_bytes (abfd, info_ptr) + rnglist_base;
+}
+
 /* Process the attributes that had to be skipped in the first round. These
    attributes are the ones that need str_offsets_base or addr_base attributes.
    They could not have been processed in the first round, because at the time
    the values of str_offsets_base or addr_base may not have been known.  */
 static void
 read_attribute_reprocess (const struct die_reader_specs *reader,
-                         struct attribute *attr)
+                         struct attribute *attr, dwarf_tag tag)
 {
   struct dwarf2_cu *cu = reader->cu;
   switch (attr->form)
@@ -19101,6 +19233,9 @@ read_attribute_reprocess (const struct die_reader_specs *reader,
       case DW_FORM_loclistx:
         DW_UNSND (attr) = read_loclist_index (cu, DW_UNSND (attr));
         break;
+      case DW_FORM_rnglistx:
+        DW_UNSND (attr) = read_rnglist_index (cu, DW_UNSND (attr), tag);
+        break;
       case DW_FORM_strx:
       case DW_FORM_strx1:
       case DW_FORM_strx2:
@@ -19282,8 +19417,10 @@ read_attribute_value (const struct die_reader_specs *reader,
       DW_SND (attr) = read_signed_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       break;
-    case DW_FORM_udata:
     case DW_FORM_rnglistx:
+      *need_reprocess = true;
+      /* FALLTHROUGH */
+    case DW_FORM_udata:
       DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
       info_ptr += bytes_read;
       break;
@@ -23372,6 +23509,34 @@ cu_debug_loc_section (struct dwarf2_cu *cu)
                                  : &per_objfile->per_bfd->loc);
 }
 
+/* Return the .debug_rnglists section to use for CU.  */
+static struct dwarf2_section_info *
+cu_debug_rnglists_section (struct dwarf2_cu *cu, dwarf_tag tag)
+{
+  if (cu->header.version < 5)
+    error (_(".debug_rnglists section cannot be used in DWARF %d"),
+          cu->header.version);
+  struct dwarf2_per_objfile *dwarf2_per_objfile = cu->per_objfile;
+
+  /* Make sure we read the .debug_rnglists section from the file that
+     contains the DW_AT_ranges attribute we are reading.  Normally that
+     would be the .dwo file, if there is one.  However for DW_TAG_compile_unit
+     or DW_TAG_skeleton unit, we always want to read from objfile/linked
+     program.  */
+  if (cu->dwo_unit != nullptr
+      && tag != DW_TAG_compile_unit
+      && tag != DW_TAG_skeleton_unit)
+    {
+      struct dwo_sections *sections = &cu->dwo_unit->dwo_file->sections;
+
+      if (sections->rnglists.size > 0)
+       return &sections->rnglists;
+      else
+       error (_(".debug_rnglists section is missing from .dwo file."));
+    }
+  return &dwarf2_per_objfile->per_bfd->rnglists;
+}
+
 /* A helper function that fills in a dwarf2_loclist_baton.  */
 
 static void
index 78344179649a28343950b44078aa78ee357d111f..5eb9847b3e086ecc02f23889669bbbba206bcaae 100644 (file)
@@ -1,3 +1,8 @@
+2020-07-16  Caroline Tice  <cmtice@google.com>
+
+       * gdb.dwarf2/dw5-rnglist-test.cc: New file.
+       * gdb.dwarf2/dw5-rnglist-test.exp: New file.
+
 2020-07-16  Tom de Vries  <tdevries@suse.de>
 
        * lib/dwarf.exp (program): Initialize _line.
diff --git a/gdb/testsuite/gdb.dwarf2/dw5-rnglist-test.cc b/gdb/testsuite/gdb.dwarf2/dw5-rnglist-test.cc
new file mode 100644 (file)
index 0000000..81693f5
--- /dev/null
@@ -0,0 +1,97 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2020 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/>.  */
+
+#include <iostream>
+#include <vector>
+
+struct node {
+  int id;
+  node *left;
+  node *right;
+  bool visited;
+};
+
+node  node_array[50];
+unsigned int CUR_IDX = 0;
+
+node *
+make_node (int val)
+{
+  node *new_node = &(node_array[CUR_IDX++]);
+  new_node->left = NULL;
+  new_node->right = NULL;
+  new_node->id = val;
+  new_node->visited = false;
+
+  return new_node;
+}
+
+void
+tree_insert (node *root, int val)
+{
+  if (val < root->id)
+    {
+      if (root->left)
+        tree_insert (root->left, val);
+      else
+        root->left = make_node(val);
+    }
+  else if (val > root->id)
+    {
+      if (root->right)
+        tree_insert (root->right, val);
+      else
+        root->right = make_node(val);
+    }
+}
+
+void
+inorder (node *root)
+{
+  std::vector<node *> todo;
+  todo.push_back (root);
+  while (!todo.empty())
+    {
+      node *curr = todo.back();
+      todo.pop_back(); /* break-here */
+      if (curr->visited)
+        std::cout << curr->id << " ";
+      else
+        {
+          curr->visited = true;
+          if (curr->right)
+            todo.push_back (curr->right);
+          todo.push_back (curr);
+          if (curr->left)
+            todo.push_back (curr->left);
+        }
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  node *root = make_node (35);
+
+  tree_insert (root, 28);
+  tree_insert (root, 20);
+  tree_insert (root, 60);
+
+  inorder (root);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/dw5-rnglist-test.exp b/gdb/testsuite/gdb.dwarf2/dw5-rnglist-test.exp
new file mode 100644 (file)
index 0000000..af6c34b
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright 2020 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/>.
+
+# Check that GDB can find the variables in a lexical block with a
+# DW_FORM_rnglistx DW_AT_ranges field.  This test is intended for DWARF-5,
+# compiled with clang++.
+
+standard_testfile .cc
+
+# This test is intended for targets which support DWARF-5.
+# Since we pass an explicit -gdwarf-5 to the compiler,
+# we let that be the test of whether the target supports it.
+
+if { [prepare_for_testing "failed to prepare" "${testfile}" \
+          $srcfile {debug c++ additional_flags=-gdwarf-5 \
+                        additional_flags=-O0}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break-here"]
+gdb_continue_to_breakpoint "break-here" ".* break-here .*"
+
+gdb_test "print curr" "\\\(node \\\*\\\) $hex <node_array>"
+gdb_test "print *curr" "= {id = 35, left = $hex <node_array\\+$decimal>, right = $hex <node_array\\+$decimal>, visited = false}"
This page took 0.056365 seconds and 4 git commands to generate.