init_dwarf_regnames_by_bfd_arch_and_mach (enum bfd_architecture arch,
					  unsigned long mach)
{
  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_x64_32:
	case bfd_mach_x64_32_intel_syntax:
	  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;

    case bfd_arch_riscv:
      init_dwarf_regnames_riscv ();
      break;

    default:
      break;
    }
}


Replace a run-time assertion failure with a warning message when parsing corrupt DWARF data.

	PR 29289
	* dwarf.c (display_debug_names): Replace assert with a warning
	message.

dwarf_select_sections_by_letters (const char *letters)
{
  int result = 0;

  while (* letters)
    {
      const debug_dump_long_opts *entry;

      for (entry = debug_option_table; entry->letter; entry++)
	{
	  if (entry->letter == * letters)
	    {
	      * entry->variable |= entry->val;
	      result |= entry->val;
	      break;
	    }
	}

      if (entry->letter == 0)
	warn (_("Unrecognized debug letter option '%c'\n"), * letters);

      letters ++;
    }

  /* The --debug-dump=frames-interp option also enables the
     --debug-dump=frames option.  */
  if (do_debug_frames_interp)
    do_debug_frames = 1;

  return result;
}


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;
}


display_debug_loc (struct dwarf_section *section, void *file)
{
  unsigned char *start = section->start, *vstart = NULL;
  dwarf_vma bytes;
  unsigned char *section_begin = start;
  unsigned int num_loc_list = 0;
  dwarf_vma last_offset = 0;
  dwarf_vma last_view = 0;
  unsigned int first = 0;
  unsigned int i;
  unsigned int j;
  int seen_first_offset = 0;
  int locs_sorted = 1;
  unsigned char *next = start, *vnext = vstart;
  unsigned int *array = NULL;
  const char *suffix = strrchr (section->name, '.');
  bool is_dwo = false;
  int is_loclists = strstr (section->name, "debug_loclists") != NULL;
  dwarf_vma expected_start = 0;

  if (suffix && strcmp (suffix, ".dwo") == 0)
    is_dwo = true;

  bytes = section->size;

  if (bytes == 0)
    {
      printf (_("\nThe %s section is empty.\n"), section->name);
      return 0;
    }

  if (is_loclists)
    {
      unsigned char *hdrptr = section_begin;
      dwarf_vma ll_length;
      unsigned short ll_version;
      unsigned char *end = section_begin + section->size;
      unsigned char address_size, segment_selector_size;
      uint32_t offset_entry_count;

      SAFE_BYTE_GET_AND_INC (ll_length, hdrptr, 4, end);
      if (ll_length == 0xffffffff)
	SAFE_BYTE_GET_AND_INC (ll_length, hdrptr, 8, end);

      SAFE_BYTE_GET_AND_INC (ll_version, hdrptr, 2, end);
      if (ll_version != 5)
	{
	  warn (_("The %s section contains corrupt or "
		  "unsupported version number: %d.\n"),
		section->name, ll_version);
	  return 0;
	}

      SAFE_BYTE_GET_AND_INC (address_size, hdrptr, 1, end);

      SAFE_BYTE_GET_AND_INC (segment_selector_size, hdrptr, 1, end);
      if (segment_selector_size != 0)
	{
	  warn (_("The %s section contains "
		  "unsupported segment selector size: %d.\n"),
		section->name, segment_selector_size);
	  return 0;
	}

      SAFE_BYTE_GET_AND_INC (offset_entry_count, hdrptr, 4, end);

      if (offset_entry_count != 0)
	return display_offset_entry_loclists (section);

      expected_start = hdrptr - section_begin;
    }

  if (load_debug_info (file) == 0)
    {
      warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"),
	    section->name);
      return 0;
    }

  /* Check the order of location list in .debug_info section. If
     offsets of location lists are in the ascending order, we can
     use `debug_information' directly.  */
  for (i = 0; i < num_debug_info_entries; i++)
    {
      unsigned int num;

      num = debug_information [i].num_loc_offsets;
      if (num > num_loc_list)
	num_loc_list = num;

      /* Check if we can use `debug_information' directly.  */
      if (locs_sorted && num != 0)
	{
	  if (!seen_first_offset)
	    {
	      /* This is the first location list.  */
	      last_offset = debug_information [i].loc_offsets [0];
	      last_view = debug_information [i].loc_views [0];
	      first = i;
	      seen_first_offset = 1;
	      j = 1;
	    }
	  else
	    j = 0;

	  for (; j < num; j++)
	    {
	      if (last_offset >
		  debug_information [i].loc_offsets [j]
		  || (last_offset == debug_information [i].loc_offsets [j]
		      && last_view > debug_information [i].loc_views [j]))
		{
		  locs_sorted = 0;
		  break;
		}
	      last_offset = debug_information [i].loc_offsets [j];
	      last_view = debug_information [i].loc_views [j];
	    }
	}
    }

  if (!seen_first_offset)
    error (_("No location lists in .debug_info section!\n"));

  if (debug_information [first].num_loc_offsets > 0
      && debug_information [first].loc_offsets [0] != expected_start
      && debug_information [first].loc_views [0] != expected_start)
    warn (_("Location lists in %s section start at 0x%s rather than 0x%s\n"),
	  section->name,
	  dwarf_vmatoa ("x", debug_information [first].loc_offsets [0]),
	  dwarf_vmatoa ("x", expected_start));

  if (!locs_sorted)
    array = (unsigned int *) xcmalloc (num_loc_list, sizeof (unsigned int));

  introduce (section, false);

  if (reloc_at (section, 0))
    printf (_(" Warning: This section has relocations - addresses seen here may not be accurate.\n\n"));

  printf (_("    Offset   Begin            End              Expression\n"));

  seen_first_offset = 0;
  for (i = first; i < num_debug_info_entries; i++)
    {
      dwarf_vma offset, voffset;
      dwarf_vma base_address;
      unsigned int k;
      int has_frame_base;

      if (!locs_sorted)
	{
	  for (k = 0; k < debug_information [i].num_loc_offsets; k++)
	    array[k] = k;
	  loc_offsets = debug_information [i].loc_offsets;
	  loc_views = debug_information [i].loc_views;
	  qsort (array, debug_information [i].num_loc_offsets,
		 sizeof (*array), loc_offsets_compar);
	}

      int adjacent_view_loclists = 1;
      for (k = 0; k < debug_information [i].num_loc_offsets; k++)
	{
	  j = locs_sorted ? k : array[k];
	  if (k
	      && (debug_information [i].loc_offsets [locs_sorted
						    ? k - 1 : array [k - 1]]
		  == debug_information [i].loc_offsets [j])
	      && (debug_information [i].loc_views [locs_sorted
						   ? k - 1 : array [k - 1]]
		  == debug_information [i].loc_views [j]))
	    continue;
	  has_frame_base = debug_information [i].have_frame_base [j];
	  offset = debug_information [i].loc_offsets [j];
	  next = section_begin + offset;
	  voffset = debug_information [i].loc_views [j];
	  if (voffset != vm1)
	    vnext = section_begin + voffset;
	  else
	    vnext = NULL;
	  base_address = debug_information [i].base_address;

	  if (vnext && vnext < next)
	    {
	      vstart = vnext;
	      display_view_pair_list (section, &vstart, i, next);
	      if (start == vnext)
		start = vstart;
	    }

	  if (!seen_first_offset || !adjacent_view_loclists)
	    seen_first_offset = 1;
	  else
	    {
	      if (start < next)
		warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
		      (unsigned long) (start - section_begin),
		      (unsigned long) offset,
		      section->name);
	      else if (start > next)
		warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
		      (unsigned long) (start - section_begin),
		      (unsigned long) offset,
		      section->name);
	    }
	  start = next;
	  vstart = vnext;

	  if (offset >= bytes)
	    {
	      warn (_("Offset 0x%lx is bigger than %s section size.\n"),
		    (unsigned long) offset,
		    section->name);
	      continue;
	    }

	  if (vnext && voffset >= bytes)
	    {
	      warn (_("View Offset 0x%lx is bigger than %s section size.\n"),
		    (unsigned long) voffset,
		    section->name);
	      continue;
	    }

	  if (!is_loclists)
	    {
	      if (is_dwo)
		display_loc_list_dwo (section, &start, i, offset,
				      &vstart, has_frame_base);
	      else
		display_loc_list (section, &start, i, offset, base_address,
				  &vstart, has_frame_base);
	    }
	  else
	    {
	      if (is_dwo)
		warn (_("DWO is not yet supported.\n"));
	      else
		display_loclists_list (section, &start, i, offset, base_address,
				       &vstart, has_frame_base);
	    }

	  /* FIXME: this arrangement is quite simplistic.  Nothing
	     requires locview lists to be adjacent to corresponding
	     loclists, and a single loclist could be augmented by
	     different locview lists, and vice-versa, unlikely as it
	     is that it would make sense to do so.  Hopefully we'll
	     have view pair support built into loclists before we ever
	     need to address all these possibilities.  */
	  if (adjacent_view_loclists && vnext
	      && vnext != start && vstart != next)
	    {
	      adjacent_view_loclists = 0;
	      warn (_("Hole and overlap detection requires adjacent view lists and loclists.\n"));
	    }

	  if (vnext && vnext == start)
	    display_view_pair_list (section, &start, i, vstart);
	}
    }

  if (start < section->start + section->size)
    warn (ngettext ("There is %ld unused byte at the end of section %s\n",
		    "There are %ld unused bytes at the end of section %s\n",
		    (long) (section->start + section->size - start)),
	  (long) (section->start + section->size - start), section->name);
  putchar ('\n');
  free (array);
  return 1;
}


loc_offsets_compar (const void *ap, const void *bp)
{
  dwarf_vma a = loc_offsets[*(const unsigned int *) ap];
  dwarf_vma b = loc_offsets[*(const unsigned int *) bp];

  int ret = (a > b) - (b > a);
  if (ret)
    return ret;

  a = loc_views[*(const unsigned int *) ap];
  b = loc_views[*(const unsigned int *) bp];

  ret = (a > b) - (b > a);

  return ret;
}


display_debug_types (struct dwarf_section *section, void *file)
{
  return process_debug_info (section, file, section->abbrev_sec, false, true);
}


display_debug_links (struct dwarf_section *  section,
		     void *                  file ATTRIBUTE_UNUSED)
{
  const unsigned char * filename;
  unsigned int          filelen;

  introduce (section, false);

  /* The .gnu_debuglink section is formatted as:
      (c-string)  Filename.
      (padding)   If needed to reach a 4 byte boundary.
      (uint32_t)  CRC32 value.

    The .gun_debugaltlink section is formatted as:
      (c-string)  Filename.
      (binary)    Build-ID.  */

  filename =  section->start;
  filelen = strnlen ((const char *) filename, section->size);
  if (filelen == section->size)
    {
      warn (_("The debuglink filename is corrupt/missing\n"));
      return 0;
    }

  printf (_("  Separate debug info file: %s\n"), filename);

  if (startswith (section->name, ".gnu_debuglink"))
    {
      unsigned int          crc32;
      unsigned int          crc_offset;

      crc_offset = filelen + 1;
      crc_offset = (crc_offset + 3) & ~3;
      if (crc_offset + 4 > section->size)
	{
	  warn (_("CRC offset missing/truncated\n"));
	  return 0;
	}

      crc32 = byte_get (filename + crc_offset, 4);

      printf (_("  CRC value: %#x\n"), crc32);

      if (crc_offset + 4 < section->size)
	{
	  warn (_("There are %#lx extraneous bytes at the end of the section\n"),
		(long)(section->size - (crc_offset + 4)));
	  return 0;
	}
    }
  else /* startswith (section->name, ".gnu_debugaltlink") */
    {
      const unsigned char * build_id = section->start + filelen + 1;
      bfd_size_type         build_id_len = section->size - (filelen + 1);
      bfd_size_type         printed;

      /* FIXME: Should we support smaller build-id notes ?  */
      if (build_id_len < 0x14)
	{
	  warn (_("Build-ID is too short (%#lx bytes)\n"), (long) build_id_len);
	  return 0;
	}

      printed = printf (_("  Build-ID (%#lx bytes):"), (long) build_id_len);
      display_data (printed, build_id, build_id_len);
      putchar ('\n');
    }

  putchar ('\n');
  return 1;
}


init_dwarf_regnames_riscv (void)
{
  dwarf_regnames = NULL;
  dwarf_regnames_count = 8192;
  dwarf_regnames_lookup_func = regname_internal_riscv;
}


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;
}


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;
}


