Use startswith more for strncmp function calls.
[binutils-gdb.git] / binutils / dwarf.c
index 5275994871849f5ab00de7ae6f8ea52dba5e1bba..293d33ec9acb849d34e7f74b0b465e06b1320194 100644 (file)
@@ -1,5 +1,5 @@
 /* dwarf.c -- display DWARF contents of a BFD binary file
-   Copyright (C) 2005-2020 Free Software Foundation, Inc.
+   Copyright (C) 2005-2021 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -21,7 +21,7 @@
 #include "sysdep.h"
 #include "libiberty.h"
 #include "bfd.h"
-#include "bfd_stdint.h"
+#include <stdint.h>
 #include "bucomm.h"
 #include "elfcomm.h"
 #include "elf/common.h"
 #include <elfutils/debuginfod.h>
 #endif
 
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
 #undef MAX
 #undef MIN
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
@@ -67,11 +74,12 @@ typedef struct dwo_info
 {
   dwo_type          type;
   const char *      value;
+  dwarf_vma         cu_offset;
   struct dwo_info * next;
 } dwo_info;
 
-static dwo_info *   first_dwo_info = NULL;
-static bfd_boolean  need_dwo_info;
+static dwo_info *first_dwo_info = NULL;
+static bool need_dwo_info;
 
 separate_info * first_separate_info = NULL;
 
@@ -98,8 +106,8 @@ int do_debug_addr;
 int do_debug_cu_index;
 int do_wide;
 int do_debug_links;
-int do_follow_links;
-bfd_boolean do_checks;
+int do_follow_links = DEFAULT_FOR_FOLLOW_LINKS;
+bool do_checks;
 
 int dwarf_cutoff_level = -1;
 unsigned long dwarf_start_die;
@@ -137,13 +145,13 @@ static int tu_count = 0;
 static struct cu_tu_set *cu_sets = NULL;
 static struct cu_tu_set *tu_sets = NULL;
 
-static bfd_boolean load_cu_tu_indexes (void *);
+static bool load_cu_tu_indexes (void *);
 
 /* An array that indicates for a given level of CU nesting whether
    the latest DW_AT_type seen for that level was a signed type or
    an unsigned type.  */
 #define MAX_CU_NESTING (1 << 8)
-static bfd_boolean level_type_signed[MAX_CU_NESTING];
+static bool level_type_signed[MAX_CU_NESTING];
 
 /* Values for do_debug_lines.  */
 #define FLAG_DEBUG_LINES_RAW    1
