Change regcache list to be an hash map
[deliverable/binutils-gdb.git] / binutils / dwarf.c
index f94f5b2fe699941b2f31c803da422b4c9b071d39..06ef1f7285e55c120fd21736c97b46d004067613 100644 (file)
@@ -1,5 +1,5 @@
 /* dwarf.c -- display DWARF contents of a BFD binary file
-   Copyright (C) 2005-2018 Free Software Foundation, Inc.
+   Copyright (C) 2005-2019 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -29,6 +29,7 @@
 #include "dwarf.h"
 #include "gdb/gdb-index.h"
 #include "filenames.h"
+#include "safe-ctype.h"
 #include <assert.h>
 
 #undef MAX
@@ -37,6 +38,7 @@
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 
 static const char *regname (unsigned int regno, int row);
+static const char *regname_internal_by_table_only (unsigned int regno);
 
 static int have_frame_base;
 static int need_base_address;
@@ -48,11 +50,26 @@ static debug_info *debug_information = NULL;
    that the .debug_info section could not be loaded/parsed.  */
 #define DEBUG_INFO_UNAVAILABLE  (unsigned int) -1
 
-static const char *           dwo_name;
-static const char *           dwo_dir;
-static const unsigned char *  dwo_id;
-static bfd_size_type          dwo_id_len;
-static bfd_boolean            need_dwo_info;
+/* A .debug_info section can contain multiple links to separate
+   DWO object files.  We use these structures to record these links.  */
+typedef enum dwo_type
+{
+ DWO_NAME,
+ DWO_DIR,
+ DWO_ID
+} dwo_type;
+
+typedef struct dwo_info
+{
+  dwo_type          type;
+  const char *      value;
+  struct dwo_info * next;
+} dwo_info;
+
+static dwo_info *   first_dwo_info = NULL;
+static bfd_boolean  need_dwo_info;
+
+separate_info * first_separate_info = NULL;
 
 unsigned int eh_addr_size;
 
@@ -96,10 +113,6 @@ static unsigned int *shndx_pool = NULL;
 static unsigned int shndx_pool_size = 0;
 static unsigned int shndx_pool_used = 0;
 
-/* Pointer to a separate file containing extra debug information.  */
-static void * separate_debug_file = NULL;
-static const char * separate_debug_filename = NULL;
-
 /* For version 2 package files, each set contains an array of section offsets
    and an array of section sizes, giving the offset and size of the
    contribution from a CU or TU within one of the debug sections.
@@ -108,9 +121,9 @@ static const char * separate_debug_filename = NULL;
 
 struct cu_tu_set
 {
-  uint64_t signature;
-  dwarf_vma section_offsets[DW_SECT_MAX];
-  size_t section_sizes[DW_SECT_MAX];
+  uint64_t   signature;
+  dwarf_vma  section_offsets[DW_SECT_MAX];
+  size_t     section_sizes[DW_SECT_MAX];
 };
 
 static int cu_count = 0;
@@ -120,6 +133,12 @@ static struct cu_tu_set *tu_sets = NULL;
 
 static bfd_boolean 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];
+
 /* Values for do_debug_lines.  */
 #define FLAG_DEBUG_LINES_RAW    1
 #define FLAG_DEBUG_LINES_DECODED 2