display_view_pair_list (struct dwarf_section *section,
			unsigned char **vstart_ptr,
			unsigned int debug_info_entry,
			unsigned char *vlistend)
{
  unsigned char *vstart = *vstart_ptr;
  unsigned char *section_end = section->start + section->size;
  unsigned int pointer_size = debug_information [debug_info_entry].pointer_size;

  if (vlistend < section_end)
    section_end = vlistend;

  putchar ('\n');

  while (vstart < section_end)
    {
      dwarf_vma off = vstart - section->start;
      dwarf_vma vbegin, vend;

      READ_ULEB (vbegin, vstart, section_end);
      if (vstart == section_end)
	break;

      READ_ULEB (vend, vstart, section_end);
      printf ("    %8.8lx ", (unsigned long) off);

      print_dwarf_view (vbegin, pointer_size, 1);
      print_dwarf_view (vend, pointer_size, 1);
      printf (_("location view pair\n"));
    }

  putchar ('\n');
  *vstart_ptr = vstart;
}


display_debug_frames (struct dwarf_section *section,
		      void *file ATTRIBUTE_UNUSED)
{
  unsigned char *start = section->start;
  unsigned char *end = start + section->size;
  unsigned char *section_start = start;
  Frame_Chunk *chunks = NULL, *forward_refs = NULL;
  Frame_Chunk *remembered_state = NULL;
  Frame_Chunk *rs;
  bool is_eh = strcmp (section->name, ".eh_frame") == 0;
  unsigned int max_regs = 0;
  const char *bad_reg = _("bad register: ");
  unsigned int saved_eh_addr_size = eh_addr_size;

  introduce (section, false);

  while (start < end)
    {
      unsigned char *saved_start;
      unsigned char *block_end;
      dwarf_vma length;
      dwarf_vma cie_id;
      Frame_Chunk *fc;
      Frame_Chunk *cie;
      int need_col_headers = 1;
      unsigned char *augmentation_data = NULL;
      bfd_size_type augmentation_data_len = 0;
      unsigned int encoded_ptr_size = saved_eh_addr_size;
      unsigned int offset_size;
      bool all_nops;
      static Frame_Chunk fde_fc;

      saved_start = start;

      SAFE_BYTE_GET_AND_INC (length, start, 4, end);

      if (length == 0)
	{
	  printf ("\n%08lx ZERO terminator\n\n",
		    (unsigned long)(saved_start - section_start));
	  /* Skip any zero terminators that directly follow.
	     A corrupt section size could have loaded a whole
	     slew of zero filled memory bytes.  eg
	     PR 17512: file: 070-19381-0.004.  */
	  while (start < end && * start == 0)
	    ++ start;
	  continue;
	}

      if (length == 0xffffffff)
	{
	  SAFE_BYTE_GET_AND_INC (length, start, 8, end);
	  offset_size = 8;
	}
      else
	offset_size = 4;

      if (length > (size_t) (end - start))
	{
	  warn ("Invalid length 0x%s in FDE at %#08lx\n",
		dwarf_vmatoa_1 (NULL, length, offset_size),
		(unsigned long) (saved_start - section_start));
	  block_end = end;
	}
      else
	block_end = start + length;

      SAFE_BYTE_GET_AND_INC (cie_id, start, offset_size, block_end);

      if (is_eh ? (cie_id == 0) : ((offset_size == 4 && cie_id == DW_CIE_ID)
				   || (offset_size == 8 && cie_id == DW64_CIE_ID)))
	{
	  int version;
	  unsigned int mreg;

	  start = read_cie (start, block_end, &cie, &version,
			    &augmentation_data_len, &augmentation_data);
	  /* PR 17512: file: 027-135133-0.005.  */
	  if (cie == NULL)
	    break;

	  fc = cie;
	  fc->next = chunks;
	  chunks = fc;
	  fc->chunk_start = saved_start;
	  mreg = max_regs > 0 ? max_regs - 1 : 0;
	  if (mreg < fc->ra)
	    mreg = fc->ra;
	  if (frame_need_space (fc, mreg) < 0)
	    break;
	  if (fc->fde_encoding)
	    encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);

	  printf ("\n%08lx ", (unsigned long) (saved_start - section_start));
	  print_dwarf_vma (length, fc->ptr_size);
	  print_dwarf_vma (cie_id, offset_size);

	  if (do_debug_frames_interp)
	    {
	      printf ("CIE \"%s\" cf=%d df=%d ra=%d\n", fc->augmentation,
		      fc->code_factor, fc->data_factor, fc->ra);
	    }
	  else
	    {
	      printf ("CIE\n");
	      printf ("  Version:               %d\n", version);
	      printf ("  Augmentation:          \"%s\"\n", fc->augmentation);
	      if (version >= 4)
		{
		  printf ("  Pointer Size:          %u\n", fc->ptr_size);
		  printf ("  Segment Size:          %u\n", fc->segment_size);
		}
	      printf ("  Code alignment factor: %u\n", fc->code_factor);
	      printf ("  Data alignment factor: %d\n", fc->data_factor);
	      printf ("  Return address column: %d\n", fc->ra);

	      if (augmentation_data_len)
		display_augmentation_data (augmentation_data, augmentation_data_len);

	      putchar ('\n');
	    }
	}
      else
	{
	  unsigned char *look_for;
	  unsigned long segment_selector;
	  dwarf_vma cie_off;

	  cie_off = cie_id;
	  if (is_eh)
	    {
	      dwarf_vma sign = (dwarf_vma) 1 << (offset_size * 8 - 1);
	      cie_off = (cie_off ^ sign) - sign;
	      cie_off = start - 4 - section_start - cie_off;
	    }

	  look_for = section_start + cie_off;
	  if (cie_off <= (dwarf_vma) (saved_start - section_start))
	    {
	      for (cie = chunks; cie ; cie = cie->next)
		if (cie->chunk_start == look_for)
		  break;
	    }
	  else if (cie_off >= section->size)
	    cie = NULL;
	  else
	    {
	      for (cie = forward_refs; cie ; cie = cie->next)
		if (cie->chunk_start == look_for)
		  break;
	      if (!cie)
		{
		  unsigned int off_size;
		  unsigned char *cie_scan;

		  cie_scan = look_for;
		  off_size = 4;
		  SAFE_BYTE_GET_AND_INC (length, cie_scan, 4, end);
		  if (length == 0xffffffff)
		    {
		      SAFE_BYTE_GET_AND_INC (length, cie_scan, 8, end);
		      off_size = 8;
		    }
		  if (length != 0 && length <= (size_t) (end - cie_scan))
		    {
		      dwarf_vma c_id;
		      unsigned char *cie_end = cie_scan + length;

		      SAFE_BYTE_GET_AND_INC (c_id, cie_scan, off_size,
					     cie_end);
		      if (is_eh
			  ? c_id == 0
			  : ((off_size == 4 && c_id == DW_CIE_ID)
			     || (off_size == 8 && c_id == DW64_CIE_ID)))
			{
			  int version;
			  unsigned int mreg;

			  read_cie (cie_scan, cie_end, &cie, &version,
				    &augmentation_data_len, &augmentation_data);
			  /* PR 17512: file: 3450-2098-0.004.  */
			  if (cie == NULL)
			    {
			      warn (_("Failed to read CIE information\n"));
			      break;
			    }
			  cie->next = forward_refs;
			  forward_refs = cie;
			  cie->chunk_start = look_for;
			  mreg = max_regs > 0 ? max_regs - 1 : 0;
			  if (mreg < cie->ra)
			    mreg = cie->ra;
			  if (frame_need_space (cie, mreg) < 0)
			    {
			      warn (_("Invalid max register\n"));
			      break;
			    }
			  if (cie->fde_encoding)
			    encoded_ptr_size
			      = size_of_encoded_value (cie->fde_encoding);
			}
		    }
		}
	    }

	  fc = &fde_fc;
	  memset (fc, 0, sizeof (Frame_Chunk));

	  if (!cie)
	    {
	      fc->ncols = 0;
	      fc->col_type = (short int *) xmalloc (sizeof (short int));
	      fc->col_offset = (int *) xmalloc (sizeof (int));
	      if (frame_need_space (fc, max_regs > 0 ? max_regs - 1 : 0) < 0)
		{
		  warn (_("Invalid max register\n"));
		  break;
		}
	      cie = fc;
	      fc->augmentation = "";
	      fc->fde_encoding = 0;
	      fc->ptr_size = eh_addr_size;
	      fc->segment_size = 0;
	    }
	  else
	    {
	      fc->ncols = cie->ncols;
	      fc->col_type = (short int *) xcmalloc (fc->ncols, sizeof (short int));
	      fc->col_offset =  (int *) xcmalloc (fc->ncols, sizeof (int));
	      memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int));
	      memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int));
	      fc->augmentation = cie->augmentation;
	      fc->ptr_size = cie->ptr_size;
	      eh_addr_size = cie->ptr_size;
	      fc->segment_size = cie->segment_size;
	      fc->code_factor = cie->code_factor;
	      fc->data_factor = cie->data_factor;
	      fc->cfa_reg = cie->cfa_reg;
	      fc->cfa_offset = cie->cfa_offset;
	      fc->ra = cie->ra;
	      if (frame_need_space (fc, max_regs > 0 ? max_regs - 1: 0) < 0)
		{
		  warn (_("Invalid max register\n"));
		  break;
		}
	      fc->fde_encoding = cie->fde_encoding;
	    }

	  if (fc->fde_encoding)
	    encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);

	  segment_selector = 0;
	  if (fc->segment_size)
	    {
	      if (fc->segment_size > sizeof (segment_selector))
		{
		  /* PR 17512: file: 9e196b3e.  */
		  warn (_("Probably corrupt segment size: %d - using 4 instead\n"), fc->segment_size);
		  fc->segment_size = 4;
		}
	      SAFE_BYTE_GET_AND_INC (segment_selector, start,
				     fc->segment_size, block_end);
	    }

	  fc->pc_begin = get_encoded_value (&start, fc->fde_encoding, section,
					    block_end);

	  /* FIXME: It appears that sometimes the final pc_range value is
	     encoded in less than encoded_ptr_size bytes.  See the x86_64
	     run of the "objcopy on compressed debug sections" test for an
	     example of this.  */
	  SAFE_BYTE_GET_AND_INC (fc->pc_range, start, encoded_ptr_size,
				 block_end);

	  if (cie->augmentation[0] == 'z')
	    {
	      READ_ULEB (augmentation_data_len, start, block_end);
	      augmentation_data = start;
	      /* PR 17512 file: 722-8446-0.004 and PR 22386.  */
	      if (augmentation_data_len > (bfd_size_type) (block_end - start))
		{
		  warn (_("Augmentation data too long: 0x%s, "
			  "expected at most %#lx\n"),
			dwarf_vmatoa ("x", augmentation_data_len),
			(unsigned long) (block_end - start));
		  start = block_end;
		  augmentation_data = NULL;
		  augmentation_data_len = 0;
		}
	      start += augmentation_data_len;
	    }

	  printf ("\n%08lx %s %s FDE ",
		  (unsigned long)(saved_start - section_start),
		  dwarf_vmatoa_1 (NULL, length, fc->ptr_size),
		  dwarf_vmatoa_1 (NULL, cie_id, offset_size));

	  if (cie->chunk_start)
	    printf ("cie=%08lx",
		    (unsigned long) (cie->chunk_start - section_start));
	  else
	    /* Ideally translate "invalid " to 8 chars, trailing space
	       is optional.  */
	    printf (_("cie=invalid "));

	  printf (" pc=");
	  if (fc->segment_size)
	    printf ("%04lx:", segment_selector);

	  printf ("%s..%s\n",
		  dwarf_vmatoa_1 (NULL, fc->pc_begin, fc->ptr_size),
		  dwarf_vmatoa_1 (NULL, fc->pc_begin + fc->pc_range, fc->ptr_size));

	  if (! do_debug_frames_interp && augmentation_data_len)
	    {
	      display_augmentation_data (augmentation_data, augmentation_data_len);
	      putchar ('\n');
	    }
	}

      /* At this point, fc is the current chunk, cie (if any) is set, and
	 we're about to interpret instructions for the chunk.  */
      /* ??? At present we need to do this always, since this sizes the
	 fc->col_type and fc->col_offset arrays, which we write into always.
	 We should probably split the interpreted and non-interpreted bits
	 into two different routines, since there's so much that doesn't
	 really overlap between them.  */
      if (1 || do_debug_frames_interp)
	{
	  /* Start by making a pass over the chunk, allocating storage
	     and taking note of what registers are used.  */
	  unsigned char *tmp = start;

	  while (start < block_end)
	    {
	      unsigned int reg, op, opa;
	      unsigned long temp;

	      op = *start++;
	      opa = op & 0x3f;
	      if (op & 0xc0)
		op &= 0xc0;

	      /* Warning: if you add any more cases to this switch, be
		 sure to add them to the corresponding switch below.  */
	      reg = -1u;
	      switch (op)
		{
		case DW_CFA_advance_loc:
		  break;
		case DW_CFA_offset:
		  SKIP_ULEB (start, block_end);
		  reg = opa;
		  break;
		case DW_CFA_restore:
		  reg = opa;
		  break;
		case DW_CFA_set_loc:
		  if ((size_t) (block_end - start) < encoded_ptr_size)
		    start = block_end;
		  else
		    start += encoded_ptr_size;
		  break;
		case DW_CFA_advance_loc1:
		  if ((size_t) (block_end - start) < 1)
		    start = block_end;
		  else
		    start += 1;
		  break;
		case DW_CFA_advance_loc2:
		  if ((size_t) (block_end - start) < 2)
		    start = block_end;
		  else
		    start += 2;
		  break;
		case DW_CFA_advance_loc4:
		  if ((size_t) (block_end - start) < 4)
		    start = block_end;
		  else
		    start += 4;
		  break;
		case DW_CFA_offset_extended:
		case DW_CFA_val_offset:
		  READ_ULEB (reg, start, block_end);
		  SKIP_ULEB (start, block_end);
		  break;
		case DW_CFA_restore_extended:
		  READ_ULEB (reg, start, block_end);
		  break;
		case DW_CFA_undefined:
		  READ_ULEB (reg, start, block_end);
		  break;
		case DW_CFA_same_value:
		  READ_ULEB (reg, start, block_end);
		  break;
		case DW_CFA_register:
		  READ_ULEB (reg, start, block_end);
		  SKIP_ULEB (start, block_end);
		  break;
		case DW_CFA_def_cfa:
		  SKIP_ULEB (start, block_end);
		  SKIP_ULEB (start, block_end);
		  break;
		case DW_CFA_def_cfa_register:
		  SKIP_ULEB (start, block_end);
		  break;
		case DW_CFA_def_cfa_offset:
		  SKIP_ULEB (start, block_end);
		  break;
		case DW_CFA_def_cfa_expression:
		  READ_ULEB (temp, start, block_end);
		  if ((size_t) (block_end - start) < temp)
		    start = block_end;
		  else
		    start += temp;
		  break;
		case DW_CFA_expression:
		case DW_CFA_val_expression:
		  READ_ULEB (reg, start, block_end);
		  READ_ULEB (temp, start, block_end);
		  if ((size_t) (block_end - start) < temp)
		    start = block_end;
		  else
		    start += temp;
		  break;
		case DW_CFA_offset_extended_sf:
		case DW_CFA_val_offset_sf:
		  READ_ULEB (reg, start, block_end);
		  SKIP_SLEB (start, block_end);
		  break;
		case DW_CFA_def_cfa_sf:
		  SKIP_ULEB (start, block_end);
		  SKIP_SLEB (start, block_end);
		  break;
		case DW_CFA_def_cfa_offset_sf:
		  SKIP_SLEB (start, block_end);
		  break;
		case DW_CFA_MIPS_advance_loc8:
		  if ((size_t) (block_end - start) < 8)
		    start = block_end;
		  else
		    start += 8;
		  break;
		case DW_CFA_GNU_args_size:
		  SKIP_ULEB (start, block_end);
		  break;
		case DW_CFA_GNU_negative_offset_extended:
		  READ_ULEB (reg, start, block_end);
		  SKIP_ULEB (start, block_end);
		  break;
		default:
		  break;
		}
	      if (reg != -1u && frame_need_space (fc, reg) >= 0)
		{
		  /* Don't leave any reg as DW_CFA_unreferenced so
		     that frame_display_row prints name of regs in
		     header, and all referenced regs in each line.  */
		  if (reg >= cie->ncols
		      || cie->col_type[reg] == DW_CFA_unreferenced)
		    fc->col_type[reg] = DW_CFA_undefined;
		  else
		    fc->col_type[reg] = cie->col_type[reg];
		}
	    }
	  start = tmp;
	}

      all_nops = true;

      /* Now we know what registers are used, make a second pass over
	 the chunk, this time actually printing out the info.  */

      while (start < block_end)
	{
	  unsigned op, opa;
	  unsigned long ul, roffs;
	  /* Note: It is tempting to use an unsigned long for 'reg' but there
	     are various functions, notably frame_space_needed() that assume that
	     reg is an unsigned int.  */
	  unsigned int reg;
	  dwarf_signed_vma l;
	  dwarf_vma ofs;
	  dwarf_vma vma;
	  const char *reg_prefix = "";

	  op = *start++;
	  opa = op & 0x3f;
	  if (op & 0xc0)
	    op &= 0xc0;

	  /* Make a note if something other than DW_CFA_nop happens.  */
	  if (op != DW_CFA_nop)
	    all_nops = false;

	  /* Warning: if you add any more cases to this switch, be
	     sure to add them to the corresponding switch above.  */
	  switch (op)
	    {
	    case DW_CFA_advance_loc:
	      if (do_debug_frames_interp)
		frame_display_row (fc, &need_col_headers, &max_regs);
	      else
		printf ("  DW_CFA_advance_loc: %d to %s\n",
			opa * fc->code_factor,
			dwarf_vmatoa_1 (NULL,
					fc->pc_begin + opa * fc->code_factor,
					fc->ptr_size));
	      fc->pc_begin += opa * fc->code_factor;
	      break;

	    case DW_CFA_offset:
	      READ_ULEB (roffs, start, block_end);
	      if (opa >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		printf ("  DW_CFA_offset: %s%s at cfa%+ld\n",
			reg_prefix, regname (opa, 0),
			roffs * fc->data_factor);
	      if (*reg_prefix == '\0')
		{
		  fc->col_type[opa] = DW_CFA_offset;
		  fc->col_offset[opa] = roffs * fc->data_factor;
		}
	      break;

	    case DW_CFA_restore:
	      if (opa >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		printf ("  DW_CFA_restore: %s%s\n",
			reg_prefix, regname (opa, 0));
	      if (*reg_prefix != '\0')
		break;

	      if (opa >= cie->ncols
		  || cie->col_type[opa] == DW_CFA_unreferenced)
		{
		  fc->col_type[opa] = DW_CFA_undefined;
		  fc->col_offset[opa] = 0;
		}
	      else
		{
		  fc->col_type[opa] = cie->col_type[opa];
		  fc->col_offset[opa] = cie->col_offset[opa];
		}
	      break;

	    case DW_CFA_set_loc:
	      vma = get_encoded_value (&start, fc->fde_encoding, section,
				       block_end);
	      if (do_debug_frames_interp)
		frame_display_row (fc, &need_col_headers, &max_regs);
	      else
		printf ("  DW_CFA_set_loc: %s\n",
			dwarf_vmatoa_1 (NULL, vma, fc->ptr_size));
	      fc->pc_begin = vma;
	      break;

	    case DW_CFA_advance_loc1:
	      SAFE_BYTE_GET_AND_INC (ofs, start, 1, block_end);
	      if (do_debug_frames_interp)
		frame_display_row (fc, &need_col_headers, &max_regs);
	      else
		printf ("  DW_CFA_advance_loc1: %ld to %s\n",
			(unsigned long) (ofs * fc->code_factor),
			dwarf_vmatoa_1 (NULL,
					fc->pc_begin + ofs * fc->code_factor,
					fc->ptr_size));
	      fc->pc_begin += ofs * fc->code_factor;
	      break;

	    case DW_CFA_advance_loc2:
	      SAFE_BYTE_GET_AND_INC (ofs, start, 2, block_end);
	      if (do_debug_frames_interp)
		frame_display_row (fc, &need_col_headers, &max_regs);
	      else
		printf ("  DW_CFA_advance_loc2: %ld to %s\n",
			(unsigned long) (ofs * fc->code_factor),
			dwarf_vmatoa_1 (NULL,
					fc->pc_begin + ofs * fc->code_factor,
					fc->ptr_size));
	      fc->pc_begin += ofs * fc->code_factor;
	      break;

	    case DW_CFA_advance_loc4:
	      SAFE_BYTE_GET_AND_INC (ofs, start, 4, block_end);
	      if (do_debug_frames_interp)
		frame_display_row (fc, &need_col_headers, &max_regs);
	      else
		printf ("  DW_CFA_advance_loc4: %ld to %s\n",
			(unsigned long) (ofs * fc->code_factor),
			dwarf_vmatoa_1 (NULL,
					fc->pc_begin + ofs * fc->code_factor,
					fc->ptr_size));
	      fc->pc_begin += ofs * fc->code_factor;
	      break;

	    case DW_CFA_offset_extended:
	      READ_ULEB (reg, start, block_end);
	      READ_ULEB (roffs, start, block_end);
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		printf ("  DW_CFA_offset_extended: %s%s at cfa%+ld\n",
			reg_prefix, regname (reg, 0),
			roffs * fc->data_factor);
	      if (*reg_prefix == '\0')
		{
		  fc->col_type[reg] = DW_CFA_offset;
		  fc->col_offset[reg] = roffs * fc->data_factor;
		}
	      break;

	    case DW_CFA_val_offset:
	      READ_ULEB (reg, start, block_end);
	      READ_ULEB (roffs, start, block_end);
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		printf ("  DW_CFA_val_offset: %s%s is cfa%+ld\n",
			reg_prefix, regname (reg, 0),
			roffs * fc->data_factor);
	      if (*reg_prefix == '\0')
		{
		  fc->col_type[reg] = DW_CFA_val_offset;
		  fc->col_offset[reg] = roffs * fc->data_factor;
		}
	      break;

	    case DW_CFA_restore_extended:
	      READ_ULEB (reg, start, block_end);
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		printf ("  DW_CFA_restore_extended: %s%s\n",
			reg_prefix, regname (reg, 0));
	      if (*reg_prefix != '\0')
		break;

	      if (reg >= cie->ncols
		  || cie->col_type[reg] == DW_CFA_unreferenced)
		{
		  fc->col_type[reg] = DW_CFA_undefined;
		  fc->col_offset[reg] = 0;
		}
	      else
		{
		  fc->col_type[reg] = cie->col_type[reg];
		  fc->col_offset[reg] = cie->col_offset[reg];
		}
	      break;

	    case DW_CFA_undefined:
	      READ_ULEB (reg, start, block_end);
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		printf ("  DW_CFA_undefined: %s%s\n",
			reg_prefix, regname (reg, 0));
	      if (*reg_prefix == '\0')
		{
		  fc->col_type[reg] = DW_CFA_undefined;
		  fc->col_offset[reg] = 0;
		}
	      break;

	    case DW_CFA_same_value:
	      READ_ULEB (reg, start, block_end);
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		printf ("  DW_CFA_same_value: %s%s\n",
			reg_prefix, regname (reg, 0));
	      if (*reg_prefix == '\0')
		{
		  fc->col_type[reg] = DW_CFA_same_value;
		  fc->col_offset[reg] = 0;
		}
	      break;

	    case DW_CFA_register:
	      READ_ULEB (reg, start, block_end);
	      READ_ULEB (roffs, start, block_end);
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		{
		  printf ("  DW_CFA_register: %s%s in ",
			  reg_prefix, regname (reg, 0));
		  puts (regname (roffs, 0));
		}
	      if (*reg_prefix == '\0')
		{
		  fc->col_type[reg] = DW_CFA_register;
		  fc->col_offset[reg] = roffs;
		}
	      break;

	    case DW_CFA_remember_state:
	      if (! do_debug_frames_interp)
		printf ("  DW_CFA_remember_state\n");
	      rs = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
	      rs->cfa_offset = fc->cfa_offset;
	      rs->cfa_reg = fc->cfa_reg;
	      rs->ra = fc->ra;
	      rs->cfa_exp = fc->cfa_exp;
	      rs->ncols = fc->ncols;
	      rs->col_type = (short int *) xcmalloc (rs->ncols,
						     sizeof (* rs->col_type));
	      rs->col_offset = (int *) xcmalloc (rs->ncols, sizeof (* rs->col_offset));
	      memcpy (rs->col_type, fc->col_type, rs->ncols * sizeof (* fc->col_type));
	      memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (* fc->col_offset));
	      rs->next = remembered_state;
	      remembered_state = rs;
	      break;

	    case DW_CFA_restore_state:
	      if (! do_debug_frames_interp)
		printf ("  DW_CFA_restore_state\n");
	      rs = remembered_state;
	      if (rs)
		{
		  remembered_state = rs->next;
		  fc->cfa_offset = rs->cfa_offset;
		  fc->cfa_reg = rs->cfa_reg;
		  fc->ra = rs->ra;
		  fc->cfa_exp = rs->cfa_exp;
		  if (frame_need_space (fc, rs->ncols - 1) < 0)
		    {
		      warn (_("Invalid column number in saved frame state\n"));
		      fc->ncols = 0;
		      break;
		    }
		  memcpy (fc->col_type, rs->col_type, rs->ncols * sizeof (* rs->col_type));
		  memcpy (fc->col_offset, rs->col_offset,
			  rs->ncols * sizeof (* rs->col_offset));
		  free (rs->col_type);
		  free (rs->col_offset);
		  free (rs);
		}
	      else if (do_debug_frames_interp)
		printf ("Mismatched DW_CFA_restore_state\n");
	      break;

	    case DW_CFA_def_cfa:
	      READ_ULEB (fc->cfa_reg, start, block_end);
	      READ_ULEB (fc->cfa_offset, start, block_end);
	      fc->cfa_exp = 0;
	      if (! do_debug_frames_interp)
		printf ("  DW_CFA_def_cfa: %s ofs %d\n",
			regname (fc->cfa_reg, 0), (int) fc->cfa_offset);
	      break;

	    case DW_CFA_def_cfa_register:
	      READ_ULEB (fc->cfa_reg, start, block_end);
	      fc->cfa_exp = 0;
	      if (! do_debug_frames_interp)
		printf ("  DW_CFA_def_cfa_register: %s\n",
			regname (fc->cfa_reg, 0));
	      break;

	    case DW_CFA_def_cfa_offset:
	      READ_ULEB (fc->cfa_offset, start, block_end);
	      if (! do_debug_frames_interp)
		printf ("  DW_CFA_def_cfa_offset: %d\n", (int) fc->cfa_offset);
	      break;

	    case DW_CFA_nop:
	      if (! do_debug_frames_interp)
		printf ("  DW_CFA_nop\n");
	      break;

	    case DW_CFA_def_cfa_expression:
	      READ_ULEB (ul, start, block_end);
	      if (ul > (size_t) (block_end - start))
		{
		  printf (_("  DW_CFA_def_cfa_expression: <corrupt len %lu>\n"), ul);
		  break;
		}
	      if (! do_debug_frames_interp)
		{
		  printf ("  DW_CFA_def_cfa_expression (");
		  decode_location_expression (start, eh_addr_size, 0, -1,
					      ul, 0, section);
		  printf (")\n");
		}
	      fc->cfa_exp = 1;
	      start += ul;
	      break;

	    case DW_CFA_expression:
	      READ_ULEB (reg, start, block_end);
	      READ_ULEB (ul, start, block_end);
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      /* PR 17512: file: 069-133014-0.006.  */
	      /* PR 17512: file: 98c02eb4.  */
	      if (ul > (size_t) (block_end - start))
		{
		  printf (_("  DW_CFA_expression: <corrupt len %lu>\n"), ul);
		  break;
		}
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		{
		  printf ("  DW_CFA_expression: %s%s (",
			  reg_prefix, regname (reg, 0));
		  decode_location_expression (start, eh_addr_size, 0, -1,
					      ul, 0, section);
		  printf (")\n");
		}
	      if (*reg_prefix == '\0')
		fc->col_type[reg] = DW_CFA_expression;
	      start += ul;
	      break;

	    case DW_CFA_val_expression:
	      READ_ULEB (reg, start, block_end);
	      READ_ULEB (ul, start, block_end);
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      if (ul > (size_t) (block_end - start))
		{
		  printf ("  DW_CFA_val_expression: <corrupt len %lu>\n", ul);
		  break;
		}
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		{
		  printf ("  DW_CFA_val_expression: %s%s (",
			  reg_prefix, regname (reg, 0));
		  decode_location_expression (start, eh_addr_size, 0, -1,
					      ul, 0, section);
		  printf (")\n");
		}
	      if (*reg_prefix == '\0')
		fc->col_type[reg] = DW_CFA_val_expression;
	      start += ul;
	      break;

	    case DW_CFA_offset_extended_sf:
	      READ_ULEB (reg, start, block_end);
	      READ_SLEB (l, start, block_end);
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		printf ("  DW_CFA_offset_extended_sf: %s%s at cfa%+ld\n",
			reg_prefix, regname (reg, 0),
			(long)(l * fc->data_factor));
	      if (*reg_prefix == '\0')
		{
		  fc->col_type[reg] = DW_CFA_offset;
		  fc->col_offset[reg] = l * fc->data_factor;
		}
	      break;

	    case DW_CFA_val_offset_sf:
	      READ_ULEB (reg, start, block_end);
	      READ_SLEB (l, start, block_end);
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		printf ("  DW_CFA_val_offset_sf: %s%s is cfa%+ld\n",
			reg_prefix, regname (reg, 0),
			(long)(l * fc->data_factor));
	      if (*reg_prefix == '\0')
		{
		  fc->col_type[reg] = DW_CFA_val_offset;
		  fc->col_offset[reg] = l * fc->data_factor;
		}
	      break;

	    case DW_CFA_def_cfa_sf:
	      READ_ULEB (fc->cfa_reg, start, block_end);
	      READ_SLEB (l, start, block_end);
	      l *= fc->data_factor;
	      fc->cfa_offset = l;
	      fc->cfa_exp = 0;
	      if (! do_debug_frames_interp)
		printf ("  DW_CFA_def_cfa_sf: %s ofs %ld\n",
			regname (fc->cfa_reg, 0), (long) l);
	      break;

	    case DW_CFA_def_cfa_offset_sf:
	      READ_SLEB (l, start, block_end);
	      l *= fc->data_factor;
	      fc->cfa_offset = l;
	      if (! do_debug_frames_interp)
		printf ("  DW_CFA_def_cfa_offset_sf: %ld\n", (long) l);
	      break;

	    case DW_CFA_MIPS_advance_loc8:
	      SAFE_BYTE_GET_AND_INC (ofs, start, 8, block_end);
	      if (do_debug_frames_interp)
		frame_display_row (fc, &need_col_headers, &max_regs);
	      else
		printf ("  DW_CFA_MIPS_advance_loc8: %ld to %s\n",
			(unsigned long) (ofs * fc->code_factor),
			dwarf_vmatoa_1 (NULL,
					fc->pc_begin + ofs * fc->code_factor,
					fc->ptr_size));
	      fc->pc_begin += ofs * fc->code_factor;
	      break;

	    case DW_CFA_GNU_window_save:
	      if (! do_debug_frames_interp)
		printf ("  DW_CFA_GNU_window_save\n");
	      break;

	    case DW_CFA_GNU_args_size:
	      READ_ULEB (ul, start, block_end);
	      if (! do_debug_frames_interp)
		printf ("  DW_CFA_GNU_args_size: %ld\n", ul);
	      break;

	    case DW_CFA_GNU_negative_offset_extended:
	      READ_ULEB (reg, start, block_end);
	      READ_SLEB (l, start, block_end);
	      l = - l;
	      if (reg >= fc->ncols)
		reg_prefix = bad_reg;
	      if (! do_debug_frames_interp || *reg_prefix != '\0')
		printf ("  DW_CFA_GNU_negative_offset_extended: %s%s at cfa%+ld\n",
			reg_prefix, regname (reg, 0),
			(long)(l * fc->data_factor));
	      if (*reg_prefix == '\0')
		{
		  fc->col_type[reg] = DW_CFA_offset;
		  fc->col_offset[reg] = l * fc->data_factor;
		}
	      break;

	    default:
	      if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user)
		printf (_("  DW_CFA_??? (User defined call frame op: %#x)\n"), op);
	      else
		warn (_("Unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op);
	      start = block_end;
	    }
	}

      /* Interpret the CFA - as long as it is not completely full of NOPs.  */
      if (do_debug_frames_interp && ! all_nops)
	frame_display_row (fc, &need_col_headers, &max_regs);

      if (fde_fc.col_type != NULL)
	{
	  free (fde_fc.col_type);
	  fde_fc.col_type = NULL;
	}
      if (fde_fc.col_offset != NULL)
	{
	  free (fde_fc.col_offset);
	  fde_fc.col_offset = NULL;
	}

      start = block_end;
      eh_addr_size = saved_eh_addr_size;
    }

  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;
}


