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