Branch data Line data Source code
1 : : /* Compute size of an aggregate type from DWARF.
2 : : Copyright (C) 2010, 2014, 2016 Red Hat, Inc.
3 : : Copyright (C) 2025, Mark J. Wielaard <mark@klomp.org>
4 : : This file is part of elfutils.
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 : : static Dwarf_Die *
39 : 908 : get_type (Dwarf_Die *die, Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem)
40 : : {
41 : 908 : Dwarf_Die *type = INTUSE(dwarf_formref_die)
42 : : (INTUSE(dwarf_attr_integrate) (die, DW_AT_type, attr_mem), type_mem);
43 : :
44 [ + + - + ]: 908 : if (type == NULL || INTUSE(dwarf_peel_type) (type, type) != 0)
45 : 394 : return NULL;
46 : :
47 : : return type;
48 : : }
49 : :
50 : : static int aggregate_size (Dwarf_Die *die, Dwarf_Word *size,
51 : : Dwarf_Die *type_mem, int depth);
52 : :
53 : : static int
54 : 452 : array_size (Dwarf_Die *die, Dwarf_Word *size,
55 : : Dwarf_Attribute *attr_mem, int depth)
56 : : {
57 : 452 : Dwarf_Word eltsize;
58 : 452 : Dwarf_Die type_mem, aggregate_type_mem;
59 [ - + ]: 452 : if (aggregate_size (get_type (die, attr_mem, &type_mem), &eltsize,
60 : : &aggregate_type_mem, depth) != 0)
61 : : return -1;
62 : :
63 : : /* An array can have DW_TAG_subrange_type or DW_TAG_enumeration_type
64 : : children instead that give the size of each dimension. */
65 : :
66 : 452 : Dwarf_Die child;
67 [ - + ]: 452 : if (INTUSE(dwarf_child) (die, &child) != 0)
68 : : return -1;
69 : :
70 : : bool any = false;
71 : : Dwarf_Word count_total = 1;
72 : 456 : do
73 : : {
74 : 456 : Dwarf_Word count;
75 [ + - - ]: 456 : switch (INTUSE(dwarf_tag) (&child))
76 : 0 : {
77 : 456 : case DW_TAG_subrange_type:
78 : : /* This has either DW_AT_count or DW_AT_upper_bound. */
79 [ - + ]: 456 : if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_count,
80 : : attr_mem) != NULL)
81 : : {
82 [ # # ]: 0 : if (INTUSE(dwarf_formudata) (attr_mem, &count) != 0)
83 : 0 : return -1;
84 : : }
85 : : else
86 : : {
87 : 456 : bool is_signed = true;
88 [ + + ]: 456 : if (INTUSE(dwarf_attr) (get_type (&child, attr_mem, &type_mem),
89 : : DW_AT_encoding, attr_mem) != NULL)
90 : : {
91 : 62 : Dwarf_Word encoding;
92 [ - + ]: 62 : if (INTUSE(dwarf_formudata) (attr_mem, &encoding) == 0)
93 : 62 : is_signed = (encoding == DW_ATE_signed
94 : 62 : || encoding == DW_ATE_signed_char);
95 : : }
96 : :
97 : 62 : Dwarf_Sword upper;
98 : 62 : Dwarf_Sword lower;
99 [ + + ]: 62 : if (is_signed)
100 : : {
101 [ + - ]: 402 : if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr_integrate)
102 : : (&child, DW_AT_upper_bound,
103 : : attr_mem), &upper) != 0)
104 : 0 : return -1;
105 : : }
106 : : else
107 : : {
108 : 54 : Dwarf_Word unsigned_upper;
109 [ - + ]: 54 : if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
110 : : (&child, DW_AT_upper_bound,
111 : : attr_mem), &unsigned_upper) != 0)
112 : 0 : return -1;
113 : 54 : upper = unsigned_upper;
114 : : }
115 : :
116 : : /* Having DW_AT_lower_bound is optional. */
117 [ + + ]: 456 : if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_lower_bound,
118 : : attr_mem) != NULL)
119 : : {
120 [ + - ]: 2 : if (is_signed)
121 : : {
122 [ + - ]: 2 : if (INTUSE(dwarf_formsdata) (attr_mem, &lower) != 0)
123 : : return -1;
124 : : }
125 : : else
126 : : {
127 : 0 : Dwarf_Word unsigned_lower;
128 [ # # ]: 0 : if (INTUSE(dwarf_formudata) (attr_mem, &unsigned_lower) != 0)
129 : 0 : return -1;
130 : 0 : lower = unsigned_lower;
131 : : }
132 : : }
133 : : else
134 : : {
135 : 454 : Dwarf_Word lang;
136 : 454 : Dwarf_Die cu = CUDIE (die->cu);
137 : 454 : int res = INTUSE(dwarf_language) (&cu, &lang, NULL);
138 [ + - ]: 454 : if (res < 0
139 [ - + ]: 454 : || INTUSE(dwarf_language_lower_bound) (lang, &lower) != 0)
140 : 0 : return -1;
141 : : }
142 [ + - ]: 456 : if (unlikely (lower > upper))
143 : : return -1;
144 : 456 : count = upper - lower + 1;
145 : : }
146 : 456 : break;
147 : :
148 : 0 : case DW_TAG_enumeration_type:
149 : : /* We have to find the DW_TAG_enumerator child with the
150 : : highest value to know the array's element count. */
151 : 0 : count = 0;
152 : 0 : Dwarf_Die enum_child;
153 : 0 : int has_children = INTUSE(dwarf_child) (die, &enum_child);
154 [ # # ]: 0 : if (has_children < 0)
155 : : return -1;
156 [ # # ]: 0 : if (has_children > 0)
157 : 0 : do
158 [ # # ]: 0 : if (INTUSE(dwarf_tag) (&enum_child) == DW_TAG_enumerator)
159 : : {
160 : 0 : Dwarf_Word value;
161 [ # # ]: 0 : if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
162 : : (&enum_child, DW_AT_const_value,
163 : : attr_mem), &value) != 0)
164 : 0 : return -1;
165 [ # # ]: 0 : if (value >= count)
166 : 0 : count = value + 1;
167 : : }
168 [ # # ]: 0 : while (INTUSE(dwarf_siblingof) (&enum_child, &enum_child) > 0);
169 : : break;
170 : :
171 : 0 : default:
172 : 0 : continue;
173 : : }
174 : :
175 : 456 : count_total *= count;
176 : :
177 : 456 : any = true;
178 : : }
179 [ + + ]: 456 : while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
180 : :
181 [ - + ]: 452 : if (!any)
182 : : return -1;
183 : :
184 : : /* This is a subrange_type or enumeration_type and we've set COUNT.
185 : : Now determine the stride for this array. */
186 : 452 : Dwarf_Word stride = eltsize;
187 [ - + ]: 452 : if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_stride,
188 : : attr_mem) != NULL)
189 : : {
190 [ # # ]: 0 : if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
191 : : return -1;
192 : : }
193 [ - + ]: 452 : else if (INTUSE(dwarf_attr_integrate) (die, DW_AT_bit_stride,
194 : : attr_mem) != NULL)
195 : : {
196 [ # # ]: 0 : if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
197 : : return -1;
198 [ # # ]: 0 : if (stride % 8) /* XXX maybe compute in bits? */
199 : : return -1;
200 : 0 : stride /= 8;
201 : : }
202 : :
203 : 452 : *size = count_total * stride;
204 : 452 : return 0;
205 : : }
206 : :
207 : : static int
208 : 1998 : aggregate_size (Dwarf_Die *die, Dwarf_Word *size,
209 : : Dwarf_Die *type_mem, int depth)
210 : : {
211 : 1998 : Dwarf_Attribute attr_mem;
212 : :
213 : : /* Arrays of arrays of subrange types of arrays... Don't recurse too deep. */
214 : : #define MAX_DEPTH 256
215 [ + - - + ]: 1998 : if (die == NULL || depth++ >= MAX_DEPTH)
216 : : return -1;
217 : :
218 [ + + ]: 1998 : if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_size, &attr_mem) != NULL)
219 : 1542 : return INTUSE(dwarf_formudata) (&attr_mem, size);
220 : :
221 [ - - + + ]: 456 : switch (INTUSE(dwarf_tag) (die))
222 : : {
223 : 0 : case DW_TAG_subrange_type:
224 : : {
225 : 0 : Dwarf_Die aggregate_type_mem;
226 : 0 : return aggregate_size (get_type (die, &attr_mem, type_mem),
227 : : size, &aggregate_type_mem, depth);
228 : : }
229 : :
230 : 452 : case DW_TAG_array_type:
231 : 452 : return array_size (die, size, &attr_mem, depth);
232 : :
233 : : /* Assume references and pointers have pointer size if not given an
234 : : explicit DW_AT_byte_size. */
235 : 4 : case DW_TAG_pointer_type:
236 : : case DW_TAG_reference_type:
237 : : case DW_TAG_rvalue_reference_type:
238 : 4 : *size = die->cu->address_size;
239 : 4 : return 0;
240 : : }
241 : :
242 : : /* Most types must give their size directly. */
243 : : return -1;
244 : : }
245 : :
246 : : NEW_VERSION (dwarf_aggregate_size, ELFUTILS_0.161)
247 : : int
248 : 1546 : dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size)
249 : : {
250 : 1546 : Dwarf_Die die_mem, type_mem;
251 : :
252 [ + - ]: 1546 : if (INTUSE (dwarf_peel_type) (die, &die_mem) != 0)
253 : : return -1;
254 : :
255 : 1546 : return aggregate_size (&die_mem, size, &type_mem, 0);
256 : : }
257 : : NEW_INTDEF (dwarf_aggregate_size)
258 : : OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144)
|