read_leb128 (unsigned char *data,
	     const unsigned char *const end,
	     bool sign,
	     unsigned int *length_return,
	     int *status_return)
{
  dwarf_vma result = 0;
  unsigned int num_read = 0;
  unsigned int shift = 0;
  int status = 1;

  while (data < end)
    {
      unsigned char byte = *data++;
      unsigned char lost, mask;

      num_read++;

      if (shift < CHAR_BIT * sizeof (result))
	{
	  result |= ((dwarf_vma) (byte & 0x7f)) << shift;
	  /* These bits overflowed.  */
	  lost = byte ^ (result >> shift);
	  /* And this is the mask of possible overflow bits.  */
	  mask = 0x7f ^ ((dwarf_vma) 0x7f << shift >> shift);
	  shift += 7;
	}
      else
	{
	  lost = byte;
	  mask = 0x7f;
	}
      if ((lost & mask) != (sign && (dwarf_signed_vma) result < 0 ? mask : 0))
	status |= 2;

      if ((byte & 0x80) == 0)
	{
	  status &= ~1;
	  if (sign && shift < CHAR_BIT * sizeof (result) && (byte & 0x40))
	    result |= -((dwarf_vma) 1 << shift);
	  break;
	}
    }

  if (length_return != NULL)
    *length_return = num_read;
  if (status_return != NULL)
    *status_return = status;

  return result;
}


