xref: /aosp_15_r20/external/elfutils/libdw/dwarf_getattrs.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Get attributes of the DIE.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2004, 2005, 2008, 2009, 2014, 2017 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker    Written by Ulrich Drepper <[email protected]>, 2004.
5*7304104dSAndroid Build Coastguard Worker 
6*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker    it under the terms of either
8*7304104dSAndroid Build Coastguard Worker 
9*7304104dSAndroid Build Coastguard Worker      * the GNU Lesser General Public License as published by the Free
10*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 3 of the License, or (at
11*7304104dSAndroid Build Coastguard Worker        your option) any later version
12*7304104dSAndroid Build Coastguard Worker 
13*7304104dSAndroid Build Coastguard Worker    or
14*7304104dSAndroid Build Coastguard Worker 
15*7304104dSAndroid Build Coastguard Worker      * the GNU General Public License as published by the Free
16*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 2 of the License, or (at
17*7304104dSAndroid Build Coastguard Worker        your option) any later version
18*7304104dSAndroid Build Coastguard Worker 
19*7304104dSAndroid Build Coastguard Worker    or both in parallel, as here.
20*7304104dSAndroid Build Coastguard Worker 
21*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
22*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
23*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24*7304104dSAndroid Build Coastguard Worker    General Public License for more details.
25*7304104dSAndroid Build Coastguard Worker 
26*7304104dSAndroid Build Coastguard Worker    You should have received copies of the GNU General Public License and
27*7304104dSAndroid Build Coastguard Worker    the GNU Lesser General Public License along with this program.  If
28*7304104dSAndroid Build Coastguard Worker    not, see <http://www.gnu.org/licenses/>.  */
29*7304104dSAndroid Build Coastguard Worker 
30*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
31*7304104dSAndroid Build Coastguard Worker # include <config.h>
32*7304104dSAndroid Build Coastguard Worker #endif
33*7304104dSAndroid Build Coastguard Worker 
34*7304104dSAndroid Build Coastguard Worker #include "libdwP.h"
35*7304104dSAndroid Build Coastguard Worker 
36*7304104dSAndroid Build Coastguard Worker 
37*7304104dSAndroid Build Coastguard Worker ptrdiff_t
dwarf_getattrs(Dwarf_Die * die,int (* callback)(Dwarf_Attribute *,void *),void * arg,ptrdiff_t offset)38*7304104dSAndroid Build Coastguard Worker dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
39*7304104dSAndroid Build Coastguard Worker 		void *arg, ptrdiff_t offset)
40*7304104dSAndroid Build Coastguard Worker {
41*7304104dSAndroid Build Coastguard Worker   if (die == NULL)
42*7304104dSAndroid Build Coastguard Worker     return -1l;
43*7304104dSAndroid Build Coastguard Worker 
44*7304104dSAndroid Build Coastguard Worker   if (unlikely (offset == 1))
45*7304104dSAndroid Build Coastguard Worker     return 1;
46*7304104dSAndroid Build Coastguard Worker 
47*7304104dSAndroid Build Coastguard Worker   const unsigned char *die_addr = NULL;
48*7304104dSAndroid Build Coastguard Worker 
49*7304104dSAndroid Build Coastguard Worker   /* Find the abbreviation entry.  */
50*7304104dSAndroid Build Coastguard Worker   Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, &die_addr);
51*7304104dSAndroid Build Coastguard Worker 
52*7304104dSAndroid Build Coastguard Worker   if (unlikely (abbrevp == DWARF_END_ABBREV))
53*7304104dSAndroid Build Coastguard Worker     {
54*7304104dSAndroid Build Coastguard Worker       __libdw_seterrno (DWARF_E_INVALID_DWARF);
55*7304104dSAndroid Build Coastguard Worker       return -1l;
56*7304104dSAndroid Build Coastguard Worker     }
57*7304104dSAndroid Build Coastguard Worker 
58*7304104dSAndroid Build Coastguard Worker   const unsigned char *endp = die->cu->endp;
59*7304104dSAndroid Build Coastguard Worker 
60*7304104dSAndroid Build Coastguard Worker   /* This is where the attributes start.  */
61*7304104dSAndroid Build Coastguard Worker   const unsigned char *attrp = abbrevp->attrp;
62*7304104dSAndroid Build Coastguard Worker   const unsigned char *const offset_attrp = abbrevp->attrp + offset;
63*7304104dSAndroid Build Coastguard Worker 
64*7304104dSAndroid Build Coastguard Worker   /* Go over the list of attributes.  */
65*7304104dSAndroid Build Coastguard Worker   while (1)
66*7304104dSAndroid Build Coastguard Worker     {
67*7304104dSAndroid Build Coastguard Worker       /* Get attribute name and form.  Dwarf_Abbrev was checked when
68*7304104dSAndroid Build Coastguard Worker 	 created, so we can read unchecked.  */
69*7304104dSAndroid Build Coastguard Worker       Dwarf_Attribute attr;
70*7304104dSAndroid Build Coastguard Worker       const unsigned char *remembered_attrp = attrp;
71*7304104dSAndroid Build Coastguard Worker 
72*7304104dSAndroid Build Coastguard Worker       get_uleb128_unchecked (attr.code, attrp);
73*7304104dSAndroid Build Coastguard Worker       get_uleb128_unchecked (attr.form, attrp);
74*7304104dSAndroid Build Coastguard Worker 
75*7304104dSAndroid Build Coastguard Worker       /* We can stop if we found the attribute with value zero.  */
76*7304104dSAndroid Build Coastguard Worker       if (attr.code == 0 && attr.form == 0)
77*7304104dSAndroid Build Coastguard Worker 	/* Do not return 0 here - there would be no way to
78*7304104dSAndroid Build Coastguard Worker 	   distinguish this value from the attribute at offset 0.
79*7304104dSAndroid Build Coastguard Worker 	   Instead we return +1 which would never be a valid
80*7304104dSAndroid Build Coastguard Worker 	   offset of an attribute.  */
81*7304104dSAndroid Build Coastguard Worker         return 1l;
82*7304104dSAndroid Build Coastguard Worker 
83*7304104dSAndroid Build Coastguard Worker       if (attr.form == DW_FORM_indirect)
84*7304104dSAndroid Build Coastguard Worker 	{
85*7304104dSAndroid Build Coastguard Worker 	  get_uleb128 (attr.form, die_addr, endp);
86*7304104dSAndroid Build Coastguard Worker 	  if (attr.form == DW_FORM_indirect ||
87*7304104dSAndroid Build Coastguard Worker 	      attr.form == DW_FORM_implicit_const)
88*7304104dSAndroid Build Coastguard Worker 	    {
89*7304104dSAndroid Build Coastguard Worker 	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
90*7304104dSAndroid Build Coastguard Worker 	      return -1l;
91*7304104dSAndroid Build Coastguard Worker 	    }
92*7304104dSAndroid Build Coastguard Worker 	}
93*7304104dSAndroid Build Coastguard Worker 
94*7304104dSAndroid Build Coastguard Worker       /* If we are not to OFFSET_ATTRP yet, we just have to skip
95*7304104dSAndroid Build Coastguard Worker 	 the values of the intervening attributes.  */
96*7304104dSAndroid Build Coastguard Worker       if (remembered_attrp >= offset_attrp)
97*7304104dSAndroid Build Coastguard Worker 	{
98*7304104dSAndroid Build Coastguard Worker 	  /* Fill in the rest.  */
99*7304104dSAndroid Build Coastguard Worker 	  if (attr.form == DW_FORM_implicit_const)
100*7304104dSAndroid Build Coastguard Worker 	    attr.valp = (unsigned char *) attrp;
101*7304104dSAndroid Build Coastguard Worker 	  else
102*7304104dSAndroid Build Coastguard Worker 	    attr.valp = (unsigned char *) die_addr;
103*7304104dSAndroid Build Coastguard Worker 	  attr.cu = die->cu;
104*7304104dSAndroid Build Coastguard Worker 
105*7304104dSAndroid Build Coastguard Worker 	  /* Now call the callback function.  */
106*7304104dSAndroid Build Coastguard Worker 	  if (callback (&attr, arg) != DWARF_CB_OK)
107*7304104dSAndroid Build Coastguard Worker 	    /* Return the offset of the start of the attribute, so that
108*7304104dSAndroid Build Coastguard Worker 	       dwarf_getattrs() can be restarted from this point if the
109*7304104dSAndroid Build Coastguard Worker 	       caller so desires.  */
110*7304104dSAndroid Build Coastguard Worker 	    return remembered_attrp - abbrevp->attrp;
111*7304104dSAndroid Build Coastguard Worker 	}
112*7304104dSAndroid Build Coastguard Worker 
113*7304104dSAndroid Build Coastguard Worker       /* Skip over the rest of this attribute (if there is any).  */
114*7304104dSAndroid Build Coastguard Worker       if (attr.form != 0)
115*7304104dSAndroid Build Coastguard Worker 	{
116*7304104dSAndroid Build Coastguard Worker 	  size_t len = __libdw_form_val_len (die->cu, attr.form, die_addr);
117*7304104dSAndroid Build Coastguard Worker 	  if (unlikely (len == (size_t) -1l))
118*7304104dSAndroid Build Coastguard Worker 	    /* Something wrong with the file.  */
119*7304104dSAndroid Build Coastguard Worker 	    return -1l;
120*7304104dSAndroid Build Coastguard Worker 
121*7304104dSAndroid Build Coastguard Worker 	  // __libdw_form_val_len will have done a bounds check.
122*7304104dSAndroid Build Coastguard Worker 	  die_addr += len;
123*7304104dSAndroid Build Coastguard Worker 
124*7304104dSAndroid Build Coastguard Worker 	  if (attr.form == DW_FORM_implicit_const)
125*7304104dSAndroid Build Coastguard Worker 	    {
126*7304104dSAndroid Build Coastguard Worker 	      int64_t attr_value __attribute__((__unused__));
127*7304104dSAndroid Build Coastguard Worker 	      get_sleb128_unchecked (attr_value, attrp);
128*7304104dSAndroid Build Coastguard Worker 	    }
129*7304104dSAndroid Build Coastguard Worker 	}
130*7304104dSAndroid Build Coastguard Worker     }
131*7304104dSAndroid Build Coastguard Worker   /* NOTREACHED */
132*7304104dSAndroid Build Coastguard Worker }
133