Blame libdw/dwarf_getscopes.c

Packit 032894
/* Return scope DIEs containing PC address.
Packit 032894
   Copyright (C) 2005, 2007, 2015 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <assert.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include "libdwP.h"
Packit 032894
#include <dwarf.h>
Packit 032894
Packit 032894
Packit 032894
struct args
Packit 032894
{
Packit 032894
  Dwarf_Addr pc;
Packit 032894
  Dwarf_Die *scopes;
Packit 032894
  unsigned int inlined, nscopes;
Packit 032894
  Dwarf_Die inlined_origin;
Packit 032894
};
Packit 032894
Packit 032894
/* Preorder visitor: prune the traversal if this DIE does not contain PC.  */
Packit 032894
static int
Packit 032894
pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
Packit 032894
{
Packit 032894
  struct args *a = arg;
Packit 032894
Packit 032894
  if (a->scopes != NULL)
Packit 032894
    die->prune = true;
Packit 032894
  else
Packit 032894
    {
Packit 032894
      /* dwarf_haspc returns an error if there are no appropriate attributes.
Packit 032894
	 But we use it indiscriminantly instead of presuming which tags can
Packit 032894
	 have PC attributes.  So when it fails for that reason, treat it just
Packit 032894
	 as a nonmatching return.  */
Packit 032894
      int result = INTUSE(dwarf_haspc) (&die->die, a->pc);
Packit 032894
      if (result < 0)
Packit 032894
	{
Packit 032894
	  int error = INTUSE(dwarf_errno) ();
Packit 032894
	  if (error != DWARF_E_NOERROR
Packit 032894
	      && error != DWARF_E_NO_DEBUG_RANGES
Packit 032894
	      && error != DWARF_E_NO_DEBUG_RNGLISTS)
Packit 032894
	    {
Packit 032894
	      __libdw_seterrno (error);
Packit 032894
	      return -1;
Packit 032894
	    }
Packit 032894
	  result = 0;
Packit 032894
	}
Packit 032894
      if (result == 0)
Packit 032894
    	die->prune = true;
Packit 032894
Packit 032894
      if (!die->prune
Packit 032894
	  && INTUSE (dwarf_tag) (&die->die) == DW_TAG_inlined_subroutine)
Packit 032894
	a->inlined = depth;
Packit 032894
    }
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
/* Preorder visitor for second partial traversal after finding a
Packit 032894
   concrete inlined instance.  */
Packit 032894
static int
Packit 032894
origin_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
Packit 032894
{
Packit 032894
  struct args *a = arg;
Packit 032894
Packit 032894
  if (die->die.addr != a->inlined_origin.addr)
Packit 032894
    return 0;
Packit 032894
Packit 032894
  /* We have a winner!  This is the abstract definition of the inline
Packit 032894
     function of which A->scopes[A->nscopes - 1] is a concrete instance.
Packit 032894
  */
Packit 032894
Packit 032894
  unsigned int nscopes = a->nscopes + depth;
Packit 032894
  Dwarf_Die *scopes = realloc (a->scopes, nscopes * sizeof scopes[0]);
Packit 032894
  if (scopes == NULL)
Packit 032894
    {
Packit 032894
      free (a->scopes);
Packit 032894
      __libdw_seterrno (DWARF_E_NOMEM);
Packit 032894
      return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  a->scopes = scopes;
Packit 032894
  do
Packit 032894
    {
Packit 032894
      die = die->parent;
Packit 032894
      scopes[a->nscopes++] = die->die;
Packit 032894
    }
Packit 032894
  while (a->nscopes < nscopes);
Packit 032894
  assert (die->parent == NULL);
Packit 032894
  return a->nscopes;
Packit 032894
}
Packit 032894
Packit 032894
/* Postorder visitor: first (innermost) call wins.  */
Packit 032894
static int
Packit 032894
pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
Packit 032894
{
Packit 032894
  struct args *a = arg;
Packit 032894
Packit 032894
  if (die->prune)
Packit 032894
    return 0;
Packit 032894
Packit 032894
  if (a->scopes == NULL)
Packit 032894
    {
Packit 032894
      /* We have hit the innermost DIE that contains the target PC.  */
Packit 032894
Packit 032894
      a->nscopes = depth + 1 - a->inlined;
Packit 032894
      a->scopes = malloc (a->nscopes * sizeof a->scopes[0]);
Packit 032894
      if (a->scopes == NULL)
Packit 032894
	{
Packit 032894
	  __libdw_seterrno (DWARF_E_NOMEM);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
Packit 032894
      for (unsigned int i = 0; i < a->nscopes; ++i)
Packit 032894
	{
Packit 032894
	  a->scopes[i] = die->die;
Packit 032894
	  die = die->parent;
Packit 032894
	}
Packit 032894
Packit 032894
      if (a->inlined == 0)
Packit 032894
	{
Packit 032894
	  assert (die == NULL);
Packit 032894
	  return a->nscopes;
Packit 032894
	}
Packit 032894
Packit 032894
      /* This is the concrete inlined instance itself.
Packit 032894
	 Record its abstract_origin pointer.  */
Packit 032894
      Dwarf_Die *const inlinedie = &a->scopes[depth - a->inlined];
Packit 032894
Packit 032894
      assert (INTUSE (dwarf_tag) (inlinedie) == DW_TAG_inlined_subroutine);
Packit 032894
      Dwarf_Attribute attr_mem;
Packit 032894
      Dwarf_Attribute *attr = INTUSE (dwarf_attr) (inlinedie,
Packit 032894
						   DW_AT_abstract_origin,
Packit 032894
						   &attr_mem);
Packit 032894
      if (INTUSE (dwarf_formref_die) (attr, &a->inlined_origin) == NULL)
Packit 032894
	return -1;
Packit 032894
      return 0;
Packit 032894
    }
Packit 032894
Packit 032894
Packit 032894
  /* We've recorded the scopes back to one that is a concrete inlined
Packit 032894
     instance.  Now return out of the traversal back to the scope
Packit 032894
     containing that instance.  */
Packit 032894
Packit 032894
  assert (a->inlined);
Packit 032894
  if (depth >= a->inlined)
Packit 032894
    /* Not there yet.  */
Packit 032894
    return 0;
Packit 032894
Packit 032894
  /* Now we are in a scope that contains the concrete inlined instance.
Packit 032894
     Search it for the inline function's abstract definition.
Packit 032894
     If we don't find it, return to search the containing scope.
Packit 032894
     If we do find it, the nonzero return value will bail us out
Packit 032894
     of the postorder traversal.  */
Packit 032894
  return __libdw_visit_scopes (depth, die, NULL, &origin_match, NULL, a);
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
int
Packit 032894
dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
Packit 032894
{
Packit 032894
  if (cudie == NULL)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie };
Packit 032894
  struct args a = { .pc = pc };
Packit 032894
Packit 032894
  int result = __libdw_visit_scopes (0, &cu, NULL, &pc_match, &pc_record, &a);
Packit 032894
Packit 032894
  if (result == 0 && a.scopes != NULL)
Packit 032894
    result = __libdw_visit_scopes (0, &cu, NULL, &origin_match, NULL, &a);
Packit 032894
Packit 032894
  if (result > 0)
Packit 032894
    *scopes = a.scopes;
Packit 032894
Packit 032894
  return result;
Packit 032894
}