display_debug_ranges (struct dwarf_section *section,
		      void *file ATTRIBUTE_UNUSED)
{
  unsigned char *       start = section->start;
  unsigned char *       last_start = start;
  dwarf_vma             bytes = section->size;
  unsigned char *       section_begin = start;
  unsigned char *       finish = start + bytes;
  unsigned int          num_range_list, i;
  struct range_entry *  range_entries;
  struct range_entry *  range_entry_fill;
  int                   is_rnglists = strstr (section->name, "debug_rnglists") != NULL;
  /* Initialize it due to a false compiler warning.  */
  unsigned char         address_size = 0;
  dwarf_vma             last_offset = 0;
  unsigned int          offset_size = 0;

  if (bytes == 0)
    {
      printf (_("\nThe %s section is empty.\n"), section->name);
      return 0;
    }

  introduce (section, false);

  if (is_rnglists)
    {
      dwarf_vma       initial_length;
      unsigned char   segment_selector_size;
      unsigned int    offset_entry_count;
      unsigned short  version;

      /* Get and check the length of the block.  */
      SAFE_BYTE_GET_AND_INC (initial_length, start, 4, finish);

      if (initial_length == 0xffffffff)
	{
	  /* This section is 64-bit DWARF 3.  */
	  SAFE_BYTE_GET_AND_INC (initial_length, start, 8, finish);
	  offset_size = 8;
	}
      else
	offset_size = 4;

      if (initial_length > (size_t) (finish - start))
	{
	  /* If the length field has a relocation against it, then we should
	     not complain if it is inaccurate (and probably negative).
	     It is copied from .debug_line handling code.  */
	  if (reloc_at (section, (start - section->start) - offset_size))
	    {
	      initial_length = finish - start;
	    }
	  else
	    {
	      warn (_("The length field (0x%lx) in the debug_rnglists header is wrong - the section is too small\n"),
		    (long) initial_length);
	      return 0;
	    }
	}

      /* Get the other fields in the header.  */
      SAFE_BYTE_GET_AND_INC (version, start, 2, finish);
      SAFE_BYTE_GET_AND_INC (address_size, start, 1, finish);
      SAFE_BYTE_GET_AND_INC (segment_selector_size, start, 1, finish);
      SAFE_BYTE_GET_AND_INC (offset_entry_count, start, 4, finish);

      printf (_("  Length:          0x%s\n"), dwarf_vmatoa ("x", initial_length));
      printf (_("  DWARF version:   %u\n"), version);
      printf (_("  Address size:    %u\n"), address_size);
      printf (_("  Segment size:    %u\n"), segment_selector_size);
      printf (_("  Offset entries:  %u\n"), offset_entry_count);

      /* Check the fields.  */
      if (segment_selector_size != 0)
	{
	  warn (_("The %s section contains "
		  "unsupported segment selector size: %d.\n"),
		section->name, segment_selector_size);
	  return 0;
	}

      if (version < 5)
	{
	  warn (_("Only DWARF version 5+ debug_rnglists info "
		  "is currently supported.\n"));
	  return 0;
	}

      if (offset_entry_count != 0)
	{
	  printf (_("\n   Offsets starting at 0x%lx:\n"), (long)(start - section->start));
	  if (offset_size == 8)
	    {
	      for (i = 0; i < offset_entry_count; i++)
		{
		  dwarf_vma entry;

		  SAFE_BYTE_GET_AND_INC (entry, start, 8, finish);
		  printf (_("    [%6u] 0x%s\n"), i, dwarf_vmatoa ("x", entry));
		}
	    }
	  else
	    {
	      for (i = 0; i < offset_entry_count; i++)
		{
		  uint32_t entry;

		  SAFE_BYTE_GET_AND_INC (entry, start, 4, finish);
		  printf (_("    [%6u] 0x%x\n"), i, entry);
		}
	    }
	}
    }

  if (load_debug_info (file) == 0)
    {
      warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"),
	    section->name);
      return 0;
    }

  num_range_list = 0;
  for (i = 0; i < num_debug_info_entries; i++)
    {
      if (debug_information [i].dwarf_version < 5 && is_rnglists)
	/* Skip .debug_rnglists reference.  */
	continue;
      if (debug_information [i].dwarf_version >= 5 && !is_rnglists)
	/* Skip .debug_range reference.  */
	continue;
      num_range_list += debug_information [i].num_range_lists;
    }

  if (num_range_list == 0)
    {
      /* This can happen when the file was compiled with -gsplit-debug
	 which removes references to range lists from the primary .o file.  */
      printf (_("No range lists in .debug_info section.\n"));
      return 1;
    }

  range_entries = (struct range_entry *)
      xmalloc (sizeof (*range_entries) * num_range_list);
  range_entry_fill = range_entries;

  for (i = 0; i < num_debug_info_entries; i++)
    {
      debug_info *debug_info_p = &debug_information[i];
      unsigned int j;

      if (debug_information [i].dwarf_version < 5 && is_rnglists)
	/* Skip .debug_rnglists reference.  */
	continue;
      if (debug_information [i].dwarf_version >= 5 && !is_rnglists)
	/* Skip .debug_range reference.  */
	continue;

      for (j = 0; j < debug_info_p->num_range_lists; j++)
	{
	  range_entry_fill->ranges_offset = debug_info_p->range_lists[j];
	  range_entry_fill->debug_info_p = debug_info_p;
	  range_entry_fill++;
	}
    }

  qsort (range_entries, num_range_list, sizeof (*range_entries),
	 range_entry_compar);

  if (dwarf_check != 0 && range_entries[0].ranges_offset != 0)
    warn (_("Range lists in %s section start at 0x%lx\n"),
	  section->name, (unsigned long) range_entries[0].ranges_offset);

  putchar ('\n');
  printf (_("    Offset   Begin    End\n"));

  for (i = 0; i < num_range_list; i++)
    {
      struct range_entry *range_entry = &range_entries[i];
      debug_info *debug_info_p = range_entry->debug_info_p;
      unsigned int pointer_size;
      dwarf_vma offset;
      unsigned char *next;
      dwarf_vma base_address;

      pointer_size = (is_rnglists ? address_size : debug_info_p->pointer_size);
      offset = range_entry->ranges_offset;
      base_address = debug_info_p->base_address;

      /* PR 17512: file: 001-101485-0.001:0.1.  */
      if (pointer_size < 2 || pointer_size > 8)
	{
	  warn (_("Corrupt pointer size (%d) in debug entry at offset %8.8lx\n"),
		pointer_size, (unsigned long) offset);
	  continue;
	}

      if (offset > (size_t) (finish - section_begin))
	{
	  warn (_("Corrupt offset (%#8.8lx) in range entry %u\n"),
		(unsigned long) offset, i);
	  continue;
	}

      next = section_begin + offset + debug_info_p->rnglists_base;

      /* If multiple DWARF entities reference the same range then we will
         have multiple entries in the `range_entries' list for the same
         offset.  Thanks to the sort above these will all be consecutive in
         the `range_entries' list, so we can easily ignore duplicates
         here.  */
      if (i > 0 && last_offset == offset)
        continue;
      last_offset = offset;

      if (dwarf_check != 0 && i > 0)
	{
	  if (start < next)
	    warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
		  (unsigned long) (start - section_begin),
		  (unsigned long) (next - section_begin), section->name);
	  else if (start > next)
	    {
	      if (next == last_start)
		continue;
	      warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
		    (unsigned long) (start - section_begin),
		    (unsigned long) (next - section_begin), section->name);
	    }
	}

      start = next;
      last_start = next;

      if (is_rnglists)
	display_debug_rnglists_list
	  (start, finish, pointer_size, offset, base_address, offset_size);
      else
	display_debug_ranges_list
	  (start, finish, pointer_size, offset, base_address);
    }
  putchar ('\n');

  free (range_entries);

  return 1;
}


