gdb, include: replace pragmas with DIAGNOSTIC macros, fix build with g++ 4.8
[binutils-gdb.git] / binutils / dwarf.c
index 14a7791c8cc4627ea835c3eac02be4c79f582894..6f2a49b48c2108b48b16f50b518dd74ef9d33698 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
 
+#include <limits.h>
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#ifndef ENABLE_CHECKING
+#define ENABLE_CHECKING 0
+#endif
+
 #undef MAX
 #undef MIN
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
@@ -67,11 +76,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 +108,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 +147,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
@@ -172,7 +182,7 @@ get_encoded_value (unsigned char **pdata,
   unsigned int size = size_of_encoded_value (encoding);
   dwarf_vma val;
 
-  if (data + size >= end)
+  if (data >= end || size > (size_t) (end - data))
     {
       warn (_("Encoded value extends past end of section\n"));
       * pdata = end;
@@ -207,7 +217,7 @@ get_encoded_value (unsigned char **pdata,
   return val;
 }
 
-#if defined HAVE_LONG_LONG && SIZEOF_LONG_LONG > SIZEOF_LONG
+#if SIZEOF_LONG_LONG > SIZEOF_LONG
 # ifndef __MINGW32__
 #  define DWARF_VMA_FMT                "ll"
 #  define DWARF_VMA_FMT_LONG   "%16.16llx"
@@ -301,31 +311,10 @@ print_dwarf_view (dwarf_vma value, unsigned num_bytes, int force)
     printf ("%*s", len + 1, "");
 }
 
-/* Format a 64-bit value, given as two 32-bit values, in hex.
-   For reentrancy, this uses a buffer provided by the caller.  */
-
-static const char *
-dwarf_vmatoa64 (dwarf_vma hvalue, dwarf_vma lvalue, char *buf,
-               unsigned int buf_len)
-{
-  int len = 0;
-
-  if (hvalue == 0)
-    snprintf (buf, buf_len, "%" DWARF_VMA_FMT "x", lvalue);
-  else
-    {
-      len = snprintf (buf, buf_len, "%" DWARF_VMA_FMT "x", hvalue);
-      snprintf (buf + len, buf_len - len,
-               "%08" DWARF_VMA_FMT "x", lvalue);
-    }
-
-  return 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 +322,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,37 +334,31 @@ read_leb128 (unsigned char *data,
   while (data < end)
     {
       unsigned char byte = *data++;
-      bfd_boolean cont = (byte & 0x80) ? TRUE : FALSE;
+      unsigned char lost, mask;
 
-      byte &= 0x7f;
       num_read++;
 
-      if (shift < sizeof (result) * 8)
+      if (shift < CHAR_BIT * sizeof (result))
        {
-         result |= ((dwarf_vma) byte) << shift;
-         if (sign)
-           {
-             if ((((dwarf_signed_vma) result >> shift) & 0x7f) != byte)
-               /* Overflow.  */
-               status |= 2;
-           }
-         else if ((result >> shift) != byte)
-           {
-             /* Overflow.  */
-             status |= 2;
-           }
-
+         result |= ((dwarf_vma) (byte & 0x7f)) << shift;
+         /* 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 != 0)
+      else
        {
-         status |= 2;
+         lost = byte;
+         mask = 0x7f;
        }
+      if ((lost & mask) != (sign && (dwarf_signed_vma) result < 0 ? mask : 0))
+       status |= 2;
 
-      if (!cont)
+      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;
        }
@@ -389,87 +372,55 @@ read_leb128 (unsigned char *data,
   return result;
 }
 
-/* Read AMOUNT bytes from PTR and store them in VAL as an unsigned value.
-   Checks to make sure that the read will not reach or pass END
-   and that VAL is big enough to hold AMOUNT bytes.  */
-#define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END)   \
-  do                                           \
-    {                                          \
-      unsigned int amount = (AMOUNT);          \
-      if (sizeof (VAL) < amount)               \
-       {                                       \
+/* Read AMOUNT bytes from PTR and store them in VAL.
+   Checks to make sure that the read will not reach or pass END.
+   FUNC chooses whether the value read is unsigned or signed, and may
+   be either byte_get or byte_get_signed.  If INC is true, PTR is
+   incremented after reading the value.
+   This macro cannot protect against PTR values derived from user input.
+   The C standard sections 6.5.6 and 6.5.8 say attempts to do so using
+   pointers is undefined behaviour.  */
+#define SAFE_BYTE_GET_INTERNAL(VAL, PTR, AMOUNT, END, FUNC, INC)       \
+  do                                                                   \
+    {                                                                  \
+      size_t amount = (AMOUNT);                                                \
+      if (sizeof (VAL) < amount)                                       \
+       {                                                               \
          error (ngettext ("internal error: attempt to read %d byte "   \
                           "of data in to %d sized variable",           \
                           "internal error: attempt to read %d bytes "  \
                           "of data in to %d sized variable",           \
                           amount),                                     \
-                amount, (int) sizeof (VAL));   \
-         amount = sizeof (VAL);                \
-       }                                       \
-      if (((PTR) + amount) >= (END))           \
-       {                                       \
-         if ((PTR) < (END))                    \
-           amount = (END) - (PTR);             \
-         else                                  \
-           amount = 0;                         \
-       }                                       \
-      if (amount == 0 || amount > 8)           \
-       VAL = 0;                                \
-      else                                     \
-       VAL = byte_get ((PTR), amount);         \
-    }                                          \
+                (int) amount, (int) sizeof (VAL));                     \
+         amount = sizeof (VAL);                                        \
+       }                                                               \
+      if (ENABLE_CHECKING)                                             \
+       assert ((PTR) <= (END));                                        \
+      size_t avail = (END) - (PTR);                                    \
+      if ((PTR) > (END))                                               \
+       avail = 0;                                                      \
+      if (amount > avail)                                              \
+       amount = avail;                                                 \
+      if (amount == 0)                                                 \
+       (VAL) = 0;                                                      \
+      else                                                             \
+       (VAL) = (FUNC) ((PTR), amount);                                 \
+      if (INC)                                                         \
+       (PTR) += amount;                                                \
+    }                                                                  \
   while (0)
 
-/* Like SAFE_BYTE_GET, but also increments PTR by AMOUNT.  */
+#define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END)   \
+  SAFE_BYTE_GET_INTERNAL (VAL, PTR, AMOUNT, END, byte_get, false)
+
 #define SAFE_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END)   \
-  do                                                   \
-    {                                                  \
-      SAFE_BYTE_GET (VAL, PTR, AMOUNT, END);           \
-      PTR += AMOUNT;                                   \
-    }                                                  \
-  while (0)
+  SAFE_BYTE_GET_INTERNAL (VAL, PTR, AMOUNT, END, byte_get, true)
 
-/* Like SAFE_BYTE_GET, but reads a signed value.  */
 #define SAFE_SIGNED_BYTE_GET(VAL, PTR, AMOUNT, END)    \
-  do                                                   \
-    {                                                  \
-      unsigned int amount = (AMOUNT);                  \
-      if (((PTR) + amount) >= (END))                   \
-       {                                               \
-         if ((PTR) < (END))                            \
-           amount = (END) - (PTR);                     \
-         else                                          \
-           amount = 0;                                 \
-       }                                               \
-      if (amount)                                      \
-       VAL = byte_get_signed ((PTR), amount);          \
-      else                                             \
-       VAL = 0;                                        \
-    }                                                  \
-  while (0)
+  SAFE_BYTE_GET_INTERNAL (VAL, PTR, AMOUNT, END, byte_get_signed, false)
 
-/* Like SAFE_SIGNED_BYTE_GET, but also increments PTR by AMOUNT.  */
 #define SAFE_SIGNED_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END)    \
-  do                                                           \
-    {                                                          \
-      SAFE_SIGNED_BYTE_GET (VAL, PTR, AMOUNT, END);            \
-      PTR += AMOUNT;                                           \
-    }                                                          \
-  while (0)
-
-#define SAFE_BYTE_GET64(PTR, HIGH, LOW, END)           \
-  do                                                   \
-    {                                                  \
-      if (((PTR) + 8) <= (END))                                \
-       {                                               \
-         byte_get_64 ((PTR), (HIGH), (LOW));           \
-       }                                               \
-      else                                             \
-       {                                               \
-         * (LOW) = * (HIGH) = 0;                       \
-       }                                               \
-    }                                                  \
-  while (0)
+  SAFE_BYTE_GET_INTERNAL (VAL, PTR, AMOUNT, END, byte_get_signed, true)
 
 typedef struct State_Machine_Registers
 {
@@ -521,7 +472,7 @@ process_extended_line_op (unsigned char * data,
   READ_ULEB (len, data, end);
   header_len = data - orig_data;
 
-  if (len == 0 || data == end || len > (size_t) (end - data))
+  if (len == 0 || data >= end || len > (size_t) (end - data))
     {
       warn (_("Badly formed extended line op encountered!\n"));
       return header_len;
@@ -564,7 +515,9 @@ process_extended_line_op (unsigned char * data,
 
        name = data;
        l = strnlen ((char *) data, end - data);
-       data += l + 1;
+       data += l;
+       if (data < end)
+         data++;
        READ_ULEB (val, data, end);
        printf ("%s\t", dwarf_vmatoa ("u", val));
        READ_ULEB (val, data, end);
@@ -574,7 +527,7 @@ process_extended_line_op (unsigned char * data,
        printf ("%.*s\n\n", (int) l, name);
       }
 
-      if (((size_t) (data - orig_data) != len + header_len) || data == end)
+      if (((size_t) (data - orig_data) != len + header_len) || data >= end)
        warn (_("DW_LNE_define_file: Bad opcode length\n"));
       break;
 
@@ -688,7 +641,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>");
     }
@@ -702,7 +655,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 *
@@ -716,7 +669,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>");
     }
@@ -735,7 +688,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;
@@ -745,7 +698,7 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
   dwarf_vma str_offset;
   const char * ret;
   unsigned char *curr = index_section->start;
-  const unsigned char *end = curr + index_section->size;
+  unsigned char *end = curr + index_section->size;
   dwarf_vma length;
 
   if (index_section->start == NULL)
@@ -780,28 +733,44 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set,
     {
       /* Skip the version and padding bytes.
         We assume that they are correct.  */
-      curr += 4;
+      if (end - curr >= 4)
+       curr += 4;
+      else
+       curr = end;
+      if (length >= 4)
+       length -= 4;
+      else
+       length = 0;
+
+      if (this_set != NULL
+         && this_set->section_sizes[DW_SECT_STR_OFFSETS] < length)
+       length = this_set->section_sizes[DW_SECT_STR_OFFSETS];
 
-      /* FIXME: The code below assumes that there is only one table
-        in the .debug_str_offsets section, so check that now.  */
-      if ((offset_size == 4 && curr + length < (end - 8))
-         || (offset_size == 8 && curr + length < (end - 16)))
+      if (length > (dwarf_vma) (end - curr))
        {
-         warn (_("index table size is too small %s vs %s\n"),
+         warn (_("index table size too large for section %s vs %s\n"),
                dwarf_vmatoa ("x", length),
                dwarf_vmatoa ("x", index_section->size));
+         length = end - curr;
+       }
+
+      if (length < offset_size)
+       {
+         warn (_("index table size %s is too small\n"),
+               dwarf_vmatoa ("x", length));
          return _("<table too small>");
        }
     }
 
   index_offset = idx * offset_size;
-      
+
   if (this_set != NULL)
     index_offset += this_set->section_offsets [DW_SECT_STR_OFFSETS];
 
-  if (index_offset >= length)
+  if (index_offset >= length
+      || length - index_offset < offset_size)
     {
-      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>");
@@ -811,7 +780,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>");
     }
@@ -837,7 +806,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>";
     }
@@ -854,7 +823,7 @@ typedef struct abbrev_attr
 {
   unsigned long          attribute;
   unsigned long          form;
-  bfd_signed_vma         implicit_const;
+  dwarf_signed_vma       implicit_const;
   struct abbrev_attr *   next;
 }
 abbrev_attr;
@@ -1029,19 +998,19 @@ add_abbrev (unsigned long  number,
 }
 
 static void
-add_abbrev_attr (unsigned long   attribute,
-                unsigned long   form,
-                bfd_signed_vma  implicit_const,
-                abbrev_list *   list)
+add_abbrev_attr (unsigned long    attribute,
+                unsigned long    form,
+                dwarf_signed_vma implicit_const,
+                abbrev_list *    list)
 {
   abbrev_attr *attr;
 
   attr = (abbrev_attr *) xmalloc (sizeof (*attr));
 
-  attr->attribute = attribute;
-  attr->form      = form;
+  attr->attribute      = attribute;
+  attr->form           = form;
   attr->implicit_const = implicit_const;
-  attr->next      = NULL;
+  attr->next           = NULL;
 
   assert (list != NULL && list->last_abbrev != NULL);
 
@@ -1059,10 +1028,34 @@ add_abbrev_attr (unsigned long   attribute,
    an abbreviation set was found.  */
 
 static unsigned char *
-process_abbrev_set (unsigned char *        start,
-                   const unsigned char *  end,
-                   abbrev_list *          list)
+process_abbrev_set (struct dwarf_section *section,
+                   dwarf_vma abbrev_base,
+                   dwarf_vma abbrev_size,
+                   dwarf_vma abbrev_offset,
+                   abbrev_list *list)
 {
+  if (abbrev_base >= section->size
+      || abbrev_size > section->size - abbrev_base)
+    {
+      /* PR 17531: file:4bcd9ce9.  */
+      warn (_("Debug info is corrupted, abbrev size (%lx) is larger than "
+             "abbrev section size (%lx)\n"),
+             (unsigned long) (abbrev_base + abbrev_size),
+             (unsigned long) section->size);
+      return NULL;
+    }
+  if (abbrev_offset >= abbrev_size)
+    {
+      warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than "
+             "abbrev section size (%lx)\n"),
+           (unsigned long) abbrev_offset,
+           (unsigned long) abbrev_size);
+      return NULL;
+    }
+
+  unsigned char *start = section->start + abbrev_base;
+  unsigned char *end = start + abbrev_size;
+  start += abbrev_offset;
   while (start < end)
     {
       unsigned long entry;
@@ -1092,7 +1085,7 @@ process_abbrev_set (unsigned char *        start,
        {
          unsigned long form;
          /* Initialize it due to a false compiler warning.  */
-         bfd_signed_vma implicit_const = -1;
+         dwarf_signed_vma implicit_const = -1;
 
          READ_ULEB (attribute, start, end);
          if (start == end)
@@ -1628,8 +1621,6 @@ decode_location_expression (unsigned char * data,
            need_frame_base = 1;
          putchar (')');
          data += uvalue;
-         if (data > end)
-           data = end;
          break;
        case DW_OP_const_type:
        case DW_OP_GNU_const_type:
@@ -1794,34 +1785,6 @@ find_cu_tu_set_v2 (dwarf_vma cu_offset, int do_types)
   return NULL;
 }
 
-/* Add INC to HIGH_BITS:LOW_BITS.  */
-static void
-add64 (dwarf_vma * high_bits, dwarf_vma * low_bits, dwarf_vma inc)
-{
-  dwarf_vma tmp = * low_bits;
-
-  tmp += inc;
-
-  /* FIXME: There is probably a better way of handling this:
-
-     We need to cope with dwarf_vma being a 32-bit or 64-bit
-     type.  Plus regardless of its size LOW_BITS is meant to
-     only hold 32-bits, so if there is overflow or wrap around
-     we must propagate into HIGH_BITS.  */
-  if (tmp < * low_bits)
-    {
-      ++ * high_bits;
-    }
-  else if (sizeof (tmp) > 8
-          && (tmp >> 31) > 1)
-    {
-      ++ * high_bits;
-      tmp &= 0xFFFFFFFF;
-    }
-
-  * low_bits = tmp;
-}
-
 static const char *
 fetch_alt_indirect_string (dwarf_vma offset)
 {
@@ -1859,7 +1822,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>");
@@ -1892,32 +1855,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
@@ -1956,16 +1920,17 @@ check_uvalue (const unsigned char * start,
 }
 
 static unsigned char *
-skip_attr_bytes (unsigned long          form,
-                unsigned char *        data,
-                unsigned const char *  end,
-                dwarf_vma              pointer_size,
-                dwarf_vma              offset_size,
-                int                    dwarf_version,
-                dwarf_vma *            value_return)
+skip_attr_bytes (unsigned long form,
+                unsigned char *data,
+                unsigned char *end,
+                dwarf_vma pointer_size,
+                dwarf_vma offset_size,
+                int dwarf_version,
+                dwarf_vma *value_return)
 {
   dwarf_signed_vma svalue;
   dwarf_vma uvalue = 0;
+  dwarf_vma inc = 0;
 
   * value_return = 0;
 
@@ -1999,16 +1964,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;
 
@@ -2020,58 +1996,66 @@ 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:
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 8, end);
+      break;
+
     case DW_FORM_data8:
     case DW_FORM_ref_sig8:
-      data += 8;
+      inc = 8;
       break;
 
     case DW_FORM_data16:
-      data += 16;
+      inc = 16;
       break;
 
     case DW_FORM_string:
-      data += strnlen ((char *) data, end - data) + 1;
+      inc = strnlen ((char *) data, end - data) + 1;
       break;
 
     case DW_FORM_block:
     case DW_FORM_exprloc:
       READ_ULEB (uvalue, data, end);
-      data += uvalue;
+      inc = uvalue;
       break;
 
     case DW_FORM_block1:
-      SAFE_BYTE_GET (uvalue, data, 1, end);
-      data += 1 + uvalue;
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
+      inc = uvalue;
       break;
 
     case DW_FORM_block2:
-      SAFE_BYTE_GET (uvalue, data, 2, end);
-      data += 2 + uvalue;
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end);
+      inc = uvalue;
       break;
 
     case DW_FORM_block4:
-      SAFE_BYTE_GET (uvalue, data, 4, end);
-      data += 4 + uvalue;
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
+      inc = uvalue;
       break;
 
     case DW_FORM_indirect:
       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);
+      return skip_attr_bytes (form, data, end, pointer_size, offset_size,
+                             dwarf_version, value_return);
 
     default:
       return NULL;
     }
 
   * value_return = uvalue;
-  if (data > end)
-    data = (unsigned char *) end;
+  if (inc <= (dwarf_vma) (end - data))
+    data += inc;
+  else
+    data = end;
   return data;
 }
 
@@ -2079,13 +2063,14 @@ skip_attr_bytes (unsigned long          form,
    associated with it.  */
 
 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)
+get_type_abbrev_from_form (unsigned long form,
+                          unsigned long uvalue,
+                          dwarf_vma cu_offset,
+                          unsigned char *cu_end,
+                          const struct dwarf_section *section,
+                          unsigned long *abbrev_num_return,
+                          unsigned char **data_return,
+                          abbrev_map **map_return)
 {
   unsigned long   abbrev_number;
   abbrev_map *    map;
@@ -2100,6 +2085,7 @@ get_type_abbrev_from_form (unsigned long                 form,
   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;
 
@@ -2112,14 +2098,19 @@ get_type_abbrev_from_form (unsigned long                 form,
        }
       break;
 
+    case DW_FORM_ref_sup4:
+    case DW_FORM_ref_sup8:
+      break;
+
     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)
+      if (uvalue + cu_offset > (size_t) (cu_end - section->start))
        {
-         warn (_("Unable to resolve ref form: uvalue %lx + cu_offset %lx > section size %lx\n"),
-               uvalue, (long) cu_offset, (long) section->size);
+         warn (_("Unable to resolve ref form: uvalue %lx + cu_offset %lx > CU size %lx\n"),
+               uvalue, (long) cu_offset, (long) (cu_end - section->start));
          return NULL;
        }
       uvalue += cu_offset;
@@ -2134,7 +2125,7 @@ get_type_abbrev_from_form (unsigned long                 form,
 
   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);
@@ -2146,12 +2137,12 @@ get_type_abbrev_from_form (unsigned long                 form,
       return NULL;
     }
 
-  if (cu_offset_return != NULL)
+  if (map_return != NULL)
     {
       if (form == DW_FORM_ref_addr)
-       * cu_offset_return = map->start;
+       *map_return = map;
       else
-       * cu_offset_return = cu_offset;
+       *map_return = NULL;
     }
        
   READ_ULEB (abbrev_number, data, section->start + section->size);
@@ -2159,7 +2150,7 @@ get_type_abbrev_from_form (unsigned long                 form,
   for (entry = map->list->first_abbrev; entry != NULL; entry = entry->next)
     if (entry->number == abbrev_number)
       break;
-  
+
   if (abbrev_num_return != NULL)
     * abbrev_num_return = abbrev_number;
 
@@ -2177,20 +2168,20 @@ get_type_abbrev_from_form (unsigned long                 form,
    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,
-                    bfd_boolean *          is_signed,
-                    unsigned int           nesting)
+get_type_signedness (abbrev_entry *entry,
+                    const struct dwarf_section *section,
+                    unsigned char *data,
+                    unsigned 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;
+  * is_signed = false;
 
 #define MAX_NESTING 20
   if (nesting > MAX_NESTING)
@@ -2221,28 +2212,31 @@ get_type_signedness (abbrev_entry *         entry,
              if (attr->form == DW_FORM_strp)
                printf (", %s", fetch_indirect_string (uvalue));
              else if (attr->form == DW_FORM_string)
-               printf (", %s", orig_data);
+               printf (", %.*s", (int) (end - orig_data), orig_data);
            }
          break;
 
        case DW_AT_type:
          /* Recurse.  */
          {
-           abbrev_entry *  type_abbrev;
-           unsigned char * type_data;
-           unsigned long   type_cu_offset;
+           abbrev_entry *type_abbrev;
+           unsigned char *type_data;
+           abbrev_map *map;
 
            type_abbrev = get_type_abbrev_from_form (attr->form,
                                                     uvalue,
                                                     cu_offset,
+                                                    end,
                                                     section,
                                                     NULL /* abbrev num return */,
-                                                    & type_data,
-                                                    & type_cu_offset);
+                                                    &type_data,
+                                                    &map);
            if (type_abbrev == NULL)
              break;
 
-           get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset,
+           get_type_signedness (type_abbrev, section, type_data,
+                                map ? section->start + map->end : end,
+                                map ? map->start : cu_offset,
                                 pointer_size, offset_size, dwarf_version,
                                 is_signed, nesting + 1);
          }
@@ -2258,7 +2252,7 @@ get_type_signedness (abbrev_entry *         entry,
            case DW_ATE_unsigned:
            case DW_ATE_unsigned_char:
            case DW_ATE_unsigned_fixed:
-             * is_signed = FALSE;
+             * is_signed = false;
              break;
 
            default:
@@ -2269,7 +2263,7 @@ get_type_signedness (abbrev_entry *         entry,
            case DW_ATE_imaginary_float:
            case DW_ATE_decimal_float:
            case DW_ATE_signed_fixed:
-             * is_signed = TRUE;
+             * is_signed = true;
              break;
            }
          break;
@@ -2278,15 +2272,15 @@ get_type_signedness (abbrev_entry *         entry,
 }
 
 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);
   if (status != 0)
-    report_leb_status (status, __FILE__, __LINE__);
+    report_leb_status (status);
   else
     printf ("%s", dwarf_vmatoa (is_signed ? "d" : "u", val));
 }
@@ -2295,15 +2289,16 @@ static void
 display_discr_list (unsigned long          form,
                    dwarf_vma              uvalue,
                    unsigned char *        data,
-                   unsigned const char *  end,
                    int                    level)
 {
+  unsigned char *end = data;
+
   if (uvalue == 0)
     {
       printf ("[default]");
       return;
     }
-  
+
   switch (form)
     {
     case DW_FORM_block:
@@ -2326,53 +2321,43 @@ display_discr_list (unsigned long          form,
       return;
     }
 
-  bfd_boolean is_signed =
-    (level > 0 && level <= MAX_CU_NESTING)
-    ? level_type_signed [level - 1] : FALSE;
-    
+  bool is_signed = (level > 0 && level <= MAX_CU_NESTING
+                   ? level_type_signed [level - 1] : false);
+
   printf ("(");
-  while (uvalue)
+  while (data < end)
     {
       unsigned char     discriminant;
       unsigned int      bytes_read;
 
-      SAFE_BYTE_GET (discriminant, data, 1, end);
-      -- uvalue;
-      data ++;
+      SAFE_BYTE_GET_AND_INC (discriminant, data, 1, end);
 
-      assert (uvalue > 0);
       switch (discriminant)
        {
        case DW_DSC_label:
          printf ("label ");
          read_and_print_leb128 (data, & bytes_read, end, is_signed);
-         assert (bytes_read <= uvalue && bytes_read > 0);
-         uvalue -= bytes_read;
          data += bytes_read;
          break;
 
        case DW_DSC_range:
          printf ("range ");
          read_and_print_leb128 (data, & bytes_read, end, is_signed);
-         assert (bytes_read <= uvalue && bytes_read > 0);
-         uvalue -= bytes_read;
          data += bytes_read;
 
          printf ("..");
          read_and_print_leb128 (data, & bytes_read, end, is_signed);
-         assert (bytes_read <= uvalue && bytes_read > 0);
-         uvalue -= bytes_read;
          data += bytes_read;
          break;
 
        default:
          printf ("<corrupt>\n");
-         warn (_("corrupt discr_list - unrecognised discriminant byte %#x\n"),
+         warn (_("corrupt discr_list - unrecognized discriminant byte %#x\n"),
                discriminant);
          return;
        }
 
-      if (uvalue)
+      if (data < end)
        printf (", ");
     }
 
@@ -2401,9 +2386,10 @@ read_and_display_attr_value (unsigned long           attribute,
                             int                     level)
 {
   dwarf_signed_vma svalue;
-  dwarf_vma        uvalue = 0;
-  unsigned char *  block_start = NULL;
-  unsigned char *  orig_data = data;
+  dwarf_vma uvalue = 0;
+  dwarf_vma uvalue_hi = 0;
+  unsigned char *block_start = NULL;
+  unsigned char *orig_data = data;
 
   if (data > end || (data == end && form != DW_FORM_flag_present))
     {
@@ -2411,6 +2397,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:
@@ -2429,6 +2426,7 @@ read_and_display_attr_value (unsigned long           attribute,
       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:
@@ -2444,28 +2442,60 @@ 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;
 
+    case DW_FORM_ref_sup8:
+    case DW_FORM_ref8:
+    case DW_FORM_data8:
+    case DW_FORM_ref_sig8:
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 8, end);
+      break;
+
+    case DW_FORM_data16:
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 8, end);
+      SAFE_BYTE_GET_AND_INC (uvalue_hi, data, 8, end);
+      if (byte_get != byte_get_little_endian)
+       {
+         dwarf_vma utmp = uvalue;
+         uvalue = uvalue_hi;
+         uvalue_hi = utmp;
+       }
+      break;
+
     case DW_FORM_sdata:
       READ_SLEB (svalue, data, end);
       uvalue = svalue;
       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;
 
@@ -2481,6 +2511,10 @@ read_and_display_attr_value (unsigned long           attribute,
                                          offset_size, dwarf_version,
                                          debug_info_p, do_loc,
                                          section, this_set, delimiter, level);
+
+    case DW_FORM_implicit_const:
+      uvalue = implicit_const;
+      break;
     }
 
   switch (form)
@@ -2492,13 +2526,20 @@ read_and_display_attr_value (unsigned long           attribute,
 
     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));
@@ -2526,64 +2567,31 @@ 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)
        {
-         dwarf_vma high_bits;
-         dwarf_vma utmp;
-         char buf[64];
-
-         SAFE_BYTE_GET64 (data, &high_bits, &uvalue, end);
-         utmp = uvalue;
+         dwarf_vma utmp = uvalue;
          if (form == DW_FORM_ref8)
-           add64 (& high_bits, & utmp, cu_offset);
-         printf ("%c0x%s", delimiter,
-                 dwarf_vmatoa64 (high_bits, utmp, buf, sizeof (buf)));
+           utmp += cu_offset;
+         printf ("%c0x%s", delimiter, dwarf_vmatoa ("x", utmp));
        }
-
-      if ((do_loc || do_debug_loc || do_debug_ranges)
-         && num_debug_info_entries == 0)
-       {
-         if (sizeof (uvalue) == 8)
-           SAFE_BYTE_GET (uvalue, data, 8, end);
-         else
-           error (_("DW_FORM_data8 is unsupported when sizeof (dwarf_vma) != 8\n"));
-       }
-
-      data += 8;
       break;
 
     case DW_FORM_data16:
       if (!do_loc)
-       {
-         dwarf_vma left_high_bits, left_low_bits;
-         dwarf_vma right_high_bits, right_low_bits;
-
-         SAFE_BYTE_GET64 (data, &left_high_bits, &left_low_bits, end);
-         SAFE_BYTE_GET64 (data + 8, &right_high_bits, &right_low_bits, end);
-         if (byte_get == byte_get_little_endian)
-           {
-             /* Swap them.  */
-             left_high_bits ^= right_high_bits;
-             right_high_bits ^= left_high_bits;
-             left_high_bits ^= right_high_bits;
-             left_low_bits ^= right_low_bits;
-             right_low_bits ^= left_low_bits;
-             left_low_bits ^= right_low_bits;
-           }
-         printf (" 0x%08" DWARF_VMA_FMT "x%08" DWARF_VMA_FMT "x"
-                 "%08" DWARF_VMA_FMT "x%08" DWARF_VMA_FMT "x",
-                 left_high_bits, left_low_bits, right_high_bits,
-                 right_low_bits);
-       }
-      data += 16;
+       printf (" 0x%s%s",
+               uvalue_hi == 0 ? "" : dwarf_vmatoa ("x", uvalue_hi),
+               dwarf_vmatoa_1 ("x", uvalue, uvalue_hi == 0 ? 0 : 8));
       break;
 
     case DW_FORM_string:
       if (!do_loc)
        printf ("%c%.*s", delimiter, (int) (end - data), data);
-      data += strnlen ((char *) data, end - data) + 1;
+      data += strnlen ((char *) data, end - data);
+      if (data < end)
+       data++;
       break;
 
     case DW_FORM_block:
@@ -2620,36 +2628,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;
 
@@ -2658,27 +2699,52 @@ read_and_display_attr_value (unsigned long           attribute,
       break;
 
     case DW_FORM_ref_sig8:
+      if (!do_loc)
+       printf ("%c%s: 0x%s", delimiter, do_wide ? "" : "signature",
+               dwarf_vmatoa ("x", uvalue));
+      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)
        {
-         dwarf_vma high_bits;
-         char buf[64];
+         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;
 
-         SAFE_BYTE_GET64 (data, &high_bits, &uvalue, end);
-         printf ("%csignature: 0x%s", delimiter,
-                 dwarf_vmatoa64 (high_bits, uvalue, buf, sizeof (buf)));
+         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));
        }
-      data += 8;
       break;
 
-    case DW_FORM_GNU_addr_index:
+    case DW_FORM_strp_sup:
       if (!do_loc)
-       printf (_("%c(addr_index: 0x%s): %s"), delimiter,
-               dwarf_vmatoa ("x", uvalue),
-               fetch_indexed_value (uvalue * pointer_size, pointer_size));
+       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);
+      /* What to do?  Consume a byte maybe?  */
+      ++data;
       break;
     }
 
@@ -2767,6 +2833,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;
 
@@ -2802,16 +2869,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"),
@@ -2819,26 +2891,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"),
@@ -2846,14 +2923,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"),
@@ -2861,7 +2938,7 @@ read_and_display_attr_value (unsigned long           attribute,
                break;
              }
          break;
-             
+
        default:
          break;
        }
@@ -2877,23 +2954,27 @@ 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;
-         abbrev_entry *  type_abbrev;
-         unsigned char * type_data;
-         unsigned long   type_cu_offset;
-         
-         type_abbrev = get_type_abbrev_from_form (form, uvalue, cu_offset,
-                                                  section, NULL, & type_data, & type_cu_offset);
+         bool is_signed = false;
+         abbrev_entry *type_abbrev;
+         unsigned char *type_data;
+         abbrev_map *map;
+
+         type_abbrev = get_type_abbrev_from_form (form, uvalue,
+                                                  cu_offset, end,
+                                                  section, NULL,
+                                                  &type_data, &map);
          if (type_abbrev != NULL)
            {
-             get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset,
+             get_type_signedness (type_abbrev, section, type_data,
+                                  map ? section->start + map->end : end,
+                                  map ? map->start : 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)
@@ -3143,9 +3224,9 @@ read_and_display_attr_value (unsigned long           attribute,
 
     case DW_AT_discr_list:
       printf ("\t");
-      display_discr_list (form, uvalue, data, end, level);
+      display_discr_list (form, uvalue, data, level);
       break;
-      
+
     case DW_AT_frame_base:
       have_frame_base = 1;
       /* Fall through.  */
@@ -3214,7 +3295,7 @@ read_and_display_attr_value (unsigned long           attribute,
        unsigned long abbrev_number;
        abbrev_entry *entry;
 
-       entry = get_type_abbrev_from_form (form, uvalue, cu_offset,
+       entry = get_type_abbrev_from_form (form, uvalue, cu_offset, end,
                                           section, & abbrev_number, NULL, NULL);
        if (entry == NULL)
          {
@@ -3272,7 +3353,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)
 {
@@ -3291,7 +3372,7 @@ load_debug_section_with_follow (enum dwarf_section_display_enum sec_enum,
              }
        }
 
-      return TRUE;
+      return true;
     }
 
   if (do_follow_links)
@@ -3306,16 +3387,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)
     {
@@ -3334,7 +3415,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.
@@ -3345,12 +3426,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;
@@ -3358,51 +3439,51 @@ process_debug_info (struct dwarf_section *           section,
   unsigned int unit;
   unsigned int num_units = 0;
 
-  if ((do_loc || do_debug_loc || do_debug_ranges)
-      && num_debug_info_entries == 0
-      && ! do_types)
+  /* First scan the section to get the number of comp units.
+     Length sanity checks are done here.  */
+  for (section_begin = start, num_units = 0; section_begin < end;
+       num_units ++)
     {
       dwarf_vma length;
 
-      /* First scan the section to get the number of comp units.  */
-      for (section_begin = start, num_units = 0; section_begin < end;
-          num_units ++)
-       {
-         /* Read the first 4 bytes.  For a 32-bit DWARF section, this
-            will be the length.  For a 64-bit DWARF section, it'll be
-            the escape code 0xffffffff followed by an 8 byte length.  */
-         SAFE_BYTE_GET (length, section_begin, 4, end);
-
-         if (length == 0xffffffff)
-           {
-             SAFE_BYTE_GET (length, section_begin + 4, 8, end);
-             section_begin += length + 12;
-           }
-         else if (length >= 0xfffffff0 && length < 0xffffffff)
-           {
-             warn (_("Reserved length value (0x%s) found in section %s\n"),
-                   dwarf_vmatoa ("x", length), section->name);
-             return FALSE;
-           }
-         else
-           section_begin += length + 4;
+      /* Read the first 4 bytes.  For a 32-bit DWARF section, this
+        will be the length.  For a 64-bit DWARF section, it'll be
+        the escape code 0xffffffff followed by an 8 byte length.  */
+      SAFE_BYTE_GET_AND_INC (length, section_begin, 4, end);
 
-         /* Negative values are illegal, they may even cause infinite
-            looping.  This can happen if we can't accurately apply
-            relocations to an object file, or if the file is corrupt.  */
-         if ((signed long) length <= 0 || section_begin < start)
-           {
-             warn (_("Corrupt unit length (0x%s) found in section %s\n"),
-                   dwarf_vmatoa ("x", length), section->name);
-             return FALSE;
-           }
+      if (length == 0xffffffff)
+       SAFE_BYTE_GET_AND_INC (length, section_begin, 8, end);
+      else if (length >= 0xfffffff0 && length < 0xffffffff)
+       {
+         warn (_("Reserved length value (0x%s) found in section %s\n"),
+               dwarf_vmatoa ("x", length), section->name);
+         return false;
        }
 
-      if (num_units == 0)
+      /* Negative values are illegal, they may even cause infinite
+        looping.  This can happen if we can't accurately apply
+        relocations to an object file, or if the file is corrupt.  */
+      if (length > (size_t) (end - section_begin))
        {
-         error (_("No comp units in %s section ?\n"), section->name);
-         return FALSE;
+         warn (_("Corrupt unit length (got 0x%s expected at most 0x%s) in section %s\n"),
+               dwarf_vmatoa ("x", length),
+               dwarf_vmatoa ("x", end - section_begin),
+               section->name);
+         return false;
        }
+      section_begin += length;
+    }
+
+  if (num_units == 0)
+    {
+      error (_("No comp units in %s section ?\n"), section->name);
+      return false;
+    }
+
+  if ((do_loc || do_debug_loc || do_debug_ranges)
+      && num_debug_info_entries == 0
+      && ! do_types)
+    {
 
       /* Then allocate an array to hold the information.  */
       debug_information = (debug_info *) cmalloc (num_units,
@@ -3412,7 +3493,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.
@@ -3434,23 +3515,23 @@ 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);
+    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
@@ -3463,11 +3544,12 @@ process_debug_info (struct dwarf_section *           section,
       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;
+      unsigned char *end_cu;
 
       hdrptr = start;
+      cu_offset = start - section_begin;
 
       SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 4, end);
 
@@ -3475,17 +3557,12 @@ process_debug_info (struct dwarf_section *           section,
        {
          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);
+       offset_size = 4;
+      end_cu = hdrptr + compunit.cu_length;
 
-      cu_offset = start - section_begin;
+      SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end_cu);
 
       this_set = find_cu_tu_set_v2 (cu_offset, do_types);
 
@@ -3497,13 +3574,21 @@ process_debug_info (struct dwarf_section *           section,
        }
       else
        {
-         SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end);
+         SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end_cu);
          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_pointer_size, hdrptr, 1, end_cu);
        }
 
-      SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end);
+      SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size,
+                            end_cu);
+
+      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_cu);
+       }
 
       if (this_set == NULL)
        {
@@ -3524,17 +3609,13 @@ process_debug_info (struct dwarf_section *           section,
 
          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);
+         next = process_abbrev_set (&debug_displays[abbrev_sec].section,
+                                    abbrev_base, abbrev_size,
+                                    compunit.cu_abbrev_offset, list);
          list->start_of_next_abbrevs = next;
        }
-                      
-      start = section_begin + cu_offset + compunit.cu_length
-       + initial_length_size;
+
+      start = end_cu;
       record_abbrev_list_for_cu (cu_offset, start - section_begin, list);
     }
 
@@ -3545,18 +3626,17 @@ process_debug_info (struct dwarf_section *           section,
       unsigned char *tags;
       int level, last_level, saved_level;
       dwarf_vma cu_offset;
-      unsigned long sec_off;
       unsigned int offset_size;
-      unsigned int initial_length_size;
-      dwarf_vma signature_high = 0;
-      dwarf_vma signature_low = 0;
+      dwarf_vma signature = 0;
       dwarf_vma type_offset = 0;
       struct cu_tu_set *this_set;
       dwarf_vma abbrev_base;
       size_t abbrev_size;
       abbrev_list * list = NULL;
+      unsigned char *end_cu;
 
       hdrptr = start;
+      cu_offset = start - section_begin;
 
       SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 4, end);
 
@@ -3564,17 +3644,12 @@ process_debug_info (struct dwarf_section *           section,
        {
          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;
-       }
+       offset_size = 4;
+      end_cu = hdrptr + compunit.cu_length;
 
-      SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end);
-
-      cu_offset = start - section_begin;
+      SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end_cu);
 
       this_set = find_cu_tu_set_v2 (cu_offset, do_types);
 
@@ -3586,13 +3661,13 @@ process_debug_info (struct dwarf_section *           section,
        }
       else
        {
-         SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end);
+         SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end_cu);
          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_pointer_size, hdrptr, 1, end_cu);
        }
 
