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