@@ -325,7 +333,7 @@ dwarf_vmatoa64 (dwarf_vma hvalue, dwarf_vma lvalue, char *buf,
 /* Read in a LEB128 encoded value starting at address DATA.
    If SIGN is true, return a signed LEB128 value.
    If LENGTH_RETURN is not NULL, return in it the number of bytes read.
-   If STATUS_RETURN in not NULL, return with bit 0 (LSB) set if the
+   If STATUS_RETURN is not NULL, return with bit 0 (LSB) set if the
    terminating byte was not found and with bit 1 set if the value
    overflows a dwarf_vma.
    No bytes will be read at address END or beyond.  */
@@ -333,7 +341,7 @@ dwarf_vmatoa64 (dwarf_vma hvalue, dwarf_vma lvalue, char *buf,
 dwarf_vma
 read_leb128 (unsigned char *data,
             const unsigned char *const end,
-            bfd_boolean sign,
+            bool sign,
             unsigned int *length_return,
             int *status_return)
 {
@@ -345,23 +353,31 @@ read_leb128 (unsigned char *data,
   while (data < end)
     {
       unsigned char byte = *data++;
+      unsigned char lost, mask;
+
       num_read++;
 
-      if (shift < sizeof (result) * 8)
+      if (shift < CHAR_BIT * sizeof (result))
        {
          result |= ((dwarf_vma) (byte & 0x7f)) << shift;
-         if ((result >> shift) != (byte & 0x7f))
-           /* Overflow.  */
-           status |= 2;
+         /* These bits overflowed.  */
+         lost = byte ^ (result >> shift);
+         /* And this is the mask of possible overflow bits.  */
+         mask = 0x7f ^ ((dwarf_vma) 0x7f << shift >> shift);
          shift += 7;
        }
-      else if ((byte & 0x7f) != 0)
+      else
+       {
+         lost = byte;
+         mask = 0x7f;
+       }
+      if ((lost & mask) != (sign && (dwarf_signed_vma) result < 0 ? mask : 0))
        status |= 2;
 
       if ((byte & 0x80) == 0)
        {
          status &= ~1;
-         if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
+         if (sign && shift < CHAR_BIT * sizeof (result) && (byte & 0x40))
            result |= -((dwarf_vma) 1 << shift);
          break;
        }
@@ -674,7 +690,7 @@ fetch_indirect_string (dwarf_vma offset)
 
   if (offset >= section->size)
     {
-      warn (_("DW_FORM_strp offset too big: %s\n"),
+      warn (_("DW_FORM_strp offset too big: 0x%s\n"),
            dwarf_vmatoa ("x", offset));
       return (const unsigned char *) _("<offset is too big>");
     }
@@ -688,7 +704,7 @@ fetch_indirect_string (dwarf_vma offset)
     ret = (const unsigned char *)
       _("<no NUL byte at end of .debug_str section>");
 
-  return ret; 
+  return ret;
 }
 
 static const unsigned char *
@@ -702,7 +718,7 @@ fetch_indirect_line_string (dwarf_vma offset)
 
   if (offset >= section->size)
     {
-      warn (_("DW_FORM_line_strp offset too big: %s\n"),
+      warn (_("DW_FORM_line_strp offset too big: 0x%s\n"),
            dwarf_vmatoa ("x", offset));
       return (const unsigned char *) _("<offset is too big>");
     }
@@ -721,7 +737,7 @@ fetch_indirect_line_string (dwarf_vma offset)
 
 static const char *
 fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
-                     dwarf_vma offset_size, bfd_boolean dwo)
+                     dwarf_vma offset_size, bool dwo)
 {
   enum dwarf_section_display_enum str_sec_idx = dwo ? str_dwo : str;
   enum dwarf_section_display_enum idx_sec_idx = dwo ? str_index_dwo : str_index;
@@ -781,13 +797,13 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
     }
 
   index_offset = idx * offset_size;
-      
+
   if (this_set != NULL)
     index_offset += this_set->section_offsets [DW_SECT_STR_OFFSETS];
 
   if (index_offset >= length)
     {
-      warn (_("DW_FORM_GNU_str_index offset too big: %s vs %s\n"),
+      warn (_("DW_FORM_GNU_str_index offset too big: 0x%s vs 0x%s\n"),
            dwarf_vmatoa ("x", index_offset),
            dwarf_vmatoa ("x", length));
       return _("<index offset is too big>");
@@ -797,7 +813,7 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
   str_offset -= str_section->address;
   if (str_offset >= str_section->size)
     {
-      warn (_("DW_FORM_GNU_str_index indirect offset too big: %s\n"),
+      warn (_("DW_FORM_GNU_str_index indirect offset too big: 0x%s\n"),
            dwarf_vmatoa ("x", str_offset));
       return _("<indirect index offset is too big>");
     }
@@ -823,7 +839,7 @@ fetch_indexed_value (dwarf_vma offset, dwarf_vma bytes)
 
   if (offset + bytes > section->size)
     {
-      warn (_("Offset into section %s too big: %s\n"),
+      warn (_("Offset into section %s too big: 0x%s\n"),
            section->name, dwarf_vmatoa ("x", offset));
       return "<offset too big>";
     }
@@ -835,101 +851,208 @@ fetch_indexed_value (dwarf_vma offset, dwarf_vma bytes)
 /* FIXME:  There are better and more efficient ways to handle
    these structures.  For now though, I just want something that
    is simple to implement.  */
+/* Records a single attribute in an abbrev.  */
 typedef struct abbrev_attr
 {
-  unsigned long attribute;
-  unsigned long form;
-  bfd_signed_vma implicit_const;
-  struct abbrev_attr *next;
+  unsigned long          attribute;
+  unsigned long          form;
+  bfd_signed_vma         implicit_const;
+  struct abbrev_attr *   next;
 }
 abbrev_attr;
 
+/* Records a single abbrev.  */
 typedef struct abbrev_entry
 {
-  unsigned long entry;
-  unsigned long tag;
-  int children;
-  struct abbrev_attr *first_attr;
-  struct abbrev_attr *last_attr;
-  struct abbrev_entry *next;
+  unsigned long          number;
+  unsigned long          tag;
+  int                    children;
+  struct abbrev_attr *   first_attr;
+  struct abbrev_attr *   last_attr;
+  struct abbrev_entry *  next;
 }
 abbrev_entry;
 
-static abbrev_entry *first_abbrev = NULL;
-static abbrev_entry *last_abbrev = NULL;
+/* Records a set of abbreviations.  */
+typedef struct abbrev_list
+{
+  abbrev_entry *        first_abbrev;
+  abbrev_entry *        last_abbrev;
+  dwarf_vma             abbrev_base;
+  dwarf_vma             abbrev_offset;
+  struct abbrev_list *  next;
+  unsigned char *       start_of_next_abbrevs;
+}
+abbrev_list;
+
+/* Records all the abbrevs found so far.  */
+static struct abbrev_list * abbrev_lists = NULL;
+
+typedef struct abbrev_map
+{
+  dwarf_vma      start;
+  dwarf_vma      end;
+  abbrev_list *  list;
+} abbrev_map;
+
+/* Maps between CU offsets and abbrev sets.  */
+static abbrev_map *   cu_abbrev_map = NULL;
+static unsigned long  num_abbrev_map_entries = 0;
+static unsigned long  next_free_abbrev_map_entry = 0;
+
+#define INITIAL_NUM_ABBREV_MAP_ENTRIES 8
+#define ABBREV_MAP_ENTRIES_INCREMENT   8
 
 static void
-free_abbrevs (void)
+record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list)
 {
-  abbrev_entry *abbrv;
+  if (cu_abbrev_map == NULL)
+    {
+      num_abbrev_map_entries = INITIAL_NUM_ABBREV_MAP_ENTRIES;
+      cu_abbrev_map = xmalloc (num_abbrev_map_entries * sizeof (* cu_abbrev_map));
+    }
+  else if (next_free_abbrev_map_entry == num_abbrev_map_entries)
+    {
+      num_abbrev_map_entries += ABBREV_MAP_ENTRIES_INCREMENT;
+      cu_abbrev_map = xrealloc (cu_abbrev_map, num_abbrev_map_entries * sizeof (* cu_abbrev_map));
+    }
+
+  cu_abbrev_map[next_free_abbrev_map_entry].start = start;
+  cu_abbrev_map[next_free_abbrev_map_entry].end = end;
+  cu_abbrev_map[next_free_abbrev_map_entry].list = list;
+  next_free_abbrev_map_entry ++;
+}
 
-  for (abbrv = first_abbrev; abbrv;)
+static void
+free_all_abbrevs (void)
+{
+  abbrev_list *  list;
+
+  for (list = abbrev_lists; list != NULL;)
     {
-      abbrev_entry *next_abbrev = abbrv->next;
-      abbrev_attr *attr;
+      abbrev_list *   next = list->next;
+      abbrev_entry *  abbrv;
 
-      for (attr = abbrv->first_attr; attr;)
+      for (abbrv = list->first_abbrev; abbrv != NULL;)
        {
-         abbrev_attr *next_attr = attr->next;
+         abbrev_entry *  next_abbrev = abbrv->next;
+         abbrev_attr *   attr;
+
+         for (attr = abbrv->first_attr; attr;)
+           {
+             abbrev_attr *next_attr = attr->next;
+
+             free (attr);
+             attr = next_attr;
+           }
 
-         free (attr);
-         attr = next_attr;
+         free (abbrv);
+         abbrv = next_abbrev;
        }
 
-      free (abbrv);
-      abbrv = next_abbrev;
+      free (list);
+      list = next;
     }
 
-  last_abbrev = first_abbrev = NULL;
+  abbrev_lists = NULL;
+}
+
+static abbrev_list *
+new_abbrev_list (dwarf_vma abbrev_base, dwarf_vma abbrev_offset)
+{
+  abbrev_list * list = (abbrev_list *) xcalloc (sizeof * list, 1);
+
+  list->abbrev_base = abbrev_base;
+  list->abbrev_offset = abbrev_offset;
+
+  list->next = abbrev_lists;
+  abbrev_lists = list;
+
+  return list;
+}
+
+static abbrev_list *
+find_abbrev_list_by_abbrev_offset (dwarf_vma abbrev_base,
+                                  dwarf_vma abbrev_offset)
+{
+  abbrev_list * list;
+
+  for (list = abbrev_lists; list != NULL; list = list->next)
+    if (list->abbrev_base == abbrev_base
+       && list->abbrev_offset == abbrev_offset)
+      return list;
+
+  return NULL;
+}
+
+/* Find the abbreviation map for the CU that includes OFFSET.
+   OFFSET is an absolute offset from the start of the .debug_info section.  */
+/* FIXME: This function is going to slow down readelf & objdump.
+   Consider using a better algorithm to mitigate this effect.  */
+
+static  abbrev_map *
+find_abbrev_map_by_offset (dwarf_vma offset)
+{
+  unsigned long i;
+
+  for (i = 0; i < next_free_abbrev_map_entry; i++)
+    if (cu_abbrev_map[i].start <= offset
+       && cu_abbrev_map[i].end > offset)
+      return cu_abbrev_map + i;
+
+  return NULL; 
 }
 
 static void
-add_abbrev (unsigned long number, unsigned long tag, int children)
+add_abbrev (unsigned long  number,
+           unsigned long  tag,
+           int            children,
+           abbrev_list *  list)
 {
-  abbrev_entry *entry;
+  abbrev_entry *  entry;
 
-  entry = (abbrev_entry *) malloc (sizeof (*entry));
-  if (entry == NULL)
-    /* ugg */
-    return;
+  entry = (abbrev_entry *) xmalloc (sizeof (*entry));
 
-  entry->entry      = number;
+  entry->number     = number;
   entry->tag        = tag;
   entry->children   = children;
   entry->first_attr = NULL;
   entry->last_attr  = NULL;
   entry->next       = NULL;
 
-  if (first_abbrev == NULL)
-    first_abbrev = entry;
+  assert (list != NULL);
+
+  if (list->first_abbrev == NULL)
+    list->first_abbrev = entry;
   else
-    last_abbrev->next = entry;
+    list->last_abbrev->next = entry;
 
-  last_abbrev = entry;
+  list->last_abbrev = entry;
 }
 
 static void
-add_abbrev_attr (unsigned long attribute, unsigned long form,
-                bfd_signed_vma implicit_const)
+add_abbrev_attr (unsigned long   attribute,
+                unsigned long   form,
+                bfd_signed_vma  implicit_const,
+                abbrev_list *   list)
 {
   abbrev_attr *attr;
 
-  attr = (abbrev_attr *) malloc (sizeof (*attr));
-  if (attr == NULL)
-    /* ugg */
-    return;
+  attr = (abbrev_attr *) xmalloc (sizeof (*attr));
 
   attr->attribute = attribute;
   attr->form      = form;
   attr->implicit_const = implicit_const;
   attr->next      = NULL;
 
-  if (last_abbrev->first_attr == NULL)
-    last_abbrev->first_attr = attr;
+  assert (list != NULL && list->last_abbrev != NULL);
+
+  if (list->last_abbrev->first_attr == NULL)
+    list->last_abbrev->first_attr = attr;
   else
-    last_abbrev->last_attr->next = attr;
+    list->last_abbrev->last_attr->next = attr;
 
-  last_abbrev->last_attr = attr;
+  list->last_abbrev->last_attr = attr;
 }
 
 /* Processes the (partial) contents of a .debug_abbrev section.
@@ -938,11 +1061,10 @@ add_abbrev_attr (unsigned long attribute, unsigned long form,
    an abbreviation set was found.  */
 
 static unsigned char *
-process_abbrev_section (unsigned char *start, unsigned char *end)
+process_abbrev_set (unsigned char *        start,
+                   const unsigned char *  end,
+                   abbrev_list *          list)
 {
-  if (first_abbrev != NULL)
-    return NULL;
-
   while (start < end)
     {
       unsigned long entry;
@@ -952,7 +1074,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end)
 
       READ_ULEB (entry, start, end);
 
-      /* A single zero is supposed to end the section according
+      /* A single zero is supposed to end the set according
         to the standard.  If there's more, then signal that to
         the caller.  */
       if (start == end)
@@ -966,7 +1088,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end)
 
       children = *start++;
 
-      add_abbrev (entry, tag, children);
+      add_abbrev (entry, tag, children, list);
 
       do
        {
@@ -989,7 +1111,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end)
                break;
            }
 
-         add_abbrev_attr (attribute, form, implicit_const);
+         add_abbrev_attr (attribute, form, implicit_const, list);
        }
       while (attribute != 0);
     }
@@ -1739,7 +1861,7 @@ fetch_alt_indirect_string (dwarf_vma offset)
 
       return ret;
     }
-  
+
   warn (_("DW_FORM_GNU_strp_alt offset (%s) too big or no string sections available\n"),
        dwarf_vmatoa ("x", offset));
   return _("<offset is too big>");
@@ -1772,32 +1894,33 @@ get_AT_name (unsigned long attribute)
 }
 
 static void
-add_dwo_info (const char * field, dwo_type type)
+add_dwo_info (const char * value, dwarf_vma cu_offset, dwo_type type)
 {
   dwo_info * dwinfo = xmalloc (sizeof * dwinfo);
 
-  dwinfo->type = type;
-  dwinfo->value = field;
-  dwinfo->next = first_dwo_info;
+  dwinfo->type   = type;
+  dwinfo->value  = value;
+  dwinfo->cu_offset = cu_offset;
+  dwinfo->next   = first_dwo_info;
   first_dwo_info = dwinfo;
 }
 
 static void
-add_dwo_name (const char * name)
+add_dwo_name (const char * name, dwarf_vma cu_offset)
 {
-  add_dwo_info (name, DWO_NAME);
+  add_dwo_info (name, cu_offset, DWO_NAME);
 }
 
 static void
-add_dwo_dir (const char * dir)
+add_dwo_dir (const char * dir, dwarf_vma cu_offset)
 {
-  add_dwo_info (dir, DWO_DIR);
+  add_dwo_info (dir, cu_offset, DWO_DIR);
 }
 
 static void
-add_dwo_id (const char * id)
+add_dwo_id (const char * id, dwarf_vma cu_offset)
 {
-  add_dwo_info (id, DWO_ID);
+  add_dwo_info (id, cu_offset, DWO_ID);
 }
 
 static void
@@ -1854,7 +1977,7 @@ skip_attr_bytes (unsigned long          form,
     case DW_FORM_ref_addr:
       if (dwarf_version == 2)
        SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
-      else if (dwarf_version == 3 || dwarf_version == 4)
+      else if (dwarf_version > 2)
        SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
       else
        return NULL;
@@ -1879,16 +2002,27 @@ skip_attr_bytes (unsigned long          form,
     case DW_FORM_ref1:
     case DW_FORM_flag:
     case DW_FORM_data1:
+    case DW_FORM_strx1:
+    case DW_FORM_addrx1:
       SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
       break;
 
+    case DW_FORM_strx3:
+    case DW_FORM_addrx3:
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 3, end);
+      break;
+
     case DW_FORM_ref2:
     case DW_FORM_data2:
+    case DW_FORM_strx2:
+    case DW_FORM_addrx2:
       SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end);
       break;
 
     case DW_FORM_ref4:
     case DW_FORM_data4:
+    case DW_FORM_strx4:
+    case DW_FORM_addrx4:
       SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
       break;
 
@@ -1900,12 +2034,30 @@ skip_attr_bytes (unsigned long          form,
     case DW_FORM_ref_udata:
     case DW_FORM_udata:
     case DW_FORM_GNU_str_index:
+    case DW_FORM_strx:
     case DW_FORM_GNU_addr_index:
+    case DW_FORM_addrx:
       READ_ULEB (uvalue, data, end);
       break;
 
     case DW_FORM_ref8:
+      {
+       dwarf_vma high_bits;
+
+       SAFE_BYTE_GET64 (data, &high_bits, &uvalue, end);
+       data += 8;
+       if (sizeof (uvalue) > 4)
+         uvalue += high_bits << 32;
+       else if (high_bits != 0)
+         {
+           /* FIXME: What to do ?  */
+           return NULL;
+         }
+       break;
+      }
+
     case DW_FORM_data8:
+    case DW_FORM_ref_sig8:
       data += 8;
       break;
 
@@ -1920,6 +2072,7 @@ skip_attr_bytes (unsigned long          form,
     case DW_FORM_block:
     case DW_FORM_exprloc:
       READ_ULEB (uvalue, data, end);
+      data += uvalue;
       break;
 
     case DW_FORM_block1:
@@ -1937,12 +2090,12 @@ skip_attr_bytes (unsigned long          form,
       data += 4 + uvalue;
       break;
 
-    case DW_FORM_ref_sig8:
-      data += 8;
-      break;
-
     case DW_FORM_indirect:
-      /* FIXME: Handle this form.  */
+      READ_ULEB (form, data, end);
+      if (form == DW_FORM_implicit_const)
+       SKIP_ULEB (data, end);
+      return skip_attr_bytes (form, data, end, pointer_size, offset_size, dwarf_version, value_return);
+
     default:
       return NULL;
     }
@@ -1953,40 +2106,142 @@ skip_attr_bytes (unsigned long          form,
   return data;
 }
 
-/* Return IS_SIGNED set to TRUE if the type at
-   DATA can be determined to be a signed type.  */
+/* Given form FORM with value UVALUE, locate and return the abbreviation
+   associated with it.  */
 
-static void
-get_type_signedness (unsigned char *        start,
-                    unsigned char *        data,
-                    unsigned const char *  end,
-                    dwarf_vma              pointer_size,
-                    dwarf_vma              offset_size,
-                    int                    dwarf_version,
-                    bfd_boolean *          is_signed,
-                    bfd_boolean            is_nested)
+static abbrev_entry *
+get_type_abbrev_from_form (unsigned long                 form,
+                          unsigned long                 uvalue,
+                          dwarf_vma                     cu_offset,
+                          const struct dwarf_section *  section,
+                          unsigned long *               abbrev_num_return,
+                          unsigned char **              data_return,
+                          unsigned long *               cu_offset_return)
 {
   unsigned long   abbrev_number;
+  abbrev_map *    map;
   abbrev_entry *  entry;
-  abbrev_attr *   attr;
+  unsigned char * data;
+
+  if (abbrev_num_return != NULL)
+    * abbrev_num_return = 0;
+  if (data_return != NULL)
+    * data_return = NULL;
+
+  switch (form)
+    {
+    case DW_FORM_GNU_ref_alt:
+    case DW_FORM_ref_sig8:
+      /* FIXME: We are unable to handle this form at the moment.  */
+      return NULL;
 
-  * is_signed = FALSE;
+    case DW_FORM_ref_addr:
+      if (uvalue >= section->size)
+       {
+         warn (_("Unable to resolve ref_addr form: uvalue %lx > section size %lx (%s)\n"),
+               uvalue, (long) section->size, section->name);
+         return NULL;
+       }
+      break;
+
+    case DW_FORM_ref_sup4:
+    case DW_FORM_ref_sup8:
+      break;
 
-  READ_ULEB (abbrev_number, data, end);
+    case DW_FORM_ref1:
+    case DW_FORM_ref2:
+    case DW_FORM_ref4:
+    case DW_FORM_ref8:
+    case DW_FORM_ref_udata:
+      if (uvalue + cu_offset > section->size)
+       {
+         warn (_("Unable to resolve ref form: uvalue %lx + cu_offset %lx > section size %lx\n"),
+               uvalue, (long) cu_offset, (long) section->size);
+         return NULL;
+       }
+      uvalue += cu_offset;
+      break;
+
+      /* FIXME: Are there other DW_FORMs that can be used by types ?  */
+
+    default:
+      warn (_("Unexpected form %lx encountered whilst finding abbreviation for type\n"), form);
+      return NULL;
+    }
+
+  data = (unsigned char *) section->start + uvalue;
+  map = find_abbrev_map_by_offset (uvalue);
+
+  if (map == NULL)
+    {
+      warn (_("Unable to find abbreviations for CU offset %#lx\n"), uvalue);
+      return NULL;
+    }
+  if (map->list == NULL)
+    {
+      warn (_("Empty abbreviation list encountered for CU offset %lx\n"), uvalue);
+      return NULL;
+    }
+
+  if (cu_offset_return != NULL)
+    {
+      if (form == DW_FORM_ref_addr)
+       * cu_offset_return = map->start;
+      else
+       * cu_offset_return = cu_offset;
+    }
+       
+  READ_ULEB (abbrev_number, data, section->start + section->size);
+
+  for (entry = map->list->first_abbrev; entry != NULL; entry = entry->next)
+    if (entry->number == abbrev_number)
+      break;
 
-  for (entry = first_abbrev;
-       entry != NULL && entry->entry != abbrev_number;
-       entry = entry->next)
-    continue;
+  if (abbrev_num_return != NULL)
+    * abbrev_num_return = abbrev_number;
+
+  if (data_return != NULL)
+    * data_return = data;
 
   if (entry == NULL)
-    /* FIXME: Issue a warning ?  */
-    return;
+    warn (_("Unable to find entry for abbreviation %lu\n"), abbrev_number);
+
+  return entry;
+}
+
+/* Return IS_SIGNED set to TRUE if the type using abbreviation ENTRY
+   can be determined to be a signed type.  The data for ENTRY can be
+   found starting at DATA.  */
+
+static void
+get_type_signedness (abbrev_entry *entry,
+                    const struct dwarf_section *section,
+                    unsigned char *data,
+                    unsigned const char *end,
+                    dwarf_vma cu_offset,
+                    dwarf_vma pointer_size,
+                    dwarf_vma offset_size,
+                    int dwarf_version,
+                    bool *is_signed,
+                    unsigned int nesting)
+{
+  abbrev_attr *   attr;
+
+  * is_signed = false;
+
+#define MAX_NESTING 20
+  if (nesting > MAX_NESTING)
+    {
+      /* FIXME: Warn - or is this expected ?
+        NB/ We need to avoid infinite recursion.  */
+      return;
+    }
 
   for (attr = entry->first_attr;
        attr != NULL && attr->attribute;
        attr = attr->next)
     {
+      unsigned char * orig_data = data;
       dwarf_vma uvalue = 0;
 
       data = skip_attr_bytes (attr->form, data, end, pointer_size,
@@ -1996,25 +2251,38 @@ get_type_signedness (unsigned char *        start,
 
       switch (attr->attribute)
        {
-#if 0 /* FIXME: It would be nice to print the name of the type,
-        but this would mean updating a lot of binutils tests.  */
+       case DW_AT_linkage_name:
        case DW_AT_name:
-         if (attr->form == DW_FORM_strp)
-           printf ("%s", fetch_indirect_string (uvalue));
+         if (do_wide)
+           {
+             if (attr->form == DW_FORM_strp)
+               printf (", %s", fetch_indirect_string (uvalue));
+             else if (attr->form == DW_FORM_string)
+               printf (", %s", orig_data);
+           }
          break;
-#endif
+
        case DW_AT_type:
          /* Recurse.  */
-         if (is_nested)
-           {
-             /* FIXME: Warn - or is this expected ?
-                NB/ We need to avoid infinite recursion.  */
-             return;
-           }
-         if (uvalue >= (size_t) (end - start))
-           return;
-         get_type_signedness (start, start + uvalue, end, pointer_size,
-                              offset_size, dwarf_version, is_signed, TRUE);
+         {
+           abbrev_entry *  type_abbrev;
+           unsigned char * type_data;
+           unsigned long   type_cu_offset;
+
+           type_abbrev = get_type_abbrev_from_form (attr->form,
+                                                    uvalue,
+                                                    cu_offset,
+                                                    section,
+                                                    NULL /* abbrev num return */,
+                                                    & type_data,
+                                                    & type_cu_offset);
+           if (type_abbrev == NULL)
+             break;
+
+           get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset,
+                                pointer_size, offset_size, dwarf_version,
+                                is_signed, nesting + 1);
+         }
          break;
 
        case DW_AT_encoding:
@@ -2027,7 +2295,7 @@ get_type_signedness (unsigned char *        start,
            case DW_ATE_unsigned:
            case DW_ATE_unsigned_char:
            case DW_ATE_unsigned_fixed:
-             * is_signed = FALSE;
+             * is_signed = false;
              break;
 
            default:
@@ -2038,7 +2306,7 @@ get_type_signedness (unsigned char *        start,
            case DW_ATE_imaginary_float:
            case DW_ATE_decimal_float:
            case DW_ATE_signed_fixed:
-             * is_signed = TRUE;
+             * is_signed = true;
              break;
            }
          break;
@@ -2047,10 +2315,10 @@ get_type_signedness (unsigned char *        start,
 }
 
 static void
-read_and_print_leb128 (unsigned char *        data,
-                      unsigned int *         bytes_read,
-                      unsigned const char *  end,
-                      bfd_boolean            is_signed)
+read_and_print_leb128 (unsigned char *data,
+                      unsigned int *bytes_read,
+                      unsigned const char *end,
+                      bool is_signed)
 {
   int status;
   dwarf_vma val = read_leb128 (data, end, is_signed, bytes_read, &status);
@@ -2072,7 +2340,7 @@ display_discr_list (unsigned long          form,
       printf ("[default]");
       return;
     }
-  
+
   switch (form)
     {
     case DW_FORM_block:
@@ -2095,10 +2363,10 @@ display_discr_list (unsigned long          form,
       return;
     }
 
-  bfd_boolean is_signed =
+  bool is_signed =
     (level > 0 && level <= MAX_CU_NESTING)
-    ? level_type_signed [level - 1] : FALSE;
-    
+    ? level_type_signed [level - 1] : false;
+
   printf ("(");
   while (uvalue)
     {
@@ -2136,7 +2404,7 @@ display_discr_list (unsigned long          form,
 
        default:
          printf ("<corrupt>\n");
-         warn (_("corrupt discr_list - unrecognised discriminant byte %#x\n"),
+         warn (_("corrupt discr_list - unrecognized discriminant byte %#x\n"),
                discriminant);
          return;
        }
@@ -2180,6 +2448,17 @@ read_and_display_attr_value (unsigned long           attribute,
       return data;
     }
 
+  if (do_wide && ! do_loc)
+    {
+      /* PR 26847: Display the name of the form.  */
+      const char * name = get_FORM_name (form);
+
+      /* For convenience we skip the DW_FORM_ prefix to the name.  */
+      if (name[0] == 'D')
+       name += 8; /* strlen ("DW_FORM_")  */
+      printf ("%c(%s)", delimiter, name);
+    }
+
   switch (form)
     {
     default:
@@ -2188,17 +2467,17 @@ read_and_display_attr_value (unsigned long           attribute,
     case DW_FORM_ref_addr:
       if (dwarf_version == 2)
        SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
-      else if (dwarf_version == 3 || dwarf_version == 4)
+      else if (dwarf_version > 2)
        SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
       else
-       error (_("Internal error: DWARF version is not 2, 3 or 4.\n"));
-
+       error (_("Internal error: DW_FORM_ref_addr is not supported in DWARF version 1.\n"));
       break;
 
     case DW_FORM_addr:
       SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
       break;
 
+    case DW_FORM_strp_sup:
     case DW_FORM_strp:
     case DW_FORM_line_strp:
     case DW_FORM_sec_offset:
@@ -2214,16 +2493,28 @@ read_and_display_attr_value (unsigned long           attribute,
     case DW_FORM_ref1:
     case DW_FORM_flag:
     case DW_FORM_data1:
+    case DW_FORM_strx1:
+    case DW_FORM_addrx1:
       SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
       break;
 
     case DW_FORM_ref2:
     case DW_FORM_data2:
+    case DW_FORM_strx2:
+    case DW_FORM_addrx2:
       SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end);
       break;
 
+    case DW_FORM_strx3:
+    case DW_FORM_addrx3:
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 3, end);
+      break;
+
+    case DW_FORM_ref_sup4:
     case DW_FORM_ref4:
     case DW_FORM_data4:
+    case DW_FORM_strx4:
+    case DW_FORM_addrx4:
       SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
       break;
 
@@ -2233,9 +2524,11 @@ read_and_display_attr_value (unsigned long           attribute,
       break;
 
     case DW_FORM_GNU_str_index:
+    case DW_FORM_strx:
     case DW_FORM_ref_udata:
     case DW_FORM_udata:
     case DW_FORM_GNU_addr_index:
+    case DW_FORM_addrx:
       READ_ULEB (uvalue, data, end);
       break;
 
@@ -2257,18 +2550,25 @@ read_and_display_attr_value (unsigned long           attribute,
     {
     case DW_FORM_ref_addr:
       if (!do_loc)
-       printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x",uvalue));
+       printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue));
       break;
 
     case DW_FORM_GNU_ref_alt:
       if (!do_loc)
-       printf ("%c<alt 0x%s>", delimiter, dwarf_vmatoa ("x",uvalue));
+       {
+         if (do_wide)
+           /* We have already printed the form name.  */
+           printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue));
+         else
+           printf ("%c<alt 0x%s>", delimiter, dwarf_vmatoa ("x", uvalue));
+       }
       /* FIXME: Follow the reference...  */
       break;
 
     case DW_FORM_ref1:
     case DW_FORM_ref2:
     case DW_FORM_ref4:
+    case DW_FORM_ref_sup4:
     case DW_FORM_ref_udata:
       if (!do_loc)
        printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue + cu_offset));
@@ -2296,6 +2596,7 @@ read_and_display_attr_value (unsigned long           attribute,
        printf ("%c%s", delimiter, dwarf_vmatoa ("d", implicit_const));
       break;
 
+    case DW_FORM_ref_sup8:
     case DW_FORM_ref8:
     case DW_FORM_data8:
       if (!do_loc)
@@ -2390,36 +2691,69 @@ read_and_display_attr_value (unsigned long           attribute,
 
     case DW_FORM_strp:
       if (!do_loc)
-       printf (_("%c(indirect string, offset: 0x%s): %s"), delimiter,
-               dwarf_vmatoa ("x", uvalue),
-               fetch_indirect_string (uvalue));
+       {
+         if (do_wide)
+           /* We have already displayed the form name.  */
+           printf (_("%c(offset: 0x%s): %s"), delimiter,
+                   dwarf_vmatoa ("x", uvalue),
+                   fetch_indirect_string (uvalue));
+         else
+           printf (_("%c(indirect string, offset: 0x%s): %s"), delimiter,
+                   dwarf_vmatoa ("x", uvalue),
+                   fetch_indirect_string (uvalue));
+       }
       break;
 
     case DW_FORM_line_strp:
       if (!do_loc)
-       printf (_("%c(indirect line string, offset: 0x%s): %s"), delimiter,
-               dwarf_vmatoa ("x", uvalue),
-               fetch_indirect_line_string (uvalue));
+       {
+         if (do_wide)
+           /* We have already displayed the form name.  */
+           printf (_("%c(offset: 0x%s): %s"), delimiter,
+                   dwarf_vmatoa ("x", uvalue),
+                   fetch_indirect_line_string (uvalue));
+         else
+           printf (_("%c(indirect line string, offset: 0x%s): %s"), delimiter,
+                   dwarf_vmatoa ("x", uvalue),
+                   fetch_indirect_line_string (uvalue));
+       }
       break;
 
     case DW_FORM_GNU_str_index:
+    case DW_FORM_strx:
+    case DW_FORM_strx1:
+    case DW_FORM_strx2:
+    case DW_FORM_strx3:
+    case DW_FORM_strx4:
       if (!do_loc)
        {
-         const char * suffix = strrchr (section->name, '.');
-         bfd_boolean  dwo = (suffix && strcmp (suffix, ".dwo") == 0) ? TRUE : FALSE;
+         const char *suffix = strrchr (section->name, '.');
+         bool dwo = suffix && strcmp (suffix, ".dwo") == 0;
 
-         printf (_("%c(indexed string: 0x%s): %s"), delimiter,
-                 dwarf_vmatoa ("x", uvalue),
-                 fetch_indexed_string (uvalue, this_set, offset_size, dwo));
+         if (do_wide)
+           /* We have already displayed the form name.  */
+           printf (_("%c(offset: 0x%s): %s"), delimiter,
+                   dwarf_vmatoa ("x", uvalue),
+                   fetch_indexed_string (uvalue, this_set, offset_size, dwo));
+         else
+           printf (_("%c(indexed string: 0x%s): %s"), delimiter,
+                   dwarf_vmatoa ("x", uvalue),
+                   fetch_indexed_string (uvalue, this_set, offset_size, dwo));
        }
       break;
 
     case DW_FORM_GNU_strp_alt:
       if (!do_loc)
        {
-         printf (_("%c(alt indirect string, offset: 0x%s) %s"), delimiter,
-                 dwarf_vmatoa ("x", uvalue),
-                 fetch_alt_indirect_string (uvalue));
+         if (do_wide)
+           /* We have already displayed the form name.  */
+           printf (_("%c(offset: 0x%s) %s"), delimiter,
+                   dwarf_vmatoa ("x", uvalue),
+                   fetch_alt_indirect_string (uvalue));
+         else
+           printf (_("%c(alt indirect string, offset: 0x%s) %s"), delimiter,
+                   dwarf_vmatoa ("x", uvalue),
+                   fetch_alt_indirect_string (uvalue));
        }
       break;
 
@@ -2434,21 +2768,56 @@ read_and_display_attr_value (unsigned long           attribute,
          char buf[64];
 
          SAFE_BYTE_GET64 (data, &high_bits, &uvalue, end);
-         printf ("%csignature: 0x%s", delimiter,
-                 dwarf_vmatoa64 (high_bits, uvalue, buf, sizeof (buf)));
+         if (do_wide)
+           /* We have already displayed the form name.  */
+           printf ("%c: 0x%s", delimiter,
+                   dwarf_vmatoa64 (high_bits, uvalue, buf, sizeof (buf)));
+         else
+           printf ("%csignature: 0x%s", delimiter,
+                   dwarf_vmatoa64 (high_bits, uvalue, buf, sizeof (buf)));
        }
       data += 8;
       break;
 
     case DW_FORM_GNU_addr_index:
+    case DW_FORM_addrx:
+    case DW_FORM_addrx1:
+    case DW_FORM_addrx2:
+    case DW_FORM_addrx3:
+    case DW_FORM_addrx4:
       if (!do_loc)
-       printf (_("%c(addr_index: 0x%s): %s"), delimiter,
-               dwarf_vmatoa ("x", uvalue),
-               fetch_indexed_value (uvalue * pointer_size, pointer_size));
+       {
+         dwarf_vma base;
+         dwarf_vma offset;
+
+         if (debug_info_p == NULL)
+           base = 0;
+         else if (debug_info_p->addr_base == DEBUG_INFO_UNAVAILABLE)
+           base = 0;
+         else
+           base = debug_info_p->addr_base;
+
+         offset = base + uvalue * pointer_size;
+
+         if (do_wide)
+           /* We have already displayed the form name.  */
+           printf (_("%c(index: 0x%s): %s"), delimiter,
+                   dwarf_vmatoa ("x", uvalue),
+                   fetch_indexed_value (offset, pointer_size));
+         else
+           printf (_("%c(addr_index: 0x%s): %s"), delimiter,
+                   dwarf_vmatoa ("x", uvalue),
+                   fetch_indexed_value (offset, pointer_size));
+       }
       break;
 
+    case DW_FORM_strp_sup:
+      if (!do_loc)
+       printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue + cu_offset));
+      break;
+      
     default:
-      warn (_("Unrecognized form: %lu\n"), form);
+      warn (_("Unrecognized form: 0x%lx\n"), form);
       break;
     }
 
@@ -2537,6 +2906,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;
 
@@ -2572,16 +2942,21 @@ read_and_display_attr_value (unsigned long           attribute,
            switch (form)
              {
              case DW_FORM_strp:
-               add_dwo_name ((const char *) fetch_indirect_string (uvalue));
+               add_dwo_name ((const char *) fetch_indirect_string (uvalue), cu_offset);
                break;
              case DW_FORM_GNU_strp_alt:
-               add_dwo_name ((const char *) fetch_alt_indirect_string (uvalue));
+               add_dwo_name ((const char *) fetch_alt_indirect_string (uvalue), cu_offset);
                break;
              case DW_FORM_GNU_str_index:
-               add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
+             case DW_FORM_strx:
+             case DW_FORM_strx1:
+             case DW_FORM_strx2:
+             case DW_FORM_strx3:
+             case DW_FORM_strx4:
+               add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, false), cu_offset);
                break;
              case DW_FORM_string:
-               add_dwo_name ((const char *) orig_data);
+               add_dwo_name ((const char *) orig_data, cu_offset);
                break;
              default:
                warn (_("Unsupported form (%s) for attribute %s\n"),
@@ -2589,26 +2964,31 @@ read_and_display_attr_value (unsigned long           attribute,
                break;
              }
          break;
-             
+
        case DW_AT_comp_dir:
          /* FIXME: Also extract a build-id in a CU/TU.  */
          if (need_dwo_info)
            switch (form)
              {
              case DW_FORM_strp:
-               add_dwo_dir ((const char *) fetch_indirect_string (uvalue));
+               add_dwo_dir ((const char *) fetch_indirect_string (uvalue), cu_offset);
                break;
              case DW_FORM_GNU_strp_alt:
-               add_dwo_dir (fetch_alt_indirect_string (uvalue));
+               add_dwo_dir (fetch_alt_indirect_string (uvalue), cu_offset);
                break;
              case DW_FORM_line_strp:
-               add_dwo_dir ((const char *) fetch_indirect_line_string (uvalue));
+               add_dwo_dir ((const char *) fetch_indirect_line_string (uvalue), cu_offset);
                break;
              case DW_FORM_GNU_str_index:
-               add_dwo_dir (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
+             case DW_FORM_strx:
+             case DW_FORM_strx1:
+             case DW_FORM_strx2:
+             case DW_FORM_strx3:
+             case DW_FORM_strx4:
+               add_dwo_dir (fetch_indexed_string (uvalue, this_set, offset_size, false), cu_offset);
                break;
              case DW_FORM_string:
-               add_dwo_dir ((const char *) orig_data);
+               add_dwo_dir ((const char *) orig_data, cu_offset);
                break;
              default:
                warn (_("Unsupported form (%s) for attribute %s\n"),
@@ -2616,14 +2996,14 @@ read_and_display_attr_value (unsigned long           attribute,
                break;
              }
          break;
-             
+
        case DW_AT_GNU_dwo_id:
          if (need_dwo_info)
            switch (form)
              {
              case DW_FORM_data8:
                /* FIXME: Record the length of the ID as well ?  */
-               add_dwo_id ((const char *) (data - 8));
+               add_dwo_id ((const char *) (data - 8), cu_offset);
                break;
              default:
                warn (_("Unsupported form (%s) for attribute %s\n"),
@@ -2631,7 +3011,7 @@ read_and_display_attr_value (unsigned long           attribute,
                break;
              }
          break;
-             
+
        default:
          break;
        }
@@ -2647,14 +3027,23 @@ read_and_display_attr_value (unsigned long           attribute,
       if (level >= 0 && level < MAX_CU_NESTING
          && uvalue < (size_t) (end - start))
        {
-         bfd_boolean is_signed = FALSE;
+         bool is_signed = false;
+         abbrev_entry *type_abbrev;
+         unsigned char *type_data;
+         unsigned long type_cu_offset;
 
-         get_type_signedness (start, start + uvalue, end, pointer_size,
-                              offset_size, dwarf_version, & is_signed, FALSE);
+         type_abbrev = get_type_abbrev_from_form (form, uvalue, cu_offset,
+                                                  section, NULL, & type_data, & type_cu_offset);
+         if (type_abbrev != NULL)
+           {
+             get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset,
+                                  pointer_size, offset_size, dwarf_version,
+                                  & is_signed, 0);
+           }
          level_type_signed[level] = is_signed;
        }
       break;
-      
+
     case DW_AT_inline:
       printf ("\t");
       switch (uvalue)
@@ -2906,7 +3295,7 @@ read_and_display_attr_value (unsigned long           attribute,
       printf ("\t");
       display_discr_list (form, uvalue, data, end, level);
       break;
-      
+
     case DW_AT_frame_base:
       have_frame_base = 1;
       /* Fall through.  */
@@ -2972,40 +3361,22 @@ read_and_display_attr_value (unsigned long           attribute,
 
     case DW_AT_import:
       {
-       if (form == DW_FORM_ref_sig8
-           || form == DW_FORM_GNU_ref_alt)
-         break;
+       unsigned long abbrev_number;
+       abbrev_entry *entry;
 
-       if (form == DW_FORM_ref1
-           || form == DW_FORM_ref2
-           || form == DW_FORM_ref4
-           || form == DW_FORM_ref_udata)
-         uvalue += cu_offset;
-
-       if (uvalue >= section->size)
-         warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"),
-               dwarf_vmatoa ("x", uvalue),
-               (unsigned long) (orig_data - section->start));
+       entry = get_type_abbrev_from_form (form, uvalue, cu_offset,
+                                          section, & abbrev_number, NULL, NULL);
+       if (entry == NULL)
+         {
+           if (form != DW_FORM_GNU_ref_alt)
+             warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"),
+                   dwarf_vmatoa ("x", uvalue),
+                   (unsigned long) (orig_data - section->start));
+         }
        else
          {
-           unsigned long abbrev_number;
-           abbrev_entry *entry;
-           unsigned char *p = section->start + uvalue;
-
-           READ_ULEB (abbrev_number, p, end);
-
            printf (_("\t[Abbrev Number: %ld"), abbrev_number);
-           /* Don't look up abbrev for DW_FORM_ref_addr, as it very often will
-              use different abbrev table, and we don't track .debug_info chunks
-              yet.  */
-           if (form != DW_FORM_ref_addr)
-             {
-               for (entry = first_abbrev; entry != NULL; entry = entry->next)
-                 if (entry->entry == abbrev_number)
-                   break;
-               if (entry != NULL)
-                 printf (" (%s)", get_TAG_name (entry->tag));
-             }
+           printf (" (%s)", get_TAG_name (entry->tag));
            printf ("]");
          }
       }
@@ -3051,7 +3422,7 @@ read_and_display_attr (unsigned long           attribute,
    following debug links, then attempt to load the requested section
    from one of the separate debug info files.  */
 
-static bfd_boolean
+static bool
 load_debug_section_with_follow (enum dwarf_section_display_enum sec_enum,
                                void * handle)
 {
@@ -3070,7 +3441,7 @@ load_debug_section_with_follow (enum dwarf_section_display_enum sec_enum,
              }
        }
 
-      return TRUE;
+      return true;
     }
 
   if (do_follow_links)
@@ -3085,16 +3456,16 @@ load_debug_section_with_follow (enum dwarf_section_display_enum sec_enum,
 
              /* FIXME: We should check to see if any of the remaining debug info
                 files also contain this section, and, umm, do something about it.  */
-             return TRUE;
+             return true;
            }
        }
     }
 
-  return FALSE;
+  return false;
 }
 
 static void
-introduce (struct dwarf_section * section, bfd_boolean raw)
+introduce (struct dwarf_section * section, bool raw)
 {
   if (raw)
     {
@@ -3113,7 +3484,7 @@ introduce (struct dwarf_section * section, bfd_boolean raw)
        printf (_("Contents of the %s section:\n\n"), section->name);
     }
 }
-  
+
 /* Process the contents of a .debug_info section.
    If do_loc is TRUE then we are scanning for location lists and dwo tags
    and we do not want to display anything to the user.
@@ -3124,12 +3495,12 @@ introduce (struct dwarf_section * section, bfd_boolean raw)
    Returns TRUE upon success.  Otherwise an error or warning message is
    printed and FALSE is returned.  */
 
-static bfd_boolean
-process_debug_info (struct dwarf_section *           section,
-                   void *                           file,
-                   enum dwarf_section_display_enum  abbrev_sec,
-                   bfd_boolean                      do_loc,
-                   bfd_boolean                      do_types)
+static bool
+process_debug_info (struct dwarf_section * section,
+                   void *file,
+                   enum dwarf_section_display_enum abbrev_sec,
+                   bool do_loc,
+                   bool do_types)
 {
   unsigned char *start = section->start;
   unsigned char *end = start + section->size;
@@ -3161,7 +3532,7 @@ process_debug_info (struct dwarf_section *           section,
            {
              warn (_("Reserved length value (0x%s) found in section %s\n"),
                    dwarf_vmatoa ("x", length), section->name);
-             return FALSE;
+             return false;
            }
          else
            section_begin += length + 4;
@@ -3173,14 +3544,14 @@ process_debug_info (struct dwarf_section *           section,
            {
              warn (_("Corrupt unit length (0x%s) found in section %s\n"),
                    dwarf_vmatoa ("x", length), section->name);
-             return FALSE;
+             return false;
            }
        }
 
       if (num_units == 0)
        {
          error (_("No comp units in %s section ?\n"), section->name);
-         return FALSE;
+         return false;
        }
 
       /* Then allocate an array to hold the information.  */
@@ -3191,7 +3562,7 @@ process_debug_info (struct dwarf_section *           section,
          error (_("Not enough memory for a debug info array of %u entries\n"),
                 num_units);
          alloc_num_debug_info_entries = num_debug_info_entries = 0;
-         return FALSE;
+         return false;
        }
 
       /* PR 17531: file: 92ca3797.
@@ -3213,19 +3584,118 @@ process_debug_info (struct dwarf_section *           section,
       load_debug_section_with_follow (str_index_dwo, file);
       load_debug_section_with_follow (debug_addr, file);
     }
-  
+
   load_debug_section_with_follow (abbrev_sec, file);
   if (debug_displays [abbrev_sec].section.start == NULL)
     {
       warn (_("Unable to locate %s section!\n"),
            debug_displays [abbrev_sec].section.uncompressed_name);
-      return FALSE;
+      return false;
     }
 
   if (!do_loc && dwarf_start_die == 0)
-    introduce (section, FALSE);
-  
-  for (section_begin = start, unit = 0; start < end; unit++)
+    introduce (section, false);
+
+  free_all_abbrevs ();
+  free (cu_abbrev_map);
+  cu_abbrev_map = NULL;
+  next_free_abbrev_map_entry = 0;
+
+  /* In order to be able to resolve DW_FORM_ref_attr forms we need
+     to load *all* of the abbrevs for all CUs in this .debug_info
+     section.  This does effectively mean that we (partially) read
+     every CU header twice.  */
+  for (section_begin = start; start < end;)
+    {
+      DWARF2_Internal_CompUnit  compunit;
+      unsigned char *           hdrptr;
+      dwarf_vma                 abbrev_base;
+      size_t                    abbrev_size;
+      dwarf_vma                 cu_offset;
+      unsigned int              offset_size;
+      unsigned int              initial_length_size;
+      struct cu_tu_set *        this_set;
+      abbrev_list *             list;
+
+      hdrptr = start;
+
+      SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 4, end);
+
+      if (compunit.cu_length == 0xffffffff)
+       {
+         SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 8, end);
+         offset_size = 8;
+         initial_length_size = 12;
+       }
+      else
+       {
+         offset_size = 4;
+         initial_length_size = 4;
+       }
+
+      SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end);
+
+      cu_offset = start - section_begin;
+
+      this_set = find_cu_tu_set_v2 (cu_offset, do_types);
+
+      if (compunit.cu_version < 5)
+       {
+         compunit.cu_unit_type = DW_UT_compile;
+         /* Initialize it due to a false compiler warning.  */
+         compunit.cu_pointer_size = -1;
+       }
+      else
+       {
+         SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end);
+         do_types = (compunit.cu_unit_type == DW_UT_type);
+
+         SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end);
+       }
+
+      SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end);
+
+      if (compunit.cu_unit_type == DW_UT_split_compile
+         || compunit.cu_unit_type == DW_UT_skeleton)
+       {
+         uint64_t dwo_id;
+         SAFE_BYTE_GET_AND_INC (dwo_id, hdrptr, 8, end);
+       }
+
+      if (this_set == NULL)
+       {
+         abbrev_base = 0;
+         abbrev_size = debug_displays [abbrev_sec].section.size;
+       }
+      else
+       {
+         abbrev_base = this_set->section_offsets [DW_SECT_ABBREV];
+         abbrev_size = this_set->section_sizes [DW_SECT_ABBREV];
+       }
+
+      list = find_abbrev_list_by_abbrev_offset (abbrev_base,
+                                               compunit.cu_abbrev_offset);
+      if (list == NULL)
+       {
+         unsigned char *  next;
+
+         list = new_abbrev_list (abbrev_base,
+                                 compunit.cu_abbrev_offset);
+         next = process_abbrev_set
+           (((unsigned char *) debug_displays [abbrev_sec].section.start
+             + abbrev_base + compunit.cu_abbrev_offset),
+            ((unsigned char *) debug_displays [abbrev_sec].section.start
+             + abbrev_base + abbrev_size),
+            list);
+         list->start_of_next_abbrevs = next;
+       }
+
+      start = section_begin + cu_offset + compunit.cu_length
+       + initial_length_size;
+      record_abbrev_list_for_cu (cu_offset, start - section_begin, list);
+    }
+
+  for (start = section_begin, unit = 0; start < end; unit++)
     {
       DWARF2_Internal_CompUnit compunit;
       unsigned char *hdrptr;
@@ -3241,6 +3711,7 @@ process_debug_info (struct dwarf_section *           section,
       struct cu_tu_set *this_set;
       dwarf_vma abbrev_base;
       size_t abbrev_size;
+      abbrev_list * list = NULL;
 
       hdrptr = start;
 
@@ -3294,6 +3765,15 @@ process_debug_info (struct dwarf_section *           section,
       if (compunit.cu_version < 5)
        SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end);
 
+      bool do_dwo_id = false;
+      uint64_t dwo_id = 0;
+      if (compunit.cu_unit_type == DW_UT_split_compile
+         || compunit.cu_unit_type == DW_UT_skeleton)
+       {
+         SAFE_BYTE_GET_AND_INC (dwo_id, hdrptr, 8, end);
+         do_dwo_id = true;
+       }
+
       /* PR 17512: file: 001-108546-0.001:0.1.  */
       if (compunit.cu_pointer_size < 2 || compunit.cu_pointer_size > 8)
        {
@@ -3347,6 +3827,10 @@ process_debug_info (struct dwarf_section *           section,
                  dwarf_vmatoa ("x", compunit.cu_length),
                  offset_size == 8 ? "64-bit" : "32-bit");
          printf (_("   Version:       %d\n"), compunit.cu_version);
+         if (compunit.cu_version >= 5)
+           printf (_("   Unit Type:     %s (%x)\n"),
+                   get_DW_UT_name (compunit.cu_unit_type) ?: "???",
+                   compunit.cu_unit_type);
          printf (_("   Abbrev Offset: 0x%s\n"),
                  dwarf_vmatoa ("x", compunit.cu_abbrev_offset));
          printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
@@ -3360,6 +3844,8 @@ process_debug_info (struct dwarf_section *           section,
              printf (_("   Type Offset:   0x%s\n"),
                      dwarf_vmatoa ("x", type_offset));
            }
+         if (do_dwo_id)
+           printf (_("   DWO ID:        0x%s\n"), dwarf_vmatoa ("x", dwo_id));
          if (this_set != NULL)
            {
              dwarf_vma *offsets = this_set->section_offsets;
@@ -3405,7 +3891,10 @@ process_debug_info (struct dwarf_section *           section,
        }
 
       if (compunit.cu_unit_type != DW_UT_compile
-         && compunit.cu_unit_type != DW_UT_type)
+         && compunit.cu_unit_type != DW_UT_partial
+         && compunit.cu_unit_type != DW_UT_type
+         && compunit.cu_unit_type != DW_UT_split_compile
+         && compunit.cu_unit_type != DW_UT_skeleton)
        {
          warn (_("CU at offset %s contains corrupt or "
                  "unsupported unit type: %d.\n"),
@@ -3413,8 +3902,6 @@ process_debug_info (struct dwarf_section *           section,
          continue;
        }
 
-      free_abbrevs ();
-
       /* Process the abbrevs used by this compilation unit.  */
       if (compunit.cu_abbrev_offset >= abbrev_size)
        warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"),
@@ -3427,11 +3914,24 @@ process_debug_info (struct dwarf_section *           section,
              (unsigned long) abbrev_base + abbrev_size,
              (unsigned long) debug_displays [abbrev_sec].section.size);
       else
-       process_abbrev_section
-         (((unsigned char *) debug_displays [abbrev_sec].section.start
-           + abbrev_base + compunit.cu_abbrev_offset),
-          ((unsigned char *) debug_displays [abbrev_sec].section.start
-           + abbrev_base + abbrev_size));
+       {
+         list = find_abbrev_list_by_abbrev_offset (abbrev_base,
+                                                   compunit.cu_abbrev_offset);
+         if (list == NULL)
+           {
+             unsigned char * next;
+
+             list = new_abbrev_list (abbrev_base,
+                                     compunit.cu_abbrev_offset);
+             next = process_abbrev_set
+               (((unsigned char *) debug_displays [abbrev_sec].section.start
+                 + abbrev_base + compunit.cu_abbrev_offset),
+                ((unsigned char *) debug_displays [abbrev_sec].section.start
+                 + abbrev_base + abbrev_size),
+                list);
+             list->start_of_next_abbrevs = next;
+           }
+       }
 
       level = 0;
       last_level = level;
@@ -3485,7 +3985,7 @@ process_debug_info (struct dwarf_section *           section,
                    }
                }
              if (dwarf_start_die != 0 && level < saved_level)
-               return TRUE;
+               return true;
              continue;
            }
 
@@ -3511,11 +4011,13 @@ process_debug_info (struct dwarf_section *           section,
 
          /* Scan through the abbreviation list until we reach the
             correct entry.  */
-         for (entry = first_abbrev;
-              entry && entry->entry != abbrev_number;
-              entry = entry->next)
+         if (list == NULL)
            continue;
 
+         for (entry = list->first_abbrev; entry != NULL; entry = entry->next)
+           if (entry->number == abbrev_number)
+             break;
+
          if (entry == NULL)
            {
              if (!do_loc && do_printing)
@@ -3525,7 +4027,7 @@ process_debug_info (struct dwarf_section *           section,
                }
              warn (_("DIE at offset 0x%lx refers to abbreviation number %lu which does not exist\n"),
                    die_offset, abbrev_number);
-             return FALSE;
+             return false;
            }
 
          if (!do_loc && do_printing)
@@ -3625,7 +4127,7 @@ process_debug_info (struct dwarf_section *           section,
   if (!do_loc)
     printf ("\n");
 
-  return TRUE;
+  return true;
 }
 
 /* Locate and scan the .debug_info section in the file and record the pointer
@@ -3650,12 +4152,12 @@ load_debug_info (void * file)
   (void) load_cu_tu_indexes (file);
 
   if (load_debug_section_with_follow (info, file)
-      && process_debug_info (&debug_displays [info].section, file, abbrev, TRUE, FALSE))
+      && process_debug_info (&debug_displays [info].section, file, abbrev, true, false))
     return num_debug_info_entries;
 
   if (load_debug_section_with_follow (info_dwo, file)
       && process_debug_info (&debug_displays [info_dwo].section, file,
-                            abbrev_dwo, TRUE, FALSE))
+                            abbrev_dwo, true, false))
     return num_debug_info_entries;
 
   num_debug_info_entries = DEBUG_INFO_UNAVAILABLE;
@@ -3780,18 +4282,18 @@ read_debug_line_header (struct dwarf_section * section,
 }
 
 static unsigned char *
-display_formatted_table (unsigned char *                   data,
-                        unsigned char *                   start,
-                        unsigned char *                   end,
-                        const DWARF2_Internal_LineInfo *  linfo,
-                        struct dwarf_section *            section,
-                        bfd_boolean                       is_dir)
+display_formatted_table (unsigned char *data,
+                        unsigned char *start,
+                        unsigned char *end,
+                        const DWARF2_Internal_LineInfo *linfo,
+                        struct dwarf_section *section,
+                        bool is_dir)
 {
   unsigned char *format_start, format_count, *format, formati;
   dwarf_vma data_count, datai;
   unsigned int namepass, last_entry = 0;
   const char * table_name = is_dir ? N_("Directory Table") : N_("File Name Table");
-  
+
   SAFE_BYTE_GET_AND_INC (format_count, data, 1, end);
   if (do_checks && format_count > 5)
     warn (_("Unexpectedly large number of columns in the %s (%u)\n"),
@@ -3834,7 +4336,7 @@ display_formatted_table (unsigned char *                   data,
          format_count);
 
   printf (_("  Entry"));
-  /* Delay displaying name as the last entry for better screen layout.  */ 
+  /* Delay displaying name as the last entry for better screen layout.  */
   for (namepass = 0; namepass < 2; namepass++)
     {
       format = format_start;
@@ -3875,7 +4377,7 @@ display_formatted_table (unsigned char *                   data,
       unsigned char *datapass = data;
 
       printf ("  %d", last_entry++);
-      /* Delay displaying name as the last entry for better screen layout.  */ 
+      /* Delay displaying name as the last entry for better screen layout.  */
       for (namepass = 0; namepass < 2; namepass++)
        {
          format = format_start;
@@ -3904,6 +4406,81 @@ display_formatted_table (unsigned char *                   data,
   return data;
 }
 
+static int
+display_debug_sup (struct dwarf_section *  section,
+                  void *                  file ATTRIBUTE_UNUSED)
+{
+  unsigned char * start = section->start;
+  unsigned char * end = section->start + section->size;
+  unsigned int version;
+  char is_supplementary;
+  const unsigned char * sup_filename;
+  size_t sup_filename_len;
+  unsigned int num_read;
+  int status;
+  dwarf_vma checksum_len;
+
+
+  introduce (section, true);
+  if (section->size < 4)
+    {
+      error (_("corrupt .debug_sup section: size is too small\n"));
+      return 0;
+    }
+
+  /* Read the data.  */
+  SAFE_BYTE_GET_AND_INC (version, start, 2, end);
+  if (version < 5)
+    warn (_("corrupt .debug_sup section: version < 5"));
+
+  SAFE_BYTE_GET_AND_INC (is_supplementary, start, 1, end);
+  if (is_supplementary != 0 && is_supplementary != 1)
+    warn (_("corrupt .debug_sup section: is_supplementary not 0 or 1\n"));    
+
+  sup_filename = start;
+  if (is_supplementary && sup_filename[0] != 0)
+    warn (_("corrupt .debug_sup section: filename not empty in supplementary section\n"));
+
+  sup_filename_len = strnlen ((const char *) start, end - start);
+  if (sup_filename_len == (size_t) (end - start))
+    {
+      error (_("corrupt .debug_sup section: filename is not NUL terminated\n"));
+      return 0;
+    }
+  start += sup_filename_len + 1;
+
+  checksum_len = read_leb128 (start, end, false /* unsigned */, & num_read, & status);
+  if (status)
+    {
+      error (_("corrupt .debug_sup section: bad LEB128 field for checksum length\n"));
+      checksum_len = 0;
+    }
+  start += num_read;
+  if (checksum_len > (dwarf_vma) (end - start))
+    {
+      error (_("corrupt .debug_sup section: checksum length is longer than the remaining section length\n"));
+      checksum_len = end - start;
+    }
+  else if (checksum_len < (dwarf_vma) (end - start))
+    {
+      warn (_("corrupt .debug_sup section: there are 0x%lx extra, unused bytes at the end of the section\n"),
+           (long) ((end - start) - checksum_len));
+    }
+
+  printf (_("  Version:      %u\n"), version);
+  printf (_("  Is Supp:      %u\n"), is_supplementary);
+  printf (_("  Filename:     %s\n"), sup_filename);
+  printf (_("  Checksum Len: %lu\n"), (long) checksum_len);
+  if (checksum_len > 0)
+    {
+      printf (_("  Checksum:     "));
+      while (checksum_len--)
+       printf ("0x%x ", * start++ );
+      printf ("\n");
+    }
+  return 1;
+}
+
 static int
 display_debug_lines_raw (struct dwarf_section *  section,
                         unsigned char *         data,
@@ -3913,7 +4490,7 @@ display_debug_lines_raw (struct dwarf_section *  section,
   unsigned char *start = section->start;
   int verbose_view = 0;
 
-  introduce (section, TRUE);
+  introduce (section, true);
 
   while (data < end)
     {
@@ -3923,7 +4500,7 @@ display_debug_lines_raw (struct dwarf_section *  section,
       unsigned char *end_of_sequence;
       int i;
 
-      if (const_strneq (section->name, ".debug_line.")
+      if (startswith (section->name, ".debug_line.")
          /* Note: the following does not apply to .debug_line.dwo sections.
             These are full debug_line sections.  */
          && strcmp (section->name, ".debug_line.dwo") != 0)
@@ -4009,9 +4586,9 @@ display_debug_lines_raw (struct dwarf_section *  section,
              load_debug_section_with_follow (line_str, file);
 
              data = display_formatted_table (data, start, end, &linfo, section,
-                                             TRUE);
+                                             true);
              data = display_formatted_table (data, start, end, &linfo, section,
-                                             FALSE);
+                                             false);
            }
          else
            {
@@ -4333,7 +4910,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
 {
   static DWARF2_Internal_LineInfo saved_linfo;
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   while (data < end)
     {
@@ -4347,7 +4924,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
       unsigned char **directory_table = NULL;
       dwarf_vma n_directories = 0;
 
-      if (const_strneq (section->name, ".debug_line.")
+      if (startswith (section->name, ".debug_line.")
          /* Note: the following does not apply to .debug_line.dwo sections.
             These are full debug_line sections.  */
          && strcmp (section->name, ".debug_line.dwo") != 0)
@@ -5161,7 +5738,7 @@ display_debug_pubnames_worker (struct dwarf_section *section,
      we test for that later on.  */
   load_debug_info (file);
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   while (start < end)
     {
@@ -5306,7 +5883,7 @@ display_debug_macinfo (struct dwarf_section *section,
   unsigned char *curr = start;
   enum dwarf_macinfo_record_type op;
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   while (curr < end)
     {
@@ -5468,17 +6045,22 @@ display_debug_macro (struct dwarf_section *section,
   unsigned char *end = start + section->size;
   unsigned char *curr = start;
   unsigned char *extended_op_buf[256];
+  bool is_dwo = false;
+  const char *suffix = strrchr (section->name, '.');
+
+  if (suffix && strcmp (suffix, ".dwo") == 0)
+    is_dwo = true;
 
   load_debug_section_with_follow (str, file);
   load_debug_section_with_follow (line, file);
   load_debug_section_with_follow (str_index, file);
-
-  introduce (section, FALSE);
+  
+  introduce (section, false);
 
   while (curr < end)
     {
       unsigned int lineno, version, flags;
-      unsigned int offset_size = 4;
+      unsigned int offset_size;
       const unsigned char *string;
       dwarf_vma line_offset = 0, sec_offset = curr - start, offset;
       unsigned char **extended_ops = NULL;
@@ -5486,14 +6068,13 @@ display_debug_macro (struct dwarf_section *section,
       SAFE_BYTE_GET_AND_INC (version, curr, 2, end);
       if (version != 4 && version != 5)
        {
-         error (_("Only GNU extension to DWARF 4 or 5 of %s is currently supported.\n"),
-                section->name);
+         error (_("Expected to find a version number of 4 or 5 in section %s but found %d instead\n"),
+                section->name, version);
          return 0;
        }
 
       SAFE_BYTE_GET_AND_INC (flags, curr, 1, end);
-      if (flags & 1)
-       offset_size = 8;
+      offset_size = (flags & 1) ? 8 : 4;
       printf (_("  Offset:                      0x%lx\n"),
              (unsigned long) sec_offset);
       printf (_("  Version:                     %d\n"), version);
@@ -5625,7 +6206,10 @@ display_debug_macro (struct dwarf_section *section,
 
            case DW_MACRO_define_strp:
              READ_ULEB (lineno, curr, end);
-             SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
+             if (version == 4 && is_dwo)
+               READ_ULEB (offset, curr, end);
+             else
+               SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
              string = fetch_indirect_string (offset);
              printf (_(" DW_MACRO_define_strp - lineno : %d macro : %s\n"),
                      lineno, string);
@@ -5633,7 +6217,10 @@ display_debug_macro (struct dwarf_section *section,
 
            case DW_MACRO_undef_strp:
              READ_ULEB (lineno, curr, end);
-             SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
+             if (version == 4 && is_dwo)
+               READ_ULEB (offset, curr, end);
+             else
+               SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
              string = fetch_indirect_string (offset);
              printf (_(" DW_MACRO_undef_strp - lineno : %d macro : %s\n"),
                      lineno, string);
@@ -5670,7 +6257,7 @@ display_debug_macro (struct dwarf_section *section,
              READ_ULEB (lineno, curr, end);
              READ_ULEB (offset, curr, end);
              string = (const unsigned char *)
-               fetch_indexed_string (offset, NULL, offset_size, FALSE);
+               fetch_indexed_string (offset, NULL, offset_size, false);
              if (op == DW_MACRO_define_strx)
                printf (" DW_MACRO_define_strx ");
              else
@@ -5737,30 +6324,37 @@ display_debug_abbrev (struct dwarf_section *section,
 {
   abbrev_entry *entry;
   unsigned char *start = section->start;
-  unsigned char *end = start + section->size;
+  const unsigned char *end = start + section->size;
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   do
     {
-      unsigned char *last;
+      abbrev_list *    list;
+      dwarf_vma        offset;
 
-      free_abbrevs ();
-
-      last = start;
-      start = process_abbrev_section (start, end);
+      offset = start - section->start;
+      list = find_abbrev_list_by_abbrev_offset (0, offset);
+      if (list == NULL)
+       {
+         list = new_abbrev_list (0, offset);
+         start = process_abbrev_set (start, end, list);
+         list->start_of_next_abbrevs = start;
+       }
+      else
+       start = list->start_of_next_abbrevs;
 
-      if (first_abbrev == NULL)
+      if (list->first_abbrev == NULL)
        continue;
 
-      printf (_("  Number TAG (0x%lx)\n"), (long) (last - section->start));
+      printf (_("  Number TAG (0x%lx)\n"), (long) offset);
 
-      for (entry = first_abbrev; entry; entry = entry->next)
+      for (entry = list->first_abbrev; entry; entry = entry->next)
        {
          abbrev_attr *attr;
 
          printf ("   %ld      %s    [%s]\n",
-                 entry->entry,
+                 entry->number,
                  get_TAG_name (entry->tag),
                  entry->children ? _("has children") : _("no children"));
 
@@ -5785,7 +6379,7 @@ display_debug_abbrev (struct dwarf_section *section,
 /* Return true when ADDR is the maximum address, when addresses are
    POINTER_SIZE bytes long.  */
 
-static bfd_boolean
+static bool
 is_max_address (dwarf_vma addr, unsigned int pointer_size)
 {
   dwarf_vma mask = ~(~(dwarf_vma) 1 << (pointer_size * 8 - 1));
@@ -6036,7 +6630,9 @@ display_loclists_list (struct dwarf_section *section,
 
       SAFE_BYTE_GET_AND_INC (llet, start, 1, section_end);
 
-      if (vstart && llet == DW_LLE_offset_pair)
+      if (vstart && (llet == DW_LLE_offset_pair
+                    || llet == DW_LLE_start_end
+                    || llet == DW_LLE_start_length))
        {
          off = offset + (vstart - *start_ptr);
 
@@ -6057,7 +6653,18 @@ display_loclists_list (struct dwarf_section *section,
          break;
        case DW_LLE_offset_pair:
          READ_ULEB (begin, start, section_end);
+         begin += base_address;
          READ_ULEB (end, start, section_end);
+         end += base_address;
+         break;
+       case DW_LLE_start_end:
+         SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
+         SAFE_BYTE_GET_AND_INC (end, start, pointer_size, section_end);
+         break;
+       case DW_LLE_start_length:
+         SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
+         READ_ULEB (end, start, section_end);
+         end += begin;
          break;
        case DW_LLE_base_address:
          SAFE_BYTE_GET_AND_INC (base_address, start, pointer_size,
@@ -6084,7 +6691,9 @@ display_loclists_list (struct dwarf_section *section,
        }
       if (llet == DW_LLE_end_of_list)
        break;
-      if (llet != DW_LLE_offset_pair)
+      if (llet != DW_LLE_offset_pair
+         && llet != DW_LLE_start_end
+         && llet != DW_LLE_start_length)
        continue;
 
       if (start + 2 > section_end)
@@ -6096,8 +6705,8 @@ display_loclists_list (struct dwarf_section *section,
 
       READ_ULEB (length, start, section_end);
 
-      print_dwarf_vma (begin + base_address, pointer_size);
-      print_dwarf_vma (end + base_address, pointer_size);
+      print_dwarf_vma (begin, pointer_size);
+      print_dwarf_vma (end, pointer_size);
 
       putchar ('(');
       need_frame_base = decode_location_expression (start,
@@ -6335,12 +6944,12 @@ display_debug_loc (struct dwarf_section *section, void *file)
   unsigned char *next = start, *vnext = vstart;
   unsigned int *array = NULL;
   const char *suffix = strrchr (section->name, '.');
-  bfd_boolean is_dwo = FALSE;
+  bool is_dwo = false;
   int is_loclists = strstr (section->name, "debug_loclists") != NULL;
   dwarf_vma expected_start = 0;
 
   if (suffix && strcmp (suffix, ".dwo") == 0)
-    is_dwo = TRUE;
+    is_dwo = true;
 
   bytes = section->size;
 
@@ -6457,7 +7066,7 @@ display_debug_loc (struct dwarf_section *section, void *file)
   if (!locs_sorted)
     array = (unsigned int *) xcmalloc (num_loc_list, sizeof (unsigned int));
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   if (reloc_at (section, 0))
     printf (_(" Warning: This section has relocations - addresses seen here may not be accurate.\n\n"));
@@ -6603,7 +7212,7 @@ display_debug_str (struct dwarf_section *section,
       return 0;
     }
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   while (bytes)
     {
@@ -6650,19 +7259,19 @@ display_debug_str (struct dwarf_section *section,
 static int
 display_debug_info (struct dwarf_section *section, void *file)
 {
-  return process_debug_info (section, file, section->abbrev_sec, FALSE, FALSE);
+  return process_debug_info (section, file, section->abbrev_sec, false, false);
 }
 
 static int
 display_debug_types (struct dwarf_section *section, void *file)
 {
-  return process_debug_info (section, file, section->abbrev_sec, FALSE, TRUE);
+  return process_debug_info (section, file, section->abbrev_sec, false, true);
 }
 
 static int
 display_trace_info (struct dwarf_section *section, void *file)
 {
-  return process_debug_info (section, file, section->abbrev_sec, FALSE, TRUE);
+  return process_debug_info (section, file, section->abbrev_sec, false, true);
 }
 
 static int
@@ -6672,7 +7281,7 @@ display_debug_aranges (struct dwarf_section *section,
   unsigned char *start = section->start;
   unsigned char *end = start + section->size;
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   /* It does not matter if this load fails,
      we test for that later on.  */
@@ -6817,6 +7426,7 @@ display_debug_addr (struct dwarf_section *section,
   unsigned char *end;
   unsigned int i;
   unsigned int count;
+  unsigned char * header;
 
   if (section->size == 0)
     {
@@ -6831,7 +7441,7 @@ display_debug_addr (struct dwarf_section *section,
       return 0;
     }
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   /* PR  17531: file: cf38d01b.
      We use xcalloc because a corrupt file may not have initialised all of the
@@ -6857,6 +7467,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);
 
+  header = section->start;
   for (i = 0; i < count; i++)
     {
       unsigned int idx;
@@ -6867,7 +7478,38 @@ 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;
+         unsigned char *  curr_header = header;
+         dwarf_vma        length;
+         int              version;
+         int              segment_selector_size;
+
+         if (header_size != 8 && header_size != 16)
+           {
+             warn (_("Corrupt %s section: expecting header size of 8 or 16, but found %ld instead\n"),
+                   section->name, (long) header_size);
+             return 0;
+           }
+
+         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;
+
+         SAFE_BYTE_GET_AND_INC (version, curr_header, 2, entry);
+         if (version != 5)
+           warn (_("Corrupt %s section: expecting version number 5 in header but found %d instead\n"),
+                 section->name, version);
+
+         SAFE_BYTE_GET_AND_INC (address_size, curr_header, 1, entry);
+         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)
        {
@@ -6903,15 +7545,15 @@ display_debug_str_offsets (struct dwarf_section *section,
   unsigned char *end = start + section->size;
   unsigned char *curr = start;
 
-  const char * suffix = strrchr (section->name, '.');
-  bfd_boolean  dwo = (suffix && strcmp (suffix, ".dwo") == 0) ? TRUE : FALSE;
+  const char *suffix = strrchr (section->name, '.');
+  bool dwo = suffix && strcmp (suffix, ".dwo") == 0;
 
   if (dwo)
     load_debug_section_with_follow (str_dwo, file);
   else
     load_debug_section_with_follow (str, file);
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   while (curr < end)
     {
@@ -6928,18 +7570,22 @@ display_debug_str_offsets (struct dwarf_section *section,
       else
        entry_length = 4;
 
+      unsigned char *entries_end;
       if (length == 0)
        {
          /* This is probably an old style .debug_str_offset section which
             just contains offsets and no header (and the first offset is 0).  */
          length = section->size;
          curr   = section->start;
+         entries_end = end;
 
          printf (_("    Length: %#lx\n"), (unsigned long) length);
          printf (_("       Index   Offset [String]\n"));
        }
       else
        {
+         entries_end = curr + length;
+
          int version;
          SAFE_BYTE_GET_AND_INC (version, curr, 2, end);
          if (version != 5)
@@ -6955,11 +7601,15 @@ display_debug_str_offsets (struct dwarf_section *section,
          printf (_("       Index   Offset [String]\n"));
        }
 
-      for (idx = 0; length >= entry_length && curr < end; idx++)
+      for (idx = 0; curr < entries_end; idx++)
        {
          dwarf_vma offset;
          const unsigned char * string;
 
+         if (curr + entry_length > entries_end)
+           /* Not enough space to read one entry_length, give up.  */
+           return 0;
+
          SAFE_BYTE_GET_AND_INC (offset, curr, entry_length, end);
          if (dwo)
            string = (const unsigned char *)
@@ -7015,7 +7665,6 @@ display_debug_ranges_list (unsigned char *start, unsigned char *finish,
        break;
       SAFE_SIGNED_BYTE_GET_AND_INC (end, start, pointer_size, finish);
 
-      
       printf ("    %8.8lx ", offset);
 
       if (begin == 0 && end == 0)
@@ -7105,8 +7754,15 @@ display_debug_rnglists_list (unsigned char *start, unsigned char *finish,
       if (rlet == DW_RLE_base_address)
        continue;
 
-      print_dwarf_vma (begin + base_address, pointer_size);
-      print_dwarf_vma (end + base_address, pointer_size);
+      /* Only a DW_RLE_offset_pair needs the base address added.  */
+      if (rlet == DW_RLE_offset_pair)
+       {
+         begin += base_address;
+         end += base_address;
+       }
+
+      print_dwarf_vma (begin, pointer_size);
+      print_dwarf_vma (end, pointer_size);
 
       if (begin == end)
        fputs (_("(start == end)"), stdout);
@@ -7220,7 +7876,15 @@ display_debug_ranges (struct dwarf_section *section,
 
   num_range_list = 0;
   for (i = 0; i < num_debug_info_entries; i++)
-    num_range_list += debug_information [i].num_range_lists;
+    {
+      if (debug_information [i].dwarf_version < 5 && is_rnglists)
+       /* Skip .debug_rnglists reference.  */
+       continue;
+      if (debug_information [i].dwarf_version >= 5 && !is_rnglists)
+       /* Skip .debug_range reference.  */
+       continue;
+      num_range_list += debug_information [i].num_range_lists;
+    }
 
   if (num_range_list == 0)
     {
@@ -7239,6 +7903,13 @@ display_debug_ranges (struct dwarf_section *section,
       debug_info *debug_info_p = &debug_information[i];
       unsigned int j;
 
+      if (debug_information [i].dwarf_version < 5 && is_rnglists)
+       /* Skip .debug_rnglists reference.  */
+       continue;
+      if (debug_information [i].dwarf_version >= 5 && !is_rnglists)
+       /* Skip .debug_range reference.  */
+       continue;
+
       for (j = 0; j < debug_info_p->num_range_lists; j++)
        {
          range_entry_fill->ranges_offset = debug_info_p->range_lists[j];
@@ -7254,7 +7925,7 @@ display_debug_ranges (struct dwarf_section *section,
     warn (_("Range lists in %s section start at 0x%lx\n"),
          section->name, (unsigned long) range_entries[0].ranges_offset);
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   printf (_("    Offset   Begin    End\n"));
 
@@ -7751,11 +8422,9 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg
 
   if (*need_col_headers)
     {
-      static const char *sloc = "   LOC";
-
       *need_col_headers = 0;
 
-      printf ("%-*s CFA      ", eh_addr_size * 2, sloc);
+      printf ("%-*s CFA      ", eh_addr_size * 2, "   LOC");
 
       for (r = 0; r < *max_regs; r++)
        if (fc->col_type[r] != DW_CFA_unreferenced)
@@ -7998,12 +8667,12 @@ display_debug_frames (struct dwarf_section *section,
   Frame_Chunk *chunks = NULL, *forward_refs = NULL;
   Frame_Chunk *remembered_state = NULL;
   Frame_Chunk *rs;
-  bfd_boolean is_eh = strcmp (section->name, ".eh_frame") == 0;
+  bool is_eh = strcmp (section->name, ".eh_frame") == 0;
   unsigned int max_regs = 0;
   const char *bad_reg = _("bad register: ");
   unsigned int saved_eh_addr_size = eh_addr_size;
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   while (start < end)
     {
@@ -8019,7 +8688,7 @@ display_debug_frames (struct dwarf_section *section,
       unsigned int encoded_ptr_size = saved_eh_addr_size;
       unsigned int offset_size;
       unsigned int initial_length_size;
-      bfd_boolean all_nops;
+      bool all_nops;
       static Frame_Chunk fde_fc;
 
       saved_start = start;
@@ -8448,7 +9117,7 @@ display_debug_frames (struct dwarf_section *section,
          start = tmp;
        }
 
-      all_nops = TRUE;
+      all_nops = true;
 
       /* Now we know what registers are used, make a second pass over
         the chunk, this time actually printing out the info.  */
@@ -8474,7 +9143,7 @@ display_debug_frames (struct dwarf_section *section,
 
          /* Make a note if something other than DW_CFA_nop happens.  */
          if (op != DW_CFA_nop)
-           all_nops = FALSE;
+           all_nops = false;
 
          /* Warning: if you add any more cases to this switch, be
             sure to add them to the corresponding switch above.  */
@@ -8985,7 +9654,7 @@ display_debug_names (struct dwarf_section *section, void *file)
   const unsigned char *const section_end = section->start + section->size;
   unsigned char *unit_end;
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   load_debug_section_with_follow (str, file);
 
@@ -8998,7 +9667,7 @@ display_debug_names (struct dwarf_section *section, void *file)
       uint32_t augmentation_string_size;
       unsigned int i;
       unsigned long sec_off;
-      bfd_boolean augmentation_printable;
+      bool augmentation_printable;
       const char *augmentation_string;
 
       unit_start = hdrptr;
@@ -9066,7 +9735,7 @@ display_debug_names (struct dwarf_section *section, void *file)
 
       printf (_("Augmentation string:"));
 
-      augmentation_printable = TRUE;
+      augmentation_printable = true;
       augmentation_string = (const char *) hdrptr;
 
       for (i = 0; i < augmentation_string_size; i++)
@@ -9077,7 +9746,7 @@ display_debug_names (struct dwarf_section *section, void *file)
          printf (" %02x", uc);
 
          if (uc != 0 && !ISPRINT (uc))
-           augmentation_printable = FALSE;
+           augmentation_printable = false;
        }
 
       if (augmentation_printable)
@@ -9341,7 +10010,7 @@ display_debug_links (struct dwarf_section *  section,
   const unsigned char * filename;
   unsigned int          filelen;
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   /* The .gnu_debuglink section is formatted as:
       (c-string)  Filename.
@@ -9351,7 +10020,7 @@ display_debug_links (struct dwarf_section *  section,
     The .gun_debugaltlink section is formatted as:
       (c-string)  Filename.
       (binary)    Build-ID.  */
-  
+
   filename =  section->start;
   filelen = strnlen ((const char *) filename, section->size);
   if (filelen == section->size)
@@ -9362,7 +10031,7 @@ display_debug_links (struct dwarf_section *  section,
 
   printf (_("  Separate debug info file: %s\n"), filename);
 
-  if (const_strneq (section->name, ".gnu_debuglink"))
+  if (startswith (section->name, ".gnu_debuglink"))
     {
       unsigned int          crc32;
       unsigned int          crc_offset;
@@ -9386,7 +10055,7 @@ display_debug_links (struct dwarf_section *  section,
          return 0;
        }
     }
-  else /* const_strneq (section->name, ".gnu_debugaltlink") */
+  else /* startswith (section->name, ".gnu_debugaltlink") */
     {
       const unsigned char * build_id = section->start + filelen + 1;
       bfd_size_type         build_id_len = section->size - (filelen + 1);
@@ -9424,7 +10093,7 @@ display_gdb_index (struct dwarf_section *section,
 
   /* The documentation for the format of this file is in gdb/dwarf2read.c.  */
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   if (section->size < 6 * sizeof (uint32_t))
     {
@@ -9763,7 +10432,7 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
 
   if (do_display)
     {
-      introduce (section, FALSE);
+      introduce (section, false);
 
       printf (_("  Version:                 %u\n"), version);
       if (version >= 2)
@@ -9845,7 +10514,7 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
       unsigned char *poffsets = ppool + (size_t) ncols * 4;
       unsigned char *psizes = poffsets + (size_t) nused * ncols * 4;
       unsigned char *pend = psizes + (size_t) nused * ncols * 4;
-      bfd_boolean is_tu_index;
+      bool is_tu_index;
       struct cu_tu_set *this_set = NULL;
       unsigned int row;
       unsigned char *prow;
@@ -10031,31 +10700,31 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
   return 1;
 }
 
+static int cu_tu_indexes_read = -1; /* Tri-state variable.  */
+
 /* Load the CU and TU indexes if present.  This will build a list of
    section sets that we can use to associate a .debug_info.dwo section
    with its associated .debug_abbrev.dwo section in a .dwp file.  */
 
-static bfd_boolean
+static bool
 load_cu_tu_indexes (void *file)
 {
-  static int cu_tu_indexes_read = -1; /* Tri-state variable.  */
-
   /* If we have already loaded (or tried to load) the CU and TU indexes
      then do not bother to repeat the task.  */
   if (cu_tu_indexes_read == -1)
     {
-      cu_tu_indexes_read = TRUE;
-  
+      cu_tu_indexes_read = true;
+
       if (load_debug_section_with_follow (dwp_cu_index, file))
        if (! process_cu_tu_index (&debug_displays [dwp_cu_index].section, 0))
-         cu_tu_indexes_read = FALSE;
+         cu_tu_indexes_read = false;
 
       if (load_debug_section_with_follow (dwp_tu_index, file))
        if (! process_cu_tu_index (&debug_displays [dwp_tu_index].section, 0))
-         cu_tu_indexes_read = FALSE;
+         cu_tu_indexes_read = false;
     }
 
-  return (bfd_boolean) cu_tu_indexes_read;
+  return (bool) cu_tu_indexes_read;
 }
 
 /* Find the set of sections that includes section SHNDX.  */
@@ -10236,10 +10905,10 @@ calc_gnu_debuglink_crc32 (unsigned long          crc,
   return ~crc & 0xffffffff;
 }
 
-typedef bfd_boolean (*   check_func_type) (const char *, void *);
-typedef const char * (*  parse_func_type) (struct dwarf_section *, void *);
+typedef bool (*check_func_type) (const char *, void *);
+typedef const char *(* parse_func_type) (struct dwarf_section *, void *);
 
-static bfd_boolean
+static bool
 check_gnu_debuglink (const char * pathname, void * crc_pointer)
 {
   static unsigned char buffer [8 * 1024];
@@ -10250,7 +10919,7 @@ check_gnu_debuglink (const char * pathname, void * crc_pointer)
 
   sep_data = open_debug_file (pathname);
   if (sep_data == NULL)
-    return FALSE;
+    return false;
 
   /* Yes - we are opening the file twice...  */
   f = fopen (pathname, "rb");
@@ -10259,7 +10928,7 @@ check_gnu_debuglink (const char * pathname, void * crc_pointer)
       /* Paranoia: This should never happen.  */
       close_debug_file (sep_data);
       warn (_("Unable to reopen separate debug info file: %s\n"), pathname);
-      return FALSE;
+      return false;
     }
 
   while ((count = fread (buffer, 1, sizeof (buffer), f)) > 0)
@@ -10272,10 +10941,10 @@ check_gnu_debuglink (const char * pathname, void * crc_pointer)
       close_debug_file (sep_data);
       warn (_("Separate debug info file %s found, but CRC does not match - ignoring\n"),
            pathname);
-      return FALSE;
+      return false;
     }
 
-  return TRUE;
+  return true;
 }
 
 static const char *
@@ -10289,7 +10958,6 @@ parse_gnu_debuglink (struct dwarf_section * section, void * data)
      The CRC value is stored after the filename, aligned up to 4 bytes.  */
   name = (const char *) section->start;
 
-  
   crc_offset = strnlen (name, section->size) + 1;
   crc_offset = (crc_offset + 3) & ~3;
   if (crc_offset + 4 > section->size)
@@ -10299,18 +10967,18 @@ parse_gnu_debuglink (struct dwarf_section * section, void * data)
   return name;
 }
 
-static bfd_boolean
+static bool
 check_gnu_debugaltlink (const char * filename, void * data ATTRIBUTE_UNUSED)
 {
   void * sep_data = open_debug_file (filename);
 
   if (sep_data == NULL)
-    return FALSE;
+    return false;
 
   /* FIXME: We should now extract the build-id in the separate file
      and check it...  */
 
-  return TRUE;
+  return true;
 }
 
 typedef struct build_id_data
@@ -10339,15 +11007,10 @@ parse_gnu_debugaltlink (struct dwarf_section * section, void * data)
   if (id_len < 0x14)
     return NULL;
 
-  build_id_data = calloc (1, sizeof * build_id_data);
-  if (build_id_data == NULL)
-    return NULL;
-
+  build_id_data = (Build_id_data *) data;
   build_id_data->len = id_len;
   build_id_data->data = section->start + namelen;
 
-  * (Build_id_data **) data = build_id_data;
-
   return name;
 }
 
@@ -10367,7 +11030,7 @@ add_separate_debug_file (const char * filename, void * handle)
    file. If successful, store the path of the file in filename and
    return TRUE, otherwise return FALSE.  */
 
-static bfd_boolean
+static bool
 debuginfod_fetch_separate_debug_info (struct dwarf_section * section,
                                       char ** filename,
                                       void * file)
@@ -10389,16 +11052,16 @@ debuginfod_fetch_separate_debug_info (struct dwarf_section * section,
       filelen = strnlen ((const char *)section->start, section->size);
       if (filelen == section->size)
         /* Corrupt debugaltlink.  */
-        return FALSE;
+        return false;
 
       build_id = section->start + filelen + 1;
       build_id_len = section->size - (filelen + 1);
 
       if (build_id_len == 0)
-        return FALSE;
+        return false;
     }
   else
-    return FALSE;
+    return false;
 
   if (build_id)
     {
@@ -10407,7 +11070,7 @@ debuginfod_fetch_separate_debug_info (struct dwarf_section * section,
 
       client = debuginfod_begin ();
       if (client == NULL)
-        return FALSE;
+        return false;
 
       /* Query debuginfod servers for the target file. If found its path
          will be stored in filename.  */
@@ -10424,11 +11087,11 @@ debuginfod_fetch_separate_debug_info (struct dwarf_section * section,
           /* File successfully retrieved. Close fd since we want to
              use open_debug_file () on filename instead.  */
           close (fd);
-          return TRUE;
+          return true;
         }
     }
 
-  return FALSE;
+  return false;
 }
 #endif
 
@@ -10450,14 +11113,14 @@ load_separate_debug_info (const char *            main_filename,
     {
       warn (_("Corrupt debuglink section: %s\n"),
            xlink->name ? xlink->name : xlink->uncompressed_name);
-      return FALSE;
+      return NULL;
     }
-    
+
   /* Attempt to locate the separate file.
      This should duplicate the logic in bfd/opncls.c:find_separate_debug_file().  */
 
   canon_dir = lrealpath (main_filename);
-  
+
   for (canon_dirlen = strlen (canon_dir); canon_dirlen > 0; canon_dirlen--)
     if (IS_DIR_SEPARATOR (canon_dir[canon_dirlen - 1]))
       break;
@@ -10557,44 +11220,52 @@ load_separate_debug_info (const char *            main_filename,
   }
 #endif
 
-  /* Failed to find the file.  */
-  warn (_("could not find separate debug file '%s'\n"), separate_filename);
-  warn (_("tried: %s\n"), debug_filename);
+  if (do_debug_links)
+    {
+      /* Failed to find the file.  */
+      warn (_("could not find separate debug file '%s'\n"),
+           separate_filename);
+      warn (_("tried: %s\n"), debug_filename);
 
 #ifdef EXTRA_DEBUG_ROOT2
-  sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
-  warn (_("tried: %s\n"), debug_filename);
+      sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2,
+              separate_filename);
+      warn (_("tried: %s\n"), debug_filename);
 #endif
 
 #ifdef EXTRA_DEBUG_ROOT1
-  sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename);
-  warn (_("tried: %s\n"), debug_filename);
+      sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1,
+              canon_dir, separate_filename);
+      warn (_("tried: %s\n"), debug_filename);
 
-  sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
-  warn (_("tried: %s\n"), debug_filename);
+      sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1,
+              separate_filename);
+      warn (_("tried: %s\n"), debug_filename);
 #endif
 
-  sprintf (debug_filename, "%s.debug/%s", canon_dir, separate_filename);
-  warn (_("tried: %s\n"), debug_filename);
+      sprintf (debug_filename, "%s.debug/%s", canon_dir,
+              separate_filename);
+      warn (_("tried: %s\n"), debug_filename);
 
-  sprintf (debug_filename, "%s%s", canon_dir, separate_filename);
-  warn (_("tried: %s\n"), debug_filename);
+      sprintf (debug_filename, "%s%s", canon_dir, separate_filename);
+      warn (_("tried: %s\n"), debug_filename);
 
-  sprintf (debug_filename, ".debug/%s", separate_filename);
-  warn (_("tried: %s\n"), debug_filename);
+      sprintf (debug_filename, ".debug/%s", separate_filename);
+      warn (_("tried: %s\n"), debug_filename);
 
-  sprintf (debug_filename, "%s", separate_filename);
-  warn (_("tried: %s\n"), debug_filename);
+      sprintf (debug_filename, "%s", separate_filename);
+      warn (_("tried: %s\n"), debug_filename);
 
 #if HAVE_LIBDEBUGINFOD
-  {
-    char *urls = getenv (DEBUGINFOD_URLS_ENV_VAR);
-    if (urls == NULL)
-      urls = "";
+      {
+       char *urls = getenv (DEBUGINFOD_URLS_ENV_VAR);
+       if (urls == NULL)
+         urls = "";
 
-    warn (_("tried: DEBUGINFOD_URLS=%s\n"), urls);
-  }
+       warn (_("tried: DEBUGINFOD_URLS=%s\n"), urls);
+      }
 #endif
+    }
 
   free (canon_dir);
   free (debug_filename);
@@ -10610,13 +11281,14 @@ load_separate_debug_info (const char *            main_filename,
     {
       warn (_("failed to open separate debug file: %s\n"), debug_filename);
       free (debug_filename);
-      return FALSE;
+      return NULL;
     }
 
   /* FIXME: We do not check to see if there are any other separate debug info
      files that would also match.  */
 
-  printf (_("%s: Found separate debug info file: %s\n\n"), main_filename, debug_filename);
+  if (do_debug_links)
+    printf (_("\n%s: Found separate debug info file: %s\n"), main_filename, debug_filename);
   add_separate_debug_file (debug_filename, debug_handle);
 
   /* Do not free debug_filename - it might be referenced inside
@@ -10632,8 +11304,11 @@ load_dwo_file (const char * main_filename, const char * name, const char * dir,
   char * separate_filename;
   void * separate_handle;
 
-  /* FIXME: Skip adding / if dwo_dir ends in /.  */
-  separate_filename = concat (dir, "/", name, NULL);
+  if (IS_ABSOLUTE_PATH (name))
+    separate_filename = strdup (name);
+  else
+    /* FIXME: Skip adding / if dwo_dir ends in /.  */
+    separate_filename = concat (dir, "/", name, NULL);
   if (separate_filename == NULL)
     {
       warn (_("Out of memory allocating dwo filename\n"));
@@ -10655,17 +11330,118 @@ load_dwo_file (const char * main_filename, const char * name, const char * dir,
   return separate_handle;
 }
 
+static void
+load_debug_sup_file (const char * main_filename, void * file)
+{
+  if (! load_debug_section (debug_sup, file))
+    return; /* No .debug_sup section.  */
+
+  struct dwarf_section * section;
+  section = & debug_displays [debug_sup].section;
+  assert (section != NULL);
+
+  if (section->start == NULL || section->size < 5)
+    {
+      warn (_(".debug_sup section is corrupt/empty\n"));
+      return;
+    }
+
+  if (section->start[2] != 0)
+    return; /* This is a supplementary file.  */
+
+  const char * filename = (const char *) section->start + 3;
+  if (strnlen (filename, section->size - 3) == section->size - 3)
+    {
+      warn (_("filename in .debug_sup section is corrupt\n"));
+      return;
+    }
+
+  if (filename[0] != '/' && strchr (main_filename, '/'))
+    {
+      char * new_name;
+      if (asprintf (& new_name, "%.*s/%s",
+                   (int) (strrchr (main_filename, '/') - main_filename),
+                   main_filename,
+                   filename) < 3)
+       warn (_("unable to construct path for supplementary debug file"));
+      else
+       filename = new_name;
+    }
+
+  void * handle;
+  handle = open_debug_file (filename);
+  if (handle == NULL)
+    {
+      warn (_("unable to open file '%s' referenced from .debug_sup section\n"), filename);
+      return;
+    }
+
+  printf (_("%s: Found supplementary debug file: %s\n\n"), main_filename, filename);
+
+  /* FIXME: Compare the checksums, if present.  */
+  add_separate_debug_file (filename, handle);
+}
+
+/* Load a debuglink section and/or a debugaltlink section, if either are present.
+   Recursively check the loaded files for more of these sections.
+   Also follow any links in .debug_sup sections.
+   FIXME: Should also check for DWO_* entries in the newly loaded files.  */
+
+static void
+check_for_and_load_links (void * file, const char * filename)
+{
+  void * handle = NULL;
+
+  if (load_debug_section (gnu_debugaltlink, file))
+    {
+      Build_id_data build_id_data;
+
+      handle = load_separate_debug_info (filename,
+                                        & debug_displays[gnu_debugaltlink].section,
+                                        parse_gnu_debugaltlink,
+                                        check_gnu_debugaltlink,
+                                        & build_id_data,
+                                        file);
+      if (handle)
+       {
+         assert (handle == first_separate_info->handle);
+         check_for_and_load_links (first_separate_info->handle,
+                                   first_separate_info->filename);
+       }
+    }
+
+  if (load_debug_section (gnu_debuglink, file))
+    {
+      unsigned long crc32;
+
+      handle = load_separate_debug_info (filename,
+                                        & debug_displays[gnu_debuglink].section,
+                                        parse_gnu_debuglink,
+                                        check_gnu_debuglink,
+                                        & crc32,
+                                        file);
+      if (handle)
+       {
+         assert (handle == first_separate_info->handle);
+         check_for_and_load_links (first_separate_info->handle,
+                                   first_separate_info->filename);
+       }
+    }
+
+  load_debug_sup_file (filename, file);
+}
+
 /* Load the separate debug info file(s) attached to FILE, if any exist.
    Returns TRUE if any were found, FALSE otherwise.
    If TRUE is returned then the linked list starting at first_separate_info
    will be populated with open file handles.  */
 
-bfd_boolean
+bool
 load_separate_debug_files (void * file, const char * filename)
 {
   /* Skip this operation if we are not interested in debug links.  */
   if (! do_follow_links && ! do_debug_links)
-    return FALSE;
+    return false;
 
   /* See if there are any dwo links.  */
   if (load_debug_section (str, file)
@@ -10674,51 +11450,72 @@ load_separate_debug_files (void * file, const char * filename)
     {
       free_dwo_info ();
 
-      if (process_debug_info (& debug_displays[info].section, file, abbrev, TRUE, FALSE))
+      if (process_debug_info (& debug_displays[info].section, file, abbrev,
+                             true, false))
        {
-         bfd_boolean introduced = FALSE;
-         dwo_info *   dwinfo;
-         const char * dir = NULL;
-         const char * id = NULL;
+         bool introduced = false;
+         dwo_info *dwinfo;
+         const char *dir = NULL;
+         const char *id = NULL;
+         const char *name = NULL;
 
          for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = dwinfo->next)
            {
+             /* Accumulate NAME, DIR and ID fields.  */
              switch (dwinfo->type)
                {
                case DWO_NAME:
+                 if (name != NULL)
+                   warn (_("Multiple DWO_NAMEs encountered for the same CU\n"));
+                 name = dwinfo->value;
+                 break;
+
+               case DWO_DIR:
+                 /* There can be multiple DW_AT_comp_dir entries in a CU,
+                    so do not complain.  */
+                 dir = dwinfo->value;
+                 break;
+
+               case DWO_ID:
+                 if (id != NULL)
+                   warn (_("multiple DWO_IDs encountered for the same CU\n"));
+                 id = dwinfo->value;
+                 break;
+
+               default:
+                 error (_("Unexpected DWO INFO type"));
+                 break;
+               }
+
+             /* If we have reached the end of our list, or we are changing
+                CUs, then display the information that we have accumulated
+                so far.  */
+             if (name != NULL
+                 && (dwinfo->next == NULL
+                     || dwinfo->next->cu_offset != dwinfo->cu_offset))
+               {
                  if (do_debug_links)
                    {
                      if (! introduced)
                        {
                          printf (_("The %s section contains link(s) to dwo file(s):\n\n"),
                                  debug_displays [info].section.uncompressed_name);
-                         introduced = TRUE;
+                         introduced = true;
                        }
 
-                     printf (_("  Name:      %s\n"), dwinfo->value);
+                     printf (_("  Name:      %s\n"), name);
                      printf (_("  Directory: %s\n"), dir ? dir : _("<not-found>"));
                      if (id != NULL)
                        display_data (printf (_("  ID:       ")), (unsigned char *) id, 8);
                      else
-                       printf (_("  ID: <unknown>\n"));
+                       printf (_("  ID:        <not specified>\n"));
                      printf ("\n\n");
                    }
 
                  if (do_follow_links)
-                   load_dwo_file (filename, dwinfo->value, dir, id);
-                 break;
-
-               case DWO_DIR:
-                 dir = dwinfo->value;
-                 break;
+                   load_dwo_file (filename, name, dir, id);
 
-               case DWO_ID:
-                 id = dwinfo->value;
-                 break;
-
-               default:
-                 error (_("Unexpected DWO INFO type"));
-                 break;
+                 name = dir = id = NULL;
                }
            }
        }
@@ -10727,50 +11524,44 @@ load_separate_debug_files (void * file, const char * filename)
   if (! do_follow_links)
     /* The other debug links will be displayed by display_debug_links()
        so we do not need to do any further processing here.  */
-    return FALSE;
+    return false;
 
   /* FIXME: We do not check for the presence of both link sections in the same file.  */
-  /* FIXME: We do not check the separate debug info file to see if it too contains debuglinks.  */
   /* FIXME: We do not check for the presence of multiple, same-name debuglink sections.  */
   /* FIXME: We do not check for the presence of a dwo link as well as a debuglink.  */
 
-  if (load_debug_section (gnu_debugaltlink, file))
-    {
-      Build_id_data * build_id_data;
-
-      load_separate_debug_info (filename,
-                               & debug_displays[gnu_debugaltlink].section,
-                               parse_gnu_debugaltlink,
-                               check_gnu_debugaltlink,
-                               & build_id_data,
-                               file);
-    }
-
-  if (load_debug_section (gnu_debuglink, file))
-    {
-      unsigned long crc32;
-
-      load_separate_debug_info (filename,
-                               & debug_displays[gnu_debuglink].section,
-                               parse_gnu_debuglink,
-                               check_gnu_debuglink,
-                               & crc32,
-                               file);
-    }
-
+  check_for_and_load_links (file, filename);
   if (first_separate_info != NULL)
-    return TRUE;
+    return true;
 
   do_follow_links = 0;
-  return FALSE;
-}  
+  return false;
+}
 
 void
 free_debug_memory (void)
 {
   unsigned int i;
 
-  free_abbrevs ();
+  free_all_abbrevs ();
+
+  free (cu_abbrev_map);
+  cu_abbrev_map = NULL;
+  next_free_abbrev_map_entry = 0;
+
+  free (shndx_pool);
+  shndx_pool = NULL;
+  shndx_pool_size = 0;
+  shndx_pool_used = 0;
+  free (cu_sets);
+  cu_sets = NULL;
+  cu_count = 0;
+  free (tu_sets);
+  tu_sets = NULL;
+  tu_count = 0;
+
+  memset (level_type_signed, 0, sizeof level_type_signed);
+  cu_tu_indexes_read = -1;
 
   for (i = 0; i < max; i++)
     free_debug_section ((enum dwarf_section_display_enum) i);
@@ -10803,7 +11594,7 @@ free_debug_memory (void)
       free ((void *) d);
     }
   first_separate_info = NULL;
-  
+
   free_dwo_info ();
 }
 
@@ -10837,6 +11628,7 @@ dwarf_select_sections_by_names (const char *names)
       { "links", & do_debug_links, 1 },
       { "loc",  & do_debug_loc, 1 },
       { "macro", & do_debug_macinfo, 1 },
+      { "no-follow-links", & do_follow_links, 0 },
       { "pubnames", & do_debug_pubnames, 1 },
       { "pubtypes", & do_debug_pubtypes, 1 },
       /* This entry is for compatibility
@@ -10866,7 +11658,7 @@ dwarf_select_sections_by_names (const char *names)
          if (strncmp (p, entry->option, len) == 0
              && (p[len] == ',' || p[len] == '\0'))
            {
-             * entry->variable |= entry->val;
+             * entry->variable = entry->val;
 
              /* The --debug-dump=frames-interp option also
                 enables the --debug-dump=frames option.  */
@@ -10907,6 +11699,7 @@ dwarf_select_sections_by_letters (const char *letters)
       case 'g':        do_gdb_index = 1; break;
       case 'i':        do_debug_info = 1; break;
       case 'K': do_follow_links = 1; break;
+      case 'N': do_follow_links = 0; break;
       case 'k':        do_debug_links = 1; break;
       case 'l':        do_debug_lines |= FLAG_DEBUG_LINES_RAW; break;
       case 'L':        do_debug_lines |= FLAG_DEBUG_LINES_DECODED; break;
@@ -10953,59 +11746,60 @@ dwarf_select_sections_all (void)
   do_debug_str_offsets = 1;
 }
 
-#define NO_ABBREVS   NULL, NULL, NULL, 0, 0, 0, NULL, 0, NULL
-#define ABBREV(N)    NULL, NULL, NULL, 0, 0, N, NULL, 0, NULL
+#define NO_ABBREVS   NULL, NULL, NULL, 0, 0, 0, NULL, 0
+#define ABBREV(N)    NULL, NULL, NULL, 0, 0, N, NULL, 0
 
 /* N.B. The order here must match the order in section_display_enum.  */
 
 struct dwarf_section_display debug_displays[] =
 {
-  { { ".debug_abbrev",     ".zdebug_abbrev",   NO_ABBREVS },      display_debug_abbrev,   &do_debug_abbrevs,   FALSE },
-  { { ".debug_aranges",            ".zdebug_aranges",  NO_ABBREVS },      display_debug_aranges,  &do_debug_aranges,   TRUE },
-  { { ".debug_frame",       ".zdebug_frame",   NO_ABBREVS },      display_debug_frames,   &do_debug_frames,    TRUE },
-  { { ".debug_info",       ".zdebug_info",     ABBREV (abbrev)},  display_debug_info,     &do_debug_info,      TRUE },
-  { { ".debug_line",       ".zdebug_line",     NO_ABBREVS },      display_debug_lines,    &do_debug_lines,     TRUE },
-  { { ".debug_pubnames",    ".zdebug_pubnames",        NO_ABBREVS },      display_debug_pubnames, &do_debug_pubnames,  FALSE },
-  { { ".debug_gnu_pubnames", ".zdebug_gnu_pubnames", NO_ABBREVS }, display_debug_gnu_pubnames, &do_debug_pubnames, FALSE },
-  { { ".eh_frame",         "",                 NO_ABBREVS },      display_debug_frames,   &do_debug_frames,    TRUE },
-  { { ".debug_macinfo",            ".zdebug_macinfo",  NO_ABBREVS },      display_debug_macinfo,  &do_debug_macinfo,   FALSE },
-  { { ".debug_macro",      ".zdebug_macro",    NO_ABBREVS },      display_debug_macro,    &do_debug_macinfo,   TRUE },
-  { { ".debug_str",        ".zdebug_str",      NO_ABBREVS },      display_debug_str,      &do_debug_str,       FALSE },
-  { { ".debug_line_str",    ".zdebug_line_str",        NO_ABBREVS },      display_debug_str,      &do_debug_str,       FALSE },
-  { { ".debug_loc",        ".zdebug_loc",      NO_ABBREVS },      display_debug_loc,      &do_debug_loc,       TRUE },
-  { { ".debug_loclists",    ".zdebug_loclists",        NO_ABBREVS },      display_debug_loc,      &do_debug_loc,       TRUE },
-  { { ".debug_pubtypes",    ".zdebug_pubtypes",        NO_ABBREVS },      display_debug_pubnames, &do_debug_pubtypes,  FALSE },
-  { { ".debug_gnu_pubtypes", ".zdebug_gnu_pubtypes", NO_ABBREVS }, display_debug_gnu_pubnames, &do_debug_pubtypes, FALSE },
-  { { ".debug_ranges",     ".zdebug_ranges",   NO_ABBREVS },      display_debug_ranges,   &do_debug_ranges,    TRUE },
-  { { ".debug_rnglists",    ".zdebug_rnglists",        NO_ABBREVS },      display_debug_ranges,   &do_debug_ranges,    TRUE },
-  { { ".debug_static_func", ".zdebug_static_func", NO_ABBREVS },   display_debug_not_supported, NULL,          FALSE },
-  { { ".debug_static_vars", ".zdebug_static_vars", NO_ABBREVS },   display_debug_not_supported, NULL,          FALSE },
-  { { ".debug_types",      ".zdebug_types",    ABBREV (abbrev) }, display_debug_types,    &do_debug_info,      TRUE },
-  { { ".debug_weaknames",   ".zdebug_weaknames", NO_ABBREVS },     display_debug_not_supported, NULL,          FALSE },
-  { { ".gdb_index",        "",                 NO_ABBREVS },      display_gdb_index,      &do_gdb_index,       FALSE },
-  { { ".debug_names",      "",                 NO_ABBREVS },      display_debug_names,    &do_gdb_index,       FALSE },
-  { { ".trace_info",       "",                 ABBREV (trace_abbrev) }, display_trace_info, &do_trace_info,    TRUE },
-  { { ".trace_abbrev",     "",                 NO_ABBREVS },      display_debug_abbrev,   &do_trace_abbrevs,   FALSE },
-  { { ".trace_aranges",            "",                 NO_ABBREVS },      display_debug_aranges,  &do_trace_aranges,   FALSE },
-  { { ".debug_info.dwo",    ".zdebug_info.dwo",        ABBREV (abbrev_dwo) }, display_debug_info, &do_debug_info,      TRUE },
-  { { ".debug_abbrev.dwo",  ".zdebug_abbrev.dwo", NO_ABBREVS },    display_debug_abbrev,   &do_debug_abbrevs,  FALSE },
-  { { ".debug_types.dwo",   ".zdebug_types.dwo", ABBREV (abbrev_dwo) }, display_debug_types, &do_debug_info,   TRUE },
-  { { ".debug_line.dwo",    ".zdebug_line.dwo", NO_ABBREVS },      display_debug_lines,    &do_debug_lines,    TRUE },
-  { { ".debug_loc.dwo",            ".zdebug_loc.dwo",  NO_ABBREVS },      display_debug_loc,      &do_debug_loc,       TRUE },
-  { { ".debug_macro.dwo",   ".zdebug_macro.dwo", NO_ABBREVS },     display_debug_macro,    &do_debug_macinfo,  TRUE },
-  { { ".debug_macinfo.dwo", ".zdebug_macinfo.dwo", NO_ABBREVS },   display_debug_macinfo,  &do_debug_macinfo,  FALSE },
-  { { ".debug_str.dwo",     ".zdebug_str.dwo",  NO_ABBREVS },      display_debug_str,      &do_debug_str,      TRUE },
-  { { ".debug_str_offsets", ".zdebug_str_offsets", NO_ABBREVS },   display_debug_str_offsets, &do_debug_str_offsets, TRUE },
-  { { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo", NO_ABBREVS }, display_debug_str_offsets, &do_debug_str_offsets, TRUE },
-  { { ".debug_addr",       ".zdebug_addr",     NO_ABBREVS },      display_debug_addr,     &do_debug_addr,      TRUE },
-  { { ".debug_cu_index",    "",                        NO_ABBREVS },      display_cu_index,       &do_debug_cu_index,  FALSE },
-  { { ".debug_tu_index",    "",                        NO_ABBREVS },      display_cu_index,       &do_debug_cu_index,  FALSE },
-  { { ".gnu_debuglink",     "",                 NO_ABBREVS },      display_debug_links,    &do_debug_links,     FALSE },
-  { { ".gnu_debugaltlink",  "",                 NO_ABBREVS },      display_debug_links,    &do_debug_links,     FALSE },
+  { { ".debug_abbrev",     ".zdebug_abbrev",   NO_ABBREVS },      display_debug_abbrev,   &do_debug_abbrevs,   false },
+  { { ".debug_aranges",            ".zdebug_aranges",  NO_ABBREVS },      display_debug_aranges,  &do_debug_aranges,   true },
+  { { ".debug_frame",       ".zdebug_frame",   NO_ABBREVS },      display_debug_frames,   &do_debug_frames,    true },
+  { { ".debug_info",       ".zdebug_info",     ABBREV (abbrev)},  display_debug_info,     &do_debug_info,      true },
+  { { ".debug_line",       ".zdebug_line",     NO_ABBREVS },      display_debug_lines,    &do_debug_lines,     true },
+  { { ".debug_pubnames",    ".zdebug_pubnames",        NO_ABBREVS },      display_debug_pubnames, &do_debug_pubnames,  false },
+  { { ".debug_gnu_pubnames", ".zdebug_gnu_pubnames", NO_ABBREVS }, display_debug_gnu_pubnames, &do_debug_pubnames, false },
+  { { ".eh_frame",         "",                 NO_ABBREVS },      display_debug_frames,   &do_debug_frames,    true },
+  { { ".debug_macinfo",            ".zdebug_macinfo",  NO_ABBREVS },      display_debug_macinfo,  &do_debug_macinfo,   false },
+  { { ".debug_macro",      ".zdebug_macro",    NO_ABBREVS },      display_debug_macro,    &do_debug_macinfo,   true },
+  { { ".debug_str",        ".zdebug_str",      NO_ABBREVS },      display_debug_str,      &do_debug_str,       false },
+  { { ".debug_line_str",    ".zdebug_line_str",        NO_ABBREVS },      display_debug_str,      &do_debug_str,       false },
+  { { ".debug_loc",        ".zdebug_loc",      NO_ABBREVS },      display_debug_loc,      &do_debug_loc,       true },
+  { { ".debug_loclists",    ".zdebug_loclists",        NO_ABBREVS },      display_debug_loc,      &do_debug_loc,       true },
+  { { ".debug_pubtypes",    ".zdebug_pubtypes",        NO_ABBREVS },      display_debug_pubnames, &do_debug_pubtypes,  false },
+  { { ".debug_gnu_pubtypes", ".zdebug_gnu_pubtypes", NO_ABBREVS }, display_debug_gnu_pubnames, &do_debug_pubtypes, false },
+  { { ".debug_ranges",     ".zdebug_ranges",   NO_ABBREVS },      display_debug_ranges,   &do_debug_ranges,    true },
+  { { ".debug_rnglists",    ".zdebug_rnglists",        NO_ABBREVS },      display_debug_ranges,   &do_debug_ranges,    true },
+  { { ".debug_static_func", ".zdebug_static_func", NO_ABBREVS },   display_debug_not_supported, NULL,          false },
+  { { ".debug_static_vars", ".zdebug_static_vars", NO_ABBREVS },   display_debug_not_supported, NULL,          false },
+  { { ".debug_types",      ".zdebug_types",    ABBREV (abbrev) }, display_debug_types,    &do_debug_info,      true },
+  { { ".debug_weaknames",   ".zdebug_weaknames", NO_ABBREVS },     display_debug_not_supported, NULL,          false },
+  { { ".gdb_index",        "",                 NO_ABBREVS },      display_gdb_index,      &do_gdb_index,       false },
+  { { ".debug_names",      "",                 NO_ABBREVS },      display_debug_names,    &do_gdb_index,       false },
+  { { ".trace_info",       "",                 ABBREV (trace_abbrev) }, display_trace_info, &do_trace_info,    true },
+  { { ".trace_abbrev",     "",                 NO_ABBREVS },      display_debug_abbrev,   &do_trace_abbrevs,   false },
+  { { ".trace_aranges",            "",                 NO_ABBREVS },      display_debug_aranges,  &do_trace_aranges,   false },
+  { { ".debug_info.dwo",    ".zdebug_info.dwo",        ABBREV (abbrev_dwo) }, display_debug_info, &do_debug_info,      true },
+  { { ".debug_abbrev.dwo",  ".zdebug_abbrev.dwo", NO_ABBREVS },    display_debug_abbrev,   &do_debug_abbrevs,  false },
+  { { ".debug_types.dwo",   ".zdebug_types.dwo", ABBREV (abbrev_dwo) }, display_debug_types, &do_debug_info,   true },
+  { { ".debug_line.dwo",    ".zdebug_line.dwo", NO_ABBREVS },      display_debug_lines,    &do_debug_lines,    true },
+  { { ".debug_loc.dwo",            ".zdebug_loc.dwo",  NO_ABBREVS },      display_debug_loc,      &do_debug_loc,       true },
+  { { ".debug_macro.dwo",   ".zdebug_macro.dwo", NO_ABBREVS },     display_debug_macro,    &do_debug_macinfo,  true },
+  { { ".debug_macinfo.dwo", ".zdebug_macinfo.dwo", NO_ABBREVS },   display_debug_macinfo,  &do_debug_macinfo,  false },
+  { { ".debug_str.dwo",     ".zdebug_str.dwo",  NO_ABBREVS },      display_debug_str,      &do_debug_str,      true },
+  { { ".debug_str_offsets", ".zdebug_str_offsets", NO_ABBREVS },   display_debug_str_offsets, &do_debug_str_offsets, true },
+  { { ".debug_str_offsets.dwo", ".zdebug_str_offsets.dwo", NO_ABBREVS }, display_debug_str_offsets, &do_debug_str_offsets, true },
+  { { ".debug_addr",       ".zdebug_addr",     NO_ABBREVS },      display_debug_addr,     &do_debug_addr,      true },
+  { { ".debug_cu_index",    "",                        NO_ABBREVS },      display_cu_index,       &do_debug_cu_index,  false },
+  { { ".debug_tu_index",    "",                        NO_ABBREVS },      display_cu_index,       &do_debug_cu_index,  false },
+  { { ".gnu_debuglink",     "",                 NO_ABBREVS },      display_debug_links,    &do_debug_links,     false },
+  { { ".gnu_debugaltlink",  "",                 NO_ABBREVS },      display_debug_links,    &do_debug_links,     false },
+  { { ".debug_sup",         "",                        NO_ABBREVS },      display_debug_sup,      &do_debug_links,     false },
   /* Separate debug info files can containt their own .debug_str section,
      and this might be in *addition* to a .debug_str section already present
      in the main file.  Hence we need to have two entries for .debug_str.  */
-  { { ".debug_str",        ".zdebug_str",      NO_ABBREVS },      display_debug_str,      &do_debug_str,       FALSE },
+  { { ".debug_str",        ".zdebug_str",      NO_ABBREVS },      display_debug_str,      &do_debug_str,       false },
 };
 
 /* A static assertion.  */