-      SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end);
+      SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end_cu);
 
       if (this_set == NULL)
        {
@@ -3606,7 +3681,16 @@ process_debug_info (struct dwarf_section *           section,
        }
 
       if (compunit.cu_version < 5)
-       SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end);
+       SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end_cu);
+
+      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_cu);
+         do_dwo_id = true;
+       }
 
       /* PR 17512: file: 001-108546-0.001:0.1.  */
       if (compunit.cu_pointer_size < 2 || compunit.cu_pointer_size > 8)
@@ -3618,16 +3702,13 @@ process_debug_info (struct dwarf_section *           section,
 
       if (do_types)
        {
-         SAFE_BYTE_GET64 (hdrptr, &signature_high, &signature_low, end);
-         hdrptr += 8;
-         SAFE_BYTE_GET_AND_INC (type_offset, hdrptr, offset_size, end);
+         SAFE_BYTE_GET_AND_INC (signature, hdrptr, 8, end_cu);
+         SAFE_BYTE_GET_AND_INC (type_offset, hdrptr, offset_size, end_cu);
        }
 
-      if (dwarf_start_die > (cu_offset + compunit.cu_length
-                            + initial_length_size))
+      if (dwarf_start_die >= (size_t) (end_cu - section_begin))
        {
-         start = section_begin + cu_offset + compunit.cu_length
-           + initial_length_size;
+         start = end_cu;
          continue;
        }
 
@@ -3662,22 +3743,25 @@ process_debug_info (struct dwarf_section *           section,
                  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);
+           {
+             const char *name = get_DW_UT_name (compunit.cu_unit_type);
+
+             printf (_("   Unit Type:     %s (%x)\n"),
+                     name ? name : "???",
+                     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);
          if (do_types)
            {
-             char buf[64];
-
              printf (_("   Signature:     0x%s\n"),
-                     dwarf_vmatoa64 (signature_high, signature_low,
-                                     buf, sizeof (buf)));
+                     dwarf_vmatoa ("x", signature));
              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;
@@ -3699,20 +3783,8 @@ process_debug_info (struct dwarf_section *           section,
            }
        }
 
-      sec_off = cu_offset + initial_length_size;
-      if (sec_off + compunit.cu_length < sec_off
-         || sec_off + compunit.cu_length > section->size)
-       {
-         warn (_("Debug info is corrupted, %s header at %#lx has length %s\n"),
-               section->name,
-               (unsigned long) cu_offset,
-               dwarf_vmatoa ("x", compunit.cu_length));
-         num_units = unit;
-         break;
-       }
-
       tags = hdrptr;
-      start += compunit.cu_length + initial_length_size;
+      start = end_cu;
 
       if (compunit.cu_version < 2 || compunit.cu_version > 5)
        {
@@ -3724,7 +3796,9 @@ process_debug_info (struct dwarf_section *           section,
 
       if (compunit.cu_unit_type != DW_UT_compile
          && compunit.cu_unit_type != DW_UT_partial
-         && compunit.cu_unit_type != DW_UT_type)
+         && 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"),
@@ -3733,34 +3807,18 @@ process_debug_info (struct dwarf_section *           section,
        }
 
       /* 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"),
-             (unsigned long) compunit.cu_abbrev_offset,
-             (unsigned long) abbrev_size);
-      /* PR 17531: file:4bcd9ce9.  */
-      else if ((abbrev_base + abbrev_size)
-              > debug_displays [abbrev_sec].section.size)
-       warn (_("Debug info is corrupted, abbrev size (%lx) is larger than abbrev section size (%lx)\n"),
-             (unsigned long) abbrev_base + abbrev_size,
-             (unsigned long) debug_displays [abbrev_sec].section.size);
-      else
+      list = find_abbrev_list_by_abbrev_offset (abbrev_base,
+                                               compunit.cu_abbrev_offset);
+      if (list == NULL)
        {
-         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;
-           }
+         unsigned char *next;
+
+         list = new_abbrev_list (abbrev_base,
+                                 compunit.cu_abbrev_offset);
+         next = process_abbrev_set (&debug_displays[abbrev_sec].section,
+                                    abbrev_base, abbrev_size,
+                                    compunit.cu_abbrev_offset, list);
+         list->start_of_next_abbrevs = next;
        }
 
       level = 0;
@@ -3815,7 +3873,7 @@ process_debug_info (struct dwarf_section *           section,
                    }
                }
              if (dwarf_start_die != 0 && level < saved_level)
-               return TRUE;
+               return true;
              continue;
            }
 
