1/* Compute size of an aggregate type from DWARF.
2   Copyright (C) 2010, 2014 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 (INTUSE(dwarf_peel_type) (type, type) != 0)
44    return NULL;
45
46  return type;
47}
48
49static int
50array_size (Dwarf_Die *die, Dwarf_Word *size,
51	    Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem)
52{
53  Dwarf_Word eltsize;
54  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  if (INTUSE(dwarf_child) (die, &child) != 0)
63    return -1;
64
65  bool any = false;
66  Dwarf_Word total = 0;
67  do
68    {
69      Dwarf_Word count;
70      switch (INTUSE(dwarf_tag) (&child))
71	{
72	case DW_TAG_subrange_type:
73	  /* This has either DW_AT_count or DW_AT_upper_bound.  */
74	  if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_count,
75					    attr_mem) != NULL)
76	    {
77	      if (INTUSE(dwarf_formudata) (attr_mem, &count) != 0)
78		return -1;
79	    }
80	  else
81	    {
82	      Dwarf_Sword upper;
83	      Dwarf_Sword lower;
84	      if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr_integrate)
85					   (&child, DW_AT_upper_bound,
86					    attr_mem), &upper) != 0)
87		return -1;
88
89	      /* Having DW_AT_lower_bound is optional.  */
90	      if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_lower_bound,
91						attr_mem) != NULL)
92		{
93		  if (INTUSE(dwarf_formsdata) (attr_mem, &lower) != 0)
94		    return -1;
95		}
96	      else
97		{
98		  /* Determine default lower bound from language,
99		     as per "4.12 Subrange Type Entries".  */
100		  Dwarf_Die cu = CUDIE (die->cu);
101		  switch (INTUSE(dwarf_srclang) (&cu))
102		    {
103		    case DW_LANG_C:
104		    case DW_LANG_C89:
105		    case DW_LANG_C99:
106		    case DW_LANG_C11:
107		    case DW_LANG_C_plus_plus:
108		    case DW_LANG_C_plus_plus_11:
109		    case DW_LANG_C_plus_plus_14:
110		    case DW_LANG_ObjC:
111		    case DW_LANG_ObjC_plus_plus:
112		    case DW_LANG_Java:
113		    case DW_LANG_D:
114		    case DW_LANG_UPC:
115		    case DW_LANG_Go:
116		      lower = 0;
117		      break;
118
119		    case DW_LANG_Ada83:
120		    case DW_LANG_Ada95:
121		    case DW_LANG_Cobol74:
122		    case DW_LANG_Cobol85:
123		    case DW_LANG_Fortran77:
124		    case DW_LANG_Fortran90:
125		    case DW_LANG_Fortran95:
126		    case DW_LANG_Fortran03:
127		    case DW_LANG_Fortran08:
128		    case DW_LANG_Pascal83:
129		    case DW_LANG_Modula2:
130		    case DW_LANG_PL1:
131		      lower = 1;
132		      break;
133
134		    default:
135		      return -1;
136		    }
137		}
138	      if (unlikely (lower > upper))
139		return -1;
140	      count = upper - lower + 1;
141	    }
142	  break;
143
144	case DW_TAG_enumeration_type:
145	  /* We have to find the DW_TAG_enumerator child with the
146	     highest value to know the array's element count.  */
147	  count = 0;
148	  Dwarf_Die enum_child;
149	  int has_children = INTUSE(dwarf_child) (die, &enum_child);
150	  if (has_children < 0)
151	    return -1;
152	  if (has_children > 0)
153	    do
154	      if (INTUSE(dwarf_tag) (&enum_child) == DW_TAG_enumerator)
155		{
156		  Dwarf_Word value;
157		  if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
158					       (&enum_child, DW_AT_const_value,
159						attr_mem), &value) != 0)
160		    return -1;
161		  if (value >= count)
162		    count = value + 1;
163		}
164	    while (INTUSE(dwarf_siblingof) (&enum_child, &enum_child) > 0);
165	  break;
166
167	default:
168	  continue;
169	}
170
171      /* This is a subrange_type or enumeration_type and we've set COUNT.
172	 Now determine the stride for this array dimension.  */
173      Dwarf_Word stride = eltsize;
174      if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_byte_stride,
175					attr_mem) != NULL)
176	{
177	  if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
178	    return -1;
179	}
180      else if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_bit_stride,
181					     attr_mem) != NULL)
182	{
183	  if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0)
184	    return -1;
185	  if (stride % 8) 	/* XXX maybe compute in bits? */
186	    return -1;
187	  stride /= 8;
188	}
189
190      any = true;
191      total += stride * count;
192    }
193  while (INTUSE(dwarf_siblingof) (&child, &child) == 0);
194
195  if (!any)
196    return -1;
197
198  *size = total;
199  return 0;
200}
201
202static int
203aggregate_size (Dwarf_Die *die, Dwarf_Word *size, Dwarf_Die *type_mem)
204{
205  Dwarf_Attribute attr_mem;
206
207  if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_size, &attr_mem) != NULL)
208    return INTUSE(dwarf_formudata) (&attr_mem, size);
209
210  switch (INTUSE(dwarf_tag) (die))
211    {
212    case DW_TAG_subrange_type:
213      return aggregate_size (get_type (die, &attr_mem, type_mem),
214			     size, type_mem); /* Tail call.  */
215
216    case DW_TAG_array_type:
217      return array_size (die, size, &attr_mem, type_mem);
218
219    /* Assume references and pointers have pointer size if not given an
220       explicit DW_AT_byte_size.  */
221    case DW_TAG_pointer_type:
222    case DW_TAG_reference_type:
223    case DW_TAG_rvalue_reference_type:
224      *size = die->cu->address_size;
225      return 0;
226    }
227
228  /* Most types must give their size directly.  */
229  return -1;
230}
231
232int
233dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size)
234{
235  Dwarf_Die type_mem;
236
237  if (INTUSE (dwarf_peel_type) (die, die) != 0)
238    return -1;
239
240  return aggregate_size (die, size, &type_mem);
241}
242INTDEF (dwarf_aggregate_size)
243OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144)
244NEW_VERSION (dwarf_aggregate_size, ELFUTILS_0.161)
245