@@ -1575,6 +1594,25 @@ decode_location_expression (unsigned char * data,
          data += bytes_read;
          printf ("DW_OP_GNU_const_index <0x%s>", dwarf_vmatoa ("x", uvalue));
          break;
+       case DW_OP_GNU_variable_value:
+         /* FIXME: Strictly speaking for 64-bit DWARF3 files
+            this ought to be an 8-byte wide computation.  */
+         if (dwarf_version == -1)
+           {
+             printf (_("(DW_OP_GNU_variable_value in frame info)"));
+             /* No way to tell where the next op is, so just bail.  */
+             return need_frame_base;
+           }
+         if (dwarf_version == 2)
+           {
+             SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
+           }
+         else
+           {
+             SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
+           }
+         printf ("DW_OP_GNU_variable_value: <0x%s>", dwarf_vmatoa ("x", uvalue));
+         break;
 
          /* HP extensions.  */
        case DW_OP_HP_is_value:
@@ -1692,37 +1730,44 @@ add64 (dwarf_vma * high_bits, dwarf_vma * low_bits, dwarf_vma inc)
 static const char *
 fetch_alt_indirect_string (dwarf_vma offset)
 {
-  struct dwarf_section * section;
-  const char *           ret;
+  separate_info * i;
 
   if (! do_follow_links)
     return "";
 
-  if (separate_debug_file == NULL)
-    return _("<following link not possible>");
+  if (first_separate_info == NULL)
+    return _("<no links available>");
 
-  if (! load_debug_section (separate_debug_str, separate_debug_file))
-    return _("<could not load separate string section>");
+  for (i = first_separate_info; i != NULL; i = i->next)
+    {
+      struct dwarf_section * section;
+      const char *           ret;
 
-  section = &debug_displays [separate_debug_str].section;
-  if (section->start == NULL)
-    return  _("<no .debug_str section>");
+      if (! load_debug_section (separate_debug_str, i->handle))
+       continue;
 
-  if (offset >= section->size)
-    {
-      warn (_("DW_FORM_GNU_strp_alt offset too big: %s\n"), dwarf_vmatoa ("x", offset));
-      return _("<offset is too big>");
-    }
+      section = &debug_displays [separate_debug_str].section;
 
-  ret = (const char *) (section->start + offset);
-  /* Unfortunately we cannot rely upon the .debug_str section ending with a
-     NUL byte.  Since our caller is expecting to receive a well formed C
-     string we test for the lack of a terminating byte here.  */
-  if (strnlen ((const char *) ret, section->size - offset)
-      == section->size - offset)
-    return _("<no NUL byte at end of .debug_str section>");
+      if (section->start == NULL)
+       continue;
 
-  return ret;
+      if (offset >= section->size)
+       continue;
+
+      ret = (const char *) (section->start + offset);
+      /* Unfortunately we cannot rely upon the .debug_str section ending with a
+        NUL byte.  Since our caller is expecting to receive a well formed C
+        string we test for the lack of a terminating byte here.  */
+      if (strnlen ((const char *) ret, section->size - offset)
+         == section->size - offset)
+       return _("<no NUL byte at end of alt .debug_str section>");
+
+      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>");
 }
        
 static const char *
@@ -1751,10 +1796,399 @@ get_AT_name (unsigned long attribute)
   return name;
 }
 
+static void
+add_dwo_info (const char * field, dwo_type type)
+{
+  dwo_info * dwinfo = xmalloc (sizeof * dwinfo);
+
+  dwinfo->type = type;
+  dwinfo->value = field;
+  dwinfo->next = first_dwo_info;
+  first_dwo_info = dwinfo;
+}
+
+static void
+add_dwo_name (const char * name)
+{
+  add_dwo_info (name, DWO_NAME);
+}
+
+static void
+add_dwo_dir (const char * dir)
+{
+  add_dwo_info (dir, DWO_DIR);
+}
+
+static void
+add_dwo_id (const char * id)
+{
+  add_dwo_info (id, DWO_ID);
+}
+
+static void
+free_dwo_info (void)
+{
+  dwo_info * dwinfo;
+  dwo_info * next;
+
+  for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = next)
+    {
+      next = dwinfo->next;
+      free (dwinfo);
+    }
+  first_dwo_info = NULL;
+}
+
+/* Ensure that START + UVALUE is less than END.
+   Return an adjusted UVALUE if necessary to ensure this relationship.  */
+
+static inline dwarf_vma
+check_uvalue (const unsigned char * start,
+             dwarf_vma             uvalue,
+             const unsigned char * end)
+{
+  dwarf_vma max_uvalue = end - start;
+
+  /* See PR 17512: file: 008-103549-0.001:0.1.
+     and PR 24829 for examples of where these tests are triggered.  */
+  if (uvalue > max_uvalue)
+    {
+      warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
+      uvalue = max_uvalue;
+    }
+
+  return uvalue;
+}
+
+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)
+{
+  unsigned int  bytes_read;
+  dwarf_vma     uvalue = 0;
+
+  * value_return = 0;
+
+  switch (form)
+    {
+    case DW_FORM_ref_addr:
+      if (dwarf_version == 2)
+       SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
+      else if (dwarf_version == 3 || dwarf_version == 4)
+       SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
+      else
+       return NULL;
+      break;
+
+    case DW_FORM_addr:
+      SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
+      break;
+
+    case DW_FORM_strp:
+    case DW_FORM_line_strp:
+    case DW_FORM_sec_offset:
+    case DW_FORM_GNU_ref_alt:
+    case DW_FORM_GNU_strp_alt:
+      SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
+      break;
+
+    case DW_FORM_flag_present:
+      uvalue = 1;
+      break;
+
+    case DW_FORM_ref1:
+    case DW_FORM_flag:
+    case DW_FORM_data1:
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
+      break;
+
+    case DW_FORM_ref2:
+    case DW_FORM_data2:
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end);
+      break;
+
+    case DW_FORM_ref4:
+    case DW_FORM_data4:
+      SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
+      break;
+
+    case DW_FORM_sdata:
+      uvalue = read_sleb128 (data, & bytes_read, end);
+      data += bytes_read;
+      break;
+
+    case DW_FORM_ref_udata:
+    case DW_FORM_udata:
+    case DW_FORM_GNU_str_index:
+    case DW_FORM_GNU_addr_index:
+      uvalue = read_uleb128 (data, & bytes_read, end);
+      data += bytes_read;
+      break;
+
+    case DW_FORM_ref8:
+    case DW_FORM_data8:
+      data += 8;
+      break;
+
+    case DW_FORM_data16:
+      data += 16;
+      break;
+
+    case DW_FORM_string:
+      data += strnlen ((char *) data, end - data) + 1;
+      break;
+
+    case DW_FORM_block:
+    case DW_FORM_exprloc:
+      uvalue = read_uleb128 (data, & bytes_read, end);
+      data += bytes_read + uvalue;
+      break;
+
+    case DW_FORM_block1:
+      SAFE_BYTE_GET (uvalue, data, 1, end);
+      data += 1 + uvalue;
+      break;
+
+    case DW_FORM_block2:
+      SAFE_BYTE_GET (uvalue, data, 2, end);
+      data += 2 + uvalue;
+      break;
+
+    case DW_FORM_block4:
+      SAFE_BYTE_GET (uvalue, data, 4, end);
+      data += 4 + uvalue;
+      break;
+
+    case DW_FORM_ref_sig8:
+      data += 8;
+      break;
+
+    case DW_FORM_indirect:
+      /* FIXME: Handle this form.  */
+    default:
+      return NULL;
+    }
+
+  * value_return = uvalue;
+  if (data > end)
+    data = (unsigned char *) end;
+  return data;
+}
+
+/* Return IS_SIGNED set to TRUE if the type at
+   DATA can be determined to be a signed type.  */
+
+static void
+get_type_signedness (unsigned char *        start,
+                    unsigned char *        data,
+                    unsigned const char *  end,
+                    dwarf_vma              pointer_size,
+                    dwarf_vma              offset_size,
+                    int                    dwarf_version,
+                    bfd_boolean *          is_signed,
+                    bfd_boolean            is_nested)
+{
+  unsigned long   abbrev_number;
+  unsigned int    bytes_read;
+  abbrev_entry *  entry;
+  abbrev_attr *   attr;
+
+  * is_signed = FALSE;
+
+  abbrev_number = read_uleb128 (data, & bytes_read, end);
+  data += bytes_read;
+
+  for (entry = first_abbrev;
+       entry != NULL && entry->entry != abbrev_number;
+       entry = entry->next)
+    continue;
+
+  if (entry == NULL)
+    /* FIXME: Issue a warning ?  */
+    return;
+
+  for (attr = entry->first_attr;
+       attr != NULL && attr->attribute;
+       attr = attr->next)
+    {
+      dwarf_vma uvalue = 0;
+
+      data = skip_attr_bytes (attr->form, data, end, pointer_size,
+                             offset_size, dwarf_version, & uvalue);
+      if (data == NULL)
+       return;
+
+      switch (attr->attribute)
+       {
+#if 0 /* FIXME: It would be nice to print the name of the type,
+        but this would mean updating a lot of binutils tests.  */
+       case DW_AT_name:
+         if (attr->form == DW_FORM_strp)
+           printf ("%s", fetch_indirect_string (uvalue));
+         break;
+#endif
+       case DW_AT_type:
+         /* Recurse.  */
+         if (is_nested)
+           {
+             /* FIXME: Warn - or is this expected ?
+                NB/ We need to avoid infinite recursion.  */
+             return;
+           }
+         if (uvalue >= (size_t) (end - start))
+           return;
+         get_type_signedness (start, start + uvalue, end, pointer_size,
+                              offset_size, dwarf_version, is_signed, TRUE);
+         break;
+
+       case DW_AT_encoding:
+         /* Determine signness.  */
+         switch (uvalue)
+           {
+           case DW_ATE_address:
+             /* FIXME - some architectures have signed addresses.  */
+           case DW_ATE_boolean:
+           case DW_ATE_unsigned:
+           case DW_ATE_unsigned_char:
+           case DW_ATE_unsigned_fixed:
+             * is_signed = FALSE;
+             break;
+
+           default:
+           case DW_ATE_complex_float:
+           case DW_ATE_float:
+           case DW_ATE_signed:
+           case DW_ATE_signed_char:
+           case DW_ATE_imaginary_float:
+           case DW_ATE_decimal_float:
+           case DW_ATE_signed_fixed:
+             * is_signed = TRUE;
+             break;
+           }
+         break;
+       }
+    }
+}
+
+static void
+read_and_print_leb128 (unsigned char *        data,
+                      unsigned int *         bytes_read,
+                      unsigned const char *  end,
+                      bfd_boolean            is_signed)
+{
+  if (is_signed)
+    {
+      dwarf_signed_vma sval = read_sleb128 (data, bytes_read, end);
+      printf ("%ld", (long) sval);
+    }
+  else
+    {
+      dwarf_vma uval = read_uleb128 (data, bytes_read, end);
+      printf ("%lu", (unsigned long) uval);
+    }
+}
+
+static void
+display_discr_list (unsigned long          form,
+                   dwarf_vma              uvalue,
+                   unsigned char *        data,
+                   unsigned const char *  end,
+                   int                    level)
+{
+  if (uvalue == 0)
+    {
+      printf ("[default]");
+      return;
+    }
+  
+  switch (form)
+    {
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+      /* Move data pointer back to the start of the byte array.  */
+      data -= uvalue;
+      break;
+    default:
+      printf ("<corrupt>\n");
+      warn (_("corrupt discr_list - not using a block form\n"));
+      return;
+    }
+
+  if (uvalue < 2)
+    {
+      printf ("<corrupt>\n");
+      warn (_("corrupt discr_list - block not long enough\n"));
+      return;
+    }
+
+  bfd_boolean is_signed =
+    (level > 0 && level <= MAX_CU_NESTING)
+    ? level_type_signed [level - 1] : FALSE;
+    
+  printf ("(");
+  while (uvalue)
+    {
+      unsigned char     discriminant;
+      unsigned int      bytes_read;
+
+      SAFE_BYTE_GET (discriminant, data, 1, end);
+      -- uvalue;
+      data ++;
+
+      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"),
+               discriminant);
+         return;
+       }
+
+      if (uvalue)
+       printf (", ");
+    }
+
+  if (is_signed)
+    printf (")(signed)");
+  else
+    printf (")(unsigned)");
+}
+
 static unsigned char *
 read_and_display_attr_value (unsigned long           attribute,
                             unsigned long           form,
                             dwarf_signed_vma        implicit_const,
+                            unsigned char *         start,
                             unsigned char *         data,
                             unsigned char *         end,
                             dwarf_vma               cu_offset,
@@ -1765,12 +2199,13 @@ read_and_display_attr_value (unsigned long           attribute,
                             int                     do_loc,
                             struct dwarf_section *  section,
                             struct cu_tu_set *      this_set,
-                            char                    delimiter)
+                            char                    delimiter,
+                            int                     level)
 {
-  dwarf_vma uvalue = 0;
-  unsigned char *block_start = NULL;
-  unsigned char * orig_data = data;
-  unsigned int bytes_read;
+  dwarf_vma        uvalue = 0;
+  unsigned char *  block_start = NULL;
+  unsigned char *  orig_data = data;
+  unsigned int     bytes_read;
 
   if (data > end || (data == end && form != DW_FORM_flag_present))
     {
@@ -1851,11 +2286,12 @@ read_and_display_attr_value (unsigned long           attribute,
          implicit_const = read_sleb128 (data, & bytes_read, end);
          data += bytes_read;
        }
-      return read_and_display_attr_value (attribute, form, implicit_const, data,
-                                         end, cu_offset, pointer_size,
+      return read_and_display_attr_value (attribute, form, implicit_const,
+                                         start, data, end,
+                                         cu_offset, pointer_size,
                                          offset_size, dwarf_version,
                                          debug_info_p, do_loc,
-                                         section, this_set, delimiter);
+                                         section, this_set, delimiter, level);
     case DW_FORM_GNU_addr_index:
       uvalue = read_uleb128 (data, & bytes_read, end);
       data += bytes_read;
@@ -1975,16 +2411,9 @@ read_and_display_attr_value (unsigned long           attribute,
          uvalue = 0;
          block_start = end;
        }
-      /* FIXME: Testing "(block_start + uvalue) < block_start" miscompiles with
-        gcc 4.8.3 running on an x86_64 host in 32-bit mode.  So we pre-compute
-        block_start + uvalue here.  */
-      data = block_start + uvalue;
-      /* PR 17512: file: 008-103549-0.001:0.1.  */
-      if (block_start + uvalue > end || data < block_start)
-       {
-         warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
-         uvalue = end - block_start;
-       }
+
+      uvalue = check_uvalue (block_start, uvalue, end);
+
       if (do_loc)
        data = block_start + uvalue;
       else
@@ -2000,12 +2429,9 @@ read_and_display_attr_value (unsigned long           attribute,
          uvalue = 0;
          block_start = end;
        }
-      data = block_start + uvalue;
-      if (block_start + uvalue > end || data < block_start)
-       {
-         warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
-         uvalue = end - block_start;
-       }
+
+      uvalue = check_uvalue (block_start, uvalue, end);
+
       if (do_loc)
        data = block_start + uvalue;
       else
@@ -2021,12 +2447,9 @@ read_and_display_attr_value (unsigned long           attribute,
          uvalue = 0;
          block_start = end;
        }
-      data = block_start + uvalue;
-      if (block_start + uvalue > end || data < block_start)
-       {
-         warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
-         uvalue = end - block_start;
-       }
+
+      uvalue = check_uvalue (block_start, uvalue, end);
+
       if (do_loc)
        data = block_start + uvalue;
       else
@@ -2043,14 +2466,9 @@ read_and_display_attr_value (unsigned long           attribute,
          uvalue = 0;
          block_start = end;
        }
-      data = block_start + uvalue;
-      if (block_start + uvalue > end
-         /* PR 17531: file: 5b5f0592.  */
-         || data < block_start)
-       {
-         warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
-         uvalue = end - block_start;
-       }
+
+      uvalue = check_uvalue (block_start, uvalue, end);
+
       if (do_loc)
        data = block_start + uvalue;
       else
@@ -2174,19 +2592,28 @@ read_and_display_attr_value (unsigned long           attribute,
              debug_info_p->have_frame_base [num] = have_frame_base;
              if (attribute != DW_AT_GNU_locviews)
                {
-                 debug_info_p->loc_offsets [num] = uvalue;
-                 debug_info_p->num_loc_offsets++;
-                 assert (debug_info_p->num_loc_offsets
-                         - debug_info_p->num_loc_views <= 1);
+                 /* Corrupt DWARF info can produce more offsets than views.
+                    See PR 23062 for an example.  */
+                 if (debug_info_p->num_loc_offsets
+                     > debug_info_p->num_loc_views)
+                   warn (_("More location offset attributes than DW_AT_GNU_locview attributes\n"));
+                 else
+                   {
+                     debug_info_p->loc_offsets [num] = uvalue;
+                     debug_info_p->num_loc_offsets++;
+                   }
                }
              else
                {
                  assert (debug_info_p->num_loc_views <= num);
                  num = debug_info_p->num_loc_views;
-                 debug_info_p->loc_views [num] = uvalue;
-                 debug_info_p->num_loc_views++;
-                 assert (debug_info_p->num_loc_views
-                         - debug_info_p->num_loc_offsets <= 1);
+                 if (num > debug_info_p->num_loc_offsets)
+                   warn (_("More DW_AT_GNU_locview attributes than location offset attributes\n"));
+                 else
+                   {
+                     debug_info_p->loc_views [num] = uvalue;
+                     debug_info_p->num_loc_views++;
+                   }
                }
            }
          break;
@@ -2232,18 +2659,17 @@ read_and_display_attr_value (unsigned long           attribute,
            switch (form)
              {
              case DW_FORM_strp:
-               dwo_name = (const char *) fetch_indirect_string (uvalue);
+               add_dwo_name ((const char *) fetch_indirect_string (uvalue));
                break;
              case DW_FORM_GNU_str_index:
-               dwo_name = fetch_indexed_string (uvalue, this_set, offset_size, FALSE);
+               add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
                break;
              case DW_FORM_string:
-               dwo_name = (const char *) orig_data;
+               add_dwo_name ((const char *) orig_data);
                break;
              default:
                warn (_("Unsupported form (%s) for attribute %s\n"),
                      get_FORM_name (form), get_AT_name (attribute));
-               dwo_name = _("<unknown>");
                break;
              }
          break;
@@ -2254,21 +2680,20 @@ read_and_display_attr_value (unsigned long           attribute,
            switch (form)
              {
              case DW_FORM_strp:
-               dwo_dir = (const char *) fetch_indirect_string (uvalue);
+               add_dwo_dir ((const char *) fetch_indirect_string (uvalue));
                break;
              case DW_FORM_line_strp:
-               dwo_dir = (const char *) fetch_indirect_line_string (uvalue);
+               add_dwo_dir ((const char *) fetch_indirect_line_string (uvalue));
                break;
              case DW_FORM_GNU_str_index:
-               dwo_dir = fetch_indexed_string (uvalue, this_set, offset_size, FALSE);
+               add_dwo_dir (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
                break;
              case DW_FORM_string:
-               dwo_dir = (const char *) orig_data;
+               add_dwo_dir ((const char *) orig_data);
                break;
              default:
                warn (_("Unsupported form (%s) for attribute %s\n"),
                      get_FORM_name (form), get_AT_name (attribute));
-               dwo_dir = _("<unknown>");
                break;
              }
          break;
@@ -2278,13 +2703,12 @@ read_and_display_attr_value (unsigned long           attribute,
            switch (form)
              {
              case DW_FORM_data8:
-               dwo_id = data - 8;
-               dwo_id_len = 8;
+               /* FIXME: Record the length of the ID as well ?  */
+               add_dwo_id ((const char *) (data - 8));
                break;
              default:
                warn (_("Unsupported form (%s) for attribute %s\n"),
                      get_FORM_name (form), get_AT_name (attribute));
-               dwo_id = NULL;
                break;
              }
          break;
@@ -2300,6 +2724,18 @@ read_and_display_attr_value (unsigned long           attribute,
   /* For some attributes we can display further information.  */
   switch (attribute)
     {
+    case DW_AT_type:
+      if (level >= 0 && level < MAX_CU_NESTING
+         && uvalue < (size_t) (end - start))
+       {
+         bfd_boolean is_signed = FALSE;
+
+         get_type_signedness (start, start + uvalue, end, pointer_size,
+                              offset_size, dwarf_version, & is_signed, FALSE);
+         level_type_signed[level] = is_signed;
+       }
+      break;
+      
     case DW_AT_inline:
       printf ("\t");
       switch (uvalue)
@@ -2549,12 +2985,7 @@ read_and_display_attr_value (unsigned long           attribute,
 
     case DW_AT_discr_list:
       printf ("\t");
-      switch (uvalue)
-       {
-       case DW_DSC_label:  printf (_("(label)")); break;
-       case DW_DSC_range:  printf (_("(range)")); break;
-       default:            printf (_("(unrecognised)")); break;
-       }
+      display_discr_list (form, uvalue, data, end, level);
       break;
       
     case DW_AT_frame_base:
@@ -2671,6 +3102,7 @@ static unsigned char *
 read_and_display_attr (unsigned long           attribute,
                       unsigned long           form,
                       dwarf_signed_vma        implicit_const,
+                      unsigned char *         start,
                       unsigned char *         data,
                       unsigned char *         end,
                       dwarf_vma               cu_offset,
@@ -2680,44 +3112,63 @@ read_and_display_attr (unsigned long           attribute,
                       debug_info *            debug_info_p,
                       int                     do_loc,
                       struct dwarf_section *  section,
-                      struct cu_tu_set *      this_set)
+                      struct cu_tu_set *      this_set,
+                      int                     level)
 {
   if (!do_loc)
     printf ("   %-18s:", get_AT_name (attribute));
-  data = read_and_display_attr_value (attribute, form, implicit_const, data, end,
+  data = read_and_display_attr_value (attribute, form, implicit_const,
+                                     start, data, end,
                                      cu_offset, pointer_size, offset_size,
                                      dwarf_version, debug_info_p,
-                                     do_loc, section, this_set, ' ');
+                                     do_loc, section, this_set, ' ', level);
   if (!do_loc)
     printf ("\n");
   return data;
 }
 
 /* Like load_debug_section, but if the ordinary call fails, and we are
-   following debug links, and we have been able to load a separate debug
-   info file, then attempt to load the requested section from the separate
-   file.  */
+   following debug links, then attempt to load the requested section
+   from one of the separate debug info files.  */
 
 static bfd_boolean
 load_debug_section_with_follow (enum dwarf_section_display_enum sec_enum,
-                               void * data)
+                               void * handle)
 {
-  if (load_debug_section (sec_enum, data))
+  if (load_debug_section (sec_enum, handle))
     {
-      if (data == separate_debug_file)
-       debug_displays[sec_enum].section.filename = separate_debug_filename;
-       
-      /* FIXME: We should check to see if there is a separate debug info file
-        that also contains this section, and if so, issue a warning.  */
+      if (debug_displays[sec_enum].section.filename == NULL)
+       {
+         /* See if we can associate a filename with this section.  */
+         separate_info * i;
+
+         for (i = first_separate_info; i != NULL; i = i->next)
+           if (i->handle == handle)
+             {
+               debug_displays[sec_enum].section.filename = i->filename;
+               break;
+             }
+       }
+
       return TRUE;
     }
 
-  if (do_follow_links && separate_debug_file != NULL)
-    if (load_debug_section (sec_enum, separate_debug_file))
-      {
-       debug_displays[sec_enum].section.filename = separate_debug_filename;
-       return TRUE;
-      }
+  if (do_follow_links)
+    {
+      separate_info * i;
+
+      for (i = first_separate_info; i != NULL; i = i->next)
+       {
+         if (load_debug_section (sec_enum, i->handle))
+           {
+             debug_displays[sec_enum].section.filename = i->filename;
+
+             /* 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 FALSE;
 }
@@ -3193,10 +3644,10 @@ process_debug_info (struct dwarf_section *           section,
              if (! do_loc && do_printing)
                /* Show the offset from where the tag was extracted.  */
                printf ("    <%lx>", (unsigned long)(tags - section_begin));
-
              tags = read_and_display_attr (attr->attribute,
                                            attr->form,
                                            attr->implicit_const,
+                                           section_begin,
                                            tags,
                                            end,
                                            cu_offset,
@@ -3206,7 +3657,8 @@ process_debug_info (struct dwarf_section *           section,
                                            debug_info_p,
                                            do_loc || ! do_printing,
                                            section,
-                                           this_set);
+                                           this_set,
+                                           level);
            }
 
          /* If a locview attribute appears before a location one,
@@ -3415,7 +3867,7 @@ display_formatted_table (unsigned char *                   data,
                         unsigned char *                   end,
                         const DWARF2_Internal_LineInfo *  linfo,
                         struct dwarf_section *            section,
-                        const char *                      what)
+                        bfd_boolean                       is_dir)
 {
   unsigned char *format_start, format_count, *format, formati;
   dwarf_vma data_count, datai;
@@ -3431,7 +3883,10 @@ display_formatted_table (unsigned char *                   data,
       data += bytes_read;
       if (data == end)
        {
-         warn (_("Corrupt %s format table entry\n"), what);
+         if (is_dir)
+           warn (_("Corrupt directory format table entry\n"));
+         else
+           warn (_("Corrupt file name format table entry\n"));
          return data;
        }
     }
@@ -3440,18 +3895,28 @@ display_formatted_table (unsigned char *                   data,
   data += bytes_read;
   if (data == end)
     {
-      warn (_("Corrupt %s list\n"), what);
+      if (is_dir)
+       warn (_("Corrupt directory list\n"));
+      else
+       warn (_("Corrupt file name list\n"));
       return data;
     }
 
   if (data_count == 0)
     {
-      printf (_("\n The %s Table is empty.\n"), what);
+      if (is_dir)
+       printf (_("\n The Directory Table is empty.\n"));
+      else
+       printf (_("\n The File Name Table is empty.\n"));
       return data;
     }
 
-  printf (_("\n The %s Table (offset 0x%lx):\n"), what,
-         (long)(data - start));
+  if (is_dir)
+    printf (_("\n The Directory Table (offset 0x%lx):\n"),
+           (long) (data - start));
+  else
+    printf (_("\n The File Name Table (offset 0x%lx):\n"),
+           (long) (data - start));
 
   printf (_("  Entry"));
   /* Delay displaying name as the last entry for better screen layout.  */ 
@@ -3510,16 +3975,19 @@ display_formatted_table (unsigned char *                   data,
              format += bytes_read;
              form = read_uleb128 (format, & bytes_read, end);
              format += bytes_read;
-             data = read_and_display_attr_value (0, form, 0, data, end, 0, 0,
+             data = read_and_display_attr_value (0, form, 0, start, data, end, 0, 0,
                                                  linfo->li_offset_size,
                                                  linfo->li_version, NULL,
                            ((content_type == DW_LNCT_path) != (namepass == 1)),
-                                                 section, NULL, '\t');
+                                                 section, NULL, '\t', -1);
            }
        }
       if (data == end)
        {
-         warn (_("Corrupt %s entries list\n"), what);
+         if (is_dir)
+           warn (_("Corrupt directory entries list\n"));
+         else
+           warn (_("Corrupt file name entries list\n"));
          return data;
        }
       putchar ('\n');
@@ -3627,9 +4095,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,
-                                             _("Directory"));
+                                             TRUE);
              data = display_formatted_table (data, start, end, &linfo, section,
-                                             _("File name"));
+                                             FALSE);
            }
          else
            {
@@ -3951,6 +4419,7 @@ typedef struct
 
 static int
 display_debug_lines_decoded (struct dwarf_section *  section,
+                            unsigned char *         start,
                             unsigned char *         data,
                             unsigned char *         end,
                             void *                  fileptr)
@@ -4084,12 +4553,12 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                            }
                          break;
                        }
-                     data = read_and_display_attr_value (0, form, 0, data, end,
+                     data = read_and_display_attr_value (0, form, 0, start, data, end,
                                                          0, 0,
                                                          linfo.li_offset_size,
                                                          linfo.li_version,
                                                          NULL, 1, section,
-                                                         NULL, '\t');
+                                                         NULL, '\t', -1);
                    }
                  if (data == end)
                    {
@@ -4174,12 +4643,12 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                            }
                          break;
                        }
-                     data = read_and_display_attr_value (0, form, 0, data, end,
+                     data = read_and_display_attr_value (0, form, 0, start, data, end,
                                                          0, 0,
                                                          linfo.li_offset_size,
                                                          linfo.li_version,
                                                          NULL, 1, section,
-                                                         NULL, '\t');
+                                                         NULL, '\t', -1);
                    }
                  if (data == end)
                    {
@@ -4313,7 +4782,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                printf ("%s:\n", file_table[0].name);
            }
 
-         printf (_("File name                            Line number    Starting address    View\n"));
+         printf (_("File name                            Line number    Starting address    View    Stmt\n"));
          saved_linfo = linfo;
        }
 
@@ -4651,9 +5120,14 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                }
 
              if (state_machine_regs.view)
