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
50 14 : array_size (Dwarf_Die *die, Dwarf_Word *size,
51 : Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem)
52 : {
53 : Dwarf_Word eltsize;
54 14 : if (INTUSE(dwarf_aggregate_size) (get_type (die, attr_mem, type_mem),
55 : &eltsize) != 0)
56 : return -1;
57 :
58 : /* An array can have DW_TAG_subrange_type or DW_TAG_enumeration_type
59 : children instead that give the size of each dimension. */
60 :
61 : Dwarf_Die child;
62 14 : if (INTUSE(dwarf_child) (die, &child) != 0)
63 : return -1;
64 :
65 : bool any = false;
66 : Dwarf_Word count_total = 1;
67 : do
68 : {
69 : Dwarf_Word count;
70 16 : switch (INTUSE(dwarf_tag) (&child))
71 : {
72 16 : case DW_TAG_subrange_type:
73 : /* This has either DW_AT_count or DW_AT_upper_bound. */
74 16 : if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_count,
75 : attr_mem) != NULL)
76 : {
77 0 : if (INTUSE(dwarf_formudata) (attr_mem, &count) != 0)
78 0 : return -1;
79 : }
80 : else
81 16 : {
82 : Dwarf_Sword upper;
83 : Dwarf_Sword lower;
84 16 : if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr_integrate)
85 : (&child, DW_AT_upper_bound,
86 : attr_mem), &upper) != 0)
87 0 : return -1;
88 :
89 : /* Having DW_AT_lower_bound is optional. */
90 16 : if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_lower_bound,
91 : attr_mem) != NULL)
92 : {
93 1 : if (INTUSE(dwarf_formsdata) (attr_mem, &lower) != 0)
94 : return -1;
95 : }
96 : else
97 : {
98 30 : Dwarf_Die cu = CUDIE (die->cu);
99 15 : int lang = INTUSE(dwarf_srclang) (&cu);
100 15 : if (lang == -1
101 15 : || INTUSE(dwarf_default_lower_bound) (lang, &lower) != 0)
102 0 : return -1;
103 : }
104 16 : if (unlikely (lower > upper))
105 : return -1;
106 16 : count = upper - lower + 1;
107 : }
108 16 : break;
109 :
110 0 : case DW_TAG_enumeration_type:
111 : /* We have to find the DW_TAG_enumerator child with the
112 : highest value to know the array's element count. */
113 0 : count = 0;
114 : Dwarf_Die enum_child;
115 0 : int has_children = INTUSE(dwarf_child) (die, &enum_child);
116 0 : if (has_children < 0)
117 : return -1;
118 0 : if (has_children > 0)
119 : do
120 0 : if (INTUSE(dwarf_tag) (&enum_child) == DW_TAG_enumerator)
121 : {
122 : Dwarf_Word value;
123 0 : if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
124 : (&enum_child, DW_AT_const_value,
125 : attr_mem), &value) != 0)
126 0 : return -1;
127 0 : if (value >= count)
128 0 : count = value + 1;
129 : }
130 0 : while (INTUSE(dwarf_siblingof) (&enum_child, &enum_child) > 0);
131 : break;
132 :
133 0 : default:
134 0 : continue;
135 : }
136 :
137 16 : count_total *= count;
138 :
139 16 : any = true;
140 : }
141 16 : while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
142 :
143 14 : if (!any)
144 : return -1;
145 :
146 : /* This is a subrange_type or enumeration_type and we've set COUNT.
147 : Now determine the stride for this array. */
148 14 : Dwarf_Word stride = eltsize;
149 14 : if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_stride,
150 : attr_mem) != NULL)
151 : {
152 0 : if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
153 : return -1;
154 : }
155 14 : else if (INTUSE(dwarf_attr_integrate) (die, DW_AT_bit_stride,
156 : attr_mem) != NULL)
157 : {
158 0 : if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
159 : return -1;
160 0 : if (stride % 8) /* XXX maybe compute in bits? */
161 : return -1;
162 0 : stride /= 8;
163 : }
164 :
165 14 : *size = count_total * stride;
166 14 : return 0;
167 : }
168 :
169 : static int
170 45 : aggregate_size (Dwarf_Die *die, Dwarf_Word *size, Dwarf_Die *type_mem)
171 : {
172 : Dwarf_Attribute attr_mem;
173 :
174 45 : if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_size, &attr_mem) != NULL)
175 29 : return INTUSE(dwarf_formudata) (&attr_mem, size);
176 :
177 16 : switch (INTUSE(dwarf_tag) (die))
178 : {
179 0 : case DW_TAG_subrange_type:
180 0 : return aggregate_size (get_type (die, &attr_mem, type_mem),
181 : size, type_mem); /* Tail call. */
182 :
183 14 : case DW_TAG_array_type:
184 14 : return array_size (die, size, &attr_mem, type_mem);
185 :
186 : /* Assume references and pointers have pointer size if not given an
187 : explicit DW_AT_byte_size. */
188 2 : case DW_TAG_pointer_type:
189 : case DW_TAG_reference_type:
190 : case DW_TAG_rvalue_reference_type:
191 2 : *size = die->cu->address_size;
192 2 : return 0;
193 : }
194 :
195 : /* Most types must give their size directly. */
196 : return -1;
197 : }
198 :
199 : int
200 45 : dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size)
201 : {
202 : Dwarf_Die die_mem, type_mem;
203 :
204 45 : if (INTUSE (dwarf_peel_type) (die, &die_mem) != 0)
205 : return -1;
206 :
207 45 : return aggregate_size (&die_mem, size, &type_mem);
208 : }
209 : INTDEF (dwarf_aggregate_size)
210 : OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144)
211 : NEW_VERSION (dwarf_aggregate_size, ELFUTILS_0.161)
|