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