@@ -3857,7 +3915,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)
@@ -3900,7 +3958,7 @@ process_debug_info (struct dwarf_section *           section,
                                            attr->implicit_const,
                                            section_begin,
                                            tags,
-                                           end,
+                                           start,
                                            cu_offset,
                                            compunit.cu_pointer_size,
                                            offset_size,
@@ -3957,7 +4015,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
@@ -3982,12 +4040,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;
@@ -4007,7 +4065,6 @@ read_debug_line_header (struct dwarf_section * section,
                        unsigned char ** end_of_sequence)
 {
   unsigned char *hdrptr;
-  unsigned int initial_length_size;
 
   /* Extract information from the Line Number Program Header.
      (section 6.2.4 in the Dwarf3 doc).  */
@@ -4021,15 +4078,11 @@ read_debug_line_header (struct dwarf_section * section,
       /* This section is 64-bit DWARF 3.  */
       SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 8, end);
       linfo->li_offset_size = 8;
-      initial_length_size = 12;
     }
   else
-    {
-      linfo->li_offset_size = 4;
-      initial_length_size = 4;
-    }
+    linfo->li_offset_size = 4;
 
-  if (linfo->li_length + initial_length_size > section->size)
+  if (linfo->li_length > (size_t) (end - hdrptr))
     {
       /* If the length field has a relocation against it, then we should
         not complain if it is inaccurate (and probably negative).  This
@@ -4039,7 +4092,7 @@ read_debug_line_header (struct dwarf_section * section,
         is used to compute the correct length once that is done.  */
       if (reloc_at (section, (hdrptr - section->start) - linfo->li_offset_size))
        {
-         linfo->li_length = (end - data) - initial_length_size;
+         linfo->li_length = end - hdrptr;
        }
       else
        {
@@ -4048,6 +4101,7 @@ read_debug_line_header (struct dwarf_section * section,
          return NULL;
        }
     }
+  end = hdrptr + linfo->li_length;
 
   /* Get and check the version number.  */
   SAFE_BYTE_GET_AND_INC (linfo->li_version, hdrptr, 2, end);
@@ -4098,32 +4152,23 @@ read_debug_line_header (struct dwarf_section * section,
   SAFE_BYTE_GET_AND_INC (linfo->li_line_range, hdrptr, 1, end);
   SAFE_BYTE_GET_AND_INC (linfo->li_opcode_base, hdrptr, 1, end);
 
-  * end_of_sequence = data + linfo->li_length + initial_length_size;
-  /* PR 17512: file:002-117414-0.004.  */
-  if (* end_of_sequence > end)
-    {
-      warn (_("Line length %s extends beyond end of section\n"),
-           dwarf_vmatoa ("u", linfo->li_length));
-      * end_of_sequence = end;
-      return NULL;
-    }
-
+  *end_of_sequence = end;
   return hdrptr;
 }
 
 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"),
@@ -4134,7 +4179,7 @@ display_formatted_table (unsigned char *                   data,
     {
       SKIP_ULEB (data, end);
       SKIP_ULEB (data, end);
-      if (data == end)
+      if (data >= end)
        {
          warn (_("%s: Corrupt format description entry\n"), table_name);
          return data;
@@ -4147,7 +4192,7 @@ display_formatted_table (unsigned char *                   data,
       printf (_("\n The %s is empty.\n"), table_name);
       return data;
     }
-  else if (data == end)
+  else if (data >= end)
     {
       warn (_("%s: Corrupt entry count - expected %s but none found\n"),
            table_name, dwarf_vmatoa ("x", data_count));
@@ -4166,7 +4211,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;
@@ -4207,7 +4252,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;
@@ -4226,14 +4271,89 @@ display_formatted_table (unsigned char *                   data,
            }
        }
 
-      if (data == end && (datai < data_count - 1))
+      if (data >= end && (datai < data_count - 1))
        {
          warn (_("\n%s: Corrupt entries list\n"), table_name);
          return data;
        }
       putchar ('\n');
     }
-  return 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
@@ -4245,7 +4365,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)
     {
@@ -4255,7 +4375,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)
@@ -4341,9 +4461,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
            {
@@ -4360,7 +4480,9 @@ display_debug_lines_raw (struct dwarf_section *  section,
                    {
                      printf ("  %d\t%.*s\n", ++last_dir_entry, (int) (end - data), data);
 
-                     data += strnlen ((char *) data, end - data) + 1;
+                     data += strnlen ((char *) data, end - data);
+                     if (data < end)
+                       data++;
                    }
 
                  /* PR 17512: file: 002-132094-0.004.  */
@@ -4369,10 +4491,11 @@ display_debug_lines_raw (struct dwarf_section *  section,
                }
 
              /* Skip the NUL at the end of the table.  */
-             data++;
+             if (data < end)
+               data++;
 
              /* Display the contents of the File Name table.  */
-             if (*data == 0)
+             if (data >= end || *data == 0)
                printf (_("\n The File Name Table is empty.\n"));
              else
                {
@@ -4387,7 +4510,9 @@ display_debug_lines_raw (struct dwarf_section *  section,
 
                      printf ("  %d\t", ++state_machine_regs.last_file_entry);
                      name = data;
-                     data += strnlen ((char *) data, end - data) + 1;
+                     data += strnlen ((char *) data, end - data);
+                     if (data < end)
+                       data++;
 
                      READ_ULEB (val, data, end);
                      printf ("%s\t", dwarf_vmatoa ("u", val));
@@ -4397,7 +4522,7 @@ display_debug_lines_raw (struct dwarf_section *  section,
                      printf ("%s\t", dwarf_vmatoa ("u", val));
                      printf ("%.*s\n", (int)(end - name), name);
 
-                     if (data == end)
+                     if (data >= end)
                        {
                          warn (_("Corrupt file name table entry\n"));
                          break;
@@ -4406,7 +4531,8 @@ display_debug_lines_raw (struct dwarf_section *  section,
                }
 
              /* Skip the NUL at the end of the table.  */
-             data++;
+             if (data < end)
+               data++;
            }
 
          putchar ('\n');
@@ -4665,7 +4791,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
 {
   static DWARF2_Internal_LineInfo saved_linfo;
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   while (data < end)
     {
@@ -4679,7 +4805,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)
@@ -4745,7 +4871,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                }
 
              READ_ULEB (n_directories, data, end);
-             if (data == end)
+             if (data >= end)
                {
                  warn (_("Corrupt directories list\n"));
                  break;
@@ -4769,7 +4895,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
 
                      READ_ULEB (content_type, format, end);
                      READ_ULEB (form, format, end);
-                     if (data == end)
+                     if (data >= end)
                        {
                          warn (_("Corrupt directories list\n"));
                          break;
@@ -4799,7 +4925,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                                                          NULL, 1, section,
                                                          NULL, '\t', -1);
                    }
-                 if (data == end)
+                 if (data >= end)
                    {
                      warn (_("Corrupt directories list\n"));
                      break;
@@ -4819,7 +4945,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                }
 
              READ_ULEB (n_files, data, end);
-             if (data == end && n_files > 0)
+             if (data >= end && n_files > 0)
                {
                  warn (_("Corrupt file name list\n"));
                  break;
@@ -4844,7 +4970,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
 
                      READ_ULEB (content_type, format, end);
                      READ_ULEB (form, format, end);
-                     if (data == end)
+                     if (data >= end)
                        {
                          warn (_("Corrupt file name list\n"));
                          break;
@@ -4891,7 +5017,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                                                          NULL, 1, section,
                                                          NULL, '\t', -1);
                    }
-                 if (data == end)
+                 if (data >= end)
                    {
                      warn (_("Corrupt file name list\n"));
                      break;
@@ -4906,7 +5032,9 @@ display_debug_lines_decoded (struct dwarf_section *  section,
 
                  while (data < end && *data != 0)
                    {
-                     data += strnlen ((char *) data, end - data) + 1;
+                     data += strnlen ((char *) data, end - data);
+                     if (data < end)
+                       data++;
                      n_directories++;
                    }
 
@@ -4926,8 +5054,8 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                  while (*ptr_directory_table != 0)
                    {
                      directory_table[i] = ptr_directory_table;
-                     ptr_directory_table += strnlen ((char *) ptr_directory_table,
-                                                     ptr_directory_table - end) + 1;
+                     ptr_directory_table
+                       += strlen ((char *) ptr_directory_table) + 1;
                      i++;
                    }
                }
@@ -4943,7 +5071,9 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                    {
                      /* Skip Name, directory index, last modification
                         time and length of file.  */
-                     data += strnlen ((char *) data, end - data) + 1;
+                     data += strnlen ((char *) data, end - data);
+                     if (data < end)
+                       data++;
                      SKIP_ULEB (data, end);
                      SKIP_ULEB (data, end);
                      SKIP_ULEB (data, end);
@@ -4964,8 +5094,8 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                  while (*ptr_file_name_table != 0)
                    {
                      file_table[i].name = ptr_file_name_table;
-                     ptr_file_name_table += strnlen ((char *) ptr_file_name_table,
-                                                     end - ptr_file_name_table) + 1;
+                     ptr_file_name_table
+                       += strlen ((char *) ptr_file_name_table) + 1;
 
                      /* We are not interested in directory, time or size.  */
                      READ_ULEB (file_table[i].directory_index,
@@ -5169,15 +5299,17 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                state_machine_regs.file = uladv;
 
                {
-                 unsigned file = state_machine_regs.file - 1;
+                 unsigned file = state_machine_regs.file;
                  unsigned dir;
 
+                 if (linfo.li_version < 5)
+                   --file;
                  if (file_table == NULL || n_files == 0)
                    printf (_("\n [Use file table entry %d]\n"), file);
                  /* PR 20439 */
                  else if (file >= n_files)
                    {
-                     warn (_("file index %u > number of files %u\n"), file + 1, n_files);
+                     warn (_("file index %u > number of files %u\n"), file, n_files);
                      printf (_("\n <over large file table index %u>"), file);
                    }
                  else if ((dir = file_table[file].directory_index) == 0)
@@ -5286,7 +5418,10 @@ display_debug_lines_decoded (struct dwarf_section *  section,
 
              if (file_table)
                {
-                 unsigned indx = state_machine_regs.file - 1;
+                 unsigned indx = state_machine_regs.file;
+
+                 if (linfo.li_version < 5)
+                   --indx;
                  /* PR 20439  */
                  if (indx >= n_files)
                    {
@@ -5300,31 +5435,22 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                fileName = _("<unknown>");
 
              fileNameLength = strlen (fileName);
-
-             if ((fileNameLength > MAX_FILENAME_LENGTH) && (!do_wide))
+             newFileName = fileName;
+             if (fileNameLength > MAX_FILENAME_LENGTH && !do_wide)
                {
                  newFileName = (char *) xmalloc (MAX_FILENAME_LENGTH + 1);
                  /* Truncate file name */
-                 strncpy (newFileName,
-                          fileName + fileNameLength - MAX_FILENAME_LENGTH,
-                          MAX_FILENAME_LENGTH + 1);
-                 /* FIXME: This is to pacify gcc-10 which can warn that the
-                    strncpy above might leave a non-NUL terminated string
-                    in newFileName.  It won't, but gcc's analysis doesn't
-                    quite go far enough to discover this.  */
+                 memcpy (newFileName,
+                         fileName + fileNameLength - MAX_FILENAME_LENGTH,
+                         MAX_FILENAME_LENGTH);
                  newFileName[MAX_FILENAME_LENGTH] = 0;
                }
-             else
-               {
-                 newFileName = (char *) xmalloc (fileNameLength + 1);
-                 strncpy (newFileName, fileName, fileNameLength + 1);
-               }
 
              /* A row with end_seq set to true has a meaningful address, but
                 the other information in the same row is not significant.
                 In such a row, print line as "-", and don't print
                 view/is_stmt.  */
-             if (!do_wide || (fileNameLength <= MAX_FILENAME_LENGTH))
+             if (!do_wide || fileNameLength <= MAX_FILENAME_LENGTH)
                {
                  if (linfo.li_max_ops_per_insn == 1)
                    {
@@ -5399,7 +5525,8 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                  putchar ('\n');
                }
 
-             free (newFileName);
+             if (newFileName != fileName)
+               free (newFileName);
            }
        }
 
@@ -5447,7 +5574,7 @@ display_debug_lines (struct dwarf_section *section, void *file)
 }
 
 static debug_info *
-find_debug_info_for_offset (unsigned long offset)
+find_debug_info_for_offset (dwarf_vma offset)
 {
   unsigned int i;
 
@@ -5493,34 +5620,28 @@ 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)
     {
       unsigned char *data;
-      unsigned long sec_off;
-      unsigned int offset_size, initial_length_size;
+      unsigned long sec_off = start - section->start;
+      unsigned int offset_size;
 
       SAFE_BYTE_GET_AND_INC (names.pn_length, start, 4, end);
       if (names.pn_length == 0xffffffff)
        {
          SAFE_BYTE_GET_AND_INC (names.pn_length, start, 8, end);
          offset_size = 8;
-         initial_length_size = 12;
        }
       else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
+       offset_size = 4;
 
-      sec_off = start - section->start;
-      if (sec_off + names.pn_length < sec_off
-         || sec_off + names.pn_length > section->size)
+      if (names.pn_length > (size_t) (end - start))
        {
          warn (_("Debug info is corrupted, %s header at %#lx has length %s\n"),
                section->name,
-               sec_off - initial_length_size,
+               sec_off,
                dwarf_vmatoa ("x", names.pn_length));
          break;
        }
@@ -5528,8 +5649,8 @@ display_debug_pubnames_worker (struct dwarf_section *section,
       data = start;
       start += names.pn_length;
 
-      SAFE_BYTE_GET_AND_INC (names.pn_version, data, 2, end);
-      SAFE_BYTE_GET_AND_INC (names.pn_offset, data, offset_size, end);
+      SAFE_BYTE_GET_AND_INC (names.pn_version, data, 2, start);
+      SAFE_BYTE_GET_AND_INC (names.pn_offset, data, offset_size, start);
 
       if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE
          && num_debug_info_entries > 0
@@ -5537,7 +5658,7 @@ display_debug_pubnames_worker (struct dwarf_section *section,
        warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"),
              (unsigned long) names.pn_offset, section->name);
 
-      SAFE_BYTE_GET_AND_INC (names.pn_size, data, offset_size, end);
+      SAFE_BYTE_GET_AND_INC (names.pn_size, data, offset_size, start);
 
       printf (_("  Length:                              %ld\n"),
              (long) names.pn_length);
@@ -5571,15 +5692,14 @@ display_debug_pubnames_worker (struct dwarf_section *section,
          bfd_size_type maxprint;
          dwarf_vma offset;
 
-         SAFE_BYTE_GET (offset, data, offset_size, end);
+         SAFE_BYTE_GET_AND_INC (offset, data, offset_size, start);
 
          if (offset == 0)
            break;
 
-         data += offset_size;
-         if (data >= end)
+         if (data >= start)
            break;
-         maxprint = (end - data) - 1;
+         maxprint = (start - data) - 1;
 
          if (is_gnu)
            {
@@ -5588,8 +5708,7 @@ display_debug_pubnames_worker (struct dwarf_section *section,
              const char *kind_name;
              int is_static;
 
-             SAFE_BYTE_GET (kind_data, data, 1, end);
-             data++;
+             SAFE_BYTE_GET_AND_INC (kind_data, data, 1, start);
              maxprint --;
              /* GCC computes the kind as the upper byte in the CU index
                 word, and then right shifts it by the CU index size.
@@ -5607,8 +5726,10 @@ display_debug_pubnames_worker (struct dwarf_section *section,
            printf ("    %-6lx\t%.*s\n",
                    (unsigned long) offset, (int) maxprint, data);
 
-         data += strnlen ((char *) data, maxprint) + 1;
-         if (data >= end)
+         data += strnlen ((char *) data, maxprint);
+         if (data < start)
+           data++;
+         if (data >= start)
            break;
        }
     }
@@ -5638,7 +5759,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)
     {
@@ -5668,17 +5789,21 @@ display_debug_macinfo (struct dwarf_section *section,
        case DW_MACINFO_define:
          READ_ULEB (lineno, curr, end);
          string = curr;
-         curr += strnlen ((char *) string, end - string) + 1;
-         printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"),
-                 lineno, string);
+         curr += strnlen ((char *) string, end - string);
+         printf (_(" DW_MACINFO_define - lineno : %d macro : %*s\n"),
+                 lineno, (int) (curr - string), string);
+         if (curr < end)
+           curr++;
          break;
 
        case DW_MACINFO_undef:
          READ_ULEB (lineno, curr, end);
          string = curr;
-         curr += strnlen ((char *) string, end - string) + 1;
-         printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"),
-                 lineno, string);
+         curr += strnlen ((char *) string, end - string);
+         printf (_(" DW_MACINFO_undef - lineno : %d macro : %*s\n"),
+                 lineno, (int) (curr - string), string);
+         if (curr < end)
+           curr++;
          break;
 
        case DW_MACINFO_vendor_ext:
@@ -5687,9 +5812,11 @@ display_debug_macinfo (struct dwarf_section *section,
 
            READ_ULEB (constant, curr, end);
            string = curr;
-           curr += strnlen ((char *) string, end - string) + 1;
-           printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"),
-                   constant, string);
+           curr += strnlen ((char *) string, end - string);
+           printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %*s\n"),
+                   constant, (int) (curr - string), string);
+           if (curr < end)
+             curr++;
          }
          break;
        }
@@ -5709,7 +5836,7 @@ get_line_filename_and_dirname (dwarf_vma line_offset,
 {
   struct dwarf_section *section = &debug_displays [line].section;
   unsigned char *hdrptr, *dirtable, *file_name;
-  unsigned int offset_size, initial_length_size;
+  unsigned int offset_size;
   unsigned int version, opcode_base;
   dwarf_vma length, diridx;
   const unsigned char * end;
@@ -5729,16 +5856,14 @@ get_line_filename_and_dirname (dwarf_vma line_offset,
       /* This section is 64-bit DWARF 3.  */
       SAFE_BYTE_GET_AND_INC (length, hdrptr, 8, end);
       offset_size = 8;
-      initial_length_size = 12;
     }
   else
-    {
-      offset_size = 4;
-      initial_length_size = 4;
-    }
-  if (length + initial_length_size < length
-      || length + initial_length_size > section->size)
+    offset_size = 4;
+
+  if (length > (size_t) (end - hdrptr)
+      || length < 2 + offset_size + 1 + 3 + 1)
     return NULL;
+  end = hdrptr + length;
 
   SAFE_BYTE_GET_AND_INC (version, hdrptr, 2, end);
   if (version != 2 && version != 3 && version != 4)
@@ -5749,18 +5874,19 @@ get_line_filename_and_dirname (dwarf_vma line_offset,
   hdrptr += 3;             /* Skip default_is_stmt, line_base, line_range.  */
 
   SAFE_BYTE_GET_AND_INC (opcode_base, hdrptr, 1, end);
-  if (opcode_base == 0)
+  if (opcode_base == 0
+      || opcode_base - 1 >= (size_t) (end - hdrptr))
     return NULL;
 
   hdrptr += opcode_base - 1;
-  if (hdrptr >= end)
-    return NULL;
 
   dirtable = hdrptr;
   /* Skip over dirname table.  */
   while (*hdrptr != '\0')
     {
-      hdrptr += strnlen ((char *) hdrptr, end - hdrptr) + 1;
+      hdrptr += strnlen ((char *) hdrptr, end - hdrptr);
+      if (hdrptr < end)
+       hdrptr++;
       if (hdrptr >= end)
        return NULL;
     }
@@ -5769,7 +5895,9 @@ get_line_filename_and_dirname (dwarf_vma line_offset,
   /* Now skip over preceding filename table entries.  */
   for (; hdrptr < end && *hdrptr != '\0' && fileidx > 1; fileidx--)
     {
-      hdrptr += strnlen ((char *) hdrptr, end - hdrptr) + 1;
+      hdrptr += strnlen ((char *) hdrptr, end - hdrptr);
+      if (hdrptr < end)
+       hdrptr++;
       SKIP_ULEB (hdrptr, end);
       SKIP_ULEB (hdrptr, end);
       SKIP_ULEB (hdrptr, end);
@@ -5778,14 +5906,20 @@ get_line_filename_and_dirname (dwarf_vma line_offset,
     return NULL;
 
   file_name = hdrptr;
-  hdrptr += strnlen ((char *) hdrptr, end - hdrptr) + 1;
+  hdrptr += strnlen ((char *) hdrptr, end - hdrptr);
+  if (hdrptr < end)
+    hdrptr++;
   if (hdrptr >= end)
     return NULL;
   READ_ULEB (diridx, hdrptr, end);
   if (diridx == 0)
     return file_name;
   for (; dirtable < end && *dirtable != '\0' && diridx > 1; diridx--)
-    dirtable += strnlen ((char *) dirtable, end - dirtable) + 1;
+    {
+      dirtable += strnlen ((char *) dirtable, end - dirtable);
+      if (dirtable < end)
+       dirtable++;
+    }
   if (dirtable >= end || *dirtable == '\0')
     return NULL;
   *dir_name = dirtable;
@@ -5800,17 +5934,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;
@@ -5818,14 +5957,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);
@@ -5913,17 +6051,21 @@ display_debug_macro (struct dwarf_section *section,
            case DW_MACRO_define:
              READ_ULEB (lineno, curr, end);
              string = curr;
-             curr += strnlen ((char *) string, end - string) + 1;
-             printf (_(" DW_MACRO_define - lineno : %d macro : %s\n"),
-                     lineno, string);
+             curr += strnlen ((char *) string, end - string);
+             printf (_(" DW_MACRO_define - lineno : %d macro : %*s\n"),
+                     lineno, (int) (curr - string), string);
+             if (curr < end)
+               curr++;
              break;
 
            case DW_MACRO_undef:
              READ_ULEB (lineno, curr, end);
              string = curr;
-             curr += strnlen ((char *) string, end - string) + 1;
-             printf (_(" DW_MACRO_undef - lineno : %d macro : %s\n"),
-                     lineno, string);
+             curr += strnlen ((char *) string, end - string);
+             printf (_(" DW_MACRO_undef - lineno : %d macro : %*s\n"),
+                     lineno, (int) (curr - string), string);
+             if (curr < end)
+               curr++;
              break;
 
            case DW_MACRO_start_file:
@@ -5957,7 +6099,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);
@@ -5965,7 +6110,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);
@@ -6002,7 +6150,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
@@ -6069,9 +6217,8 @@ display_debug_abbrev (struct dwarf_section *section,
 {
   abbrev_entry *entry;
   unsigned char *start = section->start;
-  const unsigned char *end = start + section->size;
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   do
     {
@@ -6083,7 +6230,7 @@ display_debug_abbrev (struct dwarf_section *section,
       if (list == NULL)
        {
          list = new_abbrev_list (0, offset);
-         start = process_abbrev_set (start, end, list);
+         start = process_abbrev_set (section, 0, section->size, offset, list);
          list->start_of_next_abbrevs = start;
        }
       else
@@ -6109,7 +6256,7 @@ display_debug_abbrev (struct dwarf_section *section,
                      get_AT_name (attr->attribute),
                      get_FORM_name (attr->form));
              if (attr->form == DW_FORM_implicit_const)
-               printf (": %" BFD_VMA_FMT "d", attr->implicit_const);
+               printf (": %s", dwarf_vmatoa ("d", attr->implicit_const));
              putchar ('\n');
            }
        }
@@ -6124,7 +6271,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));
@@ -6183,11 +6330,10 @@ display_loc_list (struct dwarf_section *section,
 {
   unsigned char *start = *start_ptr, *vstart = *vstart_ptr;
   unsigned char *section_end = section->start + section->size;
-  unsigned long cu_offset;
+  dwarf_vma    cu_offset;
   unsigned int pointer_size;
   unsigned int offset_size;
   int dwarf_version;
-
   dwarf_vma begin;
   dwarf_vma end;
   unsigned short length;
@@ -6217,14 +6363,15 @@ display_loc_list (struct dwarf_section *section,
       dwarf_vma off = offset + (start - *start_ptr);
       dwarf_vma vbegin = vm1, vend = vm1;
 
-      if (start + 2 * pointer_size > section_end)
+      if (2 * pointer_size > (size_t) (section_end - start))
        {
          warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
                (unsigned long) offset);
          break;
        }
 
-      printf ("    %8.8lx ", (unsigned long) off);
+      printf ("    ");
+      print_dwarf_vma (off, 4);
 
       SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
       SAFE_BYTE_GET_AND_INC (end, start, pointer_size, section_end);
@@ -6270,7 +6417,7 @@ display_loc_list (struct dwarf_section *section,
                  (unsigned long) off, 8, "");
        }
 
-      if (start + 2 > section_end)
+      if (2 > (size_t) (section_end - start))
        {
          warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
                (unsigned long) offset);
@@ -6279,7 +6426,7 @@ display_loc_list (struct dwarf_section *section,
 
       SAFE_BYTE_GET_AND_INC (length, start, 2, section_end);
 
-      if (start + length > section_end)
+      if (length > (size_t) (section_end - start))
        {
          warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
                (unsigned long) offset);
@@ -6328,7 +6475,7 @@ display_loclists_list (struct dwarf_section *section,
 {
   unsigned char *start = *start_ptr, *vstart = *vstart_ptr;
   unsigned char *section_end = section->start + section->size;
-  unsigned long cu_offset;
+  dwarf_vma    cu_offset;
   unsigned int pointer_size;
   unsigned int offset_size;
   int dwarf_version;
@@ -6371,7 +6518,8 @@ display_loclists_list (struct dwarf_section *section,
          break;
        }
 
-      printf ("    %8.8lx ", (unsigned long) off);
+      printf ("    ");
+      print_dwarf_vma (off, 4);
 
       SAFE_BYTE_GET_AND_INC (llet, start, 1, section_end);
 
@@ -6441,15 +6589,21 @@ display_loclists_list (struct dwarf_section *section,
          && llet != DW_LLE_start_length)
        continue;
 
-      if (start + 2 > section_end)
+      if (start == section_end)
        {
          warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
                (unsigned long) offset);
          break;
        }
-
       READ_ULEB (length, start, section_end);
 
+      if (length > (size_t) (section_end - start))
+       {
+         warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
+               (unsigned long) offset);
+         break;
+       }
+
       print_dwarf_vma (begin, pointer_size);
       print_dwarf_vma (end, pointer_size);
 
@@ -6508,7 +6662,7 @@ display_loc_list_dwo (struct dwarf_section *section,
 {
   unsigned char *start = *start_ptr, *vstart = *vstart_ptr;
   unsigned char *section_end = section->start + section->size;
-  unsigned long cu_offset;
+  dwarf_vma    cu_offset;
   unsigned int pointer_size;
   unsigned int offset_size;
   int dwarf_version;
@@ -6538,7 +6692,8 @@ display_loc_list_dwo (struct dwarf_section *section,
 
   while (1)
     {
-      printf ("    %8.8lx ", (unsigned long) (offset + (start - *start_ptr)));
+      printf ("    ");
+      print_dwarf_vma (offset + (start - *start_ptr), 4);
 
       if (start >= section_end)
        {
@@ -6613,7 +6768,7 @@ display_loc_list_dwo (struct dwarf_section *section,
          return;
        }
 
-      if (start + 2 > section_end)
+      if (2 > (size_t) (section_end - start))
        {
          warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
                (unsigned long) offset);
@@ -6621,7 +6776,7 @@ display_loc_list_dwo (struct dwarf_section *section,
        }
 
       SAFE_BYTE_GET_AND_INC (length, start, 2, section_end);
-      if (start + length > section_end)
+      if (length > (size_t) (section_end - start))
        {
          warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
                (unsigned long) offset);
@@ -6676,11 +6831,11 @@ static int
 display_debug_loc (struct dwarf_section *section, void *file)
 {
   unsigned char *start = section->start, *vstart = NULL;
-  unsigned long bytes;
+  dwarf_vma bytes;
   unsigned char *section_begin = start;
   unsigned int num_loc_list = 0;
-  unsigned long last_offset = 0;
-  unsigned long last_view = 0;
+  dwarf_vma last_offset = 0;
+  dwarf_vma last_view = 0;
   unsigned int first = 0;
   unsigned int i;
   unsigned int j;
@@ -6689,12 +6844,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;
 
@@ -6811,7 +6966,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"));
@@ -6871,28 +7026,32 @@ display_debug_loc (struct dwarf_section *section, void *file)
          else
            {
              if (start < next)
-               warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"),
+               warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
                      (unsigned long) (start - section_begin),
-                     (unsigned long) offset);
+                     (unsigned long) offset,
+                     section->name);
              else if (start > next)
-               warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
+               warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
                      (unsigned long) (start - section_begin),
-                     (unsigned long) offset);
+                     (unsigned long) offset,
+                     section->name);
            }
          start = next;
          vstart = vnext;
 
          if (offset >= bytes)
            {
-             warn (_("Offset 0x%lx is bigger than .debug_loc section size.\n"),
-                   (unsigned long) offset);
+             warn (_("Offset 0x%lx is bigger than %s section size.\n"),
+                   (unsigned long) offset,
+                   section->name);
              continue;
            }
 
          if (vnext && voffset >= bytes)
            {
-             warn (_("View Offset 0x%lx is bigger than .debug_loc section size.\n"),
-                   (unsigned long) voffset);
+             warn (_("View Offset 0x%lx is bigger than %s section size.\n"),
+                   (unsigned long) voffset,
+                   section->name);
              continue;
            }
 
@@ -6948,7 +7107,7 @@ display_debug_str (struct dwarf_section *section,
                   void *file ATTRIBUTE_UNUSED)
 {
   unsigned char *start = section->start;
-  unsigned long bytes = section->size;
+  dwarf_vma bytes = section->size;
   dwarf_vma addr = section->address;
 
   if (bytes == 0)
@@ -6957,7 +7116,7 @@ display_debug_str (struct dwarf_section *section,
       return 0;
     }
 
-  introduce (section, FALSE);
+  introduce (section, false);
 
   while (bytes)
     {
@@ -7004,19 +7163,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
@@ -7026,7 +7185,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.  */
@@ -7039,40 +7198,36 @@ display_debug_aranges (struct dwarf_section *section,
       unsigned char *addr_ranges;
       dwarf_vma length;
       dwarf_vma address;
-      unsigned long sec_off;
+      dwarf_vma     sec_off;
       unsigned char address_size;
-      int excess;
-      unsigned int offset_size;
-      unsigned int initial_length_size;
+      unsigned int  offset_size;
+      unsigned char *end_ranges;
 
       hdrptr = start;
+      sec_off = hdrptr - section->start;
 
       SAFE_BYTE_GET_AND_INC (arange.ar_length, hdrptr, 4, end);
       if (arange.ar_length == 0xffffffff)
        {
          SAFE_BYTE_GET_AND_INC (arange.ar_length, hdrptr, 8, end);
          offset_size = 8;
-         initial_length_size = 12;
        }
       else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
+       offset_size = 4;
 
-      sec_off = hdrptr - section->start;
-      if (sec_off + arange.ar_length < sec_off
-         || sec_off + arange.ar_length > section->size)
+      if (arange.ar_length > (size_t) (end - hdrptr))
        {
          warn (_("Debug info is corrupted, %s header at %#lx has length %s\n"),
                section->name,
-               sec_off - initial_length_size,
+               (unsigned long) sec_off,
                dwarf_vmatoa ("x", arange.ar_length));
          break;
        }
+      end_ranges = hdrptr + arange.ar_length;
 
-      SAFE_BYTE_GET_AND_INC (arange.ar_version, hdrptr, 2, end);
-      SAFE_BYTE_GET_AND_INC (arange.ar_info_offset, hdrptr, offset_size, end);
+      SAFE_BYTE_GET_AND_INC (arange.ar_version, hdrptr, 2, end_ranges);
+      SAFE_BYTE_GET_AND_INC (arange.ar_info_offset, hdrptr, offset_size,
+                            end_ranges);
 
       if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE
          && num_debug_info_entries > 0
@@ -7080,8 +7235,8 @@ display_debug_aranges (struct dwarf_section *section,
        warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"),
              (unsigned long) arange.ar_info_offset, section->name);
 
-      SAFE_BYTE_GET_AND_INC (arange.ar_pointer_size, hdrptr, 1, end);
-      SAFE_BYTE_GET_AND_INC (arange.ar_segment_size, hdrptr, 1, end);
+      SAFE_BYTE_GET_AND_INC (arange.ar_pointer_size, hdrptr, 1, end_ranges);
+      SAFE_BYTE_GET_AND_INC (arange.ar_segment_size, hdrptr, 1, end_ranges);
 
       if (arange.ar_version != 2 && arange.ar_version != 3)
        {
@@ -7129,22 +7284,22 @@ display_debug_aranges (struct dwarf_section *section,
       addr_ranges = hdrptr;
 
       /* Must pad to an alignment boundary that is twice the address size.  */
-      excess = (hdrptr - start) % (2 * address_size);
-      if (excess)
-       addr_ranges += (2 * address_size) - excess;
-
-      start += arange.ar_length + initial_length_size;
+      addr_ranges += (2 * address_size - 1
+                     - (hdrptr - start - 1) % (2 * address_size));
 
-      while (addr_ranges + 2 * address_size <= start)
+      while (2 * address_size <= end_ranges - addr_ranges)
        {
-         SAFE_BYTE_GET_AND_INC (address, addr_ranges, address_size, end);
-         SAFE_BYTE_GET_AND_INC (length, addr_ranges, address_size, end);
-
+         SAFE_BYTE_GET_AND_INC (address, addr_ranges, address_size,
+                                end_ranges);
+         SAFE_BYTE_GET_AND_INC (length, addr_ranges, address_size,
+                                end_ranges);
          printf ("    ");
          print_dwarf_vma (address, address_size);
          print_dwarf_vma (length, address_size);
          putchar ('\n');
        }
+
+      start = end_ranges;
     }
 
   printf ("\n");
@@ -7171,6 +7326,7 @@ display_debug_addr (struct dwarf_section *section,
   unsigned char *end;
   unsigned int i;
   unsigned int count;
+  unsigned char * header;
 
   if (section->size == 0)
     {
@@ -7185,7 +7341,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
@@ -7211,6 +7367,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;
@@ -7221,7 +7378,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_AND_INC (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)
        {
@@ -7257,15 +7445,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)
     {
@@ -7276,31 +7464,42 @@ display_debug_str_offsets (struct dwarf_section *section,
       /* FIXME: We assume that this means 64-bit DWARF is being used.  */
       if (length == 0xffffffff)
        {
-         SAFE_BYTE_GET (length, curr, 8, end);
+         SAFE_BYTE_GET_AND_INC (length, curr, 8, end);
          entry_length = 8;
        }
       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
        {
+         if (length <= (dwarf_vma) (end - curr))
+           entries_end = curr + length;
+         else
+           {
+             warn (_("Section %s is too small %#lx\n"),
+                   section->name, (unsigned long) section->size);
+             entries_end = end;
+           }
+
          int version;
-         SAFE_BYTE_GET_AND_INC (version, curr, 2, end);
+         SAFE_BYTE_GET_AND_INC (version, curr, 2, entries_end);
          if (version != 5)
            warn (_("Unexpected version number in str_offset header: %#x\n"), version);
 
          int padding;
-         SAFE_BYTE_GET_AND_INC (padding, curr, 2, end);
+         SAFE_BYTE_GET_AND_INC (padding, curr, 2, entries_end);
          if (padding != 0)
            warn (_("Unexpected value in str_offset header's padding field: %#x\n"), padding);
 
@@ -7309,12 +7508,16 @@ 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;
 
-         SAFE_BYTE_GET_AND_INC (offset, curr, entry_length, end);
+         if ((dwarf_vma) (entries_end - curr) < entry_length)
+           /* Not enough space to read one entry_length, give up.  */
+           return 0;
+
+         SAFE_BYTE_GET_AND_INC (offset, curr, entry_length, entries_end);
          if (dwo)
            string = (const unsigned char *)
              fetch_indexed_string (idx, NULL, entry_length, dwo);
@@ -7355,9 +7558,11 @@ range_entry_compar (const void *ap, const void *bp)
 }
 
 static void
-display_debug_ranges_list (unsigned char *start, unsigned char *finish,
-                          unsigned int pointer_size, unsigned long offset,
-                          unsigned long base_address)
+display_debug_ranges_list (unsigned char *  start,
+                          unsigned char *  finish,
+                          unsigned int     pointer_size,
+                          dwarf_vma        offset,
+                          dwarf_vma        base_address)
 {
   while (start < finish)
     {
@@ -7369,8 +7574,8 @@ 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);
+      printf ("    ");
+      print_dwarf_vma (offset, 4);
 
       if (begin == 0 && end == 0)
        {
@@ -7402,27 +7607,30 @@ display_debug_ranges_list (unsigned char *start, unsigned char *finish,
 }
 
 static void
-display_debug_rnglists_list (unsigned char *start, unsigned char *finish,
-                            unsigned int pointer_size, unsigned long offset,
-                            unsigned long base_address)
+display_debug_rnglists_list (unsigned char * start,
+                            unsigned char * finish,
+                            unsigned int    pointer_size,
+                            dwarf_vma       offset,
+                            dwarf_vma       base_address)
 {
   unsigned char *next = start;
 
   while (1)
     {
-      unsigned long off = offset + (start - next);
+      dwarf_vma off = offset + (start - next);
       enum dwarf_range_list_entry rlet;
       /* Initialize it due to a false compiler warning.  */
       dwarf_vma begin = -1, length, end = -1;
 
-      if (start + 1 > finish)
+      if (start >= finish)
        {
-         warn (_("Range list starting at offset 0x%lx is not terminated.\n"),
-               offset);
+         warn (_("Range list starting at offset 0x%s is not terminated.\n"),
+               dwarf_vmatoa ("x", offset));
          break;
        }
 
-      printf ("    %8.8lx ", off);
+      printf ("    ");
+      print_dwarf_vma (off, 4);
 
       SAFE_BYTE_GET_AND_INC (rlet, start, 1, finish);
 
@@ -7459,8 +7667,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);
@@ -7475,17 +7690,18 @@ static int
 display_debug_ranges (struct dwarf_section *section,
                      void *file ATTRIBUTE_UNUSED)
 {
-  unsigned char *start = section->start;
-  unsigned char *last_start = start;
-  unsigned long bytes = section->size;
-  unsigned char *section_begin = start;
-  unsigned char *finish = start + bytes;
-  unsigned int num_range_list, i;
-  struct range_entry *range_entries, *range_entry_fill;
-  int is_rnglists = strstr (section->name, "debug_rnglists") != NULL;
+  unsigned char *       start = section->start;
+  unsigned char *       last_start = start;
+  dwarf_vma             bytes = section->size;
+  unsigned char *       section_begin = start;
+  unsigned char *       finish = start + bytes;
+  unsigned int          num_range_list, i;
+  struct range_entry *  range_entries;
+  struct range_entry *  range_entry_fill;
+  int                   is_rnglists = strstr (section->name, "debug_rnglists") != NULL;
   /* Initialize it due to a false compiler warning.  */
-  unsigned char address_size = 0;
-  dwarf_vma last_offset = 0;
+  unsigned char         address_size = 0;
+  dwarf_vma             last_offset = 0;
 
   if (bytes == 0)
     {
@@ -7496,7 +7712,6 @@ display_debug_ranges (struct dwarf_section *section,
   if (is_rnglists)
     {
       dwarf_vma initial_length;
-      unsigned int initial_length_size;
       unsigned char segment_selector_size;
       unsigned int offset_size, offset_entry_count;
       unsigned short version;
@@ -7509,22 +7724,18 @@ display_debug_ranges (struct dwarf_section *section,
          /* This section is 64-bit DWARF 3.  */
          SAFE_BYTE_GET_AND_INC (initial_length, start, 8, finish);
          offset_size = 8;
-         initial_length_size = 12;
        }
       else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
+       offset_size = 4;
 
-      if (initial_length + initial_length_size > section->size)
+      if (initial_length > (size_t) (finish - start))
        {
          /* If the length field has a relocation against it, then we should
             not complain if it is inaccurate (and probably negative).
             It is copied from .debug_line handling code.  */
          if (reloc_at (section, (start - section->start) - offset_size))
            {
-             initial_length = (finish - start) - initial_length_size;
+             initial_length = finish - start;
            }
          else
            {
@@ -7574,7 +7785,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)
     {
@@ -7593,6 +7812,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];
@@ -7608,7 +7834,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"));
 
@@ -7623,7 +7849,6 @@ display_debug_ranges (struct dwarf_section *section,
 
       pointer_size = (is_rnglists ? address_size : debug_info_p->pointer_size);
       offset = range_entry->ranges_offset;
-      next = section_begin + offset;
       base_address = debug_info_p->base_address;
 
       /* PR 17512: file: 001-101485-0.001:0.1.  */
@@ -7634,12 +7859,13 @@ display_debug_ranges (struct dwarf_section *section,
          continue;
        }
 
-      if (next < section_begin || next >= finish)
+      if (offset > (size_t) (finish - section_begin))
        {
          warn (_("Corrupt offset (%#8.8lx) in range entry %u\n"),
                (unsigned long) offset, i);
          continue;
        }
+      next = section_begin + offset;
 
       /* If multiple DWARF entities reference the same range then we will
          have multiple entries in the `range_entries' list for the same
@@ -8105,11 +8331,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)
@@ -8205,10 +8429,16 @@ read_cie (unsigned char *start, unsigned char *end,
     }
 
   if (strcmp (fc->augmentation, "eh") == 0)
-    start += eh_addr_size;
+    {
+      if (eh_addr_size > (size_t) (end - start))
+       goto fail;
+      start += eh_addr_size;
+    }
 
   if (version >= 4)
     {
+      if (2 > (size_t) (end - start))
+       goto fail;
       GET (fc->ptr_size, 1);
       if (fc->ptr_size < 1 || fc->ptr_size > 8)
        {
@@ -8235,6 +8465,9 @@ read_cie (unsigned char *start, unsigned char *end,
   READ_ULEB (fc->code_factor, start, end);
   READ_SLEB (fc->data_factor, start, end);
 
+  if (start >= end)
+    goto fail;
+
   if (version == 1)
     {
       GET (fc->ra, 1);
@@ -8246,6 +8479,8 @@ read_cie (unsigned char *start, unsigned char *end,
 
   if (fc->augmentation[0] == 'z')
     {
+      if (start >= end)
+       goto fail;
       READ_ULEB (augmentation_data_len, start, end);
       augmentation_data = start;
       /* PR 17512: file: 11042-2589-0.004.  */
@@ -8352,12 +8587,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)
     {
@@ -8372,8 +8607,7 @@ display_debug_frames (struct dwarf_section *section,
       bfd_size_type augmentation_data_len = 0;
       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;
@@ -8397,24 +8631,21 @@ display_debug_frames (struct dwarf_section *section,
        {
          SAFE_BYTE_GET_AND_INC (length, start, 8, end);
          offset_size = 8;
-         initial_length_size = 12;
        }
       else
-       {
-         offset_size = 4;
-         initial_length_size = 4;
-       }
+       offset_size = 4;
 
-      block_end = saved_start + length + initial_length_size;
-      if (block_end > end || block_end < start)
+      if (length > (size_t) (end - start))
        {
          warn ("Invalid length 0x%s in FDE at %#08lx\n",
                dwarf_vmatoa_1 (NULL, length, offset_size),
                (unsigned long) (saved_start - section_start));
          block_end = end;
        }
+      else
+       block_end = start + length;
 
-      SAFE_BYTE_GET_AND_INC (cie_id, start, offset_size, end);
+      SAFE_BYTE_GET_AND_INC (cie_id, start, offset_size, block_end);
 
       if (is_eh ? (cie_id == 0) : ((offset_size == 4 && cie_id == DW_CIE_ID)
                                   || (offset_size == 8 && cie_id == DW64_CIE_ID)))
@@ -8422,7 +8653,7 @@ display_debug_frames (struct dwarf_section *section,
          int version;
          unsigned int mreg;
 
-         start = read_cie (start, end, &cie, &version,
+         start = read_cie (start, block_end, &cie, &version,
                            &augmentation_data_len, &augmentation_data);
          /* PR 17512: file: 027-135133-0.005.  */
          if (cie == NULL)
@@ -8473,21 +8704,25 @@ display_debug_frames (struct dwarf_section *section,
        {
          unsigned char *look_for;
          unsigned long segment_selector;
+         dwarf_vma cie_off;
 
+         cie_off = cie_id;
          if (is_eh)
            {
              dwarf_vma sign = (dwarf_vma) 1 << (offset_size * 8 - 1);
-             look_for = start - 4 - ((cie_id ^ sign) - sign);
+             cie_off = (cie_off ^ sign) - sign;
+             cie_off = start - 4 - section_start - cie_off;
            }
-         else
-           look_for = section_start + cie_id;
 
-         if (look_for <= saved_start)
+         look_for = section_start + cie_off;
+         if (cie_off <= (dwarf_vma) (saved_start - section_start))
            {
              for (cie = chunks; cie ; cie = cie->next)
                if (cie->chunk_start == look_for)
                  break;
            }
+         else if (cie_off >= section->size)
+           cie = NULL;
          else
            {
              for (cie = forward_refs; cie ; cie = cie->next)
@@ -8506,11 +8741,13 @@ display_debug_frames (struct dwarf_section *section,
                      SAFE_BYTE_GET_AND_INC (length, cie_scan, 8, end);
                      off_size = 8;
                    }
-                 if (length != 0)
+                 if (length != 0 && length <= (size_t) (end - cie_scan))
                    {
                      dwarf_vma c_id;
+                     unsigned char *cie_end = cie_scan + length;
 
-                     SAFE_BYTE_GET_AND_INC (c_id, cie_scan, off_size, end);
+                     SAFE_BYTE_GET_AND_INC (c_id, cie_scan, off_size,
+                                            cie_end);
                      if (is_eh
                          ? c_id == 0
                          : ((off_size == 4 && c_id == DW_CIE_ID)
@@ -8519,7 +8756,7 @@ display_debug_frames (struct dwarf_section *section,
                          int version;
                          unsigned int mreg;
 
-                         read_cie (cie_scan, end, &cie, &version,
+                         read_cie (cie_scan, cie_end, &cie, &version,
                                    &augmentation_data_len, &augmentation_data);
                          /* PR 17512: file: 3450-2098-0.004.  */
                          if (cie == NULL)
@@ -8551,9 +8788,6 @@ display_debug_frames (struct dwarf_section *section,
 
          if (!cie)
            {
-             warn ("Invalid CIE pointer 0x%s in FDE at %#08lx\n",
-                   dwarf_vmatoa_1 (NULL, cie_id, offset_size),
-                   (unsigned long) (saved_start - section_start));
              fc->ncols = 0;
              fc->col_type = (short int *) xmalloc (sizeof (short int));
              fc->col_offset = (int *) xmalloc (sizeof (int));
@@ -8604,41 +8838,52 @@ display_debug_frames (struct dwarf_section *section,
                  warn (_("Probably corrupt segment size: %d - using 4 instead\n"), fc->segment_size);
                  fc->segment_size = 4;
                }
-             SAFE_BYTE_GET_AND_INC (segment_selector, start, fc->segment_size, end);
+             SAFE_BYTE_GET_AND_INC (segment_selector, start,
+                                    fc->segment_size, block_end);
            }
 
-         fc->pc_begin = get_encoded_value (&start, fc->fde_encoding, section, end);
+         fc->pc_begin = get_encoded_value (&start, fc->fde_encoding, section,
+                                           block_end);
 
          /* FIXME: It appears that sometimes the final pc_range value is
             encoded in less than encoded_ptr_size bytes.  See the x86_64
             run of the "objcopy on compressed debug sections" test for an
             example of this.  */
-         SAFE_BYTE_GET_AND_INC (fc->pc_range, start, encoded_ptr_size, end);
+         SAFE_BYTE_GET_AND_INC (fc->pc_range, start, encoded_ptr_size,
+                                block_end);
 
          if (cie->augmentation[0] == 'z')
            {
-             READ_ULEB (augmentation_data_len, start, end);
+             READ_ULEB (augmentation_data_len, start, block_end);
              augmentation_data = start;
              /* PR 17512 file: 722-8446-0.004 and PR 22386.  */
-             if (augmentation_data_len > (bfd_size_type) (end - start))
+             if (augmentation_data_len > (bfd_size_type) (block_end - start))
                {
                  warn (_("Augmentation data too long: 0x%s, "
                          "expected at most %#lx\n"),
                        dwarf_vmatoa ("x", augmentation_data_len),
-                       (unsigned long) (end - start));
-                 start = end;
+                       (unsigned long) (block_end - start));
+                 start = block_end;
                  augmentation_data = NULL;
                  augmentation_data_len = 0;
                }
              start += augmentation_data_len;
            }
 
-         printf ("\n%08lx %s %s FDE cie=%08lx pc=",
+         printf ("\n%08lx %s %s FDE ",
                  (unsigned long)(saved_start - section_start),
                  dwarf_vmatoa_1 (NULL, length, fc->ptr_size),
-                 dwarf_vmatoa_1 (NULL, cie_id, offset_size),
-                 (unsigned long)(cie->chunk_start - section_start));
+                 dwarf_vmatoa_1 (NULL, cie_id, offset_size));
+
+         if (cie->chunk_start)
+           printf ("cie=%08lx",
+                   (unsigned long) (cie->chunk_start - section_start));
+         else
+           /* Ideally translate "invalid " to 8 chars, trailing space
+              is optional.  */
+           printf (_("cie=invalid "));
 
+         printf (" pc=");
          if (fc->segment_size)
            printf ("%04lx:", segment_selector);
 
@@ -8670,7 +8915,6 @@ display_debug_frames (struct dwarf_section *section,
            {
              unsigned int reg, op, opa;
              unsigned long temp;
-             unsigned char * new_start;
 
              op = *start++;
              opa = op & 0x3f;
@@ -8684,7 +8928,7 @@ display_debug_frames (struct dwarf_section *section,
                case DW_CFA_advance_loc:
                  break;
                case DW_CFA_offset:
-                 SKIP_ULEB (start, end);
+                 SKIP_ULEB (start, block_end);
                  if (frame_need_space (fc, opa) >= 0)
                    fc->col_type[opa] = DW_CFA_undefined;
                  break;
@@ -8693,105 +8937,111 @@ display_debug_frames (struct dwarf_section *section,
                    fc->col_type[opa] = DW_CFA_undefined;
                  break;
                case DW_CFA_set_loc:
-                 start += encoded_ptr_size;
+                 if ((size_t) (block_end - start) < encoded_ptr_size)
+                   start = block_end;
+                 else
+                   start += encoded_ptr_size;
                  break;
                case DW_CFA_advance_loc1:
-                 start += 1;
+                 if ((size_t) (block_end - start) < 1)
+                   start = block_end;
+                 else
+                   start += 1;
                  break;
                case DW_CFA_advance_loc2:
-                 start += 2;
+                 if ((size_t) (block_end - start) < 2)
+                   start = block_end;
+                 else
+                   start += 2;
                  break;
                case DW_CFA_advance_loc4:
-                 start += 4;
+                 if ((size_t) (block_end - start) < 4)
+                   start = block_end;
+                 else
+                   start += 4;
                  break;
                case DW_CFA_offset_extended:
                case DW_CFA_val_offset:
-                 READ_ULEB (reg, start, end);
-                 SKIP_ULEB (start, end);
+                 READ_ULEB (reg, start, block_end);
+                 SKIP_ULEB (start, block_end);
                  if (frame_need_space (fc, reg) >= 0)
                    fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_restore_extended:
-                 READ_ULEB (reg, start, end);
+                 READ_ULEB (reg, start, block_end);
                  if (frame_need_space (fc, reg) >= 0)
                    fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_undefined:
-                 READ_ULEB (reg, start, end);
+                 READ_ULEB (reg, start, block_end);
                  if (frame_need_space (fc, reg) >= 0)
                    fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_same_value:
-                 READ_ULEB (reg, start, end);
+                 READ_ULEB (reg, start, block_end);
                  if (frame_need_space (fc, reg) >= 0)
                    fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_register:
-                 READ_ULEB (reg, start, end);
-                 SKIP_ULEB (start, end);
+                 READ_ULEB (reg, start, block_end);
+                 SKIP_ULEB (start, block_end);
                  if (frame_need_space (fc, reg) >= 0)
                    fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_def_cfa:
-                 SKIP_ULEB (start, end);
-                 SKIP_ULEB (start, end);
+                 SKIP_ULEB (start, block_end);
+                 SKIP_ULEB (start, block_end);
                  break;
                case DW_CFA_def_cfa_register:
-                 SKIP_ULEB (start, end);
+                 SKIP_ULEB (start, block_end);
                  break;
                case DW_CFA_def_cfa_offset:
-                 SKIP_ULEB (start, end);
+                 SKIP_ULEB (start, block_end);
                  break;
                case DW_CFA_def_cfa_expression:
-                 READ_ULEB (temp, start, end);
-                 new_start = start + temp;
-                 if (new_start < start)
-                   {
-                     warn (_("Corrupt CFA_def expression value: %lu\n"), temp);
-                     start = block_end;
-                   }
+                 READ_ULEB (temp, start, block_end);
+                 if ((size_t) (block_end - start) < temp)
+                   start = block_end;
                  else
-                   start = new_start;
+                   start += temp;
                  break;
                case DW_CFA_expression:
                case DW_CFA_val_expression:
-                 READ_ULEB (reg, start, end);
-                 READ_ULEB (temp, start, end);
-                 new_start = start + temp;
-                 if (new_start < start)
-                   {
-                     /* PR 17512: file:306-192417-0.005.  */
-                     warn (_("Corrupt CFA expression value: %lu\n"), temp);
-                     start = block_end;
-                   }
+                 READ_ULEB (reg, start, block_end);
+                 READ_ULEB (temp, start, block_end);
+                 if ((size_t) (block_end - start) < temp)
+                   start = block_end;
                  else
-                   start = new_start;
+                   start += temp;
                  if (frame_need_space (fc, reg) >= 0)
                    fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_offset_extended_sf:
                case DW_CFA_val_offset_sf:
-                 READ_ULEB (reg, start, end);
-                 SKIP_SLEB (start, end);
+                 READ_ULEB (reg, start, block_end);
+                 SKIP_SLEB (start, block_end);
                  if (frame_need_space (fc, reg) >= 0)
                    fc->col_type[reg] = DW_CFA_undefined;
                  break;
                case DW_CFA_def_cfa_sf:
-                 SKIP_ULEB (start, end);
-                 SKIP_SLEB (start, end);
+                 SKIP_ULEB (start, block_end);
+                 SKIP_SLEB (start, block_end);
                  break;
                case DW_CFA_def_cfa_offset_sf:
-                 SKIP_SLEB (start, end);
+                 SKIP_SLEB (start, block_end);
                  break;
                case DW_CFA_MIPS_advance_loc8:
-                 start += 8;
+                 if ((size_t) (block_end - start) < 8)
+                   start = block_end;
+                 else
+                   start += 8;
                  break;
                case DW_CFA_GNU_args_size:
-                 SKIP_ULEB (start, end);
+                 SKIP_ULEB (start, block_end);
                  break;
                case DW_CFA_GNU_negative_offset_extended:
-                 READ_ULEB (reg, start, end);
-                 SKIP_ULEB (start, end);
+                 READ_ULEB (reg, start, block_end);
+                 SKIP_ULEB (start, block_end);
                  if (frame_need_space (fc, reg) >= 0)
                    fc->col_type[reg] = DW_CFA_undefined;
                  break;
@@ -8802,14 +9052,13 @@ 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.  */
 
       while (start < block_end)
        {
-         unsigned char * tmp;
          unsigned op, opa;
          unsigned long ul, roffs;
          /* Note: It is tempting to use an unsigned long for 'reg' but there
@@ -8828,7 +9077,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.  */
@@ -8847,7 +9096,7 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_offset:
-             READ_ULEB (roffs, start, end);
+             READ_ULEB (roffs, start, block_end);
              if (opa >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -8885,7 +9134,8 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_set_loc:
-             vma = get_encoded_value (&start, fc->fde_encoding, section, block_end);
+             vma = get_encoded_value (&start, fc->fde_encoding, section,
+                                      block_end);
              if (do_debug_frames_interp)
                frame_display_row (fc, &need_col_headers, &max_regs);
              else
@@ -8895,7 +9145,7 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_advance_loc1:
-             SAFE_BYTE_GET_AND_INC (ofs, start, 1, end);
+             SAFE_BYTE_GET_AND_INC (ofs, start, 1, block_end);
              if (do_debug_frames_interp)
                frame_display_row (fc, &need_col_headers, &max_regs);
              else
@@ -8934,8 +9184,8 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_offset_extended:
-             READ_ULEB (reg, start, end);
-             READ_ULEB (roffs, start, end);
+             READ_ULEB (reg, start, block_end);
+             READ_ULEB (roffs, start, block_end);
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -8950,8 +9200,8 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_val_offset:
-             READ_ULEB (reg, start, end);
-             READ_ULEB (roffs, start, end);
+             READ_ULEB (reg, start, block_end);
+             READ_ULEB (roffs, start, block_end);
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -8966,7 +9216,7 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_restore_extended:
-             READ_ULEB (reg, start, end);
+             READ_ULEB (reg, start, block_end);
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -8988,7 +9238,7 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_undefined:
-             READ_ULEB (reg, start, end);
+             READ_ULEB (reg, start, block_end);
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -9002,7 +9252,7 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_same_value:
-             READ_ULEB (reg, start, end);
+             READ_ULEB (reg, start, block_end);
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -9016,8 +9266,8 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_register:
-             READ_ULEB (reg, start, end);
-             READ_ULEB (roffs, start, end);
+             READ_ULEB (reg, start, block_end);
+             READ_ULEB (roffs, start, block_end);
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -9080,8 +9330,8 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_def_cfa:
-             READ_ULEB (fc->cfa_reg, start, end);
-             READ_ULEB (fc->cfa_offset, start, end);
+             READ_ULEB (fc->cfa_reg, start, block_end);
+             READ_ULEB (fc->cfa_offset, start, block_end);
              fc->cfa_exp = 0;
              if (! do_debug_frames_interp)
                printf ("  DW_CFA_def_cfa: %s ofs %d\n",
@@ -9089,7 +9339,7 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_def_cfa_register:
-             READ_ULEB (fc->cfa_reg, start, end);
+             READ_ULEB (fc->cfa_reg, start, block_end);
              fc->cfa_exp = 0;
              if (! do_debug_frames_interp)
                printf ("  DW_CFA_def_cfa_register: %s\n",
@@ -9097,7 +9347,7 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_def_cfa_offset:
-             READ_ULEB (fc->cfa_offset, start, end);
+             READ_ULEB (fc->cfa_offset, start, block_end);
              if (! do_debug_frames_interp)
                printf ("  DW_CFA_def_cfa_offset: %d\n", (int) fc->cfa_offset);
              break;
@@ -9108,8 +9358,8 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_def_cfa_expression:
-             READ_ULEB (ul, start, end);
-             if (start >= block_end || ul > (unsigned long) (block_end - start))
+             READ_ULEB (ul, start, block_end);
+             if (ul > (size_t) (block_end - start))
                {
                  printf (_("  DW_CFA_def_cfa_expression: <corrupt len %lu>\n"), ul);
                  break;
@@ -9126,14 +9376,13 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_expression:
-             READ_ULEB (reg, start, end);
-             READ_ULEB (ul, start, end);
+             READ_ULEB (reg, start, block_end);
+             READ_ULEB (ul, start, block_end);
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              /* PR 17512: file: 069-133014-0.006.  */
              /* PR 17512: file: 98c02eb4.  */
-             tmp = start + ul;
-             if (start >= block_end || tmp > block_end || tmp < start)
+             if (ul > (size_t) (block_end - start))
                {
                  printf (_("  DW_CFA_expression: <corrupt len %lu>\n"), ul);
                  break;
@@ -9148,16 +9397,15 @@ display_debug_frames (struct dwarf_section *section,
                }
              if (*reg_prefix == '\0')
                fc->col_type[reg] = DW_CFA_expression;
-             start = tmp;
+             start += ul;
              break;
 
            case DW_CFA_val_expression:
-             READ_ULEB (reg, start, end);
-             READ_ULEB (ul, start, end);
+             READ_ULEB (reg, start, block_end);
+             READ_ULEB (ul, start, block_end);
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
-             tmp = start + ul;
-             if (start >= block_end || tmp > block_end || tmp < start)
+             if (ul > (size_t) (block_end - start))
                {
                  printf ("  DW_CFA_val_expression: <corrupt len %lu>\n", ul);
                  break;
@@ -9172,12 +9420,12 @@ display_debug_frames (struct dwarf_section *section,
                }
              if (*reg_prefix == '\0')
                fc->col_type[reg] = DW_CFA_val_expression;
-             start = tmp;
+             start += ul;
              break;
 
            case DW_CFA_offset_extended_sf:
-             READ_ULEB (reg, start, end);
-             READ_SLEB (l, start, end);
+             READ_ULEB (reg, start, block_end);
+             READ_SLEB (l, start, block_end);
              if (frame_need_space (fc, reg) < 0)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -9192,8 +9440,8 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_val_offset_sf:
-             READ_ULEB (reg, start, end);
-             READ_SLEB (l, start, end);
+             READ_ULEB (reg, start, block_end);
+             READ_SLEB (l, start, block_end);
              if (frame_need_space (fc, reg) < 0)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
@@ -9208,20 +9456,22 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_def_cfa_sf:
-             READ_ULEB (fc->cfa_reg, start, end);
-             READ_ULEB (fc->cfa_offset, start, end);
-             fc->cfa_offset = fc->cfa_offset * fc->data_factor;
+             READ_ULEB (fc->cfa_reg, start, block_end);
+             READ_SLEB (l, start, block_end);
+             l *= fc->data_factor;
+             fc->cfa_offset = l;
              fc->cfa_exp = 0;
              if (! do_debug_frames_interp)
-               printf ("  DW_CFA_def_cfa_sf: %s ofs %d\n",
-                       regname (fc->cfa_reg, 0), (int) fc->cfa_offset);
+               printf ("  DW_CFA_def_cfa_sf: %s ofs %ld\n",
+                       regname (fc->cfa_reg, 0), (long) l);
              break;
 
            case DW_CFA_def_cfa_offset_sf:
-             READ_ULEB (fc->cfa_offset, start, end);
-             fc->cfa_offset *= fc->data_factor;
+             READ_SLEB (l, start, block_end);
+             l *= fc->data_factor;
+             fc->cfa_offset = l;
              if (! do_debug_frames_interp)
-               printf ("  DW_CFA_def_cfa_offset_sf: %d\n", (int) fc->cfa_offset);
+               printf ("  DW_CFA_def_cfa_offset_sf: %ld\n", (long) l);
              break;
 
            case DW_CFA_MIPS_advance_loc8:
@@ -9243,14 +9493,14 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_GNU_args_size:
-             READ_ULEB (ul, start, end);
+             READ_ULEB (ul, start, block_end);
              if (! do_debug_frames_interp)
                printf ("  DW_CFA_GNU_args_size: %ld\n", ul);
              break;
 
            case DW_CFA_GNU_negative_offset_extended:
-             READ_ULEB (reg, start, end);
-             READ_SLEB (l, start, end);
+             READ_ULEB (reg, start, block_end);
+             READ_SLEB (l, start, block_end);
              l = - l;
              if (frame_need_space (fc, reg) < 0)
                reg_prefix = bad_reg;
@@ -9339,7 +9589,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);
 
@@ -9348,12 +9598,12 @@ display_debug_names (struct dwarf_section *section, void *file)
       unsigned int offset_size;
       uint16_t dwarf_version, padding;
       uint32_t comp_unit_count, local_type_unit_count, foreign_type_unit_count;
-      uint32_t bucket_count, name_count, abbrev_table_size;
+      uint64_t bucket_count, name_count, abbrev_table_size;
       uint32_t augmentation_string_size;
       unsigned int i;
-      unsigned long sec_off;
-      bfd_boolean augmentation_printable;
+      bool augmentation_printable;
       const char *augmentation_string;
+      size_t total;
 
       unit_start = hdrptr;
 
@@ -9368,18 +9618,18 @@ display_debug_names (struct dwarf_section *section, void *file)
        }
       else
        offset_size = 4;
-      unit_end = hdrptr + unit_length;
 
-      sec_off = hdrptr - section->start;
-      if (sec_off + unit_length < sec_off
-         || sec_off + unit_length > section->size)
+      if (unit_length > (size_t) (section_end - hdrptr)
+         || unit_length < 2 + 2 + 4 * 7)
        {
+       too_short:
          warn (_("Debug info is corrupted, %s header at %#lx has length %s\n"),
                section->name,
                (unsigned long) (unit_start - section->start),
                dwarf_vmatoa ("x", unit_length));
          return 0;
        }
+      unit_end = hdrptr + unit_length;
 
       /* Get and check the version number.  */
       SAFE_BYTE_GET_AND_INC (dwarf_version, hdrptr, 2, unit_end);
@@ -9417,10 +9667,12 @@ display_debug_names (struct dwarf_section *section, void *file)
                augmentation_string_size);
          augmentation_string_size += (-augmentation_string_size) & 3;
        }
+      if (augmentation_string_size > (size_t) (unit_end - hdrptr))
+       goto too_short;
 
       printf (_("Augmentation string:"));
 
-      augmentation_printable = TRUE;
+      augmentation_printable = true;
       augmentation_string = (const char *) hdrptr;
 
       for (i = 0; i < augmentation_string_size; i++)
@@ -9431,7 +9683,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)
@@ -9446,6 +9698,9 @@ display_debug_names (struct dwarf_section *section, void *file)
       putchar ('\n');
 
       printf (_("CU table:\n"));
+      if (_mul_overflow (comp_unit_count, offset_size, &total)
+         || total > (size_t) (unit_end - hdrptr))
+       goto too_short;
       for (i = 0; i < comp_unit_count; i++)
        {
          uint64_t cu_offset;
@@ -9456,6 +9711,9 @@ display_debug_names (struct dwarf_section *section, void *file)
       putchar ('\n');
 
       printf (_("TU table:\n"));
+      if (_mul_overflow (local_type_unit_count, offset_size, &total)
+         || total > (size_t) (unit_end - hdrptr))
+       goto too_short;
       for (i = 0; i < local_type_unit_count; i++)
        {
          uint64_t tu_offset;
@@ -9466,6 +9724,9 @@ display_debug_names (struct dwarf_section *section, void *file)
       putchar ('\n');
 
       printf (_("Foreign TU table:\n"));
+      if (_mul_overflow (foreign_type_unit_count, 8, &total)
+         || total > (size_t) (unit_end - hdrptr))
+       goto too_short;
       for (i = 0; i < foreign_type_unit_count; i++)
        {
          uint64_t signature;
@@ -9477,6 +9738,18 @@ display_debug_names (struct dwarf_section *section, void *file)
        }
       putchar ('\n');
 
+      uint64_t xtra = (bucket_count * sizeof (uint32_t)
+                      + name_count * (sizeof (uint32_t) + 2 * offset_size)
+                      + abbrev_table_size);
+      if (xtra > (size_t) (unit_end - hdrptr))
+       {
+         warn (_("Entry pool offset (0x%lx) exceeds unit size 0x%lx "
+                 "for unit 0x%lx in the debug_names\n"),
+               (long) xtra,
+               (long) (unit_end - unit_start),
+               (long) (unit_start - section->start));
+         return 0;
+       }
       const uint32_t *const hash_table_buckets = (uint32_t *) hdrptr;
       hdrptr += bucket_count * sizeof (uint32_t);
       const uint32_t *const hash_table_hashes = (uint32_t *) hdrptr;
@@ -9489,15 +9762,6 @@ display_debug_names (struct dwarf_section *section, void *file)
       hdrptr += abbrev_table_size;
       const unsigned char *const abbrev_table_end = hdrptr;
       unsigned char *const entry_pool = hdrptr;
-      if (hdrptr > unit_end)
-       {
-         warn (_("Entry pool offset (0x%lx) exceeds unit size 0x%lx "
-                 "for unit 0x%lx in the debug_names\n"),
-               (long) (hdrptr - section->start),
-               (long) (unit_end - section->start),
-               (long) (unit_start - section->start));
-         return 0;
-       }
 
       size_t buckets_filled = 0;
       size_t bucketi;
@@ -9599,13 +9863,12 @@ display_debug_names (struct dwarf_section *section, void *file)
       for (namei = 0; namei < name_count; ++namei)
        {
          uint64_t string_offset, entry_offset;
+         unsigned char *p;
 
-         SAFE_BYTE_GET (string_offset,
-                        name_table_string_offsets + namei * offset_size,
-                        offset_size, unit_end);
-         SAFE_BYTE_GET (entry_offset,
-                        name_table_entry_offsets + namei * offset_size,
-                        offset_size, unit_end);
+         p = name_table_string_offsets + namei * offset_size;
+         SAFE_BYTE_GET (string_offset, p, offset_size, unit_end);
+         p = name_table_entry_offsets + namei * offset_size;
+         SAFE_BYTE_GET (entry_offset, p, offset_size, unit_end);
 
          printf ("[%3u] #%08x %s:", namei, hash_table_hashes[namei],
                  fetch_indirect_string (string_offset));
@@ -9695,7 +9958,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.
@@ -9705,7 +9968,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)
@@ -9716,7 +9979,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;
@@ -9740,7 +10003,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);
@@ -9778,7 +10041,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))
     {
@@ -9869,7 +10132,7 @@ display_gdb_index (struct dwarf_section *section,
   symbol_table = start + symbol_table_offset;
   constant_pool = start + constant_pool_offset;
 
-  if (address_table + address_table_size > section->start + section->size)
+  if (address_table_offset + address_table_size > section->size)
     {
       warn (_("Address table extends beyond end of section.\n"));
       return 0;
@@ -9924,11 +10187,9 @@ display_gdb_index (struct dwarf_section *section,
          || cu_vector_offset != 0)
        {
          unsigned int j;
-         unsigned char * adr;
 
-         adr = constant_pool + name_offset;
          /* PR 17531: file: 5b7b07ad.  */
-         if (adr < constant_pool || adr >= section->start + section->size)
+         if (name_offset >= section->size - constant_pool_offset)
            {
              printf (_("[%3u] <corrupt offset: %x>"), i, name_offset);
              warn (_("Corrupt name offset of 0x%x found for symbol table slot %d\n"),
@@ -9939,8 +10200,8 @@ display_gdb_index (struct dwarf_section *section,
                    (int) (section->size - (constant_pool_offset + name_offset)),
                    constant_pool + name_offset);
 
-         adr = constant_pool + cu_vector_offset;
-         if (adr < constant_pool || adr >= section->start + section->size - 3)
+         if (section->size - constant_pool_offset < 4
+             || cu_vector_offset > section->size - constant_pool_offset - 4)
            {
              printf (_("<invalid CU vector offset: %x>\n"), cu_vector_offset);
              warn (_("Corrupt CU vector offset of 0x%x found for symbol table slot %d\n"),
@@ -9948,12 +10209,10 @@ display_gdb_index (struct dwarf_section *section,
              continue;
            }
 
-         num_cus = byte_get_little_endian (adr, 4);
+         num_cus = byte_get_little_endian (constant_pool + cu_vector_offset, 4);
 
-         adr = constant_pool + cu_vector_offset + 4 + num_cus * 4;
-         if (num_cus * 4 < num_cus
-             || adr >= section->start + section->size
-             || adr < constant_pool)
+         if ((uint64_t) num_cus * 4 > section->size - (constant_pool_offset
+                                                       + cu_vector_offset + 4))
            {
              printf ("<invalid number of CUs: %d>\n", num_cus);
              warn (_("Invalid number of CUs (0x%x) for symbol table slot %d\n"),
@@ -10087,9 +10346,8 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
   unsigned int nslots;
   unsigned int i;
   unsigned int j;
-  dwarf_vma signature_high;
-  dwarf_vma signature_low;
-  char buf[64];
+  dwarf_vma signature;
+  size_t total;
 
   /* PR 17512: file: 002-168123-0.004.  */
   if (phdr == NULL)
@@ -10105,19 +10363,19 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
       return 0;
     }
 
-  SAFE_BYTE_GET (version, phdr, 4, limit);
+  phash = phdr;
+  SAFE_BYTE_GET_AND_INC (version, phash, 4, limit);
   if (version >= 2)
-    SAFE_BYTE_GET (ncols, phdr + 4, 4, limit);
-  SAFE_BYTE_GET (nused, phdr + 8, 4, limit);
-  SAFE_BYTE_GET (nslots, phdr + 12, 4, limit);
+    SAFE_BYTE_GET_AND_INC (ncols, phash, 4, limit);
+  SAFE_BYTE_GET_AND_INC (nused, phash, 4, limit);
+  SAFE_BYTE_GET_AND_INC (nslots, phash, 4, limit);
 
-  phash = phdr + 16;
   pindex = phash + (size_t) nslots * 8;
   ppool = pindex + (size_t) nslots * 4;
 
   if (do_display)
     {
-      introduce (section, FALSE);
+      introduce (section, false);
 
       printf (_("  Version:                 %u\n"), version);
       if (version >= 2)
@@ -10127,10 +10385,8 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
     }
 
   /* PR 17531: file: 45d69832.  */
-  if ((size_t) nslots * 8 / 8 != nslots
-      || phash < phdr || phash > limit
-      || pindex < phash || pindex > limit
-      || ppool < pindex || ppool > limit)
+  if (_mul_overflow ((size_t) nslots, 12, &total)
+      || total > (size_t) (limit - phash))
     {
       warn (ngettext ("Section %s is too small for %u slot\n",
                      "Section %s is too small for %u slots\n",
@@ -10148,8 +10404,8 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
          unsigned char *shndx_list;
          unsigned int shndx;
 
-         SAFE_BYTE_GET64 (phash, &signature_high, &signature_low, limit);
-         if (signature_high != 0 || signature_low != 0)
+         SAFE_BYTE_GET (signature, phash, 8, limit);
+         if (signature != 0)
            {
              SAFE_BYTE_GET (j, pindex, 4, limit);
              shndx_list = ppool + j * 4;
@@ -10162,8 +10418,7 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
 
              if (do_display)
                printf (_("  [%3d] Signature:  0x%s  Sections: "),
-                       i, dwarf_vmatoa64 (signature_high, signature_low,
-                                          buf, sizeof (buf)));
+                       i, dwarf_vmatoa ("x", signature));
              for (;;)
                {
                  if (shndx_list >= limit)
@@ -10198,23 +10453,21 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
       unsigned char *pi = pindex;
       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;
+      size_t temp;
 
       is_tu_index = strcmp (section->name, ".debug_tu_index") == 0;
 
       /* PR 17531: file: 0dd159bf.
         Check for integer overflow (can occur when size_t is 32-bit)
         with overlarge ncols or nused values.  */
-      if (ncols > 0
-         && ((size_t) ncols * 4 / 4 != ncols
-             || (size_t) nused * ncols * 4 / ((size_t) ncols * 4) != nused
-             || poffsets < ppool || poffsets > limit
-             || psizes < poffsets || psizes > limit
-             || pend < psizes || pend > limit))
+      if (nused == -1u
+         || _mul_overflow ((size_t) ncols, 4, &temp)
+         || _mul_overflow ((size_t) nused + 1, temp, &total)
+         || total > (size_t) (limit - ppool))
        {
          warn (_("Section %s too small for offset and size tables\n"),
                section->name);
@@ -10247,7 +10500,8 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
        {
          for (j = 0; j < ncols; j++)
            {
-             SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit);
+             unsigned char *p = ppool + j * 4;
+             SAFE_BYTE_GET (dw_sect, p, 4, limit);
              printf (" %8s", get_DW_SECT_short_name (dw_sect));
            }
          printf ("\n");
@@ -10255,7 +10509,7 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
 
       for (i = 0; i < nslots; i++)
        {
-         SAFE_BYTE_GET64 (ph, &signature_high, &signature_low, limit);
+         SAFE_BYTE_GET (signature, ph, 8, limit);
 
          SAFE_BYTE_GET (row, pi, 4, limit);
          if (row != 0)
@@ -10272,37 +10526,23 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
                {
                  size_t num_copy = sizeof (uint64_t);
 
-                 /* PR 23064: Beware of buffer overflow.  */
-                 if (ph + num_copy < limit)
-                   memcpy (&this_set[row - 1].signature, ph, num_copy);
-                 else
-                   {
-                     warn (_("Signature (%p) extends beyond end of space in section\n"), ph);
-                     return 0;
-                   }
+                 memcpy (&this_set[row - 1].signature, ph, num_copy);
                }
 
              prow = poffsets + (row - 1) * ncols * 4;
-             /* PR 17531: file: b8ce60a8.  */
-             if (prow < poffsets || prow > limit)
-               {
-                 warn (_("Row index (%u) * num columns (%u) > space remaining in section\n"),
-                       row, ncols);
-                 return 0;
-               }
-
              if (do_display)
                printf (_("  [%3d] 0x%s"),
-                       i, dwarf_vmatoa64 (signature_high, signature_low,
-                                          buf, sizeof (buf)));
+                       i, dwarf_vmatoa ("x", signature));
              for (j = 0; j < ncols; j++)
                {
-                 SAFE_BYTE_GET (val, prow + j * 4, 4, limit);
+                 unsigned char *p = prow + j * 4;
+                 SAFE_BYTE_GET (val, p, 4, limit);
                  if (do_display)
                    printf (" %8d", val);
                  else
                    {
-                     SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit);
+                     p = ppool + j * 4;
+                     SAFE_BYTE_GET (dw_sect, p, 4, limit);
 
                      /* PR 17531: file: 10796eb3.  */
                      if (dw_sect >= DW_SECT_MAX)
@@ -10331,7 +10571,8 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
 
       for (j = 0; j < ncols; j++)
        {
-         SAFE_BYTE_GET (val, ppool + j * 4, 4, limit);
+         unsigned char *p = ppool + j * 4;
+         SAFE_BYTE_GET (val, p, 4, limit);
          if (do_display)
            printf (" %8s", get_DW_SECT_short_name (val));
        }
@@ -10341,7 +10582,7 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
 
       for (i = 0; i < nslots; i++)
        {
-         SAFE_BYTE_GET64 (ph, &signature_high, &signature_low, limit);
+         SAFE_BYTE_GET (signature, ph, 8, limit);
 
          SAFE_BYTE_GET (row, pi, 4, limit);
          if (row != 0)
@@ -10350,17 +10591,18 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
 
              if (do_display)
                printf (_("  [%3d] 0x%s"),
-                       i, dwarf_vmatoa64 (signature_high, signature_low,
-                                          buf, sizeof (buf)));
+                       i, dwarf_vmatoa ("x", signature));
 
              for (j = 0; j < ncols; j++)
                {
-                 SAFE_BYTE_GET (val, prow + j * 4, 4, limit);
+                 unsigned char *p = prow + j * 4;
+                 SAFE_BYTE_GET (val, p, 4, limit);
                  if (do_display)
                    printf (" %8d", val);
                  else
                    {
-                     SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit);
+                     p = ppool + j * 4;
+                     SAFE_BYTE_GET (dw_sect, p, 4, limit);
                      if (dw_sect >= DW_SECT_MAX)
                        warn (_("Overlarge Dwarf section index detected: %u\n"), dw_sect);
                      else
@@ -10385,31 +10627,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.  */
@@ -10590,10 +10832,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];
@@ -10604,7 +10846,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");
@@ -10613,7 +10855,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)
@@ -10626,10 +10868,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 *
@@ -10643,8 +10885,9 @@ 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;
+  if (crc_offset == 1)
+    return NULL;
   crc_offset = (crc_offset + 3) & ~3;
   if (crc_offset + 4 > section->size)
     return NULL;
@@ -10653,18 +10896,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
@@ -10686,6 +10929,8 @@ parse_gnu_debugaltlink (struct dwarf_section * section, void * data)
 
   name = (const char *) section->start;
   namelen = strnlen (name, section->size) + 1;
+  if (namelen == 1)
+    return NULL;
   if (namelen >= section->size)
     return NULL;
 
@@ -10716,7 +10961,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)
@@ -10738,16 +10983,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)
     {
@@ -10756,7 +11001,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.  */
@@ -10773,11 +11018,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
 
@@ -10801,12 +11046,12 @@ load_separate_debug_info (const char *            main_filename,
            xlink->name ? xlink->name : xlink->uncompressed_name);
       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;
@@ -10906,44 +11151,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);
@@ -10965,7 +11218,8 @@ load_separate_debug_info (const char *            main_filename,
   /* 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
@@ -10981,8 +11235,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"));
@@ -10999,14 +11256,86 @@ load_dwo_file (const char * main_filename, const char * name, const char * dir,
   /* FIXME: We should check the dwo_id.  */
 
   printf (_("%s: Found separate debug object file: %s\n\n"), main_filename, separate_filename);
+
   add_separate_debug_file (separate_filename, separate_handle);
   /* Note - separate_filename will be freed in free_debug_memory().  */
   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;
+      int new_len;
+
+      new_len = asprintf (& new_name, "%.*s/%s",
+                         (int) (strrchr (main_filename, '/') - main_filename),
+                         main_filename,
+                         filename);
+      if (new_len < 3)
+       {
+         warn (_("unable to construct path for supplementary debug file"));
+         if (new_len > -1)
+           free (new_name);
+         return;
+       }
+      filename = new_name;
+    }
+  else
+    {
+      /* PR 27796: Make sure that we pass a filename that can be free'd to
+        add_separate_debug_file().  */
+      filename = strdup (filename);
+      if (filename == NULL)
+       {
+         warn (_("out of memory constructing filename for .debug_sup link\n"));
+         return;
+       }
+    }
+
+  void * handle = open_debug_file (filename);
+  if (handle == NULL)
+    {
+      warn (_("unable to open file '%s' referenced from .debug_sup section\n"), filename);
+      free ((void *) 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.
-   FIXME: Should also check for DWO_* entries in the newlu loaded files.  */
+   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)
@@ -11048,6 +11377,8 @@ check_for_and_load_links (void * file, const char * filename)
                                    first_separate_info->filename);
        }
     }
+
+  load_debug_sup_file (filename, file);
 }
 
 /* Load the separate debug info file(s) attached to FILE, if any exist.
@@ -11055,12 +11386,12 @@ check_for_and_load_links (void * file, const char * filename)
    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)
@@ -11069,51 +11400,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;
-
-               case DWO_ID:
-                 id = dwinfo->value;
-                 break;
+                   load_dwo_file (filename, name, dir, id);
 
-               default:
-                 error (_("Unexpected DWO INFO type"));
-                 break;
+                 name = dir = id = NULL;
                }
            }
        }
@@ -11122,7 +11474,7 @@ 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 for the presence of multiple, same-name debuglink sections.  */
@@ -11130,11 +11482,11 @@ load_separate_debug_files (void * file, const char * filename)
 
   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)
@@ -11146,7 +11498,21 @@ free_debug_memory (void)
   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);
 
@@ -11178,7 +11544,7 @@ free_debug_memory (void)
       free ((void *) d);
     }
   first_separate_info = NULL;
-  
+
   free_dwo_info ();
 }
 
@@ -11212,6 +11578,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
@@ -11241,7 +11608,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.  */
@@ -11282,6 +11649,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;
@@ -11328,59 +11696,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",        ".dwabrev", NO_ABBREVS },      display_debug_abbrev,   &do_debug_abbrevs,  false },
+  { { ".debug_aranges",            ".zdebug_aranges",       ".dwarnge", NO_ABBREVS },      display_debug_aranges,  &do_debug_aranges,  true },
+  { { ".debug_frame",      ".zdebug_frame",         ".dwframe", NO_ABBREVS },      display_debug_frames,   &do_debug_frames,   true },
+  { { ".debug_info",       ".zdebug_info",          ".dwinfo",  ABBREV (abbrev)},  display_debug_info,     &do_debug_info,     true },
+  { { ".debug_line",       ".zdebug_line",          ".dwline",  NO_ABBREVS },      display_debug_lines,    &do_debug_lines,    true },
+  { { ".debug_pubnames",    ".zdebug_pubnames",             ".dwpbnms", 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",         ".dwmac",   NO_ABBREVS },      display_debug_macro,    &do_debug_macinfo,  true },
+  { { ".debug_str",        ".zdebug_str",           ".dwstr",   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",           ".dwloc",   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",             ".dwpbtyp", 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",        ".dwrnges", 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 },
+     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 },
 };
 
 /* A static assertion.  */