Blame libdw/libdw_visit_scopes.c

Packit 032894
/* Helper functions to descend DWARF scope trees.
Packit 032894
   Copyright (C) 2005,2006,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 "libdwP.h"
Packit 032894
#include <dwarf.h>
Packit 032894
Packit 032894
Packit 032894
static bool
Packit 032894
may_have_scopes (Dwarf_Die *die)
Packit 032894
{
Packit 032894
  switch (INTUSE(dwarf_tag) (die))
Packit 032894
    {
Packit 032894
      /* DIEs with addresses we can try to match.  */
Packit 032894
    case DW_TAG_compile_unit:
Packit 032894
    case DW_TAG_module:
Packit 032894
    case DW_TAG_lexical_block:
Packit 032894
    case DW_TAG_with_stmt:
Packit 032894
    case DW_TAG_catch_block:
Packit 032894
    case DW_TAG_try_block:
Packit 032894
    case DW_TAG_entry_point:
Packit 032894
    case DW_TAG_inlined_subroutine:
Packit 032894
    case DW_TAG_subprogram:
Packit 032894
      return true;
Packit 032894
Packit 032894
      /* DIEs without addresses that can own DIEs with addresses.  */
Packit 032894
    case DW_TAG_namespace:
Packit 032894
    case DW_TAG_class_type:
Packit 032894
    case DW_TAG_structure_type:
Packit 032894
      return true;
Packit 032894
Packit 032894
      /* Other DIEs we have no reason to descend.  */
Packit 032894
    default:
Packit 032894
      break;
Packit 032894
    }
Packit 032894
  return false;
Packit 032894
}
Packit 032894
Packit 032894
struct walk_children_state
Packit 032894
{
Packit 032894
  /* Parameters of __libdw_visit_scopes. */
Packit 032894
  unsigned int depth;
Packit 032894
  struct Dwarf_Die_Chain *imports;
Packit 032894
  int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
Packit 032894
  int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
Packit 032894
  void *arg;
Packit 032894
  /* Extra local variables for the walker. */
Packit 032894
  struct Dwarf_Die_Chain child;
Packit 032894
};
Packit 032894
Packit 032894
static inline int
Packit 032894
walk_children (struct walk_children_state *state);
Packit 032894
Packit 032894
int
Packit 032894
internal_function
Packit 032894
__libdw_visit_scopes (unsigned int depth, struct Dwarf_Die_Chain *root,
Packit 032894
		      struct Dwarf_Die_Chain *imports,
Packit 032894
		      int (*previsit) (unsigned int,
Packit 032894
				       struct Dwarf_Die_Chain *,
Packit 032894
				       void *),
Packit 032894
		      int (*postvisit) (unsigned int,
Packit 032894
					struct Dwarf_Die_Chain *,
Packit 032894
					void *),
Packit 032894
		      void *arg)
