gdbsupport: re-indent ptrace.m4
[deliverable/binutils-gdb.git] / binutils / dwarf.c
index 6e61bfdca16ae830937d37a99841793015e090c1..14a7791c8cc4627ea835c3eac02be4c79f582894 100644 (file)
@@ -345,20 +345,34 @@ read_leb128 (unsigned char *data,
   while (data < end)
     {
       unsigned char byte = *data++;
+      bfd_boolean cont = (byte & 0x80) ? TRUE : FALSE;
+
+      byte &= 0x7f;
       num_read++;
 
       if (shift < sizeof (result) * 8)
        {
-         result |= ((dwarf_vma) (byte & 0x7f)) << shift;
-         if ((result >> shift) != (byte & 0x7f))
-           /* Overflow.  */
-           status |= 2;
+         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;
+           }
+
          shift += 7;
        }
-      else if ((byte & 0x7f) != 0)
-       status |= 2;
+      else if (byte != 0)
+       {
+         status |= 2;
+       }
 
-      if ((byte & 0x80) == 0)
+      if (!cont)
        {
          status &= ~1;
          if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
@@ -835,101 +849,208 @@ fetch_indexed_value (dwarf_vma offset, dwarf_vma bytes)
 /* FIXME:  There are better and more efficient ways to handle
    these structures.  For now though, I just want something that
    is simple to implement.  */
+/* Records a single attribute in an abbrev.  */
 typedef struct abbrev_attr
 {
-  unsigned long attribute;
-  unsigned long form;
-  bfd_signed_vma implicit_const;
-  struct abbrev_attr *next;
+  unsigned long          attribute;
+  unsigned long          form;
+  bfd_signed_vma         implicit_const;
+  struct abbrev_attr *   next;
 }
 abbrev_attr;
 
+/* Records a single abbrev.  */
 typedef struct abbrev_entry
 {
-  unsigned long entry;
-  unsigned long tag;
-  int children;
-  struct abbrev_attr *first_attr;
-  struct abbrev_attr *last_attr;
-  struct abbrev_entry *next;
+  unsigned long          number;
+  unsigned long          tag;
+  int                    children;
+  struct abbrev_attr *   first_attr;
+  struct abbrev_attr *   last_attr;
+  struct abbrev_entry *  next;
 }
 abbrev_entry;
 
-static abbrev_entry *first_abbrev = NULL;
-static abbrev_entry *last_abbrev = NULL;
+/* Records a set of abbreviations.  */
+typedef struct abbrev_list
+{
+  abbrev_entry *        first_abbrev;
+  abbrev_entry *        last_abbrev;
+  dwarf_vma             abbrev_base;
+  dwarf_vma             abbrev_offset;
+  struct abbrev_list *  next;
+  unsigned char *       start_of_next_abbrevs;
+}
+abbrev_list;
+
+/* Records all the abbrevs found so far.  */
+static struct abbrev_list * abbrev_lists = NULL;
+
+typedef struct abbrev_map
+{
+  dwarf_vma      start;
+  dwarf_vma      end;
+  abbrev_list *  list;
+} abbrev_map;
+
+/* Maps between CU offsets and abbrev sets.  */
+static abbrev_map *   cu_abbrev_map = NULL;
+static unsigned long  num_abbrev_map_entries = 0;
+static unsigned long  next_free_abbrev_map_entry = 0;
+
+#define INITIAL_NUM_ABBREV_MAP_ENTRIES 8
+#define ABBREV_MAP_ENTRIES_INCREMENT   8
 
 static void
-free_abbrevs (void)
+record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list)
 {
-  abbrev_entry *abbrv;
+  if (cu_abbrev_map == NULL)
+    {
+      num_abbrev_map_entries = INITIAL_NUM_ABBREV_MAP_ENTRIES;
+      cu_abbrev_map = xmalloc (num_abbrev_map_entries * sizeof (* cu_abbrev_map));
+    }
+  else if (next_free_abbrev_map_entry == num_abbrev_map_entries)
+    {
+      num_abbrev_map_entries += ABBREV_MAP_ENTRIES_INCREMENT;
+      cu_abbrev_map = xrealloc (cu_abbrev_map, num_abbrev_map_entries * sizeof (* cu_abbrev_map));
+    }
+
+  cu_abbrev_map[next_free_abbrev_map_entry].start = start;
+  cu_abbrev_map[next_free_abbrev_map_entry].end = end;
+  cu_abbrev_map[next_free_abbrev_map_entry].list = list;
+  next_free_abbrev_map_entry ++;
+}
 
-  for (abbrv = first_abbrev; abbrv;)
+static void
+free_all_abbrevs (void)
+{
+  abbrev_list *  list;
+
+  for (list = abbrev_lists; list != NULL;)
     {
-      abbrev_entry *next_abbrev = abbrv->next;
-      abbrev_attr *attr;
+      abbrev_list *   next = list->next;
+      abbrev_entry *  abbrv;
 
-      for (attr = abbrv->first_attr; attr;)
+      for (abbrv = list->first_abbrev; abbrv != NULL;)
        {
-         abbrev_attr *next_attr = attr->next;
+         abbrev_entry *  next_abbrev = abbrv->next;
+         abbrev_attr *   attr;
+
+         for (attr = abbrv->first_attr; attr;)
+           {
+             abbrev_attr *next_attr = attr->next;
 
-         free (attr);
-         attr = next_attr;
+             free (attr);
+             attr = next_attr;
+           }
+
+         free (abbrv);
+         abbrv = next_abbrev;
        }
 
-      free (abbrv);
-      abbrv = next_abbrev;
+      free (list);
+      list = next;
     }
 
-  last_abbrev = first_abbrev = NULL;
+  abbrev_lists = NULL;
+}
+
+static abbrev_list *
+new_abbrev_list (dwarf_vma abbrev_base, dwarf_vma abbrev_offset)
+{
+  abbrev_list * list = (abbrev_list *) xcalloc (sizeof * list, 1);
+
+  list->abbrev_base = abbrev_base;
+  list->abbrev_offset = abbrev_offset;
+
+  list->next = abbrev_lists;
+  abbrev_lists = list;
+
+  return list;
+}
+
+static abbrev_list *
+find_abbrev_list_by_abbrev_offset (dwarf_vma abbrev_base,
+                                  dwarf_vma abbrev_offset)
+{
+  abbrev_list * list;
+
+  for (list = abbrev_lists; list != NULL; list = list->next)
+    if (list->abbrev_base == abbrev_base
+       && list->abbrev_offset == abbrev_offset)
+      return list;
+
+  return NULL;
+}
+
+/* Find the abbreviation map for the CU that includes OFFSET.
+   OFFSET is an absolute offset from the start of the .debug_info section.  */
+/* FIXME: This function is going to slow down readelf & objdump.
+   Consider using a better algorithm to mitigate this effect.  */
+
+static  abbrev_map *
+find_abbrev_map_by_offset (dwarf_vma offset)
+{
+  unsigned long i;
+
+  for (i = 0; i < next_free_abbrev_map_entry; i++)
+    if (cu_abbrev_map[i].start <= offset
+       && cu_abbrev_map[i].end > offset)
+      return cu_abbrev_map + i;
+
+  return NULL; 
 }
 
 static void
-add_abbrev (unsigned long number, unsigned long tag, int children)
+add_abbrev (unsigned long  number,
+           unsigned long  tag,
+           int            children,
+           abbrev_list *  list)
 {
-  abbrev_entry *entry;
+  abbrev_entry *  entry;
 
-  entry = (abbrev_entry *) malloc (sizeof (*entry));
-  if (entry == NULL)
-    /* ugg */
-    return;
+  entry = (abbrev_entry *) xmalloc (sizeof (*entry));
 
-  entry->entry      = number;
+  entry->number     = number;
   entry->tag        = tag;
   entry->children   = children;
   entry->first_attr = NULL;
   entry->last_attr  = NULL;
   entry->next       = NULL;
 
-  if (first_abbrev == NULL)
-    first_abbrev = entry;
+  assert (list != NULL);
+
+  if (list->first_abbrev == NULL)
+    list->first_abbrev = entry;
   else
-    last_abbrev->next = entry;
+    list->last_abbrev->next = entry;
 
-  last_abbrev = entry;
+  list->last_abbrev = entry;
 }
 
 static void
-add_abbrev_attr (unsigned long attribute, unsigned long form,
-                bfd_signed_vma implicit_const)
+add_abbrev_attr (unsigned long   attribute,
+                unsigned long   form,
+                bfd_signed_vma  implicit_const,
+                abbrev_list *   list)
 {
   abbrev_attr *attr;
 
-  attr = (abbrev_attr *) malloc (sizeof (*attr));
-  if (attr == NULL)
-    /* ugg */
-    return;
+  attr = (abbrev_attr *) xmalloc (sizeof (*attr));
 
   attr->attribute = attribute;
   attr->form      = form;
   attr->implicit_const = implicit_const;
   attr->next      = NULL;
 
-  if (last_abbrev->first_attr == NULL)
-    last_abbrev->first_attr = attr;
+  assert (list != NULL && list->last_abbrev != NULL);
+
+  if (list->last_abbrev->first_attr == NULL)
+    list->last_abbrev->first_attr = attr;
   else
-    last_abbrev->last_attr->next = attr;
+    list->last_abbrev->last_attr->next = attr;
 
-  last_abbrev->last_attr = attr;
+  list->last_abbrev->last_attr = attr;
 }
 
 /* Processes the (partial) contents of a .debug_abbrev section.
@@ -938,11 +1059,10 @@ add_abbrev_attr (unsigned long attribute, unsigned long form,
    an abbreviation set was found.  */
 
 static unsigned char *
-process_abbrev_section (unsigned char *start, unsigned char *end)
+process_abbrev_set (unsigned char *        start,
+                   const unsigned char *  end,
+                   abbrev_list *          list)
 {
-  if (first_abbrev != NULL)
-    return NULL;
-
   while (start < end)
     {
       unsigned long entry;
@@ -952,7 +1072,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end)
 
       READ_ULEB (entry, start, end);
 
-      /* A single zero is supposed to end the section according
+      /* A single zero is supposed to end the set according
         to the standard.  If there's more, then signal that to
         the caller.  */
       if (start == end)
@@ -966,7 +1086,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end)
 
       children = *start++;
 
-      add_abbrev (entry, tag, children);
+      add_abbrev (entry, tag, children, list);
 
       do
        {
@@ -989,7 +1109,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end)
                break;
            }
 