-               printf ("  %6u\n", state_machine_regs.view);
+               printf ("  %6u", state_machine_regs.view);
              else
-               putchar ('\n');
+               printf ("        ");
+
+             if (state_machine_regs.is_stmt)
+               printf ("       x");
+
+             putchar ('\n');
              state_machine_regs.view++;
 
              if (xop == -DW_LNE_end_sequence)
@@ -4701,7 +5175,7 @@ display_debug_lines (struct dwarf_section *section, void *file)
     retValRaw = display_debug_lines_raw (section, data, end, file);
 
   if (do_debug_lines & FLAG_DEBUG_LINES_DECODED)
-    retValDecoded = display_debug_lines_decoded (section, data, end, file);
+    retValDecoded = display_debug_lines_decoded (section, data, data, end, file);
 
   if (!retValRaw || !retValDecoded)
     return 0;
@@ -5306,9 +5780,9 @@ display_debug_macro (struct dwarf_section *section,
                      SAFE_BYTE_GET_AND_INC (val, desc, 1, end);
                      curr
                        = read_and_display_attr_value (0, val, 0,
-                                                      curr, end, 0, 0, offset_size,
+                                                      start, curr, end, 0, 0, offset_size,
                                                       version, NULL, 0, NULL,
-                                                      NULL, ' ');
+                                                      NULL, ' ', -1);
                      if (n != nargs - 1)
                        printf (",");
                    }
