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 : : Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
4 : : This file is part of elfutils.
5 : : Written by Ulrich Drepper <drepper@redhat.com>, 2003.
6 : :
7 : : This file is free software; you can redistribute it and/or modify
8 : : it under the terms of either
9 : :
10 : : * the GNU Lesser General Public License as published by the Free
11 : : Software Foundation; either version 3 of the License, or (at
12 : : your option) any later version
13 : :
14 : : or
15 : :
16 : : * the GNU General Public License as published by the Free
17 : : Software Foundation; either version 2 of the License, or (at
18 : : your option) any later version
19 : :
20 : : or both in parallel, as here.
21 : :
22 : : elfutils is distributed in the hope that it will be useful, but
23 : : WITHOUT ANY WARRANTY; without even the implied warranty of
24 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 : : General Public License for more details.
26 : :
27 : : You should have received copies of the GNU General Public License and
28 : : the GNU Lesser General Public License along with this program. If
29 : : not, see <http://www.gnu.org/licenses/>. */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : # include <config.h>
33 : : #endif
34 : :
35 : : #include <dwarf.h>
36 : : #include "libdwP.h"
37 : :
38 : :
39 : : Dwarf_Abbrev *
40 : : internal_function
41 : 2766786 : __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
42 : : size_t *lengthp)
43 : : {
44 : : /* Don't fail if there is not .debug_abbrev section. */
45 [ - + ]: 2766786 : if (dbg->sectiondata[IDX_debug_abbrev] == NULL)
46 : : return NULL;
47 : :
48 [ - + ]: 2766786 : if (offset >= dbg->sectiondata[IDX_debug_abbrev]->d_size)
49 : : {
50 : 0 : __libdw_seterrno (DWARF_E_INVALID_OFFSET);
51 : 0 : return NULL;
52 : : }
53 : :
54 : 2766786 : const unsigned char *abbrevp
55 : 2766786 : = (unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + offset;
56 : :
57 [ + + ]: 2766786 : if (*abbrevp == '\0')
58 : : /* We are past the last entry. */
59 : : return DWARF_END_ABBREV;
60 : :
61 : : /* 7.5.3 Abbreviations Tables
62 : :
63 : : [...] Each declaration begins with an unsigned LEB128 number
64 : : representing the abbreviation code itself. [...] The
65 : : abbreviation code is followed by another unsigned LEB128
66 : : number that encodes the entry's tag. [...]
67 : :
68 : : [...] Following the tag encoding is a 1-byte value that
69 : : determines whether a debugging information entry using this
70 : : abbreviation has child entries or not. [...]
71 : :
72 : : [...] Finally, the child encoding is followed by a series of
73 : : attribute specifications. Each attribute specification
74 : : consists of two parts. The first part is an unsigned LEB128
75 : : number representing the attribute's name. The second part is
76 : : an unsigned LEB128 number representing the attribute's form. */
77 : 2763178 : const unsigned char *end = (dbg->sectiondata[IDX_debug_abbrev]->d_buf
78 : : + dbg->sectiondata[IDX_debug_abbrev]->d_size);
79 : 2763178 : const unsigned char *start_abbrevp = abbrevp;
80 : 2763178 : unsigned int code;
81 : : // We start off with abbrevp at offset, which is checked above.
82 : 2763178 : get_uleb128 (code, abbrevp, end);
83 : :
84 : : /* Check whether this code is already in the hash table. */
85 : 2763178 : bool foundit = false;
86 : 2763178 : Dwarf_Abbrev *abb = NULL;
87 [ + + ]: 2763178 : if (cu == NULL
88 [ + + ]: 2598944 : || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code)) == NULL)
89 [ + + ]: 2763166 : abb = libdw_typed_alloc (dbg, Dwarf_Abbrev);
90 : : else
91 : : {
92 : 12 : foundit = true;
93 : :
94 [ - + ]: 12 : if (unlikely (abb->offset != offset))
95 : : {
96 : : /* A duplicate abbrev code at a different offset,
97 : : that should never happen. */
98 : 0 : invalid:
99 [ # # ]: 0 : if (! foundit)
100 : 0 : libdw_typed_unalloc (dbg, Dwarf_Abbrev);
101 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
102 : 0 : return NULL;
103 : : }
104 : :
105 : : /* If the caller doesn't need the length we are done. */
106 [ - + ]: 12 : if (lengthp == NULL)
107 : 0 : goto out;
108 : : }
109 : :
110 : : /* If there is already a value in the hash table we are going to
111 : : overwrite its content. This must not be a problem, since the
112 : : content better be the same. */
113 : 2763178 : abb->code = code;
114 [ - + ]: 2763178 : if (abbrevp >= end)
115 : 0 : goto invalid;
116 : 2763178 : get_uleb128 (abb->tag, abbrevp, end);
117 [ - + ]: 2763178 : if (abbrevp + 1 >= end)
118 : 0 : goto invalid;
119 : 2763178 : abb->has_children = *abbrevp++ == DW_CHILDREN_yes;
120 : 2763178 : abb->attrp = (unsigned char *) abbrevp;
121 : 2763178 : abb->offset = offset;
122 : :
123 : : /* Skip over all the attributes and check rest of the abbrev is valid. */
124 : 15704740 : unsigned int attrname;
125 : 15704740 : unsigned int attrform;
126 : 15704740 : do
127 : : {
128 [ - + ]: 15704740 : if (abbrevp >= end)
129 : 0 : goto invalid;
130 : 15704740 : get_uleb128 (attrname, abbrevp, end);
131 [ - + ]: 15704740 : if (abbrevp >= end)
132 : 0 : goto invalid;
133 : 15704740 : get_uleb128 (attrform, abbrevp, end);
134 [ + + ]: 15704740 : if (attrform == DW_FORM_implicit_const)
135 : : {
136 : 1151174 : int64_t formval __attribute__((__unused__));
137 [ - + ]: 1151174 : if (abbrevp >= end)
138 : 0 : goto invalid;
139 : 1151174 : get_sleb128 (formval, abbrevp, end);
140 : : }
141 : : }
142 [ + + ]: 15704740 : while (attrname != 0 || attrform != 0);
143 : :
144 : : /* Return the length to the caller if she asked for it. */
145 [ + - ]: 2763178 : if (lengthp != NULL)
146 : 2763178 : *lengthp = abbrevp - start_abbrevp;
147 : :
148 : : /* Add the entry to the hash table. */
149 [ + + ]: 2763178 : if (cu != NULL && ! foundit)
150 [ + - ]: 2598932 : if (Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb) == -1)
151 : : {
152 : : /* The entry was already in the table, remove the one we just
153 : : created and get the one already inserted. */
154 : 0 : libdw_typed_unalloc (dbg, Dwarf_Abbrev);
155 : 0 : abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code);
156 : : }
157 : :
158 : 2763178 : out:
159 : : return abb;
160 : : }
161 : :
162 : :
163 : : Dwarf_Abbrev *
164 : 2572 : dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, size_t *lengthp)
165 : : {
166 [ + - + + ]: 2572 : if (die == NULL || die->cu == NULL)
167 : : return NULL;
168 : :
169 : 150 : Dwarf_CU *cu = die->cu;
170 : 150 : Dwarf *dbg = cu->dbg;
171 : 150 : Dwarf_Off abbrev_offset = cu->orig_abbrev_offset;
172 : 150 : Elf_Data *data = dbg->sectiondata[IDX_debug_abbrev];
173 [ - + ]: 150 : if (data == NULL)
174 : : return NULL;
175 : :
176 [ + + ]: 150 : if (offset >= data->d_size - abbrev_offset)
177 : : {
178 : 12 : __libdw_seterrno (DWARF_E_INVALID_OFFSET);
179 : 12 : return NULL;
180 : : }
181 : :
182 : 138 : return __libdw_getabbrev (dbg, cu, abbrev_offset + offset, lengthp);
183 : : }
|