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
37static Dwarf_Die *
38get_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
49static int aggregate_size (Dwarf_Die *die, Dwarf_Word *size,
50			   Dwarf_Die *type_mem, int depth);
51
52static int
53array_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
205static int
206aggregate_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
244NEW_VERSION (dwarf_aggregate_size, ELFUTILS_0.161)
245int
246dwarf_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}
255NEW_INTDEF (dwarf_aggregate_size)
256OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144)
257