load_separate_debug_info (const char *            main_filename,
			  struct dwarf_section *  xlink,
			  parse_func_type         parse_func,
			  check_func_type         check_func,
			  void *                  func_data,
                          void *                  file ATTRIBUTE_UNUSED)
{
  const char *   separate_filename;
  char *         debug_filename;
  char *         canon_dir;
  size_t         canon_dirlen;
  size_t         dirlen;
  char *         canon_filename;
  char *         canon_debug_filename;
  bool		 self;

  if ((separate_filename = parse_func (xlink, func_data)) == NULL)
    {
      warn (_("Corrupt debuglink section: %s\n"),
	    xlink->name ? xlink->name : xlink->uncompressed_name);
      return NULL;
    }

  /* Attempt to locate the separate file.
     This should duplicate the logic in bfd/opncls.c:find_separate_debug_file().  */

  canon_filename = lrealpath (main_filename);
  canon_dir = xstrdup (canon_filename);

  for (canon_dirlen = strlen (canon_dir); canon_dirlen > 0; canon_dirlen--)
    if (IS_DIR_SEPARATOR (canon_dir[canon_dirlen - 1]))
      break;
  canon_dir[canon_dirlen] = '\0';

#ifndef DEBUGDIR
#define DEBUGDIR "/lib/debug"
#endif
#ifndef EXTRA_DEBUG_ROOT1
#define EXTRA_DEBUG_ROOT1 "/usr/lib/debug"
#endif
#ifndef EXTRA_DEBUG_ROOT2
#define EXTRA_DEBUG_ROOT2 "/usr/lib/debug/usr"
#endif

  debug_filename = (char *) malloc (strlen (DEBUGDIR) + 1
				    + canon_dirlen
				    + strlen (".debug/")
#ifdef EXTRA_DEBUG_ROOT1
				    + strlen (EXTRA_DEBUG_ROOT1)
#endif
#ifdef EXTRA_DEBUG_ROOT2
				    + strlen (EXTRA_DEBUG_ROOT2)
#endif
				    + strlen (separate_filename)
				    + 1);
  if (debug_filename == NULL)
    {
      warn (_("Out of memory"));
      free (canon_dir);
      free (canon_filename);
      return NULL;
    }

  /* First try in the current directory.  */
  sprintf (debug_filename, "%s", separate_filename);
  if (check_func (debug_filename, func_data))
    goto found;

  /* Then try in a subdirectory called .debug.  */
  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 (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 (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 (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 (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
  if (check_func (debug_filename, func_data))
    goto found;
#endif

  /* Then try in the global debug_filename directory.  */
  strcpy (debug_filename, DEBUGDIR);
  dirlen = strlen (DEBUGDIR) - 1;
  if (dirlen > 0 && DEBUGDIR[dirlen] != '/')
    strcat (debug_filename, "/");
  strcat (debug_filename, (const char *) separate_filename);

  if (check_func (debug_filename, func_data))
    goto found;

#if HAVE_LIBDEBUGINFOD
  {
    char * tmp_filename;

    if (use_debuginfod
	&& debuginfod_fetch_separate_debug_info (xlink,
						 & tmp_filename,
						 file))
      {
        /* File successfully downloaded from server, replace
           debug_filename with the file's path.  */
        free (debug_filename);
        debug_filename = tmp_filename;
        goto found;
      }
  }
#endif

  if (do_debug_links)
    {
      /* Failed to find the file.  */
      warn (_("could not find separate debug file '%s'\n"),
	    separate_filename);
      warn (_("tried: %s\n"), debug_filename);

#ifdef EXTRA_DEBUG_ROOT2
      sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2,
	       separate_filename);
      warn (_("tried: %s\n"), debug_filename);
#endif

#ifdef EXTRA_DEBUG_ROOT1
      sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1,
	       canon_dir, separate_filename);
      warn (_("tried: %s\n"), debug_filename);

      sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1,
	       separate_filename);
      warn (_("tried: %s\n"), debug_filename);
#endif

      sprintf (debug_filename, "%s.debug/%s", canon_dir,
	       separate_filename);
      warn (_("tried: %s\n"), debug_filename);

      sprintf (debug_filename, "%s%s", canon_dir, separate_filename);
      warn (_("tried: %s\n"), debug_filename);

      sprintf (debug_filename, ".debug/%s", separate_filename);
      warn (_("tried: %s\n"), debug_filename);

      sprintf (debug_filename, "%s", separate_filename);
      warn (_("tried: %s\n"), debug_filename);

#if HAVE_LIBDEBUGINFOD
      if (use_debuginfod)
	{
	  char *urls = getenv (DEBUGINFOD_URLS_ENV_VAR);

	  if (urls == NULL)
	    urls = "";

	  warn (_("tried: DEBUGINFOD_URLS=%s\n"), urls);
	}
#endif
    }

  free (canon_dir);
  free (debug_filename);
  free (canon_filename);
  return NULL;

 found:
  free (canon_dir);

  canon_debug_filename = lrealpath (debug_filename);
  self = strcmp (canon_debug_filename, canon_filename) == 0;
  free (canon_filename);
  free (canon_debug_filename);
  if (self)
    {
      free (debug_filename);
      return NULL;
    }

  void * debug_handle;

  /* Now open the file.... */
  if ((debug_handle = open_debug_file (debug_filename)) == NULL)
    {
      warn (_("failed to open separate debug file: %s\n"), debug_filename);
      free (debug_filename);
      return NULL;
    }

  /* FIXME: We do not check to see if there are any other separate debug info
     files that would also match.  */

  if (do_debug_links)
    printf (_("\n%s: Found separate debug info file: %s\n"), main_filename, debug_filename);
  add_separate_debug_file (debug_filename, debug_handle);

  /* Do not free debug_filename - it might be referenced inside
     the structure returned by open_debug_file().  */
  return debug_handle;
}


display_debug_macro (struct dwarf_section *section,
		     void *file)
{
  unsigned char *start = section->start;
  unsigned char *end = start + section->size;
  unsigned char *curr = start;
  unsigned char *extended_op_buf[256];
  bool is_dwo = false;
  const char *suffix = strrchr (section->name, '.');

  if (suffix && strcmp (suffix, ".dwo") == 0)
    is_dwo = true;

  load_debug_section_with_follow (str, file);
  load_debug_section_with_follow (line, file);
  load_debug_section_with_follow (str_index, file);

  introduce (section, false);

  while (curr < end)
    {
      unsigned int lineno, version, flags;
      unsigned int offset_size;
      const unsigned char *string;
      dwarf_vma line_offset = 0, sec_offset = curr - start, offset;
      unsigned char **extended_ops = NULL;

      SAFE_BYTE_GET_AND_INC (version, curr, 2, end);
      if (version != 4 && version != 5)
	{
	  error (_("Expected to find a version number of 4 or 5 in section %s but found %d instead\n"),
		 section->name, version);
	  return 0;
	}

      SAFE_BYTE_GET_AND_INC (flags, curr, 1, end);
      offset_size = (flags & 1) ? 8 : 4;
      printf (_("  Offset:                      0x%lx\n"),
	      (unsigned long) sec_offset);
      printf (_("  Version:                     %d\n"), version);
      printf (_("  Offset size:                 %d\n"), offset_size);
      if (flags & 2)
	{
	  SAFE_BYTE_GET_AND_INC (line_offset, curr, offset_size, end);
	  printf (_("  Offset into .debug_line:     0x%lx\n"),
		  (unsigned long) line_offset);
	}
      if (flags & 4)
	{
	  unsigned int i, count, op;
	  dwarf_vma nargs, n;

	  SAFE_BYTE_GET_AND_INC (count, curr, 1, end);

	  memset (extended_op_buf, 0, sizeof (extended_op_buf));
	  extended_ops = extended_op_buf;
	  if (count)
	    {
	      printf (_("  Extension opcode arguments:\n"));
	      for (i = 0; i < count; i++)
		{
		  SAFE_BYTE_GET_AND_INC (op, curr, 1, end);
		  extended_ops[op] = curr;
		  READ_ULEB (nargs, curr, end);
		  if (nargs == 0)
		    printf (_("    DW_MACRO_%02x has no arguments\n"), op);
		  else
		    {
		      printf (_("    DW_MACRO_%02x arguments: "), op);
		      for (n = 0; n < nargs; n++)
			{
			  unsigned int form;

			  SAFE_BYTE_GET_AND_INC (form, curr, 1, end);
			  printf ("%s%s", get_FORM_name (form),
				  n == nargs - 1 ? "\n" : ", ");
			  switch (form)
			    {
			    case DW_FORM_data1:
			    case DW_FORM_data2:
			    case DW_FORM_data4:
			    case DW_FORM_data8:
			    case DW_FORM_sdata:
			    case DW_FORM_udata:
			    case DW_FORM_block:
			    case DW_FORM_block1:
			    case DW_FORM_block2:
			    case DW_FORM_block4:
			    case DW_FORM_flag:
			    case DW_FORM_string:
			    case DW_FORM_strp:
			    case DW_FORM_sec_offset:
			      break;
			    default:
			      error (_("Invalid extension opcode form %s\n"),
				     get_FORM_name (form));
			      return 0;
			    }
			}
		    }
		}
	    }
	}
      printf ("\n");

      while (1)
	{
	  unsigned int op;

	  if (curr >= end)
	    {
	      error (_(".debug_macro section not zero terminated\n"));
	      return 0;
	    }

	  SAFE_BYTE_GET_AND_INC (op, curr, 1, end);
	  if (op == 0)
	    break;

	  switch (op)
	    {
	    case DW_MACRO_define:
	      READ_ULEB (lineno, curr, end);
	      string = curr;
	      curr += strnlen ((char *) string, end - string);
	      printf (_(" DW_MACRO_define - lineno : %d macro : %*s\n"),
		      lineno, (int) (curr - string), string);
	      if (curr < end)
		curr++;
	      break;

	    case DW_MACRO_undef:
	      READ_ULEB (lineno, curr, end);
	      string = curr;
	      curr += strnlen ((char *) string, end - string);
	      printf (_(" DW_MACRO_undef - lineno : %d macro : %*s\n"),
		      lineno, (int) (curr - string), string);
	      if (curr < end)
		curr++;
	      break;

	    case DW_MACRO_start_file:
	      {
		unsigned int filenum;
		unsigned char *file_name = NULL, *dir_name = NULL;

		READ_ULEB (lineno, curr, end);
		READ_ULEB (filenum, curr, end);

		if ((flags & 2) == 0)
		  error (_("DW_MACRO_start_file used, but no .debug_line offset provided.\n"));
		else
		  file_name
		    = get_line_filename_and_dirname (line_offset, filenum,
						     &dir_name);
		if (file_name == NULL)
		  printf (_(" DW_MACRO_start_file - lineno: %d filenum: %d\n"),
			  lineno, filenum);
		else
		  printf (_(" DW_MACRO_start_file - lineno: %d filenum: %d filename: %s%s%s\n"),
			  lineno, filenum,
			  dir_name != NULL ? (const char *) dir_name : "",
			  dir_name != NULL ? "/" : "", file_name);
	      }
	      break;

	    case DW_MACRO_end_file:
	      printf (_(" DW_MACRO_end_file\n"));
	      break;

	    case DW_MACRO_define_strp:
	      READ_ULEB (lineno, curr, end);
	      if (version == 4 && is_dwo)
		READ_ULEB (offset, curr, end);
	      else
		SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
	      string = fetch_indirect_string (offset);
	      printf (_(" DW_MACRO_define_strp - lineno : %d macro : %s\n"),
		      lineno, string);
	      break;

	    case DW_MACRO_undef_strp:
	      READ_ULEB (lineno, curr, end);
	      if (version == 4 && is_dwo)
		READ_ULEB (offset, curr, end);
	      else
		SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
	      string = fetch_indirect_string (offset);
	      printf (_(" DW_MACRO_undef_strp - lineno : %d macro : %s\n"),
		      lineno, string);
	      break;

	    case DW_MACRO_import:
	      SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
	      printf (_(" DW_MACRO_import - offset : 0x%lx\n"),
		      (unsigned long) offset);
	      break;

	    case DW_MACRO_define_sup:
	      READ_ULEB (lineno, curr, end);
	      SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
	      printf (_(" DW_MACRO_define_sup - lineno : %d macro offset : 0x%lx\n"),
		      lineno, (unsigned long) offset);
	      break;

	    case DW_MACRO_undef_sup:
	      READ_ULEB (lineno, curr, end);
	      SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
	      printf (_(" DW_MACRO_undef_sup - lineno : %d macro offset : 0x%lx\n"),
		      lineno, (unsigned long) offset);
	      break;

	    case DW_MACRO_import_sup:
	      SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end);
	      printf (_(" DW_MACRO_import_sup - offset : 0x%lx\n"),
		      (unsigned long) offset);
	      break;

	    case DW_MACRO_define_strx:
	    case DW_MACRO_undef_strx:
	      READ_ULEB (lineno, curr, end);
	      READ_ULEB (offset, curr, end);
	      string = (const unsigned char *)
		fetch_indexed_string (offset, NULL, offset_size, false, 0);
	      if (op == DW_MACRO_define_strx)
		printf (" DW_MACRO_define_strx ");
	      else
		printf (" DW_MACRO_undef_strx ");
	      if (do_wide)
		printf (_("(with offset %s) "), dwarf_vmatoa ("x", offset));
	      printf (_("lineno : %d macro : %s\n"),
		      lineno, string);
	      break;

	    default:
	      if (op >= DW_MACRO_lo_user && op <= DW_MACRO_hi_user)
		{
		  printf (_(" <Target Specific macro op: %#x - UNHANDLED"), op);
		  break;
		}

	      if (extended_ops == NULL || extended_ops[op] == NULL)
		{
		  error (_(" Unknown macro opcode %02x seen\n"), op);
		  return 0;
		}
	      else
		{
		  /* Skip over unhandled opcodes.  */
		  dwarf_vma nargs, n;
		  unsigned char *desc = extended_ops[op];
		  READ_ULEB (nargs, desc, end);
		  if (nargs == 0)
		    {
		      printf (_(" DW_MACRO_%02x\n"), op);
		      break;
		    }
		  printf (_(" DW_MACRO_%02x -"), op);
		  for (n = 0; n < nargs; n++)
		    {
		      int val;

		      /* DW_FORM_implicit_const is not expected here.  */
		      SAFE_BYTE_GET_AND_INC (val, desc, 1, end);
		      curr
			= read_and_display_attr_value (0, val, 0,
						       start, curr, end, 0, 0,
						       offset_size, version,
						       NULL, 0, section,
						       NULL, ' ', -1);
		      if (n != nargs - 1)
			printf (",");
		    }
		  printf ("\n");
		}
	      break;
	    }
	}

      printf ("\n");
    }

  return 1;
}


