+static int
+display_gdb_index (struct dwarf_section *section,
+ void *file ATTRIBUTE_UNUSED)
+{
+ unsigned char *start = section->start;
+ uint32_t version;
+ uint32_t cu_list_offset, tu_list_offset;
+ uint32_t address_table_offset, symbol_table_offset, constant_pool_offset;
+ unsigned int cu_list_elements, tu_list_elements;
+ unsigned int address_table_size, symbol_table_slots;
+ unsigned char *cu_list, *tu_list;
+ unsigned char *address_table, *symbol_table, *constant_pool;
+ unsigned int i;
+
+ /* The documentation for the format of this file is in gdb/dwarf2read.c. */
+
+ printf (_("Contents of the %s section:\n"), section->name);
+
+ if (section->size < 6 * sizeof (uint32_t))
+ {
+ warn (_("Truncated header in the %s section.\n"), section->name);
+ return 0;
+ }
+
+ version = byte_get_little_endian (start, 4);
+ printf (_("Version %ld\n"), (long) version);
+
+ /* Prior versions are obsolete, and future versions may not be
+ backwards compatible. */
+ if (version < 3 || version > 8)
+ {
+ warn (_("Unsupported version %lu.\n"), (unsigned long) version);
+ return 0;
+ }
+ if (version < 4)
+ warn (_("The address table data in version 3 may be wrong.\n"));
+ if (version < 5)
+ warn (_("Version 4 does not support case insensitive lookups.\n"));
+ if (version < 6)
+ warn (_("Version 5 does not include inlined functions.\n"));
+ if (version < 7)
+ warn (_("Version 6 does not include symbol attributes.\n"));
+ /* Version 7 indices generated by Gold have bad type unit references,
+ PR binutils/15021. But we don't know if the index was generated by
+ Gold or not, so to avoid worrying users with gdb-generated indices
+ we say nothing for version 7 here. */
+
+ cu_list_offset = byte_get_little_endian (start + 4, 4);
+ tu_list_offset = byte_get_little_endian (start + 8, 4);
+ address_table_offset = byte_get_little_endian (start + 12, 4);
+ symbol_table_offset = byte_get_little_endian (start + 16, 4);
+ constant_pool_offset = byte_get_little_endian (start + 20, 4);
+
+ if (cu_list_offset > section->size
+ || tu_list_offset > section->size
+ || address_table_offset > section->size
+ || symbol_table_offset > section->size
+ || constant_pool_offset > section->size)
+ {
+ warn (_("Corrupt header in the %s section.\n"), section->name);
+ return 0;
+ }
+
+ cu_list_elements = (tu_list_offset - cu_list_offset) / 8;
+ tu_list_elements = (address_table_offset - tu_list_offset) / 8;
+ address_table_size = symbol_table_offset - address_table_offset;
+ symbol_table_slots = (constant_pool_offset - symbol_table_offset) / 8;
+
+ cu_list = start + cu_list_offset;
+ tu_list = start + tu_list_offset;
+ address_table = start + address_table_offset;
+ symbol_table = start + symbol_table_offset;
+ constant_pool = start + constant_pool_offset;
+
+ printf (_("\nCU table:\n"));
+ for (i = 0; i < cu_list_elements; i += 2)
+ {
+ uint64_t cu_offset = byte_get_little_endian (cu_list + i * 8, 8);
+ uint64_t cu_length = byte_get_little_endian (cu_list + i * 8 + 8, 8);
+
+ printf (_("[%3u] 0x%lx - 0x%lx\n"), i / 2,
+ (unsigned long) cu_offset,
+ (unsigned long) (cu_offset + cu_length - 1));
+ }
+
+ printf (_("\nTU table:\n"));
+ for (i = 0; i < tu_list_elements; i += 3)
+ {
+ uint64_t tu_offset = byte_get_little_endian (tu_list + i * 8, 8);
+ uint64_t type_offset = byte_get_little_endian (tu_list + i * 8 + 8, 8);
+ uint64_t signature = byte_get_little_endian (tu_list + i * 8 + 16, 8);
+
+ printf (_("[%3u] 0x%lx 0x%lx "), i / 3,
+ (unsigned long) tu_offset,
+ (unsigned long) type_offset);
+ print_dwarf_vma (signature, 8);
+ printf ("\n");
+ }
+
+ printf (_("\nAddress table:\n"));
+ for (i = 0; i < address_table_size; i += 2 * 8 + 4)
+ {
+ uint64_t low = byte_get_little_endian (address_table + i, 8);
+ uint64_t high = byte_get_little_endian (address_table + i + 8, 8);
+ uint32_t cu_index = byte_get_little_endian (address_table + i + 16, 4);
+
+ print_dwarf_vma (low, 8);
+ print_dwarf_vma (high, 8);
+ printf (_("%lu\n"), (unsigned long) cu_index);
+ }
+
+ printf (_("\nSymbol table:\n"));
+ for (i = 0; i < symbol_table_slots; ++i)
+ {
+ uint32_t name_offset = byte_get_little_endian (symbol_table + i * 8, 4);
+ uint32_t cu_vector_offset = byte_get_little_endian (symbol_table + i * 8 + 4, 4);
+ uint32_t num_cus, cu;
+
+ if (name_offset != 0
+ || cu_vector_offset != 0)
+ {
+ unsigned int j;
+
+ printf ("[%3u] %s:", i, constant_pool + name_offset);
+ num_cus = byte_get_little_endian (constant_pool + cu_vector_offset, 4);
+ if (num_cus > 1)
+ printf ("\n");
+ for (j = 0; j < num_cus; ++j)
+ {
+ int is_static;
+ gdb_index_symbol_kind kind;
+
+ cu = byte_get_little_endian (constant_pool + cu_vector_offset + 4 + j * 4, 4);
+ is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (cu);
+ kind = GDB_INDEX_SYMBOL_KIND_VALUE (cu);
+ cu = GDB_INDEX_CU_VALUE (cu);
+ /* Convert to TU number if it's for a type unit. */
+ if (cu >= cu_list_elements / 2)
+ printf ("%cT%lu", num_cus > 1 ? '\t' : ' ',
+ (unsigned long) (cu - cu_list_elements / 2));
+ else
+ printf ("%c%lu", num_cus > 1 ? '\t' : ' ', (unsigned long) cu);
+
+ printf (" [%s, %s]",
+ is_static ? _("static") : _("global"),
+ get_gdb_index_symbol_kind_name (kind));
+ if (num_cus > 1)
+ printf ("\n");
+ }
+ if (num_cus <= 1)
+ printf ("\n");
+ }
+ }
+
+ return 1;
+}
+
+/* Pre-allocate enough space for the CU/TU sets needed. */
+
+static void
+prealloc_cu_tu_list (unsigned int nshndx)
+{
+ if (shndx_pool == NULL)
+ {
+ shndx_pool_size = nshndx;
+ shndx_pool_used = 0;
+ shndx_pool = (unsigned int *) xcmalloc (shndx_pool_size,
+ sizeof (unsigned int));
+ }
+ else
+ {
+ shndx_pool_size = shndx_pool_used + nshndx;
+ shndx_pool = (unsigned int *) xcrealloc (shndx_pool, shndx_pool_size,
+ sizeof (unsigned int));
+ }
+}
+
+static void
+add_shndx_to_cu_tu_entry (unsigned int shndx)
+{
+ if (shndx_pool_used >= shndx_pool_size)
+ {
+ error (_("Internal error: out of space in the shndx pool.\n"));
+ return;
+ }
+ shndx_pool [shndx_pool_used++] = shndx;
+}
+
+static void
+end_cu_tu_entry (void)
+{
+ if (shndx_pool_used >= shndx_pool_size)
+ {
+ error (_("Internal error: out of space in the shndx pool.\n"));
+ return;
+ }
+ shndx_pool [shndx_pool_used++] = 0;
+}
+
+/* Return the short name of a DWARF section given by a DW_SECT enumerator. */
+
+static const char *
+get_DW_SECT_short_name (unsigned int dw_sect)
+{
+ static char buf[16];
+
+ switch (dw_sect)
+ {
+ case DW_SECT_INFO:
+ return "info";
+ case DW_SECT_TYPES:
+ return "types";
+ case DW_SECT_ABBREV:
+ return "abbrev";
+ case DW_SECT_LINE:
+ return "line";
+ case DW_SECT_LOC:
+ return "loc";
+ case DW_SECT_STR_OFFSETS:
+ return "str_off";
+ case DW_SECT_MACINFO:
+ return "macinfo";
+ case DW_SECT_MACRO:
+ return "macro";
+ default:
+ break;
+ }
+
+ snprintf (buf, sizeof (buf), "%d", dw_sect);
+ return buf;
+}
+
+/* Process a CU or TU index. If DO_DISPLAY is true, print the contents.
+ These sections are extensions for Fission.
+ See http://gcc.gnu.org/wiki/DebugFissionDWP. */
+
+static int
+process_cu_tu_index (struct dwarf_section *section, int do_display)
+{
+ unsigned char *phdr = section->start;
+ unsigned char *limit = phdr + section->size;
+ unsigned char *phash;
+ unsigned char *pindex;
+ unsigned char *ppool;
+ unsigned int version;
+ unsigned int ncols = 0;
+ unsigned int nused;
+ unsigned int nslots;
+ unsigned int i;
+ unsigned int j;
+ dwarf_vma signature_high;
+ dwarf_vma signature_low;
+ char buf[64];
+
+ version = byte_get (phdr, 4);
+ if (version >= 2)
+ ncols = byte_get (phdr + 4, 4);
+ nused = byte_get (phdr + 8, 4);
+ nslots = byte_get (phdr + 12, 4);
+ phash = phdr + 16;
+ pindex = phash + nslots * 8;
+ ppool = pindex + nslots * 4;
+
+ if (do_display)
+ {
+ printf (_("Contents of the %s section:\n\n"), section->name);
+ printf (_(" Version: %d\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);
+ }
+
+ if (ppool > limit)
+ {
+ warn (_("Section %s too small for %d hash table entries\n"),
+ section->name, nslots);
+ return 0;
+ }
+
+ if (version == 1)
+ {
+ if (!do_display)
+ prealloc_cu_tu_list ((limit - ppool) / 4);
+ for (i = 0; i < nslots; i++)
+ {
+ unsigned char *shndx_list;
+ unsigned int shndx;
+
+ byte_get_64 (phash, &signature_high, &signature_low);
+ if (signature_high != 0 || signature_low != 0)
+ {
+ j = byte_get (pindex, 4);
+ shndx_list = ppool + j * 4;
+ if (do_display)
+ printf (_(" [%3d] Signature: 0x%s Sections: "),
+ i, dwarf_vmatoa64 (signature_high, signature_low,
+ buf, sizeof (buf)));
+ for (;;)
+ {
+ if (shndx_list >= limit)
+ {
+ warn (_("Section %s too small for shndx pool\n"),
+ section->name);
+ return 0;
+ }
+ shndx = byte_get (shndx_list, 4);
+ if (shndx == 0)
+ break;
+ if (do_display)
+ printf (" %d", shndx);
+ else
+ add_shndx_to_cu_tu_entry (shndx);
+ shndx_list += 4;
+ }
+ if (do_display)
+ printf ("\n");
+ else
+ end_cu_tu_entry ();
+ }
+ phash += 8;
+ pindex += 4;
+ }
+ }
+ else if (version == 2)
+ {
+ unsigned int val;
+ 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;
+ bfd_boolean is_tu_index;
+ struct cu_tu_set *this_set = NULL;
+ unsigned int row;
+ unsigned char *prow;
+
+ is_tu_index = strcmp (section->name, ".debug_tu_index") == 0;
+
+ if (pend > limit)
+ {
+ warn (_("Section %s too small for offset and size tables\n"),
+ section->name);
+ return 0;
+ }
+
+ if (do_display)
+ {
+ printf (_(" Offset table\n"));
+ printf (" slot %-16s ",
+ is_tu_index ? _("signature") : _("dwo_id"));
+ }
+ else
+ {
+ if (is_tu_index)
+ {
+ tu_count = nused;
+ tu_sets = xcmalloc (nused, sizeof (struct cu_tu_set));
+ this_set = tu_sets;
+ }
+ else
+ {
+ cu_count = nused;
+ cu_sets = xcmalloc (nused, sizeof (struct cu_tu_set));
+ this_set = cu_sets;
+ }
+ }
+ if (do_display)
+ {
+ for (j = 0; j < ncols; j++)
+ {
+ dw_sect = byte_get (ppool + j * 4, 4);
+ printf (" %8s", get_DW_SECT_short_name (dw_sect));
+ }
+ printf ("\n");
+ }
+ for (i = 0; i < nslots; i++)
+ {
+ byte_get_64 (ph, &signature_high, &signature_low);
+ row = byte_get (pi, 4);
+ if (row != 0)
+ {
+ if (!do_display)
+ memcpy (&this_set[row - 1].signature, ph, sizeof (uint64_t));
+ prow = poffsets + (row - 1) * ncols * 4;
+ if (do_display)
+ printf (_(" [%3d] 0x%s"),
+ i, dwarf_vmatoa64 (signature_high, signature_low,
+ buf, sizeof (buf)));
+ for (j = 0; j < ncols; j++)
+ {
+ val = byte_get (prow + j * 4, 4);
+ if (do_display)
+ printf (" %8d", val);
+ else
+ {
+ dw_sect = byte_get (ppool + j * 4, 4);
+ this_set [row - 1].section_offsets [dw_sect] = val;
+ }
+ }
+ if (do_display)
+ printf ("\n");
+ }
+ ph += 8;
+ pi += 4;
+ }
+
+ ph = phash;
+ pi = pindex;
+ if (do_display)
+ {
+ printf ("\n");
+ printf (_(" Size table\n"));
+ printf (" slot %-16s ",
+ is_tu_index ? _("signature") : _("dwo_id"));
+ }
+ for (j = 0; j < ncols; j++)
+ {
+ val = byte_get (ppool + j * 4, 4);
+ if (do_display)
+ printf (" %8s", get_DW_SECT_short_name (val));
+ }
+ if (do_display)
+ printf ("\n");
+ for (i = 0; i < nslots; i++)
+ {
+ byte_get_64 (ph, &signature_high, &signature_low);
+ row = byte_get (pi, 4);
+ if (row != 0)
+ {
+ prow = psizes + (row - 1) * ncols * 4;
+ if (do_display)
+ printf (_(" [%3d] 0x%s"),
+ i, dwarf_vmatoa64 (signature_high, signature_low,
+ buf, sizeof (buf)));
+ for (j = 0; j < ncols; j++)
+ {
+ val = byte_get (prow + j * 4, 4);
+ if (do_display)
+ printf (" %8d", val);
+ else
+ {
+ dw_sect = byte_get (ppool + j * 4, 4);
+ this_set [row - 1].section_sizes [dw_sect] = val;
+ }
+ }
+ if (do_display)
+ printf ("\n");
+ }
+ ph += 8;
+ pi += 4;
+ }
+ }
+ else if (do_display)
+ printf (_(" Unsupported version\n"));
+
+ if (do_display)
+ printf ("\n");
+
+ return 1;
+}
+
+/* Load the CU and TU indexes if present. This will build a list of
+ section sets that we can use to associate a .debug_info.dwo section
+ with its associated .debug_abbrev.dwo section in a .dwp file. */
+
+static void
+load_cu_tu_indexes (void *file)
+{
+ /* If we have already loaded (or tried to load) the CU and TU indexes
+ then do not bother to repeat the task. */
+ if (cu_tu_indexes_read)
+ return;
+
+ if (load_debug_section (dwp_cu_index, file))
+ process_cu_tu_index (&debug_displays [dwp_cu_index].section, 0);
+
+ if (load_debug_section (dwp_tu_index, file))
+ process_cu_tu_index (&debug_displays [dwp_tu_index].section, 0);
+
+ cu_tu_indexes_read = 1;
+}
+
+/* Find the set of sections that includes section SHNDX. */
+
+unsigned int *
+find_cu_tu_set (void *file, unsigned int shndx)
+{
+ unsigned int i;
+
+ load_cu_tu_indexes (file);
+
+ /* Find SHNDX in the shndx pool. */
+ for (i = 0; i < shndx_pool_used; i++)
+ if (shndx_pool [i] == shndx)
+ break;
+
+ if (i >= shndx_pool_used)
+ return NULL;
+
+ /* Now backup to find the first entry in the set. */
+ while (i > 0 && shndx_pool [i - 1] != 0)
+ i--;
+
+ return shndx_pool + i;
+}
+
+/* Display a .debug_cu_index or .debug_tu_index section. */
+
+static int
+display_cu_index (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED)
+{
+ return process_cu_tu_index (section, 1);
+}
+