Logo AND Algorithmique Numérique Distribuée

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