@@ -5954,12 +6428,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, '.');
-  int is_dwo = 0;
+  bfd_boolean 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 = 1;
+    is_dwo = TRUE;
 
   bytes = section->size;
 
@@ -6421,8 +6895,8 @@ display_debug_aranges (struct dwarf_section *section,
 static int
 comp_addr_base (const void * v0, const void * v1)
 {
-  debug_info * info0 = (debug_info *) v0;
-  debug_info * info1 = (debug_info *) v1;
+  debug_info *info0 = *(debug_info **) v0;
+  debug_info *info1 = *(debug_info **) v1;
   return info0->addr_base - info1->addr_base;
 }
 
@@ -6505,6 +6979,7 @@ display_debug_addr (struct dwarf_section *section,
 }
 
 /* Display the .debug_str_offsets and .debug_str_offsets.dwo sections.  */
+
 static int
 display_debug_str_offsets (struct dwarf_section *section,
                           void *file ATTRIBUTE_UNUSED)
@@ -6886,9 +7361,12 @@ typedef struct Frame_Chunk
 }
 Frame_Chunk;
 
+typedef const char *(*dwarf_regname_lookup_ftype) (unsigned int);
+static dwarf_regname_lookup_ftype dwarf_regnames_lookup_func;
 static const char *const *dwarf_regnames;
 static unsigned int dwarf_regnames_count;
 
