Blame libdw/dwarf_getaranges.c

Packit Service 97d2fb
/* Return list address ranges.
Packit Service 97d2fb
   Copyright (C) 2000-2010, 2016, 2017 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include "libdwP.h"
Packit Service 97d2fb
#include <dwarf.h>
Packit Service 97d2fb
Packit Service 97d2fb
struct arangelist
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_Arange arange;
Packit Service 97d2fb
  struct arangelist *next;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
/* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers.  */
Packit Service 97d2fb
static int
Packit Service 97d2fb
compare_aranges (const void *a, const void *b)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct arangelist *const *p1 = a, *const *p2 = b;
Packit Service 97d2fb
  struct arangelist *l1 = *p1, *l2 = *p2;
Packit Service 97d2fb
  if (l1->arange.addr != l2->arange.addr)
Packit Service 97d2fb
    return (l1->arange.addr < l2->arange.addr) ? -1 : 1;
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (dbg == NULL)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  if (dbg->aranges != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      *aranges = dbg->aranges;
Packit Service 97d2fb
      if (naranges != NULL)
Packit Service 97d2fb
	*naranges = dbg->aranges->naranges;
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (dbg->sectiondata[IDX_debug_aranges] == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* No such section.  */
Packit Service 97d2fb
      *aranges = NULL;
Packit Service 97d2fb
      if (naranges != NULL)
Packit Service 97d2fb
	*naranges = 0;
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  struct arangelist *arangelist = NULL;
Packit Service 97d2fb
  unsigned int narangelist = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf;
Packit Service 97d2fb
  const unsigned char *readendp
Packit Service 97d2fb
    = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
Packit Service 97d2fb
Packit Service 97d2fb
  while (readp < readendp)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const unsigned char *hdrstart = readp;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Each entry starts with a header:
Packit Service 97d2fb
Packit Service 97d2fb
	 1. A 4-byte or 12-byte length containing the length of the
Packit Service 97d2fb
	 set of entries for this compilation unit, not including the
Packit Service 97d2fb
	 length field itself. [...]
Packit Service 97d2fb
Packit Service 97d2fb
	 2. A 2-byte version identifier containing the value 2 for
Packit Service 97d2fb
	 DWARF Version 2.1.
Packit Service 97d2fb
Packit Service 97d2fb
	 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
Packit Service 97d2fb
Packit Service 97d2fb
	 4. A 1-byte unsigned integer containing the size in bytes of
Packit Service 97d2fb
	 an address (or the offset portion of an address for segmented
Packit Service 97d2fb
	 addressing) on the target system.
Packit Service 97d2fb
Packit Service 97d2fb
	 5. A 1-byte unsigned integer containing the size in bytes of
Packit Service 97d2fb
	 a segment descriptor on the target system.  */
Packit Service 97d2fb
      if (unlikely (readp + 4 > readendp))
Packit Service 97d2fb
	goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
      Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
Packit Service 97d2fb
      unsigned int length_bytes = 4;
Packit Service 97d2fb
      if (length == DWARF3_LENGTH_64_BIT)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (unlikely (readp + 8 > readendp))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  length = read_8ubyte_unaligned_inc (dbg, readp);
Packit Service 97d2fb
	  length_bytes = 8;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
Packit Service 97d2fb
			 && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
Packit Service 97d2fb
	goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
      if (unlikely (readp + 2 > readendp))
Packit Service 97d2fb
	goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
      unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
Packit Service 97d2fb
      if (version != 2)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	invalid:
Packit Service 97d2fb
	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit Service 97d2fb
	fail:
Packit Service 97d2fb
	  while (arangelist != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      struct arangelist *next = arangelist->next;
Packit Service 97d2fb
	      free (arangelist);
Packit Service 97d2fb
	      arangelist = next;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  return -1;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      Dwarf_Word offset = 0;
Packit Service 97d2fb
      if (__libdw_read_offset_inc (dbg,
Packit Service 97d2fb
				   IDX_debug_aranges, &readp,
Packit Service 97d2fb
				   length_bytes, &offset, IDX_debug_info, 4))
Packit Service 97d2fb
	goto fail;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Next up two bytes for address and segment size.  */
Packit Service 97d2fb
      if (readp + 2 > readendp)
Packit Service 97d2fb
	goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
      unsigned int address_size = *readp++;
Packit Service 97d2fb
      if (unlikely (address_size != 4 && address_size != 8))
Packit Service 97d2fb
	goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
      /* We don't actually support segment selectors.  */
Packit Service 97d2fb
      unsigned int segment_size = *readp++;
Packit Service 97d2fb
      if (segment_size != 0)
Packit Service 97d2fb
	goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
      /* Round the address to the next multiple of 2*address_size.  */
Packit Service 97d2fb
      readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
Packit Service 97d2fb
		% (2 * address_size));
Packit Service 97d2fb
Packit Service 97d2fb
      while (1)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Dwarf_Word range_address;
Packit Service 97d2fb
	  Dwarf_Word range_length;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
Packit Service 97d2fb
					address_size, &range_address))
