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