+
 /* A marker for a col_type that means this column was never referenced
    in the frame info.  */
 #define DW_CFA_unreferenced (-1)
@@ -6904,7 +7382,7 @@ frame_need_space (Frame_Chunk *fc, unsigned int reg)
   if (reg < (unsigned int) fc->ncols)
     return 0;
 
-  if (dwarf_regnames_count
+  if (dwarf_regnames_count > 0
       && reg > dwarf_regnames_count)
     return -1;
 
@@ -6915,7 +7393,7 @@ frame_need_space (Frame_Chunk *fc, unsigned int reg)
     return -1;
 
   /* PR 17512: file: 2844a11d.  */
-  if (fc->ncols > 1024)
+  if (fc->ncols > 1024 && dwarf_regnames_count == 0)
     {
       error (_("Unfeasibly large register number: %u\n"), reg);
       fc->ncols = 0;
@@ -6990,18 +7468,20 @@ static const char *const dwarf_regnames_iamcu[] =
   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL  /* 93 - 100  */
 };
 
-void
+static void
 init_dwarf_regnames_i386 (void)
 {
   dwarf_regnames = dwarf_regnames_i386;
   dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_i386);
+  dwarf_regnames_lookup_func = regname_internal_by_table_only;
 }
 
-void
+static void
 init_dwarf_regnames_iamcu (void)
 {
   dwarf_regnames = dwarf_regnames_iamcu;
   dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_iamcu);
+  dwarf_regnames_lookup_func = regname_internal_by_table_only;
 }
 
 static const char *const dwarf_regnames_x86_64[] =
@@ -7036,11 +7516,12 @@ static const char *const dwarf_regnames_x86_64[] =
   "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7"
 };
 
-void
+static void
 init_dwarf_regnames_x86_64 (void)
 {
   dwarf_regnames = dwarf_regnames_x86_64;
   dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_x86_64);
+  dwarf_regnames_lookup_func = regname_internal_by_table_only;
 }
 
 static const char *const dwarf_regnames_aarch64[] =
@@ -7050,20 +7531,25 @@ static const char *const dwarf_regnames_aarch64[] =
   "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
   "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp",
    NULL, "elr",  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
-   NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
-   NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
-   NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+   NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  "vg", "ffr",
+   "p0",  "p1",  "p2",  "p3",  "p4",  "p5",  "p6",  "p7",
+   "p8",  "p9", "p10", "p11", "p12", "p13", "p14", "p15",
    "v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",
    "v8",  "v9", "v10", "v11", "v12", "v13", "v14", "v15",
   "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
   "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
+   "z0",  "z1",  "z2",  "z3",  "z4",  "z5",  "z6",  "z7",
+   "z8",  "z9", "z10", "z11", "z12", "z13", "z14", "z15",
+  "z16", "z17", "z18", "z19", "z20", "z21", "z22", "z23",
+  "z24", "z25", "z26", "z27", "z28", "z29", "z30", "z31",
 };
 
-void
+static void
 init_dwarf_regnames_aarch64 (void)
 {
   dwarf_regnames = dwarf_regnames_aarch64;
   dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_aarch64);
+  dwarf_regnames_lookup_func = regname_internal_by_table_only;
 }
 
 static const char *const dwarf_regnames_s390[] =
@@ -7083,11 +7569,12 @@ static const char *const dwarf_regnames_s390[] =
   "v24", "v26", "v28", "v30", "v25", "v27", "v29", "v31",
 };
 
-void
+static void
 init_dwarf_regnames_s390 (void)
 {
   dwarf_regnames = dwarf_regnames_s390;
   dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_s390);
+  dwarf_regnames_lookup_func = regname_internal_by_table_only;
 }
 
 static const char *const dwarf_regnames_riscv[] =
@@ -7104,16 +7591,54 @@ static const char *const dwarf_regnames_riscv[] =
  "ft8",  "ft9",  "ft10", "ft11"                             /* 60 - 63 */
 };
 
-void
+/* A RISC-V replacement for REGNAME_INTERNAL_BY_TABLE_ONLY which handles
+   the large number of CSRs.  */
+
+static const char *
+regname_internal_riscv (unsigned int regno)
+{
+  const char *name = NULL;
+
+  /* Lookup in the table first, this covers GPR and FPR.  */
+  if (regno < ARRAY_SIZE (dwarf_regnames_riscv))
+    name = dwarf_regnames_riscv [regno];
+  else if (regno >= 4096 && regno <= 8191)
+    {
+      /* This might be a CSR, these live in a sparse number space from 4096
+        to 8191  These numbers are defined in the RISC-V ELF ABI
+        document.  */
+      switch (regno)
+       {
+#define DECLARE_CSR(NAME,VALUE) case VALUE + 4096: name = #NAME; break;
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+
+       default:
+         {
+           static char csr_name[10];
+           snprintf (csr_name, sizeof (csr_name), "csr%d", (regno - 4096));
+           name = csr_name;
+         }
+         break;
+       }
+    }
+
+  return name;
+}
+
+static void
 init_dwarf_regnames_riscv (void)
 {
-  dwarf_regnames = dwarf_regnames_riscv;
-  dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_riscv);
+  dwarf_regnames = NULL;
+  dwarf_regnames_count = 8192;
+  dwarf_regnames_lookup_func = regname_internal_riscv;
 }
 
 void
