Line data Source code
1 : /* Compute size of an aggregate type from DWARF.
2 : Copyright (C) 2010, 2014, 2016 Red Hat, Inc.
3 : This file is part of elfutils.
4 :
5 : This file is free software; you can redistribute it and/or modify
6 : it under the terms of either
7 :
8 : * the GNU Lesser General Public License as published by the Free
9 : Software Foundation; either version 3 of the License, or (at
10 : your option) any later version
11 :
12 : or
13 :
14 : * the GNU General Public License as published by the Free
15 : Software Foundation; either version 2 of the License, or (at
16 : your option) any later version
17 :
18 : or both in parallel, as here.
19 :
20 : elfutils is distributed in the hope that it will be useful, but
21 : WITHOUT ANY WARRANTY; without even the implied warranty of
22 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : General Public License for more details.
24 :
25 : You should have received copies of the GNU General Public License and
26 : the GNU Lesser General Public License along with this program. If
27 : not, see <http://www.gnu.org/licenses/>. */
28 :
29 : #ifdef HAVE_CONFIG_H
30 : # include <config.h>
31 : #endif
32 :
33 : #include <dwarf.h>
34 : #include "libdwP.h"
35 :
36 :
37 : static Dwarf_Die *
38 14 : get_type (Dwarf_Die *die, Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem)
39 : {
40 14 : Dwarf_Die *type = INTUSE(dwarf_formref_die)
41 : (INTUSE(dwarf_attr_integrate) (die, DW_AT_type, attr_mem), type_mem);
42 :
43 14 : if (INTUSE(dwarf_peel_type) (type, type) != 0)
44 : return NULL;
45 :
46 14 : return type;
47 : }
48 :
49 : static int aggregate_size (Dwarf_Die *die, Dwarf_Word *size,
50 : Dwarf_Die *type_mem, int depth);
51 :
52 : static int
53 14 : array_size (Dwarf_Die *die, Dwarf_Word *size,
54 : Dwarf_Attribute *attr_mem, int depth)
55 : {
56 : Dwarf_Word eltsize;
57 : Dwarf_Die type_mem, aggregate_type_mem;
58 14 : if (aggregate_size (get_type (die, attr_mem, &type_mem), &eltsize,
59 : &aggregate_type_mem, depth) != 0)
60 : return -1;
61 :
62 : /* An array can have DW_TAG_subrange_type or DW_TAG_enumeration_type
63 : children instead that give the size of each dimension. */
64 :
65 : Dwarf_Die child;
66 14 : if (INTUSE(dwarf_child) (die, &child) != 0)
67 : return -1;
68 :
69 : bool any = false;
70 : Dwarf_Word count_total = 1;
71 : do
72 : {
73 : Dwarf_Word count;
74 16 : switch (INTUSE(dwarf_tag) (&child))
75 : {
76 16 : case DW_TAG_subrange_type:
77 : /* This has either DW_AT_count or DW_AT_upper_bound. */
78 16 : if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_count,
79 : attr_mem) != NULL)
80 : {
81 0 : if (INTUSE(dwarf_formudata) (attr_mem, &count) != 0)
82 0 : return -1;
83 : }
84 : else
85 16 : {
86 : Dwarf_Sword upper;
87 : Dwarf_Sword lower;
88 16 : if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr_integrate)
89 : (&child, DW_AT_upper_bound,
90 : attr_mem), &upper) != 0)
91 0 : return -1;
92 :
93 : /* Having DW_AT_lower_bound is optional. */
94 16 : if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_lower_bound,
95 : attr_mem) != NULL)
96 : {
97 1 : if (INTUSE(dwarf_formsdata) (attr_mem, &lower) != 0)
98 : return -1;
99 : }
100 : else
101 : {
102 30 : Dwarf_Die cu = CUDIE (die->cu);
103 15 : int lang = INTUSE(dwarf_srclang) (&cu);
104 15 : if (lang == -1
105 15 : || INTUSE(dwarf_default_lower_bound) (lang, &lower) != 0)
106 0 : return -1;
107 : }
108 16 : if (unlikely (lower > upper))
109 : return -1;
110 16 : count = upper - lower + 1;
111 : }
112 16 : break;
113 :
114 0 : case DW_TAG_enumeration_type:
115 : /* We have to find the DW_TAG_enumerator child with the
116 : highest value to know the array's element count. */
117 0 : count = 0;
118 : Dwarf_Die enum_child;
119 0 : int has_children = INTUSE(dwarf_child) (die, &enum_child);
120 0 : if (has_children < 0)
121 : return -1;
122 0 : if (has_children > 0)
123 : do
124 0 : if (INTUSE(dwarf_tag) (&enum_child) == DW_TAG_enumerator)
125 : {
126 : Dwarf_Word value;
127 0 : if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
128 : (&enum_child, DW_AT_const_value,
129 : attr_mem), &value) != 0)
130 0 : return -1;
131 0 : if (value >= count)
132 0 : count = value + 1;
133 : }
134 0 : while (INTUSE(dwarf_siblingof) (&enum_child, &enum_child) > 0);
135 : break;
136 :
137 0 : default:
138 0 : continue;
139 : }
140 :
141 16 : count_total *= count;
142 :
143 16 : any = true;
144 : }
145 16 : while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
146 :
147 14 : if (!any)
148 : return -1;
149 :
150 : /* This is a subrange_type or enumeration_type and we've set COUNT.
151 : Now determine the stride for this array. */
152 14 : Dwarf_Word stride = eltsize;
153 14 : if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_stride,
154 : attr_mem) != NULL)
155 : {
156 0 : if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
157 : return -1;
158 : }
159 14 : else if (INTUSE(dwarf_attr_integrate) (die, DW_AT_bit_stride,
160 : attr_mem) != NULL)
161 : {
162 0 : if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
163 : return -1;
164 0 : if (stride % 8) /* XXX maybe compute in bits? */
165 : return -1;
166 0 : stride /= 8;
167 : }
168 :
169 14 : *size = count_total * stride;
170 14 : return 0;
171 : }
172 :
173 : static int
174 225 : aggregate_size (Dwarf_Die *die, Dwarf_Word *size,
175 : Dwarf_Die *type_mem, int depth)
176 : {
177 : Dwarf_Attribute attr_mem;
178 :
179 : /* Arrays of arrays of subrange types of arrays... Don't recurse too deep. */
180 : #define MAX_DEPTH 256
181 225 : if (die == NULL || depth++ >= MAX_DEPTH)
182 : return -1;
183 :
184 225 : if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_size, &attr_mem) != NULL)
185 209 : return INTUSE(dwarf_formudata) (&attr_mem, size);
186 :
187 16 : switch (INTUSE(dwarf_tag) (die))
188 : {
189 0 : case DW_TAG_subrange_type:
190 : {
191 : Dwarf_Die aggregate_type_mem;
192 0 : return aggregate_size (get_type (die, &attr_mem, type_mem),
193 : size, &aggregate_type_mem, depth);
194 : }
195 :
196 14 : case DW_TAG_array_type:
197 14 : return array_size (die, size, &attr_mem, depth);
198 :
199 : /* Assume references and pointers have pointer size if not given an
200 : explicit DW_AT_byte_size. */
201 2 : case DW_TAG_pointer_type:
202 : case DW_TAG_reference_type:
203 : case DW_TAG_rvalue_reference_type:
204 2 : *size = die->cu->address_size;
205 2 : return 0;
206 : }
207 :
208 : /* Most types must give their size directly. */
209 : return -1;
210 : }
211 :
212 : int
213 211 : dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size)
214 : {
215 : Dwarf_Die die_mem, type_mem;
216 :
217 211 : if (INTUSE (dwarf_peel_type) (die, &die_mem) != 0)
218 : return -1;
219 :
220 211 : return aggregate_size (&die_mem, size, &type_mem, 0);
221 : }
222 : INTDEF (dwarf_aggregate_size)
223 : OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144)
224 : NEW_VERSION (dwarf_aggregate_size, ELFUTILS_0.161)
|