Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] libdwarf integration for types
[simgrid.git] / src / mc / mc_dwarf.c
1 /* Copyright (c) 2008-2013. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include <stdlib.h>
8 #include <dwarf.h>
9 #include <elfutils/libdw.h>
10 #include <inttypes.h>
11
12 #include <simgrid_config.h>
13 #include <xbt/log.h>
14 #include <xbt/sysdep.h>
15
16 #include "mc_private.h"
17
18 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_dwarf, mc, "DWARF processing");
19
20 /** \brief The default DW_TAG_lower_bound for a given DW_AT_language.
21  *
22  *  The default for a given language is defined in the DWARF spec.
23  */
24 static uint64_t MC_dwarf_default_lower_bound(int lang);
25
26 static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die* die, Dwarf_Die* unit);
27
28 /** \brief Computes the number of elements of a given DW_TAG_array_type
29  *
30  */
31 static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit);
32
33 /** \brief Checks if a given tag is a (known) type tag.
34  */
35 static int MC_dwarf_tag_type(int tag);
36 static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit);
37 static void MC_dwarf_handle_type_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit);
38 static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit);
39 static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit);
40 static Dwarf_Die* MC_dwarf_resolve_die(Dwarf_Die* die, int attribute);
41
42 const char* MC_dwarf_attrname(int attr) {
43   switch (attr) {
44 #include "mc_dwarf_attrnames.h"
45   default:
46     return "DW_AT_unkown";
47   }
48 }
49
50 const char* MC_dwarf_tagname(int tag) {
51   switch (tag) {
52 #include "mc_dwarf_tagnames.h"
53   case DW_TAG_invalid:
54     return "DW_TAG_invalid";
55   default:
56     return "DW_TAG_unkown";
57   }
58 }
59
60 static inline const char* MC_dwarf_die_tagname(Dwarf_Die* die) {
61   return MC_dwarf_tagname(dwarf_tag(die));
62 }
63
64 static int MC_dwarf_tag_type(int tag) {
65   switch(tag) {
66   case DW_TAG_array_type:
67   case DW_TAG_class_type:
68   case DW_TAG_enumeration_type:
69   case DW_TAG_typedef:
70   case DW_TAG_pointer_type:
71   case DW_TAG_string_type:
72   case DW_TAG_structure_type:
73   case DW_TAG_subroutine_type:
74   case DW_TAG_union_type:
75   case DW_TAG_ptr_to_member_type:
76   case DW_TAG_set_type:
77   case DW_TAG_subrange_type:
78   case DW_TAG_base_type:
79   case DW_TAG_const_type:
80   case DW_TAG_file_type:
81   case DW_TAG_packed_type:
82   case DW_TAG_volatile_type:
83   case DW_TAG_restrict_type:
84   case DW_TAG_interface_type:
85   case DW_TAG_unspecified_type:
86   case DW_TAG_mutable_type:
87   case DW_TAG_shared_type:
88   case DW_TAG_rvalue_reference_type:
89     return 1;
90   default:
91     return 0;
92   }
93 }
94
95 static const char* MC_dwarf_attr_string(Dwarf_Die* die, int attribute) {
96   Dwarf_Attribute attr;
97   if (!dwarf_attr_integrate(die, attribute, &attr)) {
98         return NULL;
99   } else {
100         return dwarf_formstring(&attr);
101   }
102 }
103
104 // Return a new string for the type (NULL if none)
105 static char* MC_dwarf_at_type(Dwarf_Die* die) {
106   Dwarf_Attribute attr;
107   if (dwarf_hasattr_integrate(die, DW_AT_type)) {
108         dwarf_attr_integrate(die, DW_AT_type, &attr);
109         Dwarf_Die subtype_die;
110         if (dwarf_formref_die(&attr, &subtype_die)==NULL) {
111           xbt_die("Could not find DIE for type");
112         }
113         Dwarf_Off subtype_global_offset = dwarf_dieoffset(&subtype_die);
114     return bprintf("%" PRIx64 , subtype_global_offset);
115   }
116   else return NULL;
117 }
118
119 static uint64_t MC_dwarf_attr_uint(Dwarf_Die* die, int attribute, uint64_t default_value) {
120   Dwarf_Attribute attr;
121   Dwarf_Word value;
122   return dwarf_formudata(dwarf_attr_integrate(die, attribute, &attr), &value) == 0 ? (uint64_t) value : default_value;
123 }
124
125 static uint64_t MC_dwarf_default_lower_bound(int lang) {
126   switch(lang) {
127   case DW_LANG_C:
128   case DW_LANG_C89:
129   case DW_LANG_C99:
130   case DW_LANG_C_plus_plus:
131   case DW_LANG_D:
132   case DW_LANG_Java:
133   case DW_LANG_ObjC:
134   case DW_LANG_ObjC_plus_plus:
135   case DW_LANG_Python:
136   case DW_LANG_UPC:
137     return 0;
138   case DW_LANG_Ada83:
139   case DW_LANG_Ada95:
140   case DW_LANG_Fortran77:
141   case DW_LANG_Fortran90:
142   case DW_LANG_Fortran95:
143   case DW_LANG_Modula2:
144   case DW_LANG_Pascal83:
145   case DW_LANG_PL1:
146   case DW_LANG_Cobol74:
147   case DW_LANG_Cobol85:
148     return 1;
149   default:
150     xbt_die("No default MT_TAG_lower_bound for language %i and none given", lang);
151     return 0;
152   }
153 }
154
155 static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die* die, Dwarf_Die* unit) {
156   // Use DW_TAG_count if present:
157   if (dwarf_hasattr_integrate(die, DW_AT_count)) {
158     return MC_dwarf_attr_uint(die, DW_AT_count, 0);
159   }
160
161   // Otherwise compute DW_TAG_upper_bound-DW_TAG_lower_bound:
162
163   if (!dwarf_hasattr_integrate(die, DW_AT_upper_bound)) {
164         // This is not really 0, but the code expects this (we do not know):
165     return 0;
166   }
167   uint64_t upper_bound = MC_dwarf_attr_uint(die, DW_AT_upper_bound, -1);
168
169   uint64_t lower_bound = 0;
170   if (dwarf_hasattr_integrate(die, DW_AT_lower_bound)) {
171     lower_bound = MC_dwarf_attr_uint(die, DW_AT_lower_bound, -1);
172   } else {
173         lower_bound = MC_dwarf_default_lower_bound(dwarf_srclang(unit));
174   }
175   return upper_bound - lower_bound;
176 }
177
178 static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit) {
179   xbt_assert(dwarf_tag(die)==DW_TAG_array_type,
180     "MC_dwarf_array_element_count called with DIE of type %s", MC_dwarf_die_tagname(die));
181
182   int result = 1;
183   Dwarf_Die child;
184   int res;
185   for (res=dwarf_child(die, &child); res==0; res=dwarf_siblingof(&child,&child)) {
186         int child_tag = dwarf_tag(&child);
187     if (child_tag==DW_TAG_subrange_type ||child_tag==DW_TAG_enumeration_type) {
188       result *= MC_dwarf_subrange_element_count(&child, unit);
189     }
190   }
191   return result;
192 }
193
194 static void MC_dwarf_fill_member_location(dw_type_t type, dw_type_t member, Dwarf_Die* child) {
195   if (dwarf_hasattr(child, DW_AT_data_bit_offset)) {
196     xbt_die("Can't groke DW_AT_data_bit_offset.");
197   }
198
199   if (!dwarf_hasattr_integrate(child, DW_AT_data_member_location)) {
200     if (type->type != DW_TAG_union_type) {
201         xbt_die(
202           "Missing DW_AT_data_member_location field in DW_TAG_member %s of type <%p>%s",
203           member->name, type->id, type->name);
204     } else {
205       return;
206     }
207   }
208
209   Dwarf_Attribute attr;
210   dwarf_attr_integrate(child, DW_AT_data_member_location, &attr);
211   switch (dwarf_whatform(&attr)) {
212
213   case DW_FORM_exprloc:
214     {
215       //TODO, location can be an integer as well
216       Dwarf_Op* expr;
217       size_t len;
218       if (dwarf_getlocation(&attr, &expr, &len)) {
219         xbt_die(
220           "Could not read location expression DW_AT_data_member_location in DW_TAG_member %s of type <%p>%s",
221           MC_dwarf_attr_string(child, DW_AT_name),
222           type->id, type->name);
223       }
224       if (len==1 && expr[0].atom == DW_OP_plus_uconst) {
225         member->offset =  expr[0].number;
226       } else {
227         xbt_die("Can't groke this location expression yet. %i %i",
228           len==1 , expr[0].atom == DW_OP_plus_uconst);
229       }
230       break;
231     }
232   case DW_FORM_data1:
233   case DW_FORM_data2:
234   case DW_FORM_data4:
235   case DW_FORM_data8:
236   case DW_FORM_sdata:
237   case DW_FORM_udata:
238     {
239       Dwarf_Word offset;
240       if (!dwarf_formudata(&attr, &offset))
241         member->offset = offset;
242       else
243         xbt_die("Cannot get DW_AT_data_member_%s location <%p>%s",
244           MC_dwarf_attr_string(child, DW_AT_name),
245           type->id, type->name);
246       break;
247     }
248   }
249 }
250
251 static void MC_dwarf_add_members(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_type_t type) {
252   int res;
253   Dwarf_Die child;
254   xbt_assert(!type->members);
255   type->members = xbt_dynar_new(sizeof(dw_type_t), (void(*)(void*))dw_type_free);
256   for (res=dwarf_child(die, &child); res==0; res=dwarf_siblingof(&child,&child)) {
257     if (dwarf_tag(&child)==DW_TAG_member) {
258       // TODO, we should use another type (because is is not a type but a member)
259       dw_type_t member = xbt_new0(s_dw_type_t, 1);
260       member->type = -1;
261       member->id = NULL;
262
263       const char* name = MC_dwarf_attr_string(&child, DW_AT_name);
264       if(name)
265         member->name = xbt_strdup(name);
266       else
267         member->name = NULL;
268
269       member->byte_size = MC_dwarf_attr_uint(&child, DW_AT_byte_size, 0);
270       member->element_count = -1;
271       member->dw_type_id = MC_dwarf_at_type(&child);
272       member->members = NULL;
273       member->is_pointer_type = 0;
274       member->offset = 0;
275
276       if(dwarf_hasattr(&child, DW_AT_data_bit_offset)) {
277         xbt_die("Can't groke DW_AT_data_bit_offset.");
278       }
279
280       MC_dwarf_fill_member_location(type, member, &child);
281
282       xbt_dynar_push(type->members, &member);
283     }
284   }
285 }
286
287 static dw_type_t MC_dwarf_die_to_type(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit) {
288
289   dw_type_t type = xbt_new0(s_dw_type_t, 1);
290   type->type = -1;
291   type->id = NULL;
292   type->name = NULL;
293   type->byte_size = 0;
294   type->element_count = -1;
295   type->dw_type_id = NULL;
296   type->members = NULL;
297   type->is_pointer_type = 0;
298   type->offset = 0;
299
300   type->type = dwarf_tag(die);
301
302   // Global Offset
303   type->id = (void *) dwarf_dieoffset(die);
304
305   const char* name = MC_dwarf_attr_string(die, DW_AT_name);
306   if (name!=NULL) {
307         type->name = xbt_strdup(name);
308   }
309
310   XBT_DEBUG("Processing type <%p>%s", type->id, type->name);
311
312   type->dw_type_id = MC_dwarf_at_type(die);
313
314   // Computation of the byte_size;
315   if (dwarf_hasattr_integrate(die, DW_AT_byte_size))
316     type->byte_size = MC_dwarf_attr_uint(die, DW_AT_byte_size, 0);
317   else if (type->type == DW_TAG_array_type || type->type==DW_TAG_structure_type || type->type==DW_TAG_class_type) {
318     Dwarf_Word size;
319     if (dwarf_aggregate_size(die, &size)==0) {
320       type->byte_size = size;
321     }
322   }
323
324   switch (type->type) {
325   case DW_TAG_array_type:
326         type->element_count = MC_dwarf_array_element_count(die, unit);
327         // TODO, handle DW_byte_stride and (not) DW_bit_stride
328         break;
329
330   case DW_TAG_pointer_type:
331   case DW_TAG_reference_type:
332   case DW_TAG_rvalue_reference_type:
333     type->is_pointer_type = 1;
334     break;
335
336   case DW_TAG_structure_type:
337   case DW_TAG_union_type:
338   case DW_TAG_class_type:
339           MC_dwarf_add_members(info, die, unit, type);
340   }
341
342   return type;
343 }
344
345 static void MC_dwarf_handle_type_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit) {
346   dw_type_t type = MC_dwarf_die_to_type(info, die, unit);
347
348   char* key = bprintf("%" PRIx64, (uint64_t) type->id);
349   xbt_dict_set(info->types, key, type, NULL);
350 }
351
352
353 static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit) {
354   Dwarf_Die child;
355   int res;
356   for (res=dwarf_child(die, &child); res==0; res=dwarf_siblingof(&child,&child)) {
357     MC_dwarf_handle_die(info, &child, unit);
358   }
359 }
360
361 static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit) {
362         int tag = dwarf_tag(die);
363
364         // Register types:
365         if (MC_dwarf_tag_type(tag))
366                 MC_dwarf_handle_type_die(info, die, unit);
367
368         // Other tag-specific handling:
369         else switch(tag) {
370
371         }
372
373         // Recursive processing od children DIE:
374         MC_dwarf_handle_children(info, die, unit);
375 }
376
377 void MC_dwarf_get_variables_libdw(mc_object_info_t info) {
378   int fd = open(info->file_name, O_RDONLY);
379   if (fd<0) {
380     xbt_die("Could not open file %s", info->file_name);
381   }
382   Dwarf *dwarf = dwarf_begin(fd, DWARF_C_READ);
383   if (dwarf==NULL) {
384     xbt_die("Your program must be compiled with -g");
385   }
386
387   Dwarf_Off offset = 0;
388   Dwarf_Off next_offset = 0;
389   size_t length;
390   while (dwarf_nextcu (dwarf, offset, &next_offset, &length, NULL, NULL, NULL) == 0) {
391     Dwarf_Die die;
392     if(dwarf_offdie(dwarf, offset+length, &die)!=NULL) {
393       MC_dwarf_handle_die(info, &die, &die);
394     }
395     offset = next_offset;
396   }
397
398   dwarf_end(dwarf);
399   close(fd);
400 }