Line data Source code
1 : /* Get abbreviation at given offset.
2 : Copyright (C) 2003, 2004, 2005, 2006, 2014, 2017 Red Hat, Inc.
3 : This file is part of elfutils.
4 : Written by Ulrich Drepper <drepper@redhat.com>, 2003.
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 <dwarf.h>
35 : #include "libdwP.h"
36 :
37 :
38 : Dwarf_Abbrev *
39 : internal_function
40 654747 : __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
41 : size_t *lengthp, Dwarf_Abbrev *result)
42 : {
43 : /* Don't fail if there is not .debug_abbrev section. */
44 654747 : if (dbg->sectiondata[IDX_debug_abbrev] == NULL)
45 : return NULL;
46 :
47 654747 : if (offset >= dbg->sectiondata[IDX_debug_abbrev]->d_size)
48 : {
49 0 : __libdw_seterrno (DWARF_E_INVALID_OFFSET);
50 0 : return NULL;
51 : }
52 :
53 654747 : const unsigned char *abbrevp
54 654747 : = (unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + offset;
55 :
56 654747 : if (*abbrevp == '\0')
57 : /* We are past the last entry. */
58 : return DWARF_END_ABBREV;
59 :
60 : /* 7.5.3 Abbreviations Tables
61 :
62 : [...] Each declaration begins with an unsigned LEB128 number
63 : representing the abbreviation code itself. [...] The
64 : abbreviation code is followed by another unsigned LEB128
65 : number that encodes the entry's tag. [...]
66 :
67 : [...] Following the tag encoding is a 1-byte value that
68 : determines whether a debugging information entry using this
69 : abbreviation has child entries or not. [...]
70 :
71 : [...] Finally, the child encoding is followed by a series of
72 : attribute specifications. Each attribute specification
73 : consists of two parts. The first part is an unsigned LEB128
74 : number representing the attribute's name. The second part is
75 : an unsigned LEB128 number representing the attribute's form. */
76 653671 : const unsigned char *end = (dbg->sectiondata[IDX_debug_abbrev]->d_buf
77 : + dbg->sectiondata[IDX_debug_abbrev]->d_size);
78 653671 : const unsigned char *start_abbrevp = abbrevp;
79 : unsigned int code;
80 653671 : get_uleb128 (code, abbrevp, end);
81 :
82 : /* Check whether this code is already in the hash table. */
83 653671 : bool foundit = false;
84 653671 : Dwarf_Abbrev *abb = NULL;
85 653671 : if (cu == NULL
86 597607 : || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL)) == NULL)
87 : {
88 653665 : if (result == NULL)
89 597601 : abb = libdw_typed_alloc (dbg, Dwarf_Abbrev);
90 : else
91 : abb = result;
92 : }
93 : else
94 : {
95 6 : foundit = true;
96 :
97 6 : if (unlikely (abb->offset != offset))
98 : {
99 : /* A duplicate abbrev code at a different offset,
100 : that should never happen. */
101 0 : invalid:
102 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
103 0 : return NULL;
104 : }
105 :
106 : /* If the caller doesn't need the length we are done. */
107 6 : if (lengthp == NULL)
108 : goto out;
109 : }
110 :
111 : /* If there is already a value in the hash table we are going to
112 : overwrite its content. This must not be a problem, since the
113 : content better be the same. */
114 653671 : abb->code = code;
115 653671 : if (abbrevp >= end)
116 : goto invalid;
117 653671 : get_uleb128 (abb->tag, abbrevp, end);
118 653671 : if (abbrevp + 1 >= end)
119 : goto invalid;
120 653671 : abb->has_children = *abbrevp++ == DW_CHILDREN_yes;
121 653671 : abb->attrp = (unsigned char *) abbrevp;
122 653671 : abb->offset = offset;
123 :
124 : /* Skip over all the attributes and check rest of the abbrev is valid. */
125 : unsigned int attrname;
126 : unsigned int attrform;
127 : do
128 : {
129 3217955 : if (abbrevp >= end)
130 : goto invalid;
131 3217955 : get_uleb128 (attrname, abbrevp, end);
132 3217955 : if (abbrevp >= end)
133 : goto invalid;
134 3217955 : get_uleb128 (attrform, abbrevp, end);
135 3217955 : if (attrform == DW_FORM_implicit_const)
136 : {
137 : int64_t formval __attribute__((__unused__));
138 225 : if (abbrevp >= end)
139 : goto invalid;
140 225 : get_sleb128 (formval, abbrevp, end);
141 : }
142 : }
143 3217955 : while (attrname != 0 && attrform != 0);
144 :
145 : /* Return the length to the caller if she asked for it. */
146 653671 : if (lengthp != NULL)
147 653671 : *lengthp = abbrevp - start_abbrevp;
148 :
149 : /* Add the entry to the hash table. */
150 653671 : if (cu != NULL && ! foundit)
151 597601 : (void) Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb);
152 :
153 56070 : out:
154 : return abb;
155 : }
156 :
157 :
158 : Dwarf_Abbrev *
159 948 : dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, size_t *lengthp)
160 : {
161 948 : if (die == NULL || die->cu == NULL)
162 : return NULL;
163 :
164 75 : Dwarf_CU *cu = die->cu;
165 75 : Dwarf *dbg = cu->dbg;
166 75 : Dwarf_Off abbrev_offset = cu->orig_abbrev_offset;
167 75 : Elf_Data *data = dbg->sectiondata[IDX_debug_abbrev];
168 75 : if (data == NULL)
169 : return NULL;
170 :
171 75 : if (offset >= data->d_size - abbrev_offset)
172 : {
173 6 : __libdw_seterrno (DWARF_E_INVALID_OFFSET);
174 6 : return NULL;
175 : }
176 :
177 69 : return __libdw_getabbrev (dbg, cu, abbrev_offset + offset, lengthp, NULL);
178 : }
|