Packit 032894
{
Packit 032894
  struct walk_children_state state =
Packit 032894
    {
Packit 032894
      .depth = depth,
Packit 032894
      .imports = imports,
Packit 032894
      .previsit = previsit,
Packit 032894
      .postvisit = postvisit,
Packit 032894
      .arg = arg
Packit 032894
    };
Packit 032894
Packit 032894
  state.child.parent = root;
Packit 032894
  int ret;
Packit 032894
  if ((ret = INTUSE(dwarf_child) (&root->die, &state.child.die)) != 0)
Packit 032894
    return ret < 0 ? -1 : 0; // Having zero children is legal.
Packit 032894
Packit 032894
  return walk_children (&state);
Packit 032894
}
Packit 032894
Packit 032894
static inline int
Packit 032894
walk_children (struct walk_children_state *state)
Packit 032894
{
Packit 032894
  int ret;
Packit 032894
  do
Packit 032894
    {
Packit 032894
      /* For an imported unit, it is logically as if the children of
Packit 032894
	 that unit are siblings of the other children.  So don't do
Packit 032894
	 a full recursion into the imported unit, but just walk the
Packit 032894
	 children in place before moving to the next real child.  */
Packit 032894
      while (INTUSE(dwarf_tag) (&state->child.die) == DW_TAG_imported_unit)
Packit 032894
	{
Packit 032894
	  Dwarf_Die orig_child_die = state->child.die;
Packit 032894
	  Dwarf_Attribute attr_mem;
Packit 032894
	  Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&state->child.die,
Packit 032894
						      DW_AT_import,
Packit 032894
						      &attr_mem);
Packit Service 35cfd5
	  /* Some gcc -flto versions imported other top-level compile units,
Packit Service 35cfd5
	     skip those.  */
Packit 032894
	  if (INTUSE(dwarf_formref_die) (attr, &state->child.die) != NULL
Packit Service 35cfd5
	      && INTUSE(dwarf_tag) (&state->child.die) != DW_TAG_compile_unit
Packit Service 35cfd5
	      && (INTUSE(dwarf_child) (&state->child.die, &state->child.die)
Packit Service 35cfd5
		  == 0))
Packit 032894
	    {
Packit 032894
	      /* Checks the given DIE hasn't been imported yet
Packit 032894
	         to prevent cycles.  */
Packit 032894
	      bool imported = false;
Packit 032894
	      for (struct Dwarf_Die_Chain *import = state->imports; import != NULL;
Packit 032894
	        import = import->parent)
Packit 032894
	        if (import->die.addr == orig_child_die.addr)
Packit 032894
	          {
Packit 032894
	            imported = true;
Packit 032894
	            break;
Packit 032894
	          }
Packit 032894
	      if (imported)
Packit 032894
		{
Packit 032894
		  __libdw_seterrno (DWARF_E_INVALID_DWARF);
Packit 032894
		  return -1;
Packit 032894
		}
Packit 032894
	      struct Dwarf_Die_Chain *orig_imports = state->imports;
Packit 032894
	      struct Dwarf_Die_Chain import = { .die = orig_child_die,
Packit 032894
					        .parent = orig_imports };
Packit 032894
	      state->imports = &import;
Packit 032894
	      int result = walk_children (state);
Packit 032894
	      state->imports = orig_imports;
Packit 032894
	      if (result != DWARF_CB_OK)
Packit 032894
		return result;
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* Any "real" children left?  */
Packit 032894
	  if ((ret = INTUSE(dwarf_siblingof) (&orig_child_die,
Packit 032894
					      &state->child.die)) != 0)
Packit 032894
	    return ret < 0 ? -1 : 0;
Packit 032894
	};
Packit 032894
Packit 032894
	state->child.prune = false;
Packit 032894
Packit 032894
	/* previsit is declared NN */
Packit 032894
	int result = (*state->previsit) (state->depth + 1, &state->child, state->arg);
Packit 032894
	if (result != DWARF_CB_OK)
Packit 032894
	  return result;
Packit 032894
Packit 032894
	if (!state->child.prune && may_have_scopes (&state->child.die)
Packit 032894
	    && INTUSE(dwarf_haschildren) (&state->child.die))
Packit 032894
	  {
Packit 032894
	    result = __libdw_visit_scopes (state->depth + 1, &state->child, state->imports,
Packit 032894
				           state->previsit, state->postvisit, state->arg);
Packit 032894
	    if (result != DWARF_CB_OK)
Packit 032894
	      return result;
Packit 032894
	  }
Packit 032894
Packit 032894
	if (state->postvisit != NULL)
Packit 032894
	  {
Packit 032894
	    result = (*state->postvisit) (state->depth + 1, &state->child, state->arg);
Packit 032894
	    if (result != DWARF_CB_OK)
Packit 032894
	      return result;
Packit 032894
	  }
Packit 032894
    }
Packit 032894
  while ((ret = INTUSE(dwarf_siblingof) (&state->child.die, &state->child.die)) == 0);
Packit 032894
Packit 032894
  return ret < 0 ? -1 : 0;
Packit 032894
}