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