Blame libdw/dwarf_getfuncs.c

Packit Service 97d2fb
/* Get function information.
Packit Service 97d2fb
   Copyright (C) 2005, 2013, 2015 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
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 <dwarf.h>
Packit Service 97d2fb
#include "libdwP.h"
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
struct visitor_info
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* The user callback of dwarf_getfuncs.  */
Packit Service 97d2fb
  int (*callback) (Dwarf_Die *, void *);
Packit Service 97d2fb
Packit Service 97d2fb
  /* The user arg value to dwarf_getfuncs.  */
Packit Service 97d2fb
  void *arg;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Addr of the DIE offset where to (re)start the search.  Zero for all.  */
Packit Service 97d2fb
  void *start_addr;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Last subprogram DIE addr seen.  */
Packit Service 97d2fb
  void *last_addr;
Packit Service 97d2fb
Packit Service 97d2fb
  /* The CU only contains C functions.  Allows pruning of most subtrees.  */
Packit Service 97d2fb
  bool c_cu;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
tree_visitor (unsigned int depth __attribute__ ((unused)),
Packit Service 97d2fb
	      struct Dwarf_Die_Chain *chain, void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct visitor_info *const v = arg;
Packit Service 97d2fb
  Dwarf_Die *die = &chain->die;
Packit Service 97d2fb
  void *start_addr = v->start_addr;
Packit Service 97d2fb
  void *die_addr = die->addr;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Pure C CUs can only contain defining subprogram DIEs as direct
Packit Service 97d2fb
     children of the CU DIE or as nested function inside a normal C
Packit Service 97d2fb
     code constructs.  */
Packit Service 97d2fb
  int tag = INTUSE(dwarf_tag) (die);
Packit Service 97d2fb
  if (v->c_cu
Packit Service 97d2fb
      && tag != DW_TAG_subprogram
Packit Service 97d2fb
      && tag != DW_TAG_lexical_block
Packit Service 97d2fb
      && tag != DW_TAG_inlined_subroutine)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      chain->prune = true;
Packit Service 97d2fb
      return DWARF_CB_OK;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Skip all DIEs till we found the (re)start addr.  */
Packit Service 97d2fb
  if (start_addr != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (die_addr == start_addr)
Packit Service 97d2fb
	v->start_addr = NULL;
Packit Service 97d2fb
      return DWARF_CB_OK;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* If this isn't a (defining) subprogram entity, skip DIE.  */
Packit Service 97d2fb
  if (tag != DW_TAG_subprogram
Packit Service 97d2fb
      || INTUSE(dwarf_hasattr) (die, DW_AT_declaration))
Packit Service 97d2fb
    return DWARF_CB_OK;
Packit Service 97d2fb
Packit Service 97d2fb
  v->last_addr = die_addr;
Packit Service 97d2fb
  return (*v->callback) (die, v->arg);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
ptrdiff_t
Packit Service 97d2fb
dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *),
Packit Service 97d2fb
		void *arg, ptrdiff_t offset)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (unlikely (cudie == NULL
Packit Service 97d2fb
		|| INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit))
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  int lang = INTUSE(dwarf_srclang) (cudie);
Packit Service 97d2fb
  bool c_cu = (lang == DW_LANG_C89
Packit Service 97d2fb
	       || lang == DW_LANG_C
Packit Service 97d2fb
	       || lang == DW_LANG_C99
Packit Service 97d2fb
	       || lang == DW_LANG_C11);
Packit Service 97d2fb
Packit Service 97d2fb
  struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu };
Packit Service 97d2fb
  struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu),
Packit Service 97d2fb
				   .parent = NULL };
Packit Service 97d2fb
  int res = __libdw_visit_scopes (0, &chain, NULL, &tree_visitor, NULL, &v);
Packit Service 97d2fb
Packit Service 97d2fb
  if (res == DWARF_CB_ABORT)
Packit Service 97d2fb
    return (ptrdiff_t) v.last_addr;
Packit Service 97d2fb
  else
Packit Service 97d2fb
    return res;
Packit Service 97d2fb
}