-init_dwarf_regnames (unsigned int e_machine)
+init_dwarf_regnames_by_elf_machine_code (unsigned int e_machine)
 {
+  dwarf_regnames_lookup_func = NULL;
+
   switch (e_machine)
     {
     case EM_386:
@@ -7147,19 +7672,82 @@ init_dwarf_regnames (unsigned int e_machine)
     }
 }
 
-static const char *
-regname (unsigned int regno, int row)
+/* Initialize the DWARF register name lookup state based on the
+   architecture and specific machine type of a BFD.  */
+
+void
+init_dwarf_regnames_by_bfd_arch_and_mach (enum bfd_architecture arch,
+                                         unsigned long mach)
 {
-  static char reg[64];
+  dwarf_regnames_lookup_func = NULL;
+
+  switch (arch)
+    {
+    case bfd_arch_i386:
+      switch (mach)
+       {
+       case bfd_mach_x86_64:
+       case bfd_mach_x86_64_intel_syntax:
+       case bfd_mach_x86_64_nacl:
+       case bfd_mach_x64_32:
+       case bfd_mach_x64_32_intel_syntax:
+       case bfd_mach_x64_32_nacl:
+         init_dwarf_regnames_x86_64 ();
+         break;
+
+       default:
+         init_dwarf_regnames_i386 ();
+         break;
+       }
+      break;
+
+    case bfd_arch_iamcu:
+      init_dwarf_regnames_iamcu ();
+      break;
+
+    case bfd_arch_aarch64:
+      init_dwarf_regnames_aarch64();
+      break;
+
+    case bfd_arch_s390:
+      init_dwarf_regnames_s390 ();
+      break;
 
-  if (dwarf_regnames
+    case bfd_arch_riscv:
+      init_dwarf_regnames_riscv ();
+      break;
+
+    default:
+      break;
+    }
+}
+
+static const char *
+regname_internal_by_table_only (unsigned int regno)
+{
+  if (dwarf_regnames != NULL
       && regno < dwarf_regnames_count
       && dwarf_regnames [regno] != NULL)
+    return dwarf_regnames [regno];
+
+  return NULL;
+}
+
+static const char *
+regname (unsigned int regno, int name_only_p)
+{
+  static char reg[64];
+
+  const char *name = NULL;
+
+  if (dwarf_regnames_lookup_func != NULL)
+    name = dwarf_regnames_lookup_func (regno);
+
+  if (name != NULL)
     {
-      if (row)
-       return dwarf_regnames [regno];
-      snprintf (reg, sizeof (reg), "r%d (%s)", regno,
-               dwarf_regnames [regno]);
+      if (name_only_p)
+       return name;
+      snprintf (reg, sizeof (reg), "r%d (%s)", regno, name);
     }
   else
     snprintf (reg, sizeof (reg), "r%d", regno);
@@ -7274,7 +7862,7 @@ read_cie (unsigned char *start, unsigned char *end,
   if (start == end)
     {
       warn (_("No terminator for augmentation name\n"));
-      return start;
+      goto fail;
     }
 
   if (strcmp (fc->augmentation, "eh") == 0)
@@ -7286,7 +7874,7 @@ read_cie (unsigned char *start, unsigned char *end,
       if (fc->ptr_size < 1 || fc->ptr_size > 8)
        {
          warn (_("Invalid pointer size (%d) in CIE data\n"), fc->ptr_size);
-         return end;
+         goto fail;
        }
 
       GET (fc->segment_size, 1);
@@ -7294,7 +7882,7 @@ read_cie (unsigned char *start, unsigned char *end,
       if (fc->segment_size > 8 || fc->segment_size + fc->ptr_size > 8)
        {
          warn (_("Invalid segment size (%d) in CIE data\n"), fc->segment_size);
-         return end;
+         goto fail;
        }
 
       eh_addr_size = fc->ptr_size;
@@ -7304,8 +7892,10 @@ read_cie (unsigned char *start, unsigned char *end,
       fc->ptr_size = eh_addr_size;
       fc->segment_size = 0;
     }
+
   READ_ULEB (fc->code_factor);
   READ_SLEB (fc->data_factor);
+
   if (version == 1)
     {
       GET (fc->ra, 1);
@@ -7325,7 +7915,7 @@ read_cie (unsigned char *start, unsigned char *end,
          warn (_("Augmentation data too long: 0x%s, expected at most %#lx\n"),
                dwarf_vmatoa ("x", augmentation_data_len),
                (unsigned long) (end - start));
-         return end;
+         goto fail;
        }
       start += augmentation_data_len;
     }
@@ -7350,6 +7940,8 @@ read_cie (unsigned char *start, unsigned char *end,
            fc->fde_encoding = *q++;
          else if (*p == 'S')
            ;
+         else if (*p == 'B')
+           ;
          else
            break;
          p++;
@@ -7367,6 +7959,12 @@ read_cie (unsigned char *start, unsigned char *end,
       *p_aug = augmentation_data;
     }
   return start;
+
+ fail:
+  free (fc->col_offset);
+  free (fc->col_type);
+  free (fc);
+  return end;
 }
 
 /* Prints out the contents on the DATA array formatted as unsigned bytes.
@@ -7412,10 +8010,10 @@ display_debug_frames (struct dwarf_section *section,
   unsigned char *start = section->start;
   unsigned char *end = start + section->size;
   unsigned char *section_start = start;
-  Frame_Chunk *chunks = 0, *forward_refs = 0;
-  Frame_Chunk *remembered_state = 0;
+  Frame_Chunk *chunks = NULL, *forward_refs = NULL;
+  Frame_Chunk *remembered_state = NULL;
   Frame_Chunk *rs;
-  int is_eh = strcmp (section->name, ".eh_frame") == 0;
+  bfd_boolean is_eh = strcmp (section->name, ".eh_frame") == 0;
   unsigned int length_return;
   unsigned int max_regs = 0;
   const char *bad_reg = _("bad register: ");
@@ -7683,18 +8281,18 @@ display_debug_frames (struct dwarf_section *section,
            {
              READ_ULEB (augmentation_data_len);
              augmentation_data = start;
-             start += augmentation_data_len;
              /* PR 17512 file: 722-8446-0.004 and PR 22386.  */
-             if (start >= end
-                 || ((bfd_signed_vma) augmentation_data_len) < 0
-                 || augmentation_data > start)
+             if (augmentation_data_len > (bfd_size_type) (end - start))
                {
-                 warn (_("Corrupt augmentation data length: 0x%s\n"),
-                       dwarf_vmatoa ("x", augmentation_data_len));
+                 warn (_("Augmentation data too long: 0x%s, "
+                         "expected at most %#lx\n"),
+                       dwarf_vmatoa ("x", augmentation_data_len),
+                       (unsigned long) (end - start));
                  start = end;
                  augmentation_data = NULL;
                  augmentation_data_len = 0;
                }
+             start += augmentation_data_len;
            }
 
          printf ("\n%08lx %s %s FDE cie=%08lx pc=",
@@ -8348,6 +8946,36 @@ display_debug_frames (struct dwarf_section *section,
 
   printf ("\n");
 
+  while (remembered_state != NULL)
+    {
+      rs = remembered_state;
+      remembered_state = rs->next;
+      free (rs->col_type);
+      free (rs->col_offset);
+      rs->next = NULL; /* Paranoia.  */
+      free (rs);
+    }
+
+  while (chunks != NULL)
+    {
+      rs = chunks;
+      chunks = rs->next;
+      free (rs->col_type);
+      free (rs->col_offset);
+      rs->next = NULL; /* Paranoia.  */
+      free (rs);
+    }
+
+  while (forward_refs != NULL)
+    {
+      rs = forward_refs;
+      forward_refs = rs->next;
+      free (rs->col_type);
+      free (rs->col_offset);
+      rs->next = NULL; /* Paranoia.  */
+      free (rs);
+    }
+
   return 1;
 }
 
@@ -8375,6 +9003,8 @@ display_debug_names (struct dwarf_section *section, void *file)
       uint32_t augmentation_string_size;
       unsigned int i;
       unsigned long sec_off;
+      bfd_boolean augmentation_printable;
+      const char *augmentation_string;
 
       unit_start = hdrptr;
 
@@ -8438,15 +9068,32 @@ display_debug_names (struct dwarf_section *section, void *file)
                augmentation_string_size);
          augmentation_string_size += (-augmentation_string_size) & 3;
        }
+
       printf (_("Augmentation string:"));
+
+      augmentation_printable = TRUE;
+      augmentation_string = (const char *) hdrptr;
+
       for (i = 0; i < augmentation_string_size; i++)
        {
          unsigned char uc;
 
          SAFE_BYTE_GET_AND_INC (uc, hdrptr, 1, unit_end);
          printf (" %02x", uc);
+
+         if (uc != 0 && !ISPRINT (uc))
+           augmentation_printable = FALSE;
+       }
+
+      if (augmentation_printable)
+       {
+         printf ("  (\"");
+         for (i = 0;
+              i < augmentation_string_size && augmentation_string[i];
+              ++i)
+           putchar (augmentation_string[i]);
+         printf ("\")");
        }
-      putchar ('\n');
       putchar ('\n');
 
       printf (_("CU table:\n"));
@@ -8682,12 +9329,12 @@ display_debug_names (struct dwarf_section *section, void *file)
 
                  if (tagno >= 0)
                    printf (" %s", get_IDX_name (xindex));
-                 entryptr = read_and_display_attr_value (0, form, 0, entryptr,
-                                                         unit_end, 0, 0,
-                                                         offset_size,
+                 entryptr = read_and_display_attr_value (0, form, 0,
+                                                         unit_start, entryptr, unit_end,
+                                                         0, 0, offset_size,
                                                          dwarf_version, NULL,
                                                          (tagno < 0), NULL,
-                                                         NULL, '=');
+                                                         NULL, '=', -1);
                }
              ++tagno;
            }
@@ -9126,33 +9773,29 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
   SAFE_BYTE_GET (nslots, phdr + 12, 4, limit);
 
   phash = phdr + 16;
-  pindex = phash + nslots * 8;
-  ppool = pindex + nslots * 4;
-
-  /* PR 17531: file: 45d69832.  */
-  if (pindex < phash || ppool < phdr || (pindex == phash && nslots != 0))
-    {
-      warn (ngettext ("Section %s is too small for %d slot\n",
-                     "Section %s is too small for %d slots\n",
-                     nslots),
-           section->name, nslots);
-      return 0;
-    }
+  pindex = phash + (size_t) nslots * 8;
+  ppool = pindex + (size_t) nslots * 4;
 
   if (do_display)
     {
       introduce (section, FALSE);
 
-      printf (_("  Version:                 %d\n"), version);
+      printf (_("  Version:                 %u\n"), version);
       if (version >= 2)
-       printf (_("  Number of columns:       %d\n"), ncols);
-      printf (_("  Number of used entries:  %d\n"), nused);
-      printf (_("  Number of slots:         %d\n\n"), nslots);
+       printf (_("  Number of columns:       %u\n"), ncols);
+      printf (_("  Number of used entries:  %u\n"), nused);
+      printf (_("  Number of slots:         %u\n\n"), nslots);
     }
 
-  if (ppool > limit || ppool < phdr)
+  /* PR 17531: file: 45d69832.  */
+  if ((size_t) nslots * 8 / 8 != nslots
+      || phash < phdr || phash > limit
+      || pindex < phash || pindex > limit
+      || ppool < pindex || ppool > limit)
     {
-      warn (_("Section %s too small for %d hash table entries\n"),
+      warn (ngettext ("Section %s is too small for %u slot\n",
+                     "Section %s is too small for %u slots\n",
+                     nslots),
            section->name, nslots);
       return 0;
     }
@@ -9214,9 +9857,9 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
       unsigned int dw_sect;
       unsigned char *ph = phash;
       unsigned char *pi = pindex;
-      unsigned char *poffsets = ppool + ncols * 4;
-      unsigned char *psizes = poffsets + nused * ncols * 4;
-      unsigned char *pend = psizes + nused * ncols * 4;
+      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;
       struct cu_tu_set *this_set = NULL;
       unsigned int row;
@@ -9225,14 +9868,14 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
       is_tu_index = strcmp (section->name, ".debug_tu_index") == 0;
 
       /* PR 17531: file: 0dd159bf.
-        Check for wraparound with an overlarge ncols value.  */
-      if (poffsets < ppool || (unsigned int) ((poffsets - ppool) / 4) != ncols)
-       {
-         warn (_("Overlarge number of columns: %x\n"), ncols);
-         return 0;
-       }
-
-      if (pend > limit)
+        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))
        {
          warn (_("Section %s too small for offset and size tables\n"),
                section->name);
@@ -9661,6 +10304,7 @@ parse_gnu_debuglink (struct dwarf_section * section, void * data)
      The CRC value is stored after the filename, aligned up to 4 bytes.  */
   name = (const char *) section->start;
 
+  
   crc_offset = strnlen (name, section->size) + 1;
   crc_offset = (crc_offset + 3) & ~3;
   if (crc_offset + 4 > section->size)
@@ -9722,6 +10366,17 @@ parse_gnu_debugaltlink (struct dwarf_section * section, void * data)
   return name;
 }
 
