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 830195 : __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 830195 : if (dbg->sectiondata[IDX_debug_abbrev] == NULL)
45 : return NULL;
46 :
47 830195 : 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 1660390 : const unsigned char *abbrevp
54 830195 : = (unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + offset;
55 :
56 830195 : 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 828520 : const unsigned char *end = (dbg->sectiondata[IDX_debug_abbrev]->d_buf
77 : + dbg->sectiondata[IDX_debug_abbrev]->d_size);
78 828520 : const unsigned char *start_abbrevp = abbrevp;
79 828520 : unsigned int code;
80 828520 : get_uleb128 (code, abbrevp, end);
81 :
82 : /* Check whether this code is already in the hash table. */
83 828520 : bool foundit = false;
84 828520 : Dwarf_Abbrev *abb = NULL;
85 828520 : if (cu == NULL
86 746973 : || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code)) == NULL)
87 : {
88 828514 : if (result == NULL)
89 746967 : 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 : if (! foundit)
103 0 : libdw_typed_unalloc (dbg, Dwarf_Abbrev);
104 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
105 0 : return NULL;
106 : }
107 :
108 : /* If the caller doesn't need the length we are done. */
109 6 : if (lengthp == NULL)
110 : goto out;
111 : }
112 :
113 : /* If there is already a value in the hash table we are going to
114 : overwrite its content. This must not be a problem, since the
115 : content better be the same. */
116 828520 : abb->code = code;
117 828520 : if (abbrevp >= end)
118 : goto invalid;
119 828520 : get_uleb128 (abb->tag, abbrevp, end);
120 828520 : if (abbrevp + 1 >= end)
121 : goto invalid;
122 828520 : abb->has_children = *abbrevp++ == DW_CHILDREN_yes;
123 828520 : abb->attrp = (unsigned char *) abbrevp;
124 828520 : abb->offset = offset;
125 :
126 : /* Skip over all the attributes and check rest of the abbrev is valid. */
127 4623786 : unsigned int attrname;
128 4623786 : unsigned int attrform;
129 4623786 : do
130 : {
131 4623786 : if (abbrevp >= end)
132 : goto invalid;
133 4623786 : get_uleb128 (attrname, abbrevp, end);
134 4623786 : if (abbrevp >= end)
135 : goto invalid;
136 4623786 : get_uleb128 (attrform, abbrevp, end);
137 4623786 : if (attrform == DW_FORM_implicit_const)
138 : {
139 221 : int64_t formval __attribute__((__unused__));
140 221 : if (abbrevp >= end)
141 : goto invalid;
142 221 : get_sleb128 (formval, abbrevp, end);
143 : }
144 : }
145 4623786 : while (attrname != 0 || attrform != 0);
146 :
147 : /* Return the length to the caller if she asked for it. */
148 828520 : if (lengthp != NULL)
149 828520 : *lengthp = abbrevp - start_abbrevp;
150 :
151 : /* Add the entry to the hash table. */
152 828520 : if (cu != NULL && ! foundit)
153 746967 : if (Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb) == -1)
154 : {
155 : /* The entry was already in the table, remove the one we just
156 : created and get the one already inserted. */
157 0 : libdw_typed_unalloc (dbg, Dwarf_Abbrev);
158 0 : abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code);
159 : }
160 :
161 828520 : out:
162 : return abb;
163 : }
164 :
165 :
166 : Dwarf_Abbrev *
167 1207 : dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, size_t *lengthp)
168 : {
169 1207 : if (die == NULL || die->cu == NULL)
170 : return NULL;
171 :
172 75 : Dwarf_CU *cu = die->cu;
173 75 : Dwarf *dbg = cu->dbg;
174 75 : Dwarf_Off abbrev_offset = cu->orig_abbrev_offset;
175 75 : Elf_Data *data = dbg->sectiondata[IDX_debug_abbrev];
176 75 : if (data == NULL)
177 : return NULL;
178 :
179 75 : if (offset >= data->d_size - abbrev_offset)
180 : {
181 6 : __libdw_seterrno (DWARF_E_INVALID_OFFSET);
182 6 : return NULL;
183 : }
184 :
185 69 : return __libdw_getabbrev (dbg, cu, abbrev_offset + offset, lengthp, NULL);
186 : }
|