LCOV - code coverage report
Current view: top level - libdw - libdw_visit_scopes.c (source / functions) Hit Total Coverage
Test: elfutils-0.175 Lines: 37 42 88.1 %
Date: 2018-11-16 13:02:39 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Helper functions to descend DWARF scope trees.
       2             :    Copyright (C) 2005,2006,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 "libdwP.h"
      34             : #include <dwarf.h>
      35             : 
      36             : 
      37             : static bool
      38    19486782 : may_have_scopes (Dwarf_Die *die)
      39             : {
      40    19486782 :   switch (INTUSE(dwarf_tag) (die))
      41             :     {
      42             :       /* DIEs with addresses we can try to match.  */
      43             :     case DW_TAG_compile_unit:
      44             :     case DW_TAG_module:
      45             :     case DW_TAG_lexical_block:
      46             :     case DW_TAG_with_stmt:
      47             :     case DW_TAG_catch_block:
      48             :     case DW_TAG_try_block:
      49             :     case DW_TAG_entry_point:
      50             :     case DW_TAG_inlined_subroutine:
      51             :     case DW_TAG_subprogram:
      52             :       return true;
      53             : 
      54             :       /* DIEs without addresses that can own DIEs with addresses.  */
      55             :     case DW_TAG_namespace:
      56             :     case DW_TAG_class_type:
      57             :     case DW_TAG_structure_type:
      58             :       return true;
      59             : 
      60             :       /* Other DIEs we have no reason to descend.  */
      61             :     default:
      62             :       break;
      63             :     }
      64    15279809 :   return false;
      65             : }
      66             : 
      67             : struct walk_children_state
      68             : {
      69             :   /* Parameters of __libdw_visit_scopes. */
      70             :   unsigned int depth;
      71             :   struct Dwarf_Die_Chain *imports;
      72             :   int (*previsit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
      73             :   int (*postvisit) (unsigned int depth, struct Dwarf_Die_Chain *, void *);
      74             :   void *arg;
      75             :   /* Extra local variables for the walker. */
      76             :   struct Dwarf_Die_Chain child;
      77             : };
      78             : 
      79             : static inline int
      80             : walk_children (struct walk_children_state *state);
      81             : 
      82             : int
      83             : internal_function
      84     4112378 : __libdw_visit_scopes (unsigned int depth, struct Dwarf_Die_Chain *root,
      85             :                       struct Dwarf_Die_Chain *imports,
      86             :                       int (*previsit) (unsigned int,
      87             :                                        struct Dwarf_Die_Chain *,
      88             :                                        void *),
      89             :                       int (*postvisit) (unsigned int,
      90             :                                         struct Dwarf_Die_Chain *,
      91             :                                         void *),
      92             :                       void *arg)
      93             : {
      94     4112378 :   struct walk_children_state state =
      95             :     {
      96             :       .depth = depth,
      97             :       .imports = imports,
      98             :       .previsit = previsit,
      99             :       .postvisit = postvisit,
     100             :       .arg = arg
     101             :     };
     102             : 
     103     4112378 :   state.child.parent = root;
     104             :   int ret;
     105     4112378 :   if ((ret = INTUSE(dwarf_child) (&root->die, &state.child.die)) != 0)
     106         582 :     return ret < 0 ? -1 : 0; // Having zero children is legal.
     107             : 
     108     4111796 :   return walk_children (&state);
     109             : }
     110             : 
     111             : static inline int
     112     4111812 : walk_children (struct walk_children_state *state)
     113             : {
     114             :   int ret;
     115             :   do
     116             :     {
     117             :       /* For an imported unit, it is logically as if the children of
     118             :          that unit are siblings of the other children.  So don't do
     119             :          a full recursion into the imported unit, but just walk the
     120             :          children in place before moving to the next real child.  */
     121    42063502 :       while (INTUSE(dwarf_tag) (&state->child.die) == DW_TAG_imported_unit)
     122             :         {
     123          16 :           Dwarf_Die orig_child_die = state->child.die;
     124             :           Dwarf_Attribute attr_mem;
     125          16 :           Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&state->child.die,
     126             :                                                       DW_AT_import,
     127             :                                                       &attr_mem);
     128          16 :           if (INTUSE(dwarf_formref_die) (attr, &state->child.die) != NULL
     129          16 :               && INTUSE(dwarf_child) (&state->child.die, &state->child.die) == 0)
     130             :             {
     131             :               /* Checks the given DIE hasn't been imported yet
     132             :                  to prevent cycles.  */
     133          16 :               bool imported = false;
     134          32 :               for (struct Dwarf_Die_Chain *import = state->imports; import != NULL;
     135           0 :                 import = import->parent)
     136           0 :                 if (import->die.addr == orig_child_die.addr)
     137             :                   {
     138             :                     imported = true;
     139             :                     break;
     140             :                   }
     141          16 :               if (imported)
     142             :                 {
     143           0 :                   __libdw_seterrno (DWARF_E_INVALID_DWARF);
     144           0 :                   return -1;
     145             :                 }
     146          16 :               struct Dwarf_Die_Chain *orig_imports = state->imports;
     147          16 :               struct Dwarf_Die_Chain import = { .die = orig_child_die,
     148             :                                                 .parent = orig_imports };
     149          16 :               state->imports = &import;
     150          16 :               int result = walk_children (state);
     151          16 :               state->imports = orig_imports;
     152          16 :               if (result != DWARF_CB_OK)
     153             :                 return result;
     154             :             }
     155             : 
     156             :           /* Any "real" children left?  */
     157          12 :           if ((ret = INTUSE(dwarf_siblingof) (&orig_child_die,
     158             :                                               &state->child.die)) != 0)
     159           0 :             return ret < 0 ? -1 : 0;
     160             :         };
     161             : 
     162    21031741 :         state->child.prune = false;
     163             : 
     164             :         /* previsit is declared NN */
     165    21031741 :         int result = (*state->previsit) (state->depth + 1, &state->child, state->arg);
     166    21031741 :         if (result != DWARF_CB_OK)
     167             :           return result;
     168             : 
     169    21023141 :         if (!state->child.prune && may_have_scopes (&state->child.die)
     170     4206973 :             && INTUSE(dwarf_haschildren) (&state->child.die))
     171             :           {
     172     4095534 :             result = __libdw_visit_scopes (state->depth + 1, &state->child, state->imports,
     173             :                                            state->previsit, state->postvisit, state->arg);
     174     4095534 :             if (result != DWARF_CB_OK)
     175             :               return result;
     176             :           }
     177             : 
     178    20996327 :         if (state->postvisit != NULL)
     179             :           {
     180        1520 :             result = (*state->postvisit) (state->depth + 1, &state->child, state->arg);
     181        1520 :             if (result != DWARF_CB_OK)
     182             :               return result;
     183             :           }
     184             :     }
     185    20996224 :   while ((ret = INTUSE(dwarf_siblingof) (&state->child.die, &state->child.die)) == 0);
     186             : 
     187     4076291 :   return ret < 0 ? -1 : 0;
     188             : }

Generated by: LCOV version 1.13