display_debug_ranges_list (unsigned char *  start,
			   unsigned char *  finish,
			   unsigned int     pointer_size,
			   dwarf_vma        offset,
			   dwarf_vma        base_address)
{
  while (start < finish)
    {
      dwarf_vma begin;
      dwarf_vma end;

      SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, finish);
      if (start >= finish)
	break;
      SAFE_SIGNED_BYTE_GET_AND_INC (end, start, pointer_size, finish);

      printf ("    ");
      print_dwarf_vma (offset, 4);

      if (begin == 0 && end == 0)
	{
	  printf (_("<End of list>\n"));
	  break;
	}

      /* Check base address specifiers.  */
      if (is_max_address (begin, pointer_size)
	  && !is_max_address (end, pointer_size))
	{
	  base_address = end;
	  print_dwarf_vma (begin, pointer_size);
	  print_dwarf_vma (end, pointer_size);
	  printf ("(base address)\n");
	  continue;
	}

      print_dwarf_vma (begin + base_address, pointer_size);
      print_dwarf_vma (end + base_address, pointer_size);

      if (begin == end)
	fputs (_("(start == end)"), stdout);
      else if (begin > end)
	fputs (_("(start > end)"), stdout);

      putchar ('\n');
    }
}


add_abbrev (unsigned long  number,
	    unsigned long  tag,
	    int            children,
	    abbrev_list *  list)
{
  abbrev_entry *  entry;

  entry = (abbrev_entry *) xmalloc (sizeof (*entry));

  entry->number     = number;
  entry->tag        = tag;
  entry->children   = children;
  entry->first_attr = NULL;
  entry->last_attr  = NULL;
  entry->next       = NULL;

  assert (list != NULL);

  if (list->first_abbrev == NULL)
    list->first_abbrev = entry;
  else
    list->last_abbrev->next = entry;

  list->last_abbrev = entry;
}


try_build_id_prefix (const char * prefix, char * filename, const unsigned char * data, unsigned long id_len)
{
  char * f = filename;

  f += sprintf (f, "%s.build-id/%02x/", prefix, (unsigned) *data++);
  id_len --;
  while (id_len --)
    f += sprintf (f, "%02x", (unsigned) *data++);
  strcpy (f, ".debug");

  return open_debug_file (filename);
}


display_trace_info (struct dwarf_section *section, void *file)
{
  return process_debug_info (section, file, section->abbrev_sec, false, true);
}


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;
}


find_debug_info_for_offset (dwarf_vma offset)
{
  unsigned int i;

  if (num_debug_info_entries == DEBUG_INFO_UNAVAILABLE)
    return NULL;

  for (i = 0; i < num_debug_info_entries; i++)
    if (debug_information[i].cu_offset == offset)
      return debug_information + i;

  return NULL;
}


add_dwo_id (const char * id, dwarf_vma cu_offset)
{
  add_dwo_info (id, cu_offset, DWO_ID);
}


display_debug_addr (struct dwarf_section *section,
		    void *file)
{
  debug_info **debug_addr_info;
  unsigned char *entry;
  unsigned char *end;
  unsigned int i;
  unsigned int count;
  unsigned char * header;

  if (section->size == 0)
    {
      printf (_("\nThe %s section is empty.\n"), section->name);
      return 0;
    }

  if (load_debug_info (file) == 0)
    {
      warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"),
	    section->name);
      return 0;
    }

  introduce (section, false);

  /* PR  17531: file: cf38d01b.
     We use xcalloc because a corrupt file may not have initialised all of the
     fields in the debug_info structure, which means that the sort below might
     try to move uninitialised data.  */
  debug_addr_info = (debug_info **) xcalloc ((num_debug_info_entries + 1),
					     sizeof (debug_info *));

  count = 0;
  for (i = 0; i < num_debug_info_entries; i++)
    if (debug_information [i].addr_base != DEBUG_INFO_UNAVAILABLE)
      {
	/* PR 17531: file: cf38d01b.  */
	if (debug_information[i].addr_base >= section->size)
	  warn (_("Corrupt address base (%lx) found in debug section %u\n"),
		(unsigned long) debug_information[i].addr_base, i);
	else
	  debug_addr_info [count++] = debug_information + i;
      }

  /* Add a sentinel to make iteration convenient.  */
  debug_addr_info [count] = (debug_info *) xmalloc (sizeof (debug_info));
  debug_addr_info [count]->addr_base = section->size;
  qsort (debug_addr_info, count, sizeof (debug_info *), comp_addr_base);

  header = section->start;
  for (i = 0; i < count; i++)
    {
      unsigned int idx;
      unsigned int address_size = debug_addr_info [i]->pointer_size;

      printf (_("  For compilation unit at offset 0x%s:\n"),
	      dwarf_vmatoa ("x", debug_addr_info [i]->cu_offset));

      printf (_("\tIndex\tAddress\n"));
      entry = section->start + debug_addr_info [i]->addr_base;
      if (debug_addr_info [i]->dwarf_version >= 5)
	{
	  size_t           header_size = entry - header;
	  unsigned char *  curr_header = header;
	  dwarf_vma        length;
	  int              version;
	  int              segment_selector_size;

	  if (header_size != 8 && header_size != 16)
	    {
	      warn (_("Corrupt %s section: expecting header size of 8 or 16, but found %ld instead\n"),
		    section->name, (long) header_size);
	      return 0;
	    }

	  SAFE_BYTE_GET_AND_INC (length, curr_header, 4, entry);
	  if (length == 0xffffffff)
	    SAFE_BYTE_GET_AND_INC (length, curr_header, 8, entry);
	  end = curr_header + length;

	  SAFE_BYTE_GET_AND_INC (version, curr_header, 2, entry);
	  if (version != 5)
	    warn (_("Corrupt %s section: expecting version number 5 in header but found %d instead\n"),
		  section->name, version);

	  SAFE_BYTE_GET_AND_INC (address_size, curr_header, 1, entry);
	  SAFE_BYTE_GET_AND_INC (segment_selector_size, curr_header, 1, entry);
	  address_size += segment_selector_size;
	}
      else
	end = section->start + debug_addr_info [i + 1]->addr_base;
      header = end;
      idx = 0;
      while (entry < end)
	{
	  dwarf_vma base = byte_get (entry, address_size);
	  printf (_("\t%d:\t"), idx);
	  print_dwarf_vma (base, address_size);
	  printf ("\n");
	  entry += address_size;
	  idx++;
	}
    }
  printf ("\n");

  free (debug_addr_info);
  return 1;
}


debuginfod_fetch_separate_debug_info (struct dwarf_section * section,
                                      char ** filename,
                                      void * file)
{
  size_t build_id_len;
  unsigned char * build_id;

  if (strcmp (section->uncompressed_name, ".gnu_debuglink") == 0)
    {
      /* Get the build-id of file.  */
      build_id = get_build_id (file);
      build_id_len = 0;
    }
  else if (strcmp (section->uncompressed_name, ".gnu_debugaltlink") == 0)
    {
      /* Get the build-id of the debugaltlink file.  */
      unsigned int filelen;

      filelen = strnlen ((const char *)section->start, section->size);
      if (filelen == section->size)
        /* Corrupt debugaltlink.  */
        return false;

      build_id = section->start + filelen + 1;
      build_id_len = section->size - (filelen + 1);

      if (build_id_len == 0)
        return false;
    }
  else
    return false;

  if (build_id)
    {
      int fd;
      debuginfod_client * client;

      client = debuginfod_begin ();
      if (client == NULL)
        return false;

      /* Query debuginfod servers for the target file. If found its path
         will be stored in filename.  */
      fd = debuginfod_find_debuginfo (client, build_id, build_id_len, filename);
      debuginfod_end (client);

      /* Only free build_id if we allocated space for a hex string
         in get_build_id ().  */
      if (build_id_len == 0)
        free (build_id);

      if (fd >= 0)
        {
          /* File successfully retrieved. Close fd since we want to
             use open_debug_file () on filename instead.  */
          close (fd);
          return true;
        }
    }

  return false;
}


