Logo AND Algorithmique Numérique Distribuée

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