Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Use libdw for location list
[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, dw_frame_t frame);
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, dw_frame_t frame);
39 static void MC_dwarf_handle_variable_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame);
40 static dw_location_t MC_dwarf_get_expression(Dwarf_Op* expr,  size_t len);
41 static Dwarf_Die* MC_dwarf_resolve_die(Dwarf_Die* die, int attribute);
42 static char* MC_dwarf_at_type(Dwarf_Die* die);
43
44 const char* MC_dwarf_attrname(int attr) {
45   switch (attr) {
46 #include "mc_dwarf_attrnames.h"
47   default:
48     return "DW_AT_unkown";
49   }
50 }
51
52 const char* MC_dwarf_tagname(int tag) {
53   switch (tag) {
54 #include "mc_dwarf_tagnames.h"
55   case DW_TAG_invalid:
56     return "DW_TAG_invalid";
57   default:
58     return "DW_TAG_unkown";
59   }
60 }
61
62 static inline const char* MC_dwarf_die_tagname(Dwarf_Die* die) {
63   return MC_dwarf_tagname(dwarf_tag(die));
64 }
65
66 // ***** Attributes
67
68 static const char* MC_dwarf_attr_string(Dwarf_Die* die, int attribute) {
69   Dwarf_Attribute attr;
70   if (!dwarf_attr_integrate(die, attribute, &attr)) {
71         return NULL;
72   } else {
73         return dwarf_formstring(&attr);
74   }
75 }
76
77 /** \brief Get the linkage name (DW_AT_linkage_name or DW_AR_MIPS_linkage_name)
78  *  of a DIE. */
79 static const char* MC_dwarf_at_linkage_name(Dwarf_Die* die) {
80   const char* name = MC_dwarf_attr_string(die, DW_AT_linkage_name);
81   if (!name)
82     name = MC_dwarf_attr_string(die, DW_AT_MIPS_linkage_name);
83   return name;
84 }
85
86 static dw_location_t MC_dwarf_resolve_location_list(mc_object_info_t info, Dwarf_Word offset) {
87   char *key = bprintf("%ld", (long) offset);
88   dw_location_t loc = xbt_new0(s_dw_location_t, 1);
89   loc->type = e_dw_loclist;
90   loc->location.loclist =  (xbt_dynar_t)xbt_dict_get_or_null(info->location_list, key);
91   if (!loc->location.loclist)
92     XBT_INFO("Key not found in loclist");
93   xbt_free(key);
94   return loc;
95 }
96
97 /** \brief Create a location_list from a given attribute */
98 static dw_location_t MC_dwarf_get_location_list_libdw(Dwarf_Die* die, Dwarf_Attribute* attr) {
99
100
101   dw_location_t location = xbt_new0(s_dw_location_t, 1);
102   location->type = e_dw_loclist;
103   xbt_dynar_t loclist = xbt_dynar_new(sizeof(dw_location_entry_t), NULL);
104   location->location.loclist = loclist;
105
106   ptrdiff_t offset = 0;
107   Dwarf_Addr base, start, end;
108   Dwarf_Op *expr;
109   size_t len;
110
111   while (1) {
112
113     offset = dwarf_getlocations(attr, offset, &base, &start, &end, &expr, &len);
114     if (offset==0)
115       return location;
116     else if (offset==-1)
117       xbt_die("Error while loading location list");
118
119     dw_location_entry_t new_entry = xbt_new0(s_dw_location_entry_t, 1);
120     new_entry->lowpc = start;
121     new_entry->highpc = end;
122     new_entry->location = MC_dwarf_get_expression(expr, len);
123
124     xbt_dynar_push(loclist, &new_entry);
125
126   }
127 }
128
129 static dw_location_t MC_dwarf_get_location(Dwarf_Die* die, Dwarf_Attribute* attr, mc_object_info_t info) {
130   int form = dwarf_whatform(attr);
131   switch (form) {
132   case DW_FORM_exprloc:
133   case DW_FORM_block1: // not in the spec
134   case DW_FORM_block2:
135   case DW_FORM_block4:
136   case DW_FORM_block:
137     {
138       Dwarf_Op* expr;
139       size_t len;
140       if (dwarf_getlocation(attr, &expr, &len))
141         xbt_die("Could not read location expression");
142       return MC_dwarf_get_expression(expr, len);
143     }
144   case DW_FORM_sec_offset:
145   case DW_FORM_data2:
146   case DW_FORM_data4:
147   case DW_FORM_data8:
148     {
149       if (MC_USE_LIBDW_LOCATION_LIST)
150         return MC_dwarf_get_location_list_libdw(die, attr);
151
152       Dwarf_Word offset;
153       if (!dwarf_formudata(attr, &offset))
154         return MC_dwarf_resolve_location_list(info, offset);
155       else
156         xbt_die("Location list not found");
157     }
158     break;
159   default:
160     xbt_die("Unexpected form %i list for location in attribute %s of <%p>%s",
161       form,
162       MC_dwarf_attrname(attr->code),
163       (void*) dwarf_dieoffset(die),
164       MC_dwarf_attr_string(die, DW_AT_name));
165     return NULL;
166   }
167 }
168
169 static dw_location_t MC_dwarf_at_location(Dwarf_Die* die, int attribute, mc_object_info_t info) {
170   if(!dwarf_hasattr_integrate(die, attribute))
171     return xbt_new0(s_dw_location_t, 1);
172
173   Dwarf_Attribute attr;
174   dwarf_attr_integrate(die, attribute, &attr);
175   return MC_dwarf_get_location(die, &attr, info);
176 }
177
178 // Return a new string for the type (NULL if none)
179 static char* MC_dwarf_at_type(Dwarf_Die* die) {
180   Dwarf_Attribute attr;
181   if (dwarf_hasattr_integrate(die, DW_AT_type)) {
182         dwarf_attr_integrate(die, DW_AT_type, &attr);
183         Dwarf_Die subtype_die;
184         if (dwarf_formref_die(&attr, &subtype_die)==NULL) {
185           xbt_die("Could not find DIE for type");
186         }
187         Dwarf_Off subtype_global_offset = dwarf_dieoffset(&subtype_die);
188     return bprintf("%" PRIx64 , subtype_global_offset);
189   }
190   else return NULL;
191 }
192
193 static uint64_t MC_dwarf_attr_addr(Dwarf_Die* die, int attribute) {
194   Dwarf_Attribute attr;
195   if(dwarf_attr_integrate(die, attribute, &attr)==NULL)
196     return 0;
197   Dwarf_Addr value;
198   if (dwarf_formaddr(&attr, &value) == 0)
199     return (uint64_t) value;
200   else
201     return 0;
202 }
203
204 static uint64_t MC_dwarf_attr_uint(Dwarf_Die* die, int attribute, uint64_t default_value) {
205   Dwarf_Attribute attr;
206   if (dwarf_attr_integrate(die, attribute, &attr)==NULL)
207     return default_value;
208   Dwarf_Word value;
209   return dwarf_formudata(dwarf_attr_integrate(die, attribute, &attr), &value) == 0 ? (uint64_t) value : default_value;
210 }
211
212 static bool MC_dwarf_attr_flag(Dwarf_Die* die, int attribute, int integrate) {
213   Dwarf_Attribute attr;
214   if ((integrate ? dwarf_attr_integrate(die, attribute, &attr)
215                     : dwarf_attr(die, attribute, &attr))==0)
216     return false;
217
218   bool result;
219   if (dwarf_formflag(&attr, &result))
220     xbt_die("Unexpected form for attribute %s",
221       MC_dwarf_attrname(attribute));
222   return result;
223 }
224
225 static uint64_t MC_dwarf_default_lower_bound(int lang) {
226   switch(lang) {
227   case DW_LANG_C:
228   case DW_LANG_C89:
229   case DW_LANG_C99:
230   case DW_LANG_C_plus_plus:
231   case DW_LANG_D:
232   case DW_LANG_Java:
233   case DW_LANG_ObjC:
234   case DW_LANG_ObjC_plus_plus:
235   case DW_LANG_Python:
236   case DW_LANG_UPC:
237     return 0;
238   case DW_LANG_Ada83:
239   case DW_LANG_Ada95:
240   case DW_LANG_Fortran77:
241   case DW_LANG_Fortran90:
242   case DW_LANG_Fortran95:
243   case DW_LANG_Modula2:
244   case DW_LANG_Pascal83:
245   case DW_LANG_PL1:
246   case DW_LANG_Cobol74:
247   case DW_LANG_Cobol85:
248     return 1;
249   default:
250     xbt_die("No default MT_TAG_lower_bound for language %i and none given", lang);
251     return 0;
252   }
253 }
254
255 static uint64_t MC_dwarf_subrange_element_count(Dwarf_Die* die, Dwarf_Die* unit) {
256   // Use DW_TAG_count if present:
257   if (dwarf_hasattr_integrate(die, DW_AT_count)) {
258     return MC_dwarf_attr_uint(die, DW_AT_count, 0);
259   }
260
261   // Otherwise compute DW_TAG_upper_bound-DW_TAG_lower_bound:
262
263   if (!dwarf_hasattr_integrate(die, DW_AT_upper_bound)) {
264         // This is not really 0, but the code expects this (we do not know):
265     return 0;
266   }
267   uint64_t upper_bound = MC_dwarf_attr_uint(die, DW_AT_upper_bound, -1);
268
269   uint64_t lower_bound = 0;
270   if (dwarf_hasattr_integrate(die, DW_AT_lower_bound)) {
271     lower_bound = MC_dwarf_attr_uint(die, DW_AT_lower_bound, -1);
272   } else {
273         lower_bound = MC_dwarf_default_lower_bound(dwarf_srclang(unit));
274   }
275   return upper_bound - lower_bound;
276 }
277
278 static uint64_t MC_dwarf_array_element_count(Dwarf_Die* die, Dwarf_Die* unit) {
279   xbt_assert(dwarf_tag(die)==DW_TAG_array_type,
280     "MC_dwarf_array_element_count called with DIE of type %s", MC_dwarf_die_tagname(die));
281
282   int result = 1;
283   Dwarf_Die child;
284   int res;
285   for (res=dwarf_child(die, &child); res==0; res=dwarf_siblingof(&child,&child)) {
286         int child_tag = dwarf_tag(&child);
287     if (child_tag==DW_TAG_subrange_type ||child_tag==DW_TAG_enumeration_type) {
288       result *= MC_dwarf_subrange_element_count(&child, unit);
289     }
290   }
291   return result;
292 }
293
294 // ***** Location
295
296 Dwarf_Off MC_dwarf_resolve_location(unw_cursor_t* c, dw_location_t location, void* frame_pointer_address) {
297   unw_word_t res;
298   switch (location->type){
299   case e_dw_compose:
300     if (xbt_dynar_length(location->location.compose) > 1){
301       return 0; /* TODO : location list with optimizations enabled */
302     }
303     dw_location_t location_entry = xbt_dynar_get_as(location->location.compose, 0, dw_location_t);
304     switch (location_entry->type){
305     case e_dw_register:
306       unw_get_reg(c, location_entry->location.reg, &res);
307       return res;
308     case e_dw_bregister_op:
309       unw_get_reg(c, location_entry->location.breg_op.reg, &res);
310       return (Dwarf_Off) ((long)res + location_entry->location.breg_op.offset);
311       break;
312     case e_dw_fbregister_op:
313       if (frame_pointer_address != NULL)
314         return (Dwarf_Off)((char *)frame_pointer_address + location_entry->location.fbreg_op);
315       else
316         return 0;
317     default:
318       return 0; /* FIXME : implement other cases (with optimizations enabled) */
319     }
320     break;
321     default:
322       return 0;
323   }
324 }
325
326 // ***** dw_type_t
327
328 static void MC_dwarf_fill_member_location(dw_type_t type, dw_type_t member, Dwarf_Die* child) {
329   if (dwarf_hasattr(child, DW_AT_data_bit_offset)) {
330     xbt_die("Can't groke DW_AT_data_bit_offset.");
331   }
332
333   if (!dwarf_hasattr_integrate(child, DW_AT_data_member_location)) {
334     if (type->type != DW_TAG_union_type) {
335         xbt_die(
336           "Missing DW_AT_data_member_location field in DW_TAG_member %s of type <%p>%s",
337           member->name, type->id, type->name);
338     } else {
339       return;
340     }
341   }
342
343   Dwarf_Attribute attr;
344   dwarf_attr_integrate(child, DW_AT_data_member_location, &attr);
345   switch (dwarf_whatform(&attr)) {
346
347   case DW_FORM_exprloc:
348     {
349       Dwarf_Op* expr;
350       size_t len;
351       if (dwarf_getlocation(&attr, &expr, &len)) {
352         xbt_die(
353           "Could not read location expression DW_AT_data_member_location in DW_TAG_member %s of type <%p>%s",
354           MC_dwarf_attr_string(child, DW_AT_name),
355           type->id, type->name);
356       }
357       if (len==1 && expr[0].atom == DW_OP_plus_uconst) {
358         member->offset =  expr[0].number;
359       } else {
360         xbt_die("Can't groke this location expression yet. %i %i",
361           len==1 , expr[0].atom == DW_OP_plus_uconst);
362       }
363       break;
364     }
365   case DW_FORM_data1:
366   case DW_FORM_data2:
367   case DW_FORM_data4:
368   case DW_FORM_data8:
369   case DW_FORM_sdata:
370   case DW_FORM_udata:
371     {
372       Dwarf_Word offset;
373       if (!dwarf_formudata(&attr, &offset))
374         member->offset = offset;
375       else
376         xbt_die("Cannot get DW_AT_data_member_%s location <%p>%s",
377           MC_dwarf_attr_string(child, DW_AT_name),
378           type->id, type->name);
379       break;
380     }
381   }
382 }
383
384 static void MC_dwarf_add_members(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_type_t type) {
385   int res;
386   Dwarf_Die child;
387   xbt_assert(!type->members);
388   type->members = xbt_dynar_new(sizeof(dw_type_t), (void(*)(void*))dw_type_free);
389   for (res=dwarf_child(die, &child); res==0; res=dwarf_siblingof(&child,&child)) {
390     if (dwarf_tag(&child)==DW_TAG_member) {
391       // TODO, we should use another type (because is is not a type but a member)
392       dw_type_t member = xbt_new0(s_dw_type_t, 1);
393       member->type = -1;
394       member->id = NULL;
395
396       const char* name = MC_dwarf_attr_string(&child, DW_AT_name);
397       if(name)
398         member->name = xbt_strdup(name);
399       else
400         member->name = NULL;
401
402       member->byte_size = MC_dwarf_attr_uint(&child, DW_AT_byte_size, 0);
403       member->element_count = -1;
404       member->dw_type_id = MC_dwarf_at_type(&child);
405       member->members = NULL;
406       member->is_pointer_type = 0;
407       member->offset = 0;
408
409       if(dwarf_hasattr(&child, DW_AT_data_bit_offset)) {
410         xbt_die("Can't groke DW_AT_data_bit_offset.");
411       }
412
413       MC_dwarf_fill_member_location(type, member, &child);
414
415       if (!member->dw_type_id) {
416         xbt_die("Missing type for member %s of <%p>%s", member->name, type->id, type->name);
417       }
418
419       xbt_dynar_push(type->members, &member);
420     }
421   }
422 }
423
424 static dw_type_t MC_dwarf_die_to_type(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit) {
425
426   dw_type_t type = xbt_new0(s_dw_type_t, 1);
427   type->type = -1;
428   type->id = NULL;
429   type->name = NULL;
430   type->byte_size = 0;
431   type->element_count = -1;
432   type->dw_type_id = NULL;
433   type->members = NULL;
434   type->is_pointer_type = 0;
435   type->offset = 0;
436
437   type->type = dwarf_tag(die);
438
439   // Global Offset
440   type->id = (void *) dwarf_dieoffset(die);
441
442   const char* name = MC_dwarf_attr_string(die, DW_AT_name);
443   if (name!=NULL) {
444         type->name = xbt_strdup(name);
445   }
446
447   XBT_DEBUG("Processing type <%p>%s", type->id, type->name);
448
449   type->dw_type_id = MC_dwarf_at_type(die);
450
451   // Computation of the byte_size;
452   if (dwarf_hasattr_integrate(die, DW_AT_byte_size))
453     type->byte_size = MC_dwarf_attr_uint(die, DW_AT_byte_size, 0);
454   else if (type->type == DW_TAG_array_type || type->type==DW_TAG_structure_type || type->type==DW_TAG_class_type) {
455     Dwarf_Word size;
456     if (dwarf_aggregate_size(die, &size)==0) {
457       type->byte_size = size;
458     }
459   }
460
461   switch (type->type) {
462   case DW_TAG_array_type:
463         type->element_count = MC_dwarf_array_element_count(die, unit);
464         // TODO, handle DW_byte_stride and (not) DW_bit_stride
465         break;
466
467   case DW_TAG_pointer_type:
468   case DW_TAG_reference_type:
469   case DW_TAG_rvalue_reference_type:
470     type->is_pointer_type = 1;
471     break;
472
473   case DW_TAG_structure_type:
474   case DW_TAG_union_type:
475   case DW_TAG_class_type:
476           MC_dwarf_add_members(info, die, unit, type);
477   }
478
479   return type;
480 }
481
482 static void MC_dwarf_handle_type_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit) {
483   dw_type_t type = MC_dwarf_die_to_type(info, die, unit);
484
485   char* key = bprintf("%" PRIx64, (uint64_t) type->id);
486   xbt_dict_set(info->types, key, type, NULL);
487 }
488
489 /** \brief Convert libdw location expresion elment into native one (or NULL in some cases) */
490 static dw_location_t MC_dwarf_get_expression_element(Dwarf_Op* op) {
491   dw_location_t element = xbt_new0(s_dw_location_t, 1);
492   uint8_t atom = op->atom;
493   if (atom >= DW_OP_reg0 && atom<= DW_OP_reg31) {
494     element->type = e_dw_register;
495     element->location.reg = atom - DW_OP_reg0;
496   }
497   else if (atom >= DW_OP_breg0 && atom<= DW_OP_breg31) {
498     element->type = e_dw_bregister_op;
499     element->location.reg = atom - DW_OP_breg0;
500     element->location.breg_op.offset = op->number;
501   }
502   else if (atom >= DW_OP_lit0 && atom<= DW_OP_lit31) {
503     element->type = e_dw_lit;
504     element->location.reg = atom - DW_OP_lit0;
505   }
506   else switch (atom) {
507   case DW_OP_fbreg:
508     element->type = e_dw_fbregister_op;
509     element->location.fbreg_op = op->number;
510     break;
511   case DW_OP_piece:
512     element->type = e_dw_piece;
513     element->location.piece = op->number;
514     break;
515   case DW_OP_plus_uconst:
516     element->type = e_dw_plus_uconst;
517     element->location.plus_uconst = op->number;
518     break;
519   case DW_OP_abs:
520     element->type = e_dw_arithmetic;
521     element->location.arithmetic = xbt_strdup("abs");
522     break;
523   case DW_OP_and:
524     element->type = e_dw_arithmetic;
525     element->location.arithmetic = xbt_strdup("and");
526     break;
527   case DW_OP_div:
528     element->type = e_dw_arithmetic;
529     element->location.arithmetic = xbt_strdup("div");
530     break;
531   case DW_OP_minus:
532     element->type = e_dw_arithmetic;
533     element->location.arithmetic = xbt_strdup("minus");
534     break;
535   case DW_OP_mod:
536     element->type = e_dw_arithmetic;
537     element->location.arithmetic = xbt_strdup("mod");
538     break;
539   case DW_OP_mul:
540     element->type = e_dw_arithmetic;
541     element->location.arithmetic = xbt_strdup("mul");
542     break;
543   case DW_OP_neg:
544     element->type = e_dw_arithmetic;
545     element->location.arithmetic = xbt_strdup("neg");
546     break;
547   case DW_OP_not:
548     element->type = e_dw_arithmetic;
549     element->location.arithmetic = xbt_strdup("not");
550     break;
551   case DW_OP_or:
552     element->type = e_dw_arithmetic;
553     element->location.arithmetic = xbt_strdup("or");
554     break;
555   case DW_OP_plus:
556     element->type = e_dw_arithmetic;
557     element->location.arithmetic = xbt_strdup("plus");
558     break;
559
560   case DW_OP_stack_value:
561     // Why nothing here?
562     xbt_free(element);
563     return NULL;
564
565   case DW_OP_deref_size:
566     element->type = e_dw_deref;
567     element->location.deref_size =  (unsigned int short) op->number;
568     break;
569   case DW_OP_deref:
570     element->type = e_dw_deref;
571     element->location.deref_size = sizeof(void *);
572     break;
573   case DW_OP_constu:
574     element->type = e_dw_uconstant;
575     element->location.uconstant.bytes = 1;
576     element->location.uconstant.value = (unsigned long int) op->number;
577     break;
578   case DW_OP_consts:
579     element->type = e_dw_sconstant;
580     element->location.uconstant.bytes = 1;
581     element->location.uconstant.value = (unsigned long int) op->number;
582     break;
583
584   case DW_OP_const1u:
585     element->type = e_dw_uconstant;
586     element->location.uconstant.bytes = 1;
587     element->location.uconstant.value = (unsigned long int) op->number;
588     break;
589   case DW_OP_const2u:
590     element->type = e_dw_uconstant;
591     element->location.uconstant.bytes = 2;
592     element->location.uconstant.value = (unsigned long int) op->number;
593     break;
594   case DW_OP_const4u:
595     element->type = e_dw_uconstant;
596     element->location.uconstant.bytes = 4;
597     element->location.uconstant.value = (unsigned long int) op->number;
598     break;
599   case DW_OP_const8u:
600     element->type = e_dw_uconstant;
601     element->location.uconstant.bytes = 8;
602     element->location.uconstant.value = (unsigned long int) op->number;
603     break;
604
605   case DW_OP_const1s:
606     element->type = e_dw_sconstant;
607     element->location.uconstant.bytes = 1;
608     element->location.uconstant.value = (unsigned long int) op->number;
609     break;
610   case DW_OP_const2s:
611     element->type = e_dw_sconstant;
612     element->location.uconstant.bytes = 2;
613     element->location.uconstant.value = (unsigned long int) op->number;
614     break;
615   case DW_OP_const4s:
616     element->type = e_dw_sconstant;
617     element->location.uconstant.bytes = 4;
618     element->location.uconstant.value = (unsigned long int) op->number;
619     break;
620   case DW_OP_const8s:
621     element->type = e_dw_sconstant;
622     element->location.uconstant.bytes = 8;
623     element->location.uconstant.value = (unsigned long int) op->number;
624     break;
625   default:
626     element->type = e_dw_unsupported;
627     break;
628   }
629   return element;
630 }
631
632 /** \brief Convert libdw location expresion into native one */
633 static dw_location_t MC_dwarf_get_expression(Dwarf_Op* expr,  size_t len) {
634   dw_location_t loc = xbt_new0(s_dw_location_t, 1);
635   loc->type = e_dw_compose;
636   loc->location.compose = xbt_dynar_new(sizeof(dw_location_t), NULL);
637
638   int i;
639   for (i=0; i!=len; ++i) {
640     dw_location_t element =  MC_dwarf_get_expression_element(expr+i);
641     if (element)
642       xbt_dynar_push(loc->location.compose, &element);
643   }
644
645   return loc;
646 }
647
648 static dw_variable_t MC_die_to_variable(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame) {
649   // Drop declaration:
650   if (MC_dwarf_attr_flag(die, DW_AT_declaration, false))
651     return NULL;
652
653   Dwarf_Attribute attr_location;
654   if (dwarf_attr(die, DW_AT_location, &attr_location)==NULL) {
655     // No location: do not add it ?
656     return NULL;
657   }
658
659   dw_variable_t variable = xbt_new0(s_dw_variable_t, 1);
660   variable->dwarf_offset = dwarf_dieoffset(die);
661   variable->global = frame == NULL; // Can be override base on DW_AT_location
662   variable->name = xbt_strdup(MC_dwarf_attr_string(die, DW_AT_name));
663   variable->type_origin = MC_dwarf_at_type(die);
664   variable->address.address = NULL;
665
666   int form;
667   switch (form = dwarf_whatform(&attr_location)) {
668   case DW_FORM_exprloc:
669   case DW_FORM_block1: // Not in the spec but found in the wild.
670     {
671       Dwarf_Op* expr;
672       size_t len;
673       if (dwarf_getlocation(&attr_location, &expr, &len)) {
674         xbt_die(
675           "Could not read location expression in DW_AT_location of variable <%p>%s",
676           (void*) variable->dwarf_offset, variable->name);
677       }
678
679       if (len==1 && expr[0].atom == DW_OP_addr) {
680         variable->global = 1;
681         Dwarf_Off offset = expr[0].number;
682         // TODO, Why is this different base on the object?
683         Dwarf_Off base = strcmp(info->file_name, xbt_binary_name) !=0 ? (Dwarf_Off) info->start_text : 0;
684         variable->address.address = (void*) (base + offset);
685       } else {
686         variable->address.location = MC_dwarf_get_expression(expr, len);
687       }
688
689       break;
690     }
691   case DW_FORM_sec_offset: // type loclistptr
692   case DW_FORM_data4:
693     xbt_die("Do not handle loclist locations yet");
694     break;
695   default:
696     xbt_die("Unexpected form %i list for location in <%p>%s",
697       form, (void*) variable->dwarf_offset, variable->name);
698   }
699
700   return variable;
701 }
702
703 static void MC_dwarf_handle_variable_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame) {
704   dw_variable_t variable = MC_die_to_variable(info, die, unit, frame);
705   if(variable==NULL)
706       return;
707   MC_dwarf_register_variable(info, frame, variable);
708 }
709
710 static void MC_dwarf_handle_subprogram_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t parent_frame) {
711   dw_frame_t frame = xbt_new0(s_dw_frame_t, 1);
712
713   frame->start = dwarf_dieoffset(die);
714
715   const char* name = MC_dwarf_at_linkage_name(die);
716   if (name==NULL)
717     name = MC_dwarf_attr_string(die, DW_AT_name);
718   frame->name = xbt_strdup(name);
719
720   // Variables are filled in the (recursive) call of MC_dwarf_handle_children:
721   frame->variables = xbt_dynar_new(sizeof(dw_variable_t), dw_variable_free_voidp);
722   frame->high_pc = (void*) MC_dwarf_attr_addr(die, DW_AT_high_pc);
723   frame->low_pc = (void*) MC_dwarf_attr_addr(die, DW_AT_low_pc);
724   frame->frame_base = MC_dwarf_at_location(die, DW_AT_frame_base, info);
725   frame->end = -1; // This one is now useless:
726
727   // Handle children:
728   MC_dwarf_handle_children(info, die, unit, frame);
729
730   // Register it:
731   xbt_dict_set(info->local_variables, frame->name, frame, NULL);
732 }
733
734 static void MC_dwarf_handle_children(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame) {
735   Dwarf_Die child;
736   int res;
737   for (res=dwarf_child(die, &child); res==0; res=dwarf_siblingof(&child,&child)) {
738     MC_dwarf_handle_die(info, &child, unit, frame);
739   }
740 }
741
742 static void MC_dwarf_handle_die(mc_object_info_t info, Dwarf_Die* die, Dwarf_Die* unit, dw_frame_t frame) {
743   int tag = dwarf_tag(die);
744   switch (tag) {
745     case DW_TAG_array_type:
746     case DW_TAG_class_type:
747     case DW_TAG_enumeration_type:
748     case DW_TAG_typedef:
749     case DW_TAG_pointer_type:
750     case DW_TAG_string_type:
751     case DW_TAG_structure_type:
752     case DW_TAG_subroutine_type:
753     case DW_TAG_union_type:
754     case DW_TAG_ptr_to_member_type:
755     case DW_TAG_set_type:
756     case DW_TAG_subrange_type:
757     case DW_TAG_base_type:
758     case DW_TAG_const_type:
759     case DW_TAG_file_type:
760     case DW_TAG_packed_type:
761     case DW_TAG_volatile_type:
762     case DW_TAG_restrict_type:
763     case DW_TAG_interface_type:
764     case DW_TAG_unspecified_type:
765     case DW_TAG_mutable_type:
766     case DW_TAG_shared_type:
767       MC_dwarf_handle_type_die(info, die, unit);
768       break;
769     case DW_TAG_inlined_subroutine:
770     case DW_TAG_subprogram:
771       MC_dwarf_handle_subprogram_die(info, die, unit, frame);
772       return;
773     // case DW_TAG_formal_parameter:
774     case DW_TAG_variable:
775       MC_dwarf_handle_variable_die(info, die, unit, frame);
776       break;
777   }
778
779   // Recursive processing of children DIE:
780   MC_dwarf_handle_children(info, die, unit, frame);
781 }
782
783 void MC_dwarf_get_variables_libdw(mc_object_info_t info) {
784   int fd = open(info->file_name, O_RDONLY);
785   if (fd<0) {
786     xbt_die("Could not open file %s", info->file_name);
787   }
788   Dwarf *dwarf = dwarf_begin(fd, DWARF_C_READ);
789   if (dwarf==NULL) {
790     xbt_die("Your program must be compiled with -g");
791   }
792
793   Dwarf_Off offset = 0;
794   Dwarf_Off next_offset = 0;
795   size_t length;
796   while (dwarf_nextcu (dwarf, offset, &next_offset, &length, NULL, NULL, NULL) == 0) {
797     Dwarf_Die die;
798     if(dwarf_offdie(dwarf, offset+length, &die)!=NULL) {
799       MC_dwarf_handle_die(info, &die, &die, NULL);
800     }
801     offset = next_offset;
802   }
803
804   dwarf_end(dwarf);
805   close(fd);
806 }