+static void
+add_separate_debug_file (const char * filename, void * handle)
+{
+  separate_info * i = xmalloc (sizeof * i);
+
+  i->filename = filename;
+  i->handle   = handle;
+  i->next     = first_separate_info;
+  first_separate_info = i;
+}
+
 static void *
 load_separate_debug_info (const char *            main_filename,
                          struct dwarf_section *  xlink,
@@ -9730,7 +10385,7 @@ load_separate_debug_info (const char *            main_filename,
                          void *                  func_data)
 {
   const char *   separate_filename;
-  char *         debugfile;
+  char *         debug_filename;
   char *         canon_dir;
   size_t         canon_dirlen;
   size_t         dirlen;
@@ -9762,189 +10417,226 @@ load_separate_debug_info (const char *            main_filename,
 #define EXTRA_DEBUG_ROOT2 "/usr/lib/debug/usr"
 #endif
 
-  debugfile = (char *) malloc (strlen (DEBUGDIR) + 1
-                              + canon_dirlen
-                              + strlen (".debug/")
+  debug_filename = (char *) malloc (strlen (DEBUGDIR) + 1
+                                   + canon_dirlen
+                                   + strlen (".debug/")
 #ifdef EXTRA_DEBUG_ROOT1
-                              + strlen (EXTRA_DEBUG_ROOT1)
+                                   + strlen (EXTRA_DEBUG_ROOT1)
 #endif
 #ifdef EXTRA_DEBUG_ROOT2
-                              + strlen (EXTRA_DEBUG_ROOT2)
+                                   + strlen (EXTRA_DEBUG_ROOT2)
 #endif
-                              + strlen (separate_filename)
-                              + 1);
-  if (debugfile == NULL)
+                                   + strlen (separate_filename)
+                                   + 1);
+  if (debug_filename == NULL)
     {
       warn (_("Out of memory"));
+      free (canon_dir);
       return NULL;
     }
 
   /* First try in the current directory.  */
-  sprintf (debugfile, "%s", separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, "%s", separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 
   /* Then try in a subdirectory called .debug.  */
-  sprintf (debugfile, ".debug/%s", separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, ".debug/%s", separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 
   /* Then try in the same directory as the original file.  */
-  sprintf (debugfile, "%s%s", canon_dir, separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, "%s%s", canon_dir, separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 
   /* And the .debug subdirectory of that directory.  */
-  sprintf (debugfile, "%s.debug/%s", canon_dir, separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, "%s.debug/%s", canon_dir, separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 
 #ifdef EXTRA_DEBUG_ROOT1
   /* Try the first extra debug file root.  */
-  sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
+  if (check_func (debug_filename, func_data))
+    goto found;
+
+  /* Try the first extra debug file root.  */
+  sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 #endif
 
 #ifdef EXTRA_DEBUG_ROOT2
   /* Try the second extra debug file root.  */
-  sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 #endif
 
-  /* Then try in the global debugfile directory.  */
-  strcpy (debugfile, DEBUGDIR);
+  /* Then try in the global debug_filename directory.  */
+  strcpy (debug_filename, DEBUGDIR);
   dirlen = strlen (DEBUGDIR) - 1;
   if (dirlen > 0 && DEBUGDIR[dirlen] != '/')
-    strcat (debugfile, "/");
-  strcat (debugfile, (const char *) separate_filename);
+    strcat (debug_filename, "/");
+  strcat (debug_filename, (const char *) separate_filename);
 
-  if (check_func (debugfile, func_data))
+  if (check_func (debug_filename, func_data))
     goto found;
 
   /* Failed to find the file.  */
   warn (_("could not find separate debug file '%s'\n"), separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  warn (_("tried: %s\n"), debug_filename);
 
 #ifdef EXTRA_DEBUG_ROOT2
-  sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 #endif
 
 #ifdef EXTRA_DEBUG_ROOT1
-  sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  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);
 #endif
 
-  sprintf (debugfile, "%s.debug/%s", canon_dir, separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, "%s.debug/%s", canon_dir, separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 
-  sprintf (debugfile, "%s%s", canon_dir, separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, "%s%s", canon_dir, separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 
-  sprintf (debugfile, ".debug/%s", separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, ".debug/%s", separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 
-  sprintf (debugfile, "%s", separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, "%s", separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 
   free (canon_dir);
-  free (debugfile);
+  free (debug_filename);
   return NULL;
 
  found:
   free (canon_dir);
 
+  void * debug_handle;
+
   /* Now open the file.... */
-  if ((separate_debug_file = open_debug_file (debugfile)) == NULL)
+  if ((debug_handle = open_debug_file (debug_filename)) == NULL)
     {
-      warn (_("failed to open separate debug file: %s\n"), debugfile);
-      free (debugfile);
+      warn (_("failed to open separate debug file: %s\n"), debug_filename);
+      free (debug_filename);
       return FALSE;
     }
 
   /* 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, debugfile);
-  separate_debug_filename = debugfile;
+  printf (_("%s: Found separate debug info file: %s\n\n"), main_filename, debug_filename);
+  add_separate_debug_file (debug_filename, debug_handle);
 
-  /* Do not free debugfile - it might be referenced inside
+  /* Do not free debug_filename - it might be referenced inside
      the structure returned by open_debug_file().  */
-  return separate_debug_file;
+  return debug_handle;
 }
 
 /* Attempt to load a separate dwarf object file.  */
 
 static void *
-load_dwo_file (const char * main_filename)
+load_dwo_file (const char * main_filename, const char * name, const char * dir, const char * id ATTRIBUTE_UNUSED)
 {
-  char * filename;
+  char * separate_filename;
+  void * separate_handle;
 
   /* FIXME: Skip adding / if dwo_dir ends in /.  */
-  filename = concat (dwo_dir, "/", dwo_name, NULL);
-  if (filename == NULL)
+  separate_filename = concat (dir, "/", name, NULL);
+  if (separate_filename == NULL)
     {
       warn (_("Out of memory allocating dwo filename\n"));
       return NULL;
     }
 
-  if ((separate_debug_file = open_debug_file (filename)) == NULL)
+  if ((separate_handle = open_debug_file (separate_filename)) == NULL)
     {
-      warn (_("Unable to load dwo file: %s\n"), filename);
-      free (filename);
+      warn (_("Unable to load dwo file: %s\n"), separate_filename);
+      free (separate_filename);
       return NULL;
     }
 
   /* FIXME: We should check the dwo_id.  */
 
-  printf (_("%s: Found separate debug object file: %s\n\n"), main_filename, filename);
-  separate_debug_filename = filename;
-  return separate_debug_file;
+  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;
 }
 
-/* Load a separate debug info file, if it exists.
-   Returns the data pointer that is the result of calling open_debug_file
-   on the separate debug info file, or NULL if there were problems or there
-   is no such file.  */
+/* Load the separate debug info file(s) attached to FILE, if any exist.
+   Returns TRUE if any were found, FALSE otherwise.
+   If TRUE is returned then the linked list starting at first_separate_info
+   will be populated with open file handles.  */
 
-void *
-load_separate_debug_file (void * file, const char * filename)
+bfd_boolean
+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 NULL;
+    return FALSE;
 
-  /* See if there is a dwo link.  */
+  /* See if there are any dwo links.  */
   if (load_debug_section (str, file)
       && load_debug_section (abbrev, file)
       && load_debug_section (info, file))
     {
-      dwo_name = dwo_dir = NULL;
-      dwo_id = NULL;
-      dwo_id_len = 0;
+      free_dwo_info ();
 
       if (process_debug_info (& debug_displays[info].section, file, abbrev, TRUE, FALSE))
        {
-         if (dwo_name != NULL)
+         bfd_boolean introduced = FALSE;
+         dwo_info *   dwinfo;
+         const char * dir = NULL;
+         const char * id = NULL;
+
+         for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = dwinfo->next)
            {
-             if (do_debug_links)
+             switch (dwinfo->type)
                {
-                 printf (_("The %s section contains a link to a dwo file:\n"),
-                         debug_displays [info].section.uncompressed_name);
-                 printf (_("  Name:      %s\n"), dwo_name);
-                 printf (_("  Directory: %s\n"), dwo_dir ? dwo_dir : _("<not-found>"));
-                 if (dwo_id != NULL)
-                   display_data (printf (_("  ID:       ")), dwo_id, dwo_id_len);
-                 else
-                   printf (_("  ID: <unknown>\n"));
-                 printf ("\n\n");
-               }
+               case DWO_NAME:
+                 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;
+                       }
+
+                     printf (_("  Name:      %s\n"), dwinfo->value);
+                     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 ("\n\n");
+                   }
 
-             /* FIXME: We do not check to see if there are any more dwo links in the file...  */
-             if (do_follow_links)
-               return load_dwo_file (filename);
+                 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;
+
+               default:
+                 error (_("Unexpected DWO INFO type"));
+                 break;
+               }
            }
        }
     }
@@ -9952,7 +10644,7 @@ load_separate_debug_file (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 NULL;
+    return FALSE;
 
   /* FIXME: We do not check for the presence of both link sections in the same file.  */
   /* FIXME: We do not check the separate debug info file to see if it too contains debuglinks.  */
@@ -9963,26 +10655,29 @@ load_separate_debug_file (void * file, const char * filename)
     {
       Build_id_data * build_id_data;
 
-      return load_separate_debug_info (filename,
-                                      & debug_displays[gnu_debugaltlink].section,
-                                      parse_gnu_debugaltlink,
-                                      check_gnu_debugaltlink,
-                                      & build_id_data);
+      load_separate_debug_info (filename,
+                               & debug_displays[gnu_debugaltlink].section,
+                               parse_gnu_debugaltlink,
+                               check_gnu_debugaltlink,
+                               & build_id_data);
     }
 
   if (load_debug_section (gnu_debuglink, file))
     {
       unsigned long crc32;
 
-      return load_separate_debug_info (filename,
-                                      & debug_displays[gnu_debuglink].section,
-                                      parse_gnu_debuglink,
-                                      check_gnu_debuglink,
-                                      & crc32);
+      load_separate_debug_info (filename,
+                               & debug_displays[gnu_debuglink].section,
+                               parse_gnu_debuglink,
+                               check_gnu_debuglink,
+                               & crc32);
     }
 
+  if (first_separate_info != NULL)
+    return TRUE;
+
   do_follow_links = 0;
-  return NULL;
+  return FALSE;
 }  
 
 void
@@ -10015,14 +10710,19 @@ free_debug_memory (void)
       alloc_num_debug_info_entries = num_debug_info_entries = 0;
     }
 
-  if (separate_debug_file != NULL)
-    {
-      close_debug_file (separate_debug_file);
-      separate_debug_file = NULL;
+  separate_info * d;
+  separate_info * next;
 
-      free ((void *) separate_debug_filename);
-      separate_debug_filename = NULL;
+  for (d = first_separate_info; d != NULL; d = next)
+    {
+      close_debug_file (d->handle);
+      free ((void *) d->filename);
+      next = d->next;
+      free ((void *) d);
     }
+  first_separate_info = NULL;
+  
+  free_dwo_info ();
 }
 
 void
This page took 0.050607 seconds and 4 git commands to generate.