Packit Service 97d2fb
	    goto fail;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (readp + address_size > readendp)
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (address_size == 4)
Packit Service 97d2fb
	    range_length = read_4ubyte_unaligned_inc (dbg, readp);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    range_length = read_8ubyte_unaligned_inc (dbg, readp);
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Two zero values mark the end.  */
Packit Service 97d2fb
	  if (range_address == 0 && range_length == 0)
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* We don't use alloca for these temporary structures because
Packit Service 97d2fb
	     the total number of them can be quite large.  */
Packit Service 97d2fb
	  struct arangelist *new_arange = malloc (sizeof *new_arange);
Packit Service 97d2fb
	  if (unlikely (new_arange == NULL))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      __libdw_seterrno (DWARF_E_NOMEM);
Packit Service 97d2fb
	      goto fail;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  new_arange->arange.addr = range_address;
Packit Service 97d2fb
	  new_arange->arange.length = range_length;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* We store the actual CU DIE offset, not the CU header offset.  */
Packit Service 97d2fb
	  Dwarf_CU *cu = __libdw_findcu (dbg, offset, false);
Packit Service 97d2fb
	  if (unlikely (cu == NULL))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* We haven't gotten a chance to link in the new_arange
Packit Service 97d2fb
		 into the arangelist, don't leak it.  */
Packit Service 97d2fb
	      free (new_arange);
Packit Service 97d2fb
	      goto fail;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
Packit Service 97d2fb
Packit Service 97d2fb
	  new_arange->next = arangelist;
Packit Service 97d2fb
	  arangelist = new_arange;
Packit Service 97d2fb
	  ++narangelist;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Sanity-check the data.  */
Packit Service 97d2fb
	  if (unlikely (new_arange->arange.offset
Packit Service 97d2fb
			>= dbg->sectiondata[IDX_debug_info]->d_size))
Packit Service 97d2fb
	    goto invalid;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (narangelist == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      assert (arangelist == NULL);
Packit Service 97d2fb
      if (naranges != NULL)
Packit Service 97d2fb
	*naranges = 0;
Packit Service 97d2fb
      *aranges = NULL;
Packit Service 97d2fb
      return 0;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Allocate the array for the result.  */
Packit Service 97d2fb
  void *buf = libdw_alloc (dbg, Dwarf_Aranges,
Packit Service 97d2fb
			   sizeof (Dwarf_Aranges)
Packit Service 97d2fb
			   + narangelist * sizeof (Dwarf_Arange), 1);
Packit Service 97d2fb
Packit Service 97d2fb
  /* First use the buffer for the pointers, and sort the entries.
Packit Service 97d2fb
     We'll write the pointers in the end of the buffer, and then
Packit Service 97d2fb
     copy into the buffer from the beginning so the overlap works.  */
Packit Service 97d2fb
  assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
Packit Service 97d2fb
  struct arangelist **sortaranges
Packit Service 97d2fb
    = (buf + sizeof (Dwarf_Aranges)
Packit Service 97d2fb
       + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
Packit Service 97d2fb
Packit Service 97d2fb
  /* The list is in LIFO order and usually they come in clumps with
Packit Service 97d2fb
     ascending addresses.  So fill from the back to probably start with
Packit Service 97d2fb
     runs already in order before we sort.  */
Packit Service 97d2fb
  unsigned int i = narangelist;
Packit Service 97d2fb
  while (i-- > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      sortaranges[i] = arangelist;
Packit Service 97d2fb
      arangelist = arangelist->next;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  assert (arangelist == NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Sort by ascending address.  */
Packit Service 97d2fb
  qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now that they are sorted, put them in the final array.
Packit Service 97d2fb
     The buffers overlap, so we've clobbered the early elements
Packit Service 97d2fb
     of SORTARANGES by the time we're reading the later ones.  */
Packit Service 97d2fb
  *aranges = buf;
Packit Service 97d2fb
  (*aranges)->dbg = dbg;
Packit Service 97d2fb
  (*aranges)->naranges = narangelist;
Packit Service 97d2fb
  dbg->aranges = *aranges;
Packit Service 97d2fb
  if (naranges != NULL)
Packit Service 97d2fb
    *naranges = narangelist;
Packit Service 97d2fb
  for (i = 0; i < narangelist; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      struct arangelist *elt = sortaranges[i];
Packit Service 97d2fb
      (*aranges)->info[i] = elt->arange;
Packit Service 97d2fb
      free (elt);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(dwarf_getaranges)