-         add_abbrev_attr (attribute, form, implicit_const);
+         add_abbrev_attr (attribute, form, implicit_const, list);
        }
       while (attribute != 0);
     }
@@ -1854,7 +1974,7 @@ skip_attr_bytes (unsigned long          form,
     case DW_FORM_ref_addr:
       if (dwarf_version == 2)
        SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
-      else if (dwarf_version == 3 || dwarf_version == 4)
+      else if (dwarf_version > 2)
        SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
       else
        return NULL;
@@ -1906,6 +2026,7 @@ skip_attr_bytes (unsigned long          form,
 
     case DW_FORM_ref8:
     case DW_FORM_data8:
+    case DW_FORM_ref_sig8:
       data += 8;
       break;
 
@@ -1920,6 +2041,7 @@ skip_attr_bytes (unsigned long          form,
     case DW_FORM_block:
     case DW_FORM_exprloc:
       READ_ULEB (uvalue, data, end);
+      data += uvalue;
       break;
 
     case DW_FORM_block1:
@@ -1937,12 +2059,12 @@ skip_attr_bytes (unsigned long          form,
       data += 4 + uvalue;
       break;
 
-    case DW_FORM_ref_sig8:
-      data += 8;
-      break;
-
     case DW_FORM_indirect:
-      /* FIXME: Handle this form.  */
+      READ_ULEB (form, data, end);
+      if (form == DW_FORM_implicit_const)
+       SKIP_ULEB (data, end);
+      return skip_attr_bytes (form, data, end, pointer_size, offset_size, dwarf_version, value_return);
+
     default:
       return NULL;
     }
@@ -1953,40 +2075,136 @@ skip_attr_bytes (unsigned long          form,
   return data;
 }
 
-/* Return IS_SIGNED set to TRUE if the type at
-   DATA can be determined to be a signed type.  */
+/* Given form FORM with value UVALUE, locate and return the abbreviation
+   associated with it.  */
+
+static abbrev_entry *
+get_type_abbrev_from_form (unsigned long                 form,
+                          unsigned long                 uvalue,
+                          dwarf_vma                     cu_offset,
+                          const struct dwarf_section *  section,
+                          unsigned long *               abbrev_num_return,
+                          unsigned char **              data_return,
+                          unsigned long *               cu_offset_return)
+{
+  unsigned long   abbrev_number;
+  abbrev_map *    map;
+  abbrev_entry *  entry;
+  unsigned char * data;
+
+  if (abbrev_num_return != NULL)
+    * abbrev_num_return = 0;
+  if (data_return != NULL)
+    * data_return = NULL;
+
+  switch (form)
+    {
+    case DW_FORM_GNU_ref_alt:
+      /* FIXME: We are unable to handle this form at the moment.  */
+      return NULL;
+
+    case DW_FORM_ref_addr:
+      if (uvalue >= section->size)
+       {
+         warn (_("Unable to resolve ref_addr form: uvalue %lx > section size %lx (%s)\n"),
+               uvalue, (long) section->size, section->name);
+         return NULL;
+       }
+      break;
+
+    case DW_FORM_ref1:
+    case DW_FORM_ref2:
+    case DW_FORM_ref4:
+    case DW_FORM_ref_udata:
+      if (uvalue + cu_offset > section->size)
+       {
+         warn (_("Unable to resolve ref form: uvalue %lx + cu_offset %lx > section size %lx\n"),
+               uvalue, (long) cu_offset, (long) section->size);
+         return NULL;
+       }
+      uvalue += cu_offset;
+      break;
+
+      /* FIXME: Are there other DW_FORMs that can be used by types ?  */
+
+    default:
+      warn (_("Unexpected form %lx encountered whilst finding abbreviation for type\n"), form);
+      return NULL;
+    }
+
+  data = (unsigned char *) section->start + uvalue;
+  map = find_abbrev_map_by_offset (uvalue);
+  
+  if (map == NULL)
+    {
+      warn (_("Unable to find abbreviations for CU offset %#lx\n"), uvalue);
+      return NULL;
+    }
+  if (map->list == NULL)
+    {
+      warn (_("Empty abbreviation list encountered for CU offset %lx\n"), uvalue);
+      return NULL;
+    }
+
+  if (cu_offset_return != NULL)
+    {
+      if (form == DW_FORM_ref_addr)
+       * cu_offset_return = map->start;
+      else
+       * cu_offset_return = cu_offset;
+    }
+       
+  READ_ULEB (abbrev_number, data, section->start + section->size);
+
+  for (entry = map->list->first_abbrev; entry != NULL; entry = entry->next)
+    if (entry->number == abbrev_number)
+      break;
+  
+  if (abbrev_num_return != NULL)
+    * abbrev_num_return = abbrev_number;
+
+  if (data_return != NULL)
+    * data_return = data;
+
+  if (entry == NULL)
+    warn (_("Unable to find entry for abbreviation %lu\n"), abbrev_number);
+
+  return entry;
+}
+
+/* Return IS_SIGNED set to TRUE if the type using abbreviation ENTRY
+   can be determined to be a signed type.  The data for ENTRY can be
+   found starting at DATA.  */
 
 static void
-get_type_signedness (unsigned char *        start,
+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,
-                    bfd_boolean            is_nested)
+                    unsigned int           nesting)
 {
-  unsigned long   abbrev_number;
-  abbrev_entry *  entry;
   abbrev_attr *   attr;
 
   * is_signed = FALSE;
 
-  READ_ULEB (abbrev_number, data, end);
-
-  for (entry = first_abbrev;
-       entry != NULL && entry->entry != abbrev_number;
-       entry = entry->next)
-    continue;
-
-  if (entry == NULL)
-    /* FIXME: Issue a warning ?  */
-    return;
+#define MAX_NESTING 20
+  if (nesting > MAX_NESTING)
+    {
+      /* FIXME: Warn - or is this expected ?
+        NB/ We need to avoid infinite recursion.  */
+      return;
+    }
 
   for (attr = entry->first_attr;
        attr != NULL && attr->attribute;
        attr = attr->next)
     {
+      unsigned char * orig_data = data;
       dwarf_vma uvalue = 0;
 
       data = skip_attr_bytes (attr->form, data, end, pointer_size,
@@ -1996,25 +2214,38 @@ get_type_signedness (unsigned char *        start,
 
       switch (attr->attribute)
        {
-#if 0 /* FIXME: It would be nice to print the name of the type,
-        but this would mean updating a lot of binutils tests.  */
+       case DW_AT_linkage_name:
        case DW_AT_name:
-         if (attr->form == DW_FORM_strp)
-           printf ("%s", fetch_indirect_string (uvalue));
+         if (do_wide)
+           {
+             if (attr->form == DW_FORM_strp)
+               printf (", %s", fetch_indirect_string (uvalue));
+             else if (attr->form == DW_FORM_string)
+               printf (", %s", orig_data);
+           }
          break;
-#endif
+
        case DW_AT_type:
          /* Recurse.  */
-         if (is_nested)
-           {
-             /* FIXME: Warn - or is this expected ?
-                NB/ We need to avoid infinite recursion.  */
-             return;
-           }
-         if (uvalue >= (size_t) (end - start))
-           return;
-         get_type_signedness (start, start + uvalue, end, pointer_size,
-                              offset_size, dwarf_version, is_signed, TRUE);
+         {
+           abbrev_entry *  type_abbrev;
+           unsigned char * type_data;
+           unsigned long   type_cu_offset;
+
+           type_abbrev = get_type_abbrev_from_form (attr->form,
+                                                    uvalue,
+                                                    cu_offset,
+                                                    section,
+                                                    NULL /* abbrev num return */,
+                                                    & type_data,
+                                                    & type_cu_offset);
+           if (type_abbrev == NULL)
+             break;
+
+           get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset,
+                                pointer_size, offset_size, dwarf_version,
+                                is_signed, nesting + 1);
+         }
          break;
 
        case DW_AT_encoding:
@@ -2188,11 +2419,10 @@ read_and_display_attr_value (unsigned long           attribute,
     case DW_FORM_ref_addr:
       if (dwarf_version == 2)
        SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
-      else if (dwarf_version == 3 || dwarf_version == 4)
+      else if (dwarf_version > 2)
        SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
       else
-       error (_("Internal error: DWARF version is not 2, 3 or 4.\n"));
-
+       error (_("Internal error: DW_FORM_ref_addr is not supported in DWARF version 1.\n"));
       break;
 
     case DW_FORM_addr:
@@ -2257,12 +2487,12 @@ read_and_display_attr_value (unsigned long           attribute,
     {
     case DW_FORM_ref_addr:
       if (!do_loc)
-       printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x",uvalue));
+       printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue));
       break;
 
     case DW_FORM_GNU_ref_alt:
       if (!do_loc)
-       printf ("%c<alt 0x%s>", delimiter, dwarf_vmatoa ("x",uvalue));
+       printf ("%c<alt 0x%s>", delimiter, dwarf_vmatoa ("x", uvalue));
       /* FIXME: Follow the reference...  */
       break;
 
@@ -2574,6 +2804,9 @@ read_and_display_attr_value (unsigned long           attribute,
              case DW_FORM_strp:
                add_dwo_name ((const char *) fetch_indirect_string (uvalue));
                break;
+             case DW_FORM_GNU_strp_alt:
+               add_dwo_name ((const char *) fetch_alt_indirect_string (uvalue));
+               break;
              case DW_FORM_GNU_str_index:
                add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
                break;
@@ -2595,6 +2828,9 @@ read_and_display_attr_value (unsigned long           attribute,
              case DW_FORM_strp:
                add_dwo_dir ((const char *) fetch_indirect_string (uvalue));
                break;
+             case DW_FORM_GNU_strp_alt:
+               add_dwo_dir (fetch_alt_indirect_string (uvalue));
+               break;
              case DW_FORM_line_strp:
                add_dwo_dir ((const char *) fetch_indirect_line_string (uvalue));
                break;
@@ -2642,9 +2878,18 @@ read_and_display_attr_value (unsigned long           attribute,
          && 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);
+         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);
+         if (type_abbrev != NULL)
+           {
+             get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset,
+                                  pointer_size, offset_size, dwarf_version,
+                                  & is_signed, 0);
+           }
          level_type_signed[level] = is_signed;
        }
       break;
@@ -2966,40 +3211,22 @@ read_and_display_attr_value (unsigned long           attribute,
 
     case DW_AT_import:
       {
-       if (form == DW_FORM_ref_sig8
-           || form == DW_FORM_GNU_ref_alt)
-         break;
-
-       if (form == DW_FORM_ref1
-           || form == DW_FORM_ref2
-           || form == DW_FORM_ref4
-           || form == DW_FORM_ref_udata)
-         uvalue += cu_offset;
+       unsigned long abbrev_number;
+       abbrev_entry *entry;
 
-       if (uvalue >= section->size)
-         warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"),
-               dwarf_vmatoa ("x", uvalue),
-               (unsigned long) (orig_data - section->start));
+       entry = get_type_abbrev_from_form (form, uvalue, cu_offset,
+                                          section, & abbrev_number, NULL, NULL);
+       if (entry == NULL)
+         {
+           if (form != DW_FORM_GNU_ref_alt)
+             warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"),
+                   dwarf_vmatoa ("x", uvalue),
+                   (unsigned long) (orig_data - section->start));
+         }
        else
          {
-           unsigned long abbrev_number;
-           abbrev_entry *entry;
-           unsigned char *p = section->start + uvalue;
-
-           READ_ULEB (abbrev_number, p, end);
-
            printf (_("\t[Abbrev Number: %ld"), abbrev_number);
-           /* Don't look up abbrev for DW_FORM_ref_addr, as it very often will
-              use different abbrev table, and we don't track .debug_info chunks
-              yet.  */
-           if (form != DW_FORM_ref_addr)
-             {
-               for (entry = first_abbrev; entry != NULL; entry = entry->next)
-                 if (entry->entry == abbrev_number)
-                   break;
-               if (entry != NULL)
-                 printf (" (%s)", get_TAG_name (entry->tag));
-             }
+           printf (" (%s)", get_TAG_name (entry->tag));
            printf ("]");
          }
       }
@@ -3218,8 +3445,100 @@ process_debug_info (struct dwarf_section *           section,
 
   if (!do_loc && dwarf_start_die == 0)
     introduce (section, FALSE);
+
+  free_all_abbrevs ();
+  free (cu_abbrev_map);
+  cu_abbrev_map = NULL;
+  next_free_abbrev_map_entry = 0;
   
-  for (section_begin = start, unit = 0; start < end; unit++)
+  /* In order to be able to resolve DW_FORM_ref_attr forms we need
+     to load *all* of the abbrevs for all CUs in this .debug_info
+     section.  This does effectively mean that we (partially) read
+     every CU header twice.  */
+  for (section_begin = start; start < end;)
+    {
+      DWARF2_Internal_CompUnit  compunit;
+      unsigned char *           hdrptr;
+      dwarf_vma                 abbrev_base;
+      size_t                    abbrev_size;
+      dwarf_vma                 cu_offset;
+      unsigned int              offset_size;
+      unsigned int              initial_length_size;
+      struct cu_tu_set *        this_set;
+      abbrev_list *             list;
+
+      hdrptr = start;
+
+      SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 4, end);
+
+      if (compunit.cu_length == 0xffffffff)
+       {
+         SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 8, end);
+         offset_size = 8;
+         initial_length_size = 12;
+       }
+      else
+       {
+         offset_size = 4;
+         initial_length_size = 4;
+       }
+
+      SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end);
+
+      cu_offset = start - section_begin;
+
+      this_set = find_cu_tu_set_v2 (cu_offset, do_types);
+
+      if (compunit.cu_version < 5)
+       {
+         compunit.cu_unit_type = DW_UT_compile;
+         /* Initialize it due to a false compiler warning.  */
+         compunit.cu_pointer_size = -1;
+       }
+      else
+       {
+         SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end);
+         do_types = (compunit.cu_unit_type == DW_UT_type);
+
+         SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end);
+       }
+
+      SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end);
+
+      if (this_set == NULL)
+       {
+         abbrev_base = 0;
+         abbrev_size = debug_displays [abbrev_sec].section.size;
+       }
+      else
+       {
+         abbrev_base = this_set->section_offsets [DW_SECT_ABBREV];
+         abbrev_size = this_set->section_sizes [DW_SECT_ABBREV];
+       }
+
+      list = find_abbrev_list_by_abbrev_offset (abbrev_base,
+                                               compunit.cu_abbrev_offset);
+      if (list == NULL)
+       {
+         unsigned char *  next;
+
+         list = new_abbrev_list (abbrev_base,
+                                 compunit.cu_abbrev_offset);
+         next = process_abbrev_set
+           (((unsigned char *) debug_displays [abbrev_sec].section.start
+             + abbrev_base + compunit.cu_abbrev_offset),
+            ((unsigned char *) debug_displays [abbrev_sec].section.start
+             + abbrev_base + abbrev_size),
+            list);
+         list->start_of_next_abbrevs = next;
+       }
+                      
+      start = section_begin + cu_offset + compunit.cu_length
+       + initial_length_size;
+      record_abbrev_list_for_cu (cu_offset, start - section_begin, list);
+    }
+
+  for (start = section_begin, unit = 0; start < end; unit++)
     {
       DWARF2_Internal_CompUnit compunit;
       unsigned char *hdrptr;
@@ -3235,6 +3554,7 @@ process_debug_info (struct dwarf_section *           section,
       struct cu_tu_set *this_set;
       dwarf_vma abbrev_base;
       size_t abbrev_size;
+      abbrev_list * list = NULL;
 
       hdrptr = start;
 
@@ -3341,6 +3661,10 @@ process_debug_info (struct dwarf_section *           section,
                  dwarf_vmatoa ("x", compunit.cu_length),
                  offset_size == 8 ? "64-bit" : "32-bit");
          printf (_("   Version:       %d\n"), compunit.cu_version);
+         if (compunit.cu_version >= 5)
+           printf (_("   Unit Type:     %s (%x)\n"),
+                   get_DW_UT_name (compunit.cu_unit_type) ?: "???",
+                   compunit.cu_unit_type);
          printf (_("   Abbrev Offset: 0x%s\n"),
                  dwarf_vmatoa ("x", compunit.cu_abbrev_offset));
          printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
@@ -3399,6 +3723,7 @@ 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)
        {
          warn (_("CU at offset %s contains corrupt or "
@@ -3407,8 +3732,6 @@ process_debug_info (struct dwarf_section *           section,
          continue;
        }
 
-      free_abbrevs ();
-
       /* Process the abbrevs used by this compilation unit.  */
       if (compunit.cu_abbrev_offset >= abbrev_size)
        warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"),
@@ -3421,11 +3744,24 @@ process_debug_info (struct dwarf_section *           section,
              (unsigned long) abbrev_base + abbrev_size,
              (unsigned long) debug_displays [abbrev_sec].section.size);
       else
-       process_abbrev_section
-         (((unsigned char *) debug_displays [abbrev_sec].section.start
-           + abbrev_base + compunit.cu_abbrev_offset),
-          ((unsigned char *) debug_displays [abbrev_sec].section.start
-           + abbrev_base + abbrev_size));
+       {
+         list = find_abbrev_list_by_abbrev_offset (abbrev_base,
+                                                   compunit.cu_abbrev_offset);
+         if (list == NULL)
+           {
+             unsigned char * next;
+
+             list = new_abbrev_list (abbrev_base,
+                                     compunit.cu_abbrev_offset);
+             next = process_abbrev_set
+               (((unsigned char *) debug_displays [abbrev_sec].section.start
+                 + abbrev_base + compunit.cu_abbrev_offset),
+                ((unsigned char *) debug_displays [abbrev_sec].section.start
+                 + abbrev_base + abbrev_size),
+                list);
+             list->start_of_next_abbrevs = next;
+           }
+       }
 
       level = 0;
       last_level = level;
@@ -3505,11 +3841,13 @@ process_debug_info (struct dwarf_section *           section,
 
          /* Scan through the abbreviation list until we reach the
             correct entry.  */
-         for (entry = first_abbrev;
-              entry && entry->entry != abbrev_number;
-              entry = entry->next)
+         if (list == NULL)
            continue;
 
+         for (entry = list->first_abbrev; entry != NULL; entry = entry->next)
+           if (entry->number == abbrev_number)
+             break;
+
          if (entry == NULL)
            {
              if (!do_loc && do_printing)
@@ -4982,38 +5320,75 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                  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 (linfo.li_max_ops_per_insn == 1)
-                   printf ("%-35s  %11d  %#18" DWARF_VMA_FMT "x",
-                           newFileName, state_machine_regs.line,
-                           state_machine_regs.address);
+                   {
+                     if (xop == -DW_LNE_end_sequence)
+                       printf ("%-35s  %11s  %#18" DWARF_VMA_FMT "x",
+                               newFileName, "-",
+                               state_machine_regs.address);
+                     else
+                       printf ("%-35s  %11d  %#18" DWARF_VMA_FMT "x",
+                               newFileName, state_machine_regs.line,
+                               state_machine_regs.address);
+                   }
                  else
-                   printf ("%-35s  %11d  %#18" DWARF_VMA_FMT "x[%d]",
-                           newFileName, state_machine_regs.line,
-                           state_machine_regs.address,
-                           state_machine_regs.op_index);
+                   {
+                     if (xop == -DW_LNE_end_sequence)
+                       printf ("%-35s  %11s  %#18" DWARF_VMA_FMT "x[%d]",
+                               newFileName, "-",
+                               state_machine_regs.address,
+                               state_machine_regs.op_index);
+                     else
+                       printf ("%-35s  %11d  %#18" DWARF_VMA_FMT "x[%d]",
+                               newFileName, state_machine_regs.line,
+                               state_machine_regs.address,
+                               state_machine_regs.op_index);
+                   }
                }
              else
                {
                  if (linfo.li_max_ops_per_insn == 1)
-                   printf ("%s  %11d  %#18" DWARF_VMA_FMT "x",
-                           newFileName, state_machine_regs.line,
-                           state_machine_regs.address);
+                   {
+                     if (xop == -DW_LNE_end_sequence)
+                       printf ("%s  %11s  %#18" DWARF_VMA_FMT "x",
+                               newFileName, "-",
+                               state_machine_regs.address);
+                     else
+                       printf ("%s  %11d  %#18" DWARF_VMA_FMT "x",
+                               newFileName, state_machine_regs.line,
+                               state_machine_regs.address);
+                   }                   
                  else
-                   printf ("%s  %11d  %#18" DWARF_VMA_FMT "x[%d]",
-                           newFileName, state_machine_regs.line,
-                           state_machine_regs.address,
-                           state_machine_regs.op_index);
+                   {
+                     if (xop == -DW_LNE_end_sequence)
+                       printf ("%s  %11s  %#18" DWARF_VMA_FMT "x[%d]",
+                               newFileName, "-",
+                               state_machine_regs.address,
+                               state_machine_regs.op_index);
+                     else
+                       printf ("%s  %11d  %#18" DWARF_VMA_FMT "x[%d]",
+                               newFileName, state_machine_regs.line,
+                               state_machine_regs.address,
+                               state_machine_regs.op_index);
+                   }
                }
 
-             if (state_machine_regs.view)
-               printf ("  %6u", state_machine_regs.view);
-             else
-               printf ("        ");
+             if (xop != -DW_LNE_end_sequence)
+               {
+                 if (state_machine_regs.view)
+                   printf ("  %6u", state_machine_regs.view);
+                 else
+                   printf ("        ");
 
-             if (state_machine_regs.is_stmt)
-               printf ("       x");
+                 if (state_machine_regs.is_stmt)
+                   printf ("       x");
+               }
 
              putchar ('\n');
              state_machine_regs.view++;
@@ -5694,30 +6069,37 @@ display_debug_abbrev (struct dwarf_section *section,
 {
   abbrev_entry *entry;
   unsigned char *start = section->start;
-  unsigned char *end = start + section->size;
+  const unsigned char *end = start + section->size;
 
   introduce (section, FALSE);
 
   do
     {
-      unsigned char *last;
+      abbrev_list *    list;
+      dwarf_vma        offset;
 
-      free_abbrevs ();
-
-      last = start;
-      start = process_abbrev_section (start, end);
+      offset = start - section->start;
+      list = find_abbrev_list_by_abbrev_offset (0, offset);
+      if (list == NULL)
+       {
+         list = new_abbrev_list (0, offset);
+         start = process_abbrev_set (start, end, list);
+         list->start_of_next_abbrevs = start;
+       }
+      else
+       start = list->start_of_next_abbrevs;
 
-      if (first_abbrev == NULL)
+      if (list->first_abbrev == NULL)
        continue;
 
-      printf (_("  Number TAG (0x%lx)\n"), (long) (last - section->start));
+      printf (_("  Number TAG (0x%lx)\n"), (long) offset);
 
-      for (entry = first_abbrev; entry; entry = entry->next)
+      for (entry = list->first_abbrev; entry; entry = entry->next)
        {
          abbrev_attr *attr;
 
          printf ("   %ld      %s    [%s]\n",
-                 entry->entry,
+                 entry->number,
                  get_TAG_name (entry->tag),
                  entry->children ? _("has children") : _("no children"));
 
@@ -5993,7 +6375,9 @@ display_loclists_list (struct dwarf_section *section,
 
       SAFE_BYTE_GET_AND_INC (llet, start, 1, section_end);
 
-      if (vstart && llet == DW_LLE_offset_pair)
+      if (vstart && (llet == DW_LLE_offset_pair
+                    || llet == DW_LLE_start_end
+                    || llet == DW_LLE_start_length))
        {
          off = offset + (vstart - *start_ptr);
 
@@ -6014,7 +6398,18 @@ display_loclists_list (struct dwarf_section *section,
          break;
        case DW_LLE_offset_pair:
          READ_ULEB (begin, start, section_end);
+         begin += base_address;
          READ_ULEB (end, start, section_end);
+         end += base_address;
+         break;
+       case DW_LLE_start_end:
+         SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
+         SAFE_BYTE_GET_AND_INC (end, start, pointer_size, section_end);
+         break;
+       case DW_LLE_start_length:
+         SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
+         READ_ULEB (end, start, section_end);
+         end += begin;
          break;
        case DW_LLE_base_address:
          SAFE_BYTE_GET_AND_INC (base_address, start, pointer_size,
@@ -6041,7 +6436,9 @@ display_loclists_list (struct dwarf_section *section,
        }
       if (llet == DW_LLE_end_of_list)
        break;
-      if (llet != DW_LLE_offset_pair)
+      if (llet != DW_LLE_offset_pair
+         && llet != DW_LLE_start_end
+         && llet != DW_LLE_start_length)
        continue;
 
       if (start + 2 > section_end)
@@ -6053,8 +6450,8 @@ display_loclists_list (struct dwarf_section *section,
 
       READ_ULEB (length, start, section_end);
 
-      print_dwarf_vma (begin + base_address, pointer_size);
-      print_dwarf_vma (end + base_address, pointer_size);
+      print_dwarf_vma (begin, pointer_size);
+      print_dwarf_vma (end, pointer_size);
 
       putchar ('(');
       need_frame_base = decode_location_expression (start,
@@ -6848,6 +7245,8 @@ static int
 display_debug_str_offsets (struct dwarf_section *section,
                           void *file ATTRIBUTE_UNUSED)
 {
+  unsigned long idx;
+
   if (section->size == 0)
     {
       printf (_("\nThe %s section is empty.\n"), section->name);
@@ -6910,8 +7309,7 @@ display_debug_str_offsets (struct dwarf_section *section,
          printf (_("       Index   Offset [String]\n"));
        }
 
-      unsigned long index;
-      for (index = 0; length >= entry_length && curr < end; index ++)
+      for (idx = 0; length >= entry_length && curr < end; idx++)
        {
          dwarf_vma offset;
          const unsigned char * string;
@@ -6919,11 +7317,11 @@ display_debug_str_offsets (struct dwarf_section *section,
          SAFE_BYTE_GET_AND_INC (offset, curr, entry_length, end);
          if (dwo)
            string = (const unsigned char *)
-             fetch_indexed_string (index, NULL, entry_length, dwo);
+             fetch_indexed_string (idx, NULL, entry_length, dwo);
          else
            string = fetch_indirect_string (offset);
 
-         printf ("    %8lu %8s %s\n", index, dwarf_vmatoa ("x", offset),
+         printf ("    %8lu %8s %s\n", idx, dwarf_vmatoa ("x", offset),
                  string);
        }
     }
@@ -7632,10 +8030,8 @@ init_dwarf_regnames_by_bfd_arch_and_mach (enum bfd_architecture arch,
        {
        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;
 
@@ -10297,15 +10693,10 @@ parse_gnu_debugaltlink (struct dwarf_section * section, void * data)
   if (id_len < 0x14)
     return NULL;
 
-  build_id_data = calloc (1, sizeof * build_id_data);
-  if (build_id_data == NULL)
-    return NULL;
-
+  build_id_data = (Build_id_data *) data;
   build_id_data->len = id_len;
   build_id_data->data = section->start + namelen;
 
-  * (Build_id_data **) data = build_id_data;
-
   return name;
 }
 
@@ -10408,7 +10799,7 @@ load_separate_debug_info (const char *            main_filename,
     {
       warn (_("Corrupt debuglink section: %s\n"),
            xlink->name ? xlink->name : xlink->uncompressed_name);
-      return FALSE;
+      return NULL;
     }
     
   /* Attempt to locate the separate file.
@@ -10568,7 +10959,7 @@ load_separate_debug_info (const char *            main_filename,
     {
       warn (_("failed to open separate debug file: %s\n"), debug_filename);
       free (debug_filename);
-      return FALSE;
+      return NULL;
     }
 
   /* FIXME: We do not check to see if there are any other separate debug info
@@ -10613,6 +11004,52 @@ load_dwo_file (const char * main_filename, const char * name, const char * dir,
   return separate_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.  */
+
+static void
+check_for_and_load_links (void * file, const char * filename)
+{
+  void * handle = NULL;
+
+  if (load_debug_section (gnu_debugaltlink, file))
+    {
+      Build_id_data build_id_data;
+
+      handle = load_separate_debug_info (filename,
+                                        & debug_displays[gnu_debugaltlink].section,
+                                        parse_gnu_debugaltlink,
+                                        check_gnu_debugaltlink,
+                                        & build_id_data,
+                                        file);
+      if (handle)
+       {
+         assert (handle == first_separate_info->handle);
+         check_for_and_load_links (first_separate_info->handle,
+                                   first_separate_info->filename);
+       }
+    }
+
+  if (load_debug_section (gnu_debuglink, file))
+    {
+      unsigned long crc32;
+
+      handle = load_separate_debug_info (filename,
+                                        & debug_displays[gnu_debuglink].section,
+                                        parse_gnu_debuglink,
+                                        check_gnu_debuglink,
+                                        & crc32,
+                                        file);
+      if (handle)
+       {
+         assert (handle == first_separate_info->handle);
+         check_for_and_load_links (first_separate_info->handle,
+                                   first_separate_info->filename);
+       }
+    }
+}
+
 /* Load 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
@@ -10688,34 +11125,10 @@ load_separate_debug_files (void * file, const char * filename)
     return FALSE;
 
   /* FIXME: We do not check for the presence of both link sections in the same file.  */
-  /* FIXME: We do not check the separate debug info file to see if it too contains debuglinks.  */
   /* FIXME: We do not check for the presence of multiple, same-name debuglink sections.  */
   /* FIXME: We do not check for the presence of a dwo link as well as a debuglink.  */
 
-  if (load_debug_section (gnu_debugaltlink, file))
-    {
-      Build_id_data * build_id_data;
-
-      load_separate_debug_info (filename,
-                               & debug_displays[gnu_debugaltlink].section,
-                               parse_gnu_debugaltlink,
-                               check_gnu_debugaltlink,
-                               & build_id_data,
-                               file);
-    }
-
-  if (load_debug_section (gnu_debuglink, file))
-    {
-      unsigned long crc32;
-
-      load_separate_debug_info (filename,
-                               & debug_displays[gnu_debuglink].section,
-                               parse_gnu_debuglink,
-                               check_gnu_debuglink,
-                               & crc32,
-                               file);
-    }
-
+  check_for_and_load_links (file, filename);
   if (first_separate_info != NULL)
     return TRUE;
 
@@ -10728,25 +11141,26 @@ free_debug_memory (void)
 {
   unsigned int i;
 
-  free_abbrevs ();
+  free_all_abbrevs ();
 
+  free (cu_abbrev_map);
+  cu_abbrev_map = NULL;
+  next_free_abbrev_map_entry = 0;
+  
   for (i = 0; i < max; i++)
     free_debug_section ((enum dwarf_section_display_enum) i);
 
   if (debug_information != NULL)
     {
-      if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE)
+      for (i = 0; i < alloc_num_debug_info_entries; i++)
        {
-         for (i = 0; i < num_debug_info_entries; i++)
+         if (debug_information [i].max_loc_offsets)
            {
-             if (!debug_information [i].max_loc_offsets)
-               {
-                 free (debug_information [i].loc_offsets);
-                 free (debug_information [i].have_frame_base);
-               }
-             if (!debug_information [i].max_range_lists)
-               free (debug_information [i].range_lists);
+             free (debug_information [i].loc_offsets);
+             free (debug_information [i].have_frame_base);
            }
+         if (debug_information [i].max_range_lists)
+           free (debug_information [i].range_lists);
        }
       free (debug_information);
       debug_information = NULL;
This page took 0.043436 seconds and 4 git commands to generate.