get_IDX_name (unsigned long idx)
{
  const char *name = get_DW_IDX_name ((unsigned int) idx);

  if (name == NULL)
    {
      static char buffer[100];

      snprintf (buffer, sizeof (buffer), _("Unknown IDX value: %lx"), idx);
      return buffer;
    }

  return name;
}


add_dwo_info (const char * value, dwarf_vma cu_offset, dwo_type type)
{
  dwo_info * dwinfo = xmalloc (sizeof * dwinfo);

  dwinfo->type   = type;
  dwinfo->value  = value;
  dwinfo->cu_offset = cu_offset;
  dwinfo->next   = first_dwo_info;
  first_dwo_info = dwinfo;
}


load_debug_info (void * file)
{
  /* If we have already tried and failed to load the .debug_info
     section then do not bother to repeat the task.  */
  if (num_debug_info_entries == DEBUG_INFO_UNAVAILABLE)
    return 0;

  /* If we already have the information there is nothing else to do.  */
  if (num_debug_info_entries > 0)
    return num_debug_info_entries;

  /* If this is a DWARF package file, load the CU and TU indexes.  */
  (void) load_cu_tu_indexes (file);

  if (load_debug_section_with_follow (info, file)
      && process_debug_info (&debug_displays [info].section, file, abbrev, true, false))
    return num_debug_info_entries;

  if (load_debug_section_with_follow (info_dwo, file)
      && process_debug_info (&debug_displays [info_dwo].section, file,
			     abbrev_dwo, true, false))
    return num_debug_info_entries;

  num_debug_info_entries = DEBUG_INFO_UNAVAILABLE;
  return 0;
}


display_debug_rnglists_list (unsigned char * start,
			     unsigned char * finish,
			     unsigned int    pointer_size,
			     dwarf_vma       offset,
			     dwarf_vma       base_address,
			     unsigned int    offset_size)
{
  unsigned char *next = start;
  unsigned int debug_addr_section_hdr_len;

  if (offset_size == 4)
    debug_addr_section_hdr_len = 8;
  else
    debug_addr_section_hdr_len = 16;

  while (1)
    {
      dwarf_vma off = offset + (start - next);
      enum dwarf_range_list_entry rlet;
      /* Initialize it due to a false compiler warning.  */
      dwarf_vma begin = -1, length, end = -1;

      if (start >= finish)
	{
	  warn (_("Range list starting at offset 0x%s is not terminated.\n"),
		dwarf_vmatoa ("x", offset));
	  break;
	}

      printf ("    ");
      print_dwarf_vma (off, 4);

      SAFE_BYTE_GET_AND_INC (rlet, start, 1, finish);

      switch (rlet)
	{
	case DW_RLE_end_of_list:
	  printf (_("<End of list>\n"));
	  break;
	case DW_RLE_base_addressx:
	  READ_ULEB (base_address, start, finish);
	  print_dwarf_vma (base_address, pointer_size);
	  printf (_("(base address index) "));
	  base_address = fetch_indexed_addr ((base_address * pointer_size)
			                     + debug_addr_section_hdr_len, pointer_size);
	  print_dwarf_vma (base_address, pointer_size);
	  printf (_("(base address)\n"));
	  break;
	case DW_RLE_startx_endx:
	  READ_ULEB (begin, start, finish);
	  READ_ULEB (end, start, finish);
	  begin = fetch_indexed_addr ((begin * pointer_size)
			              + debug_addr_section_hdr_len, pointer_size);
	  end   = fetch_indexed_addr ((begin * pointer_size)
			              + debug_addr_section_hdr_len, pointer_size);
	  break;
	case DW_RLE_startx_length:
	  READ_ULEB (begin, start, finish);
	  READ_ULEB (length, start, finish);
	  begin = fetch_indexed_addr ((begin * pointer_size)
			              + debug_addr_section_hdr_len, pointer_size);
	  end = begin + length;
	  break;
	case DW_RLE_offset_pair:
	  READ_ULEB (begin, start, finish);
	  READ_ULEB (end, start, finish);
	  break;
	case DW_RLE_base_address:
	  SAFE_BYTE_GET_AND_INC (base_address, start, pointer_size, finish);
	  print_dwarf_vma (base_address, pointer_size);
	  printf (_("(base address)\n"));
	  break;
	case DW_RLE_start_end:
	  SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, finish);
	  SAFE_BYTE_GET_AND_INC (end, start, pointer_size, finish);
	  break;
	case DW_RLE_start_length:
	  SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, finish);
	  READ_ULEB (length, start, finish);
	  end = begin + length;
	  break;
	default:
	  error (_("Invalid range list entry type %d\n"), rlet);
	  rlet = DW_RLE_end_of_list;
	  break;
	}

      if (rlet == DW_RLE_end_of_list)
	break;
      if (rlet == DW_RLE_base_address || rlet == DW_RLE_base_addressx)
	continue;

      /* Only a DW_RLE_offset_pair needs the base address added.  */
      if (rlet == DW_RLE_offset_pair)
	{
	  begin += base_address;
	  end += base_address;
	}

      print_dwarf_vma (begin, pointer_size);
      print_dwarf_vma (end, pointer_size);

      if (begin == end)
	fputs (_("(start == end)"), stdout);
      else if (begin > end)
	fputs (_("(start > end)"), stdout);

      putchar ('\n');
    }
}


display_debug_lines (struct dwarf_section *section, void *file)
{
  unsigned char *data = section->start;
  unsigned char *end = data + section->size;
  int retValRaw = 1;
  int retValDecoded = 1;

  if (do_debug_lines == 0)
    do_debug_lines |= FLAG_DEBUG_LINES_RAW;

  if (do_debug_lines & FLAG_DEBUG_LINES_RAW)
    retValRaw = display_debug_lines_raw (section, data, end, file);

  if (do_debug_lines & FLAG_DEBUG_LINES_DECODED)
    retValDecoded = display_debug_lines_decoded (section, data, data, end, file);

  if (!retValRaw || !retValDecoded)
    return 0;

  return 1;
}


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;
}


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 (name_only_p)
	return name;
      snprintf (reg, sizeof (reg), "r%d (%s)", regno, name);
    }
  else
    snprintf (reg, sizeof (reg), "r%d", regno);
  return reg;
}


get_gdb_index_symbol_kind_name (gdb_index_symbol_kind kind)
{
  /* See gdb/gdb-index.h.  */
  static const char * const kinds[] =
  {
    N_ ("no info"),
    N_ ("type"),
    N_ ("variable"),
    N_ ("function"),
    N_ ("other"),
    N_ ("unused5"),
    N_ ("unused6"),
    N_ ("unused7")
  };

  return _ (kinds[kind]);
}


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;
}


display_debug_aranges (struct dwarf_section *section,
		       void *file ATTRIBUTE_UNUSED)
{
  unsigned char *start = section->start;
  unsigned char *end = start + section->size;

  introduce (section, false);

  /* It does not matter if this load fails,
     we test for that later on.  */
  load_debug_info (file);

  while (start < end)
    {
      unsigned char *hdrptr;
      DWARF2_Internal_ARange arange;
      unsigned char *addr_ranges;
      dwarf_vma length;
      dwarf_vma address;
      dwarf_vma     sec_off;
      unsigned char address_size;
      unsigned int  offset_size;
      unsigned char *end_ranges;

      hdrptr = start;
      sec_off = hdrptr - section->start;

      SAFE_BYTE_GET_AND_INC (arange.ar_length, hdrptr, 4, end);
      if (arange.ar_length == 0xffffffff)
	{
	  SAFE_BYTE_GET_AND_INC (arange.ar_length, hdrptr, 8, end);
	  offset_size = 8;
	}
      else
	offset_size = 4;

      if (arange.ar_length > (size_t) (end - hdrptr))
	{
	  warn (_("Debug info is corrupted, %s header at %#lx has length %s\n"),
		section->name,
		(unsigned long) sec_off,
		dwarf_vmatoa ("x", arange.ar_length));
	  break;
	}
      end_ranges = hdrptr + arange.ar_length;

      SAFE_BYTE_GET_AND_INC (arange.ar_version, hdrptr, 2, end_ranges);
      SAFE_BYTE_GET_AND_INC (arange.ar_info_offset, hdrptr, offset_size,
			     end_ranges);

      if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE
	  && num_debug_info_entries > 0
	  && find_debug_info_for_offset (arange.ar_info_offset) == NULL)
	warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"),
	      (unsigned long) arange.ar_info_offset, section->name);

      SAFE_BYTE_GET_AND_INC (arange.ar_pointer_size, hdrptr, 1, end_ranges);
      SAFE_BYTE_GET_AND_INC (arange.ar_segment_size, hdrptr, 1, end_ranges);

      if (arange.ar_version != 2 && arange.ar_version != 3)
	{
	  /* PR 19872: A version number of 0 probably means that there is
	     padding at the end of the .debug_aranges section.  Gold puts
	     it there when performing an incremental link, for example.
	     So do not generate a warning in this case.  */
	  if (arange.ar_version)
	    warn (_("Only DWARF 2 and 3 aranges are currently supported.\n"));
	  break;
	}

      printf (_("  Length:                   %ld\n"),
	      (long) arange.ar_length);
      printf (_("  Version:                  %d\n"), arange.ar_version);
      printf (_("  Offset into .debug_info:  0x%lx\n"),
	      (unsigned long) arange.ar_info_offset);
      printf (_("  Pointer Size:             %d\n"), arange.ar_pointer_size);
      printf (_("  Segment Size:             %d\n"), arange.ar_segment_size);

      address_size = arange.ar_pointer_size + arange.ar_segment_size;

      /* PR 17512: file: 001-108546-0.001:0.1.  */
      if (address_size == 0 || address_size > 8)
	{
	  error (_("Invalid address size in %s section!\n"),
		 section->name);
	  break;
	}

      /* The DWARF spec does not require that the address size be a power
	 of two, but we do.  This will have to change if we ever encounter
	 an uneven architecture.  */
      if ((address_size & (address_size - 1)) != 0)
	{
	  warn (_("Pointer size + Segment size is not a power of two.\n"));
	  break;
	}

      if (address_size > 4)
	printf (_("\n    Address            Length\n"));
      else
	printf (_("\n    Address    Length\n"));

      addr_ranges = hdrptr;

      /* Must pad to an alignment boundary that is twice the address size.  */
      addr_ranges += (2 * address_size - 1
		      - (hdrptr - start - 1) % (2 * address_size));

      while (2 * address_size <= end_ranges - addr_ranges)
	{
	  SAFE_BYTE_GET_AND_INC (address, addr_ranges, address_size,
				 end_ranges);
	  SAFE_BYTE_GET_AND_INC (length, addr_ranges, address_size,
				 end_ranges);
	  printf ("    ");
	  print_dwarf_vma (address, address_size);
	  print_dwarf_vma (length, address_size);
	  putchar ('\n');
	}

      start = end_ranges;
    }

  printf ("\n");

  return 1;
}


display_debug_macinfo (struct dwarf_section *section,
		       void *file ATTRIBUTE_UNUSED)
{
  unsigned char *start = section->start;
  unsigned char *end = start + section->size;
  unsigned char *curr = start;
  enum dwarf_macinfo_record_type op;

  introduce (section, false);

  while (curr < end)
    {
      unsigned int lineno;
      const unsigned char *string;

      op = (enum dwarf_macinfo_record_type) *curr;
      curr++;

      switch (op)
	{
	case DW_MACINFO_start_file:
	  {
	    unsigned int filenum;

	    READ_ULEB (lineno, curr, end);
	    READ_ULEB (filenum, curr, end);
	    printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"),
		    lineno, filenum);
	  }
	  break;

	case DW_MACINFO_end_file:
	  printf (_(" DW_MACINFO_end_file\n"));
	  break;

	case DW_MACINFO_define:
	  READ_ULEB (lineno, curr, end);
	  string = curr;
	  curr += strnlen ((char *) string, end - string);
	  printf (_(" DW_MACINFO_define - lineno : %d macro : %*s\n"),
		  lineno, (int) (curr - string), string);
	  if (curr < end)
	    curr++;
	  break;

	case DW_MACINFO_undef:
	  READ_ULEB (lineno, curr, end);
	  string = curr;
	  curr += strnlen ((char *) string, end - string);
	  printf (_(" DW_MACINFO_undef - lineno : %d macro : %*s\n"),
		  lineno, (int) (curr - string), string);
	  if (curr < end)
	    curr++;
	  break;

	case DW_MACINFO_vendor_ext:
	  {
	    unsigned int constant;

	    READ_ULEB (constant, curr, end);
	    string = curr;
	    curr += strnlen ((char *) string, end - string);
	    printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %*s\n"),
		    constant, (int) (curr - string), string);
	    if (curr < end)
	      curr++;
	  }
	  break;
	}
    }

  return 1;
}


