Home | History | Annotate | Download | only in libdw
      1 /* Return scope DIEs containing PC address.
      2    Copyright (C) 2005, 2007, 2015 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of either
      7 
      8      * the GNU Lesser General Public License as published by the Free
      9        Software Foundation; either version 3 of the License, or (at
     10        your option) any later version
     11 
     12    or
     13 
     14      * the GNU General Public License as published by the Free
     15        Software Foundation; either version 2 of the License, or (at
     16        your option) any later version
     17 
     18    or both in parallel, as here.
     19 
     20    elfutils is distributed in the hope that it will be useful, but
     21    WITHOUT ANY WARRANTY; without even the implied warranty of
     22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23    General Public License for more details.
     24 
     25    You should have received copies of the GNU General Public License and
     26    the GNU Lesser General Public License along with this program.  If
     27    not, see <http://www.gnu.org/licenses/>.  */
     28 
     29 #ifdef HAVE_CONFIG_H
     30 # include <config.h>
     31 #endif
     32 
     33 #include <assert.h>
     34 #include <stdlib.h>
     35 #include "libdwP.h"
     36 #include <dwarf.h>
     37 
     38 
     39 struct args
     40 {
     41   Dwarf_Addr pc;
     42   Dwarf_Die *scopes;
     43   unsigned int inlined, nscopes;
     44   Dwarf_Die inlined_origin;
     45 };
     46 
     47 /* Preorder visitor: prune the traversal if this DIE does not contain PC.  */
     48 static int
     49 pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
     50 {
     51   struct args *a = arg;
     52 
     53   if (a->scopes != NULL)
     54     die->prune = true;
     55   else
     56     {
     57       /* dwarf_haspc returns an error if there are no appropriate attributes.
     58 	 But we use it indiscriminantly instead of presuming which tags can
     59 	 have PC attributes.  So when it fails for that reason, treat it just
     60 	 as a nonmatching return.  */
     61       int result = INTUSE(dwarf_haspc) (&die->die, a->pc);
     62       if (result < 0)
     63 	{
     64 	  int error = INTUSE(dwarf_errno) ();
     65 	  if (error != DWARF_E_NOERROR && error != DWARF_E_NO_DEBUG_RANGES)
     66 	    {
     67 	      __libdw_seterrno (error);
     68 	      return -1;
     69 	    }
     70 	  result = 0;
     71 	}
     72       if (result == 0)
     73     	die->prune = true;
     74 
     75       if (!die->prune
     76 	  && INTUSE (dwarf_tag) (&die->die) == DW_TAG_inlined_subroutine)
     77 	a->inlined = depth;
     78     }
     79 
     80   return 0;
     81 }
     82 
     83 /* Preorder visitor for second partial traversal after finding a
     84    concrete inlined instance.  */
     85 static int
     86 origin_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
     87 {
     88   struct args *a = arg;
     89 
     90   if (die->die.addr != a->inlined_origin.addr)
     91     return 0;
     92 
     93   /* We have a winner!  This is the abstract definition of the inline
     94      function of which A->scopes[A->nscopes - 1] is a concrete instance.
     95   */
     96 
     97   unsigned int nscopes = a->nscopes + depth;
     98   Dwarf_Die *scopes = realloc (a->scopes, nscopes * sizeof scopes[0]);
     99   if (scopes == NULL)
    100     {
    101       free (a->scopes);
    102       __libdw_seterrno (DWARF_E_NOMEM);
    103       return -1;
    104     }
    105 
    106   a->scopes = scopes;
    107   do
    108     {
    109       die = die->parent;
    110       scopes[a->nscopes++] = die->die;
    111     }
    112   while (a->nscopes < nscopes);
    113   assert (die->parent == NULL);
    114   return a->nscopes;
    115 }
    116 
    117 /* Postorder visitor: first (innermost) call wins.  */
    118 static int
    119 pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
    120 {
    121   struct args *a = arg;
    122 
    123   if (die->prune)
    124     return 0;
    125 
    126   if (a->scopes == NULL)
    127     {
    128       /* We have hit the innermost DIE that contains the target PC.  */
    129 
    130       a->nscopes = depth + 1 - a->inlined;
    131       a->scopes = malloc (a->nscopes * sizeof a->scopes[0]);
    132       if (a->scopes == NULL)
    133 	{
    134 	  __libdw_seterrno (DWARF_E_NOMEM);
    135 	  return -1;
    136 	}
    137 
    138       for (unsigned int i = 0; i < a->nscopes; ++i)
    139 	{
    140 	  a->scopes[i] = die->die;
    141 	  die = die->parent;
    142 	}
    143 
    144       if (a->inlined == 0)
    145 	{
    146 	  assert (die == NULL);
    147 	  return a->nscopes;
    148 	}
    149 
    150       /* This is the concrete inlined instance itself.
    151 	 Record its abstract_origin pointer.  */
    152       Dwarf_Die *const inlinedie = &a->scopes[depth - a->inlined];
    153 
    154       assert (INTUSE (dwarf_tag) (inlinedie) == DW_TAG_inlined_subroutine);
    155       Dwarf_Attribute attr_mem;
    156       Dwarf_Attribute *attr = INTUSE (dwarf_attr) (inlinedie,
    157 						   DW_AT_abstract_origin,
    158 						   &attr_mem);
    159       if (INTUSE (dwarf_formref_die) (attr, &a->inlined_origin) == NULL)
    160 	return -1;
    161       return 0;
    162     }
    163 
    164 
    165   /* We've recorded the scopes back to one that is a concrete inlined
    166      instance.  Now return out of the traversal back to the scope
    167      containing that instance.  */
    168 
    169   assert (a->inlined);
    170   if (depth >= a->inlined)
    171     /* Not there yet.  */
    172     return 0;
    173 
    174   /* Now we are in a scope that contains the concrete inlined instance.
    175      Search it for the inline function's abstract definition.
    176      If we don't find it, return to search the containing scope.
    177      If we do find it, the nonzero return value will bail us out
    178      of the postorder traversal.  */
    179   return __libdw_visit_scopes (depth, die, NULL, &origin_match, NULL, a);
    180 }
    181 
    182 
    183 int
    184 dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
    185 {
    186   if (cudie == NULL)
    187     return -1;
    188 
    189   struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie };
    190   struct args a = { .pc = pc };
    191 
    192   int result = __libdw_visit_scopes (0, &cu, NULL, &pc_match, &pc_record, &a);
    193 
    194   if (result == 0 && a.scopes != NULL)
    195     result = __libdw_visit_scopes (0, &cu, NULL, &origin_match, NULL, &a);
    196 
    197   if (result > 0)
    198     *scopes = a.scopes;
    199 
    200   return result;
    201 }
    202