process_abbrev_set (struct dwarf_section *section,
		    dwarf_vma abbrev_base,
		    dwarf_vma abbrev_size,
		    dwarf_vma abbrev_offset,
		    abbrev_list *list)
{
  if (abbrev_base >= section->size
      || abbrev_size > section->size - abbrev_base)
    {
      /* PR 17531: file:4bcd9ce9.  */
      warn (_("Debug info is corrupted, abbrev size (%lx) is larger than "
	      "abbrev section size (%lx)\n"),
	      (unsigned long) (abbrev_base + abbrev_size),
	      (unsigned long) section->size);
      return NULL;
    }
  if (abbrev_offset >= abbrev_size)
    {
      warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than "
	      "abbrev section size (%lx)\n"),
	    (unsigned long) abbrev_offset,
	    (unsigned long) abbrev_size);
      return NULL;
    }

  unsigned char *start = section->start + abbrev_base;
  unsigned char *end = start + abbrev_size;
  start += abbrev_offset;
  while (start < end)
    {
      unsigned long entry;
      unsigned long tag;
      unsigned long attribute;
      int children;

      READ_ULEB (entry, start, end);

      /* 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)
	return NULL;
      if (entry == 0)
	return start;

      READ_ULEB (tag, start, end);
      if (start == end)
	return NULL;

      children = *start++;

      add_abbrev (entry, tag, children, list);

      do
	{
	  unsigned long form;
	  /* Initialize it due to a false compiler warning.  */
	  dwarf_signed_vma implicit_const = -1;

	  READ_ULEB (attribute, start, end);
	  if (start == end)
	    break;

	  READ_ULEB (form, start, end);
	  if (start == end)
	    break;

	  if (form == DW_FORM_implicit_const)
	    {
	      READ_SLEB (implicit_const, start, end);
	      if (start == end)
		break;
	    }

	  add_abbrev_attr (attribute, form, implicit_const, list);
	}
      while (attribute != 0);
    }

  /* Report the missing single zero which ends the section.  */
  error (_(".debug_abbrev section not zero terminated\n"));

  return NULL;
}


display_debug_not_supported (struct dwarf_section *section,
			     void *file ATTRIBUTE_UNUSED)
{
  printf (_("Displaying the debug contents of section %s is not yet supported.\n"),
	    section->name);

  return 1;
}


get_AT_name (unsigned long attribute)
{
  const char *name;

  if (attribute == 0)
    return "DW_AT value: 0";

  /* One value is shared by the MIPS and HP extensions:  */
  if (attribute == DW_AT_MIPS_fde)
    return "DW_AT_MIPS_fde or DW_AT_HP_unmodifiable";

  name = get_DW_AT_name (attribute);

  if (name == NULL)
    {
      static char buffer[100];

      snprintf (buffer, sizeof (buffer), _("Unknown AT value: %lx"),
		attribute);
      return buffer;
    }

  return name;
}


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));
    }
}


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;
}


fetch_indexed_string (dwarf_vma           idx,
		      struct cu_tu_set *  this_set,
		      dwarf_vma           offset_size,
		      bool                dwo,
		      dwarf_vma           str_offsets_base)
{
  enum dwarf_section_display_enum str_sec_idx = dwo ? str_dwo : str;
  enum dwarf_section_display_enum idx_sec_idx = dwo ? str_index_dwo : str_index;
  struct dwarf_section *index_section = &debug_displays [idx_sec_idx].section;
  struct dwarf_section *str_section = &debug_displays [str_sec_idx].section;
  dwarf_vma index_offset;
  dwarf_vma str_offset;
  const char * ret;

  if (index_section->start == NULL)
    return (dwo ? _("<no .debug_str_offsets.dwo section>")
		: _("<no .debug_str_offsets section>"));

  if (str_section->start == NULL)
    return (dwo ? _("<no .debug_str.dwo section>")
		: _("<no .debug_str section>"));

  index_offset = idx * offset_size;

  if (this_set != NULL)
    index_offset += this_set->section_offsets [DW_SECT_STR_OFFSETS];

  index_offset += str_offsets_base;

  if (index_offset + offset_size > index_section->size)
    {
      warn (_("string index of %s converts to an offset of 0x%s which is too big for section %s"),
	    dwarf_vmatoa ("d", idx),
	    dwarf_vmatoa ("x", index_offset),
	    str_section->name);

      return _("<string index too big>");
    }

  /* FIXME: If we are being paranoid then we should also check to see if
     IDX references an entry beyond the end of the string table pointed to
     by STR_OFFSETS_BASE.  (Since there can be more than one string table
     in a DWARF string section).  */

  str_offset = byte_get (index_section->start + index_offset, offset_size);

  str_offset -= str_section->address;
  if (str_offset >= str_section->size)
    {
      warn (_("indirect offset too big: 0x%s\n"),
	    dwarf_vmatoa ("x", str_offset));
      return _("<indirect index offset is too big>");
    }

  ret = (const char *) str_section->start + str_offset;

  /* Unfortunately we cannot rely upon 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 (ret, str_section->size - str_offset)
      == str_section->size - str_offset)
    return _("<no NUL byte at end of section>");

  return ret;
}


check_gnu_debugaltlink (const char * filename, void * data ATTRIBUTE_UNUSED)
{
  void * sep_data = open_debug_file (filename);

  if (sep_data == NULL)
    return false;

  /* FIXME: We should now extract the build-id in the separate file
     and check it...  */

  return true;
}


xcmalloc (size_t nmemb, size_t size)
{
  /* Check for overflow.  */
  if (nmemb >= ~(size_t) 0 / size)
    {
      fprintf (stderr,
	       _("Attempt to allocate an array with an excessive number of elements: 0x%lx\n"),
	       (long) nmemb);
      xexit (1);
    }

  return xmalloc (nmemb * size);
}


load_debug_section_with_follow (enum dwarf_section_display_enum sec_enum,
				void * handle)
{
  if (load_debug_section (sec_enum, handle))
    {
      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_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;
}


free_all_abbrevs (void)
{
  abbrev_list *  list;

  for (list = abbrev_lists; list != NULL;)
    {
      abbrev_list *   next = list->next;
      abbrev_entry *  abbrv;

      for (abbrv = list->first_abbrev; abbrv != NULL;)
	{
	  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 (abbrv);
	  abbrv = next_abbrev;
	}

      free (list);
      list = next;
    }

  abbrev_lists = NULL;
}


add_abbrev_attr (unsigned long    attribute,
		 unsigned long    form,
		 dwarf_signed_vma implicit_const,
		 abbrev_list *    list)
{
  abbrev_attr *attr;

  attr = (abbrev_attr *) xmalloc (sizeof (*attr));

  attr->attribute      = attribute;
  attr->form           = form;
  attr->implicit_const = implicit_const;
  attr->next           = NULL;

  assert (list != NULL && list->last_abbrev != NULL);

  if (list->last_abbrev->first_attr == NULL)
    list->last_abbrev->first_attr = attr;
  else
    list->last_abbrev->last_attr->next = attr;

  list->last_abbrev->last_attr = attr;
}


check_for_and_load_links (void * file, const char * filename)
{
  void * handle = NULL;

  if (load_debug_section (gnu_debugaltlink, file))
    {
      Build_id_data build_id_data;

      handle = load_separate_debug_info (filename,
					 & debug_displays[gnu_debugaltlink].section,
					 parse_gnu_debugaltlink,
					 check_gnu_debugaltlink,
					 & build_id_data,
					 file);
      if (handle)
	{
	  assert (handle == first_separate_info->handle);
	  check_for_and_load_links (first_separate_info->handle,
				    first_separate_info->filename);
	}
    }

  if (load_debug_section (gnu_debuglink, file))
    {
      unsigned long crc32;

      handle = load_separate_debug_info (filename,
					 & debug_displays[gnu_debuglink].section,
					 parse_gnu_debuglink,
					 check_gnu_debuglink,
					 & crc32,
					 file);
      if (handle)
	{
	  assert (handle == first_separate_info->handle);
	  check_for_and_load_links (first_separate_info->handle,
				    first_separate_info->filename);
	}
    }

  load_debug_sup_file (filename, file);

  load_build_id_debug_file (filename, file);
}


add_dwo_name (const char * name, dwarf_vma cu_offset)
{
  add_dwo_info (name, cu_offset, DWO_NAME);
}


display_debug_pubnames_worker (struct dwarf_section *section,
			       void *file ATTRIBUTE_UNUSED,
			       int is_gnu)
{
  DWARF2_Internal_PubNames names;
  unsigned char *start = section->start;
  unsigned char *end = start + section->size;

  /* It does not matter if this load fails,
     we test for that later on.  */
  load_debug_info (file);

  introduce (section, false);

  while (start < end)
    {
      unsigned char *data;
      unsigned long sec_off = start - section->start;
      unsigned int offset_size;

      SAFE_BYTE_GET_AND_INC (names.pn_length, start, 4, end);
      if (names.pn_length == 0xffffffff)
	{
	  SAFE_BYTE_GET_AND_INC (names.pn_length, start, 8, end);
	  offset_size = 8;
	}
      else
	offset_size = 4;

      if (names.pn_length > (size_t) (end - start))
	{
	  warn (_("Debug info is corrupted, %s header at %#lx has length %s\n"),
		section->name,
		sec_off,
		dwarf_vmatoa ("x", names.pn_length));
	  break;
	}

      data = start;
      start += names.pn_length;

      SAFE_BYTE_GET_AND_INC (names.pn_version, data, 2, start);
      SAFE_BYTE_GET_AND_INC (names.pn_offset, data, offset_size, start);

      if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE
	  && num_debug_info_entries > 0
	  && find_debug_info_for_offset (names.pn_offset) == NULL)
	warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"),
	      (unsigned long) names.pn_offset, section->name);

      SAFE_BYTE_GET_AND_INC (names.pn_size, data, offset_size, start);

      printf (_("  Length:                              %ld\n"),
	      (long) names.pn_length);
      printf (_("  Version:                             %d\n"),
	      names.pn_version);
      printf (_("  Offset into .debug_info section:     0x%lx\n"),
	      (unsigned long) names.pn_offset);
      printf (_("  Size of area in .debug_info section: %ld\n"),
	      (long) names.pn_size);

      if (names.pn_version != 2 && names.pn_version != 3)
	{
	  static int warned = 0;

	  if (! warned)
	    {
	      warn (_("Only DWARF 2 and 3 pubnames are currently supported\n"));
	      warned = 1;
	    }

	  continue;
	}

      if (is_gnu)
	printf (_("\n    Offset  Kind          Name\n"));
      else
	printf (_("\n    Offset\tName\n"));

      while (1)
	{
	  bfd_size_type maxprint;
	  dwarf_vma offset;

	  SAFE_BYTE_GET_AND_INC (offset, data, offset_size, start);

	  if (offset == 0)
	    break;

	  if (data >= start)
	    break;
	  maxprint = (start - data) - 1;

	  if (is_gnu)
	    {
	      unsigned int kind_data;
	      gdb_index_symbol_kind kind;
	      const char *kind_name;
	      int is_static;

	      SAFE_BYTE_GET_AND_INC (kind_data, data, 1, start);
	      maxprint --;
	      /* GCC computes the kind as the upper byte in the CU index
		 word, and then right shifts it by the CU index size.
		 Left shift KIND to where the gdb-index.h accessor macros
		 can use it.  */
	      kind_data <<= GDB_INDEX_CU_BITSIZE;
	      kind = GDB_INDEX_SYMBOL_KIND_VALUE (kind_data);
	      kind_name = get_gdb_index_symbol_kind_name (kind);
	      is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (kind_data);
	      printf ("    %-6lx  %s,%-10s  %.*s\n",
		      (unsigned long) offset, is_static ? _("s") : _("g"),
		      kind_name, (int) maxprint, data);
	    }
	  else
	    printf ("    %-6lx\t%.*s\n",
		    (unsigned long) offset, (int) maxprint, data);

	  data += strnlen ((char *) data, maxprint);
	  if (data < start)
	    data++;
	  if (data >= start)
	    break;
	}
    }

  printf ("\n");
  return 1;
}


get_encoded_value (unsigned char **pdata,
		   int encoding,
		   struct dwarf_section *section,
		   unsigned char * end)
{
  unsigned char * data = * pdata;
  unsigned int size = size_of_encoded_value (encoding);
  dwarf_vma val;

  if (data >= end || size > (size_t) (end - data))
    {
      warn (_("Encoded value extends past end of section\n"));
      * pdata = end;
      return 0;
    }

  /* PR 17512: file: 002-829853-0.004.  */
  if (size > 8)
    {
      warn (_("Encoded size of %d is too large to read\n"), size);
      * pdata = end;
      return 0;
    }

  /* PR 17512: file: 1085-5603-0.004.  */
  if (size == 0)
    {
      warn (_("Encoded size of 0 is too small to read\n"));
      * pdata = end;
      return 0;
    }

  if (encoding & DW_EH_PE_signed)
    val = byte_get_signed (data, size);
  else
    val = byte_get (data, size);

  if ((encoding & 0x70) == DW_EH_PE_pcrel)
    val += section->address + (data - section->start);

  * pdata = data + size;
  return val;
}