Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
ea58470370529f01790338228c42fd162d391dea
[simgrid.git] / src / mc / mc_dwarf_expression.c
1 /* Copyright (c) 2014. 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 <stdint.h>
8 #include <stdarg.h>
9
10 #include <dwarf.h>
11 #include <elfutils/libdw.h>
12
13 #include "mc_private.h"
14
15 static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value)
16 {
17   if (state->stack_size >= MC_EXPRESSION_STACK_SIZE)
18     return MC_EXPRESSION_E_STACK_OVERFLOW;
19
20   state->stack[state->stack_size++] = value;
21   return 0;
22 }
23
24 static int mc_dwarf_register_to_libunwind(int dwarf_register)
25 {
26 #if defined(UNW_TARGET_X86_64)
27   // It seems for this arch, DWARF and libunwind agree in the numbering:
28   return dwarf_register;
29 #elif defined(UNW_TARGET_X86)
30   // Could't find the authoritative source of information for this.
31   // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517.
32   switch (dwarf_register) {
33   case 0:
34     return UNW_X86_EAX;
35   case 1:
36     return UNW_X86_ECX;
37   case 2:
38     return UNW_X86_EDX;
39   case 3:
40     return UNW_X86_EBX;
41   case 4:
42     return UNW_X86_ESP;
43   case 5:
44     return UNW_X86_EBP;
45   case 6:
46     return UNW_X86_ESI;
47   case 7:
48     return UNW_X86_EDI;
49   case 8:
50     return UNW_X86_EIP;
51   case 9:
52     return UNW_X86_EFLAGS;
53   case 10:
54     return UNW_X86_CS;
55   case 11:
56     return UNW_X86_SS;
57   case 12:
58     return UNW_X86_DS;
59   case 13:
60     return UNW_X86_ES;
61   case 14:
62     return UNW_X86_FS;
63   case 15:
64     return UNW_X86_GS;
65   case 16:
66     return UNW_X86_ST0;
67   case 17:
68     return UNW_X86_ST1;
69   case 18:
70     return UNW_X86_ST2;
71   case 19:
72     return UNW_X86_ST3;
73   case 20:
74     return UNW_X86_ST4;
75   case 21:
76     return UNW_X86_ST5;
77   case 22:
78     return UNW_X86_ST6;
79   case 23:
80     return UNW_X86_ST7;
81   default:
82     xbt_die("Bad/unknown register number.");
83   }
84 #else
85 #error This architecture is not supported yet.
86 #endif
87 }
88
89 int mc_dwarf_execute_expression(size_t n, const Dwarf_Op * ops,
90                                 mc_expression_state_t state)
91 {
92   for (int i = 0; i != n; ++i) {
93     int error = 0;
94     const Dwarf_Op *op = ops + i;
95     uint8_t atom = op->atom;
96
97     switch (atom) {
98
99       // Registers:
100
101     case DW_OP_breg0:
102     case DW_OP_breg1:
103     case DW_OP_breg2:
104     case DW_OP_breg3:
105     case DW_OP_breg4:
106     case DW_OP_breg5:
107     case DW_OP_breg6:
108     case DW_OP_breg7:
109     case DW_OP_breg8:
110     case DW_OP_breg9:
111     case DW_OP_breg10:
112     case DW_OP_breg11:
113     case DW_OP_breg12:
114     case DW_OP_breg13:
115     case DW_OP_breg14:
116     case DW_OP_breg15:
117     case DW_OP_breg16:
118     case DW_OP_breg17:
119     case DW_OP_breg18:
120     case DW_OP_breg19:
121     case DW_OP_breg20:
122     case DW_OP_breg21:
123     case DW_OP_breg22:
124     case DW_OP_breg23:
125     case DW_OP_breg24:
126     case DW_OP_breg25:
127     case DW_OP_breg26:
128     case DW_OP_breg27:
129     case DW_OP_breg28:
130     case DW_OP_breg29:
131     case DW_OP_breg30:
132     case DW_OP_breg31:{
133         int register_id =
134             mc_dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
135         unw_word_t res;
136         if (!state->cursor)
137           return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
138         unw_get_reg(state->cursor, register_id, &res);
139         error = mc_dwarf_push_value(state, res + op->number);
140         break;
141       }
142
143       // Push the CFA (Canonical Frame Addresse):
144     case DW_OP_call_frame_cfa:
145       {
146         // UNW_X86_64_CFA does not return the CFA DWARF expects
147         // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
148         // unwind it once in order to find the parent SP:
149
150         if (!state->cursor)
151           return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
152
153         // Get frame:
154         unw_cursor_t cursor = *(state->cursor);
155         unw_step(&cursor);
156
157         unw_word_t res;
158         unw_get_reg(&cursor, UNW_TDEP_SP, &res);
159         error = mc_dwarf_push_value(state, res);
160         break;
161       }
162
163       // Frame base:
164
165     case DW_OP_fbreg:
166       {
167         if (!state->frame_base)
168           return MC_EXPRESSION_E_MISSING_FRAME_BASE;
169         error =
170             mc_dwarf_push_value(state,
171                                 ((uintptr_t) state->frame_base) + op->number);
172         break;
173       }
174
175
176       // Constants:
177
178     case DW_OP_lit0:
179     case DW_OP_lit1:
180     case DW_OP_lit2:
181     case DW_OP_lit3:
182     case DW_OP_lit4:
183     case DW_OP_lit5:
184     case DW_OP_lit6:
185     case DW_OP_lit7:
186     case DW_OP_lit8:
187     case DW_OP_lit9:
188     case DW_OP_lit10:
189     case DW_OP_lit11:
190     case DW_OP_lit12:
191     case DW_OP_lit13:
192     case DW_OP_lit14:
193     case DW_OP_lit15:
194     case DW_OP_lit16:
195     case DW_OP_lit17:
196     case DW_OP_lit18:
197     case DW_OP_lit19:
198     case DW_OP_lit20:
199     case DW_OP_lit21:
200     case DW_OP_lit22:
201     case DW_OP_lit23:
202     case DW_OP_lit24:
203     case DW_OP_lit25:
204     case DW_OP_lit26:
205     case DW_OP_lit27:
206     case DW_OP_lit28:
207     case DW_OP_lit29:
208     case DW_OP_lit30:
209     case DW_OP_lit31:
210       error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
211       break;
212
213     case DW_OP_addr:
214       if (!state->object_info)
215         return MC_EXPRESSION_E_NO_BASE_ADDRESS;
216       if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
217         return MC_EXPRESSION_E_STACK_OVERFLOW;
218       error = mc_dwarf_push_value(state,
219                                   (Dwarf_Off) (uintptr_t)
220                                   MC_object_base_address(state->object_info) +
221                                   op->number);
222       break;
223
224     case DW_OP_const1u:
225     case DW_OP_const2u:
226     case DW_OP_const4u:
227     case DW_OP_const8u:
228     case DW_OP_const1s:
229     case DW_OP_const2s:
230     case DW_OP_const4s:
231     case DW_OP_const8s:
232     case DW_OP_constu:
233     case DW_OP_consts:
234       if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
235         return MC_EXPRESSION_E_STACK_OVERFLOW;
236       error = mc_dwarf_push_value(state, op->number);
237       break;
238
239       // Stack manipulation:
240
241       // Push the value at the top of the stack:
242     case DW_OP_dup:
243       if (state->stack_size == 0)
244         return MC_EXPRESSION_E_STACK_UNDERFLOW;
245       else
246         error = mc_dwarf_push_value(state, state->stack[state->stack_size - 1]);
247       break;
248
249     case DW_OP_drop:
250       if (state->stack_size == 0)
251         return MC_EXPRESSION_E_STACK_UNDERFLOW;
252       else
253         state->stack_size--;
254       break;
255
256     case DW_OP_swap:
257       if (state->stack_size < 2)
258         return MC_EXPRESSION_E_STACK_UNDERFLOW;
259       {
260         uintptr_t temp = state->stack[state->stack_size - 2];
261         state->stack[state->stack_size - 2] =
262             state->stack[state->stack_size - 1];
263         state->stack[state->stack_size - 1] = temp;
264       }
265       break;
266
267     case DW_OP_over:
268       if (state->stack_size < 2)
269         return MC_EXPRESSION_E_STACK_UNDERFLOW;
270       error = mc_dwarf_push_value(state, state->stack[state->stack_size - 2]);
271       break;
272
273       // Operations:
274
275     case DW_OP_plus:
276       if (state->stack_size < 2)
277         return MC_EXPRESSION_E_STACK_UNDERFLOW;
278       {
279         uintptr_t result =
280             state->stack[state->stack_size - 2] +
281             state->stack[state->stack_size - 1];
282         state->stack[state->stack_size - 2] = result;
283         state->stack_size--;
284       }
285       break;
286
287     case DW_OP_mul:
288       if (state->stack_size < 2)
289         return MC_EXPRESSION_E_STACK_UNDERFLOW;
290       {
291         uintptr_t result =
292             state->stack[state->stack_size - 2] -
293             state->stack[state->stack_size - 1];
294         state->stack[state->stack_size - 2] = result;
295         state->stack_size--;
296       }
297       break;
298
299     case DW_OP_plus_uconst:
300       if (state->stack_size == 0)
301         return MC_EXPRESSION_E_STACK_UNDERFLOW;
302       state->stack[state->stack_size - 1] += op->number;
303       break;
304
305     case DW_OP_not:
306       if (state->stack_size == 0)
307         return MC_EXPRESSION_E_STACK_UNDERFLOW;
308       state->stack[state->stack_size - 1] =
309           ~state->stack[state->stack_size - 1];
310       break;
311
312     case DW_OP_neg:
313       if (state->stack_size == 0)
314         return MC_EXPRESSION_E_STACK_UNDERFLOW;
315       {
316         intptr_t value = state->stack[state->stack_size - 1];
317         if (value < 0)
318           value = -value;
319         state->stack[state->stack_size - 1] = value;
320       }
321       break;
322
323     case DW_OP_minus:
324       if (state->stack_size < 2)
325         return MC_EXPRESSION_E_STACK_UNDERFLOW;
326       {
327         uintptr_t result =
328             state->stack[state->stack_size - 2] -
329             state->stack[state->stack_size - 1];
330         state->stack[state->stack_size - 2] = result;
331         state->stack_size--;
332       }
333       break;
334
335     case DW_OP_and:
336       if (state->stack_size < 2)
337         return MC_EXPRESSION_E_STACK_UNDERFLOW;
338       {
339         uintptr_t result =
340             state->stack[state->stack_size -
341                          2] & state->stack[state->stack_size - 1];
342         state->stack[state->stack_size - 2] = result;
343         state->stack_size--;
344       }
345       break;
346
347     case DW_OP_or:
348       if (state->stack_size < 2)
349         return MC_EXPRESSION_E_STACK_UNDERFLOW;
350       {
351         uintptr_t result =
352             state->stack[state->stack_size -
353                          2] | state->stack[state->stack_size - 1];
354         state->stack[state->stack_size - 2] = result;
355         state->stack_size--;
356       }
357       break;
358
359     case DW_OP_xor:
360       if (state->stack_size < 2)
361         return MC_EXPRESSION_E_STACK_UNDERFLOW;
362       {
363         uintptr_t result =
364             state->stack[state->stack_size -
365                          2] ^ state->stack[state->stack_size - 1];
366         state->stack[state->stack_size - 2] = result;
367         state->stack_size--;
368       }
369       break;
370
371     case DW_OP_nop:
372       break;
373
374       // Dereference:
375     case DW_OP_deref_size:
376       return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
377
378     case DW_OP_deref:
379       if (state->stack_size == 0)
380         return MC_EXPRESSION_E_STACK_UNDERFLOW;
381       {
382         // Computed address:
383         uintptr_t address = (uintptr_t) state->stack[state->stack_size - 1];
384         uintptr_t temp;
385         uintptr_t* res = (uintptr_t*) mc_snapshot_read((void*) address, state->snapshot, state->process_index, &temp, sizeof(uintptr_t));
386         state->stack[state->stack_size - 1] = *res;
387       }
388       break;
389
390       // Not handled:
391     default:
392       return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
393     }
394
395     if (error)
396       return error;
397   }
398   return 0;
399 }
400
401 // ***** Location
402
403 /** \brief Resolve a location expression
404  *  \deprecated Use mc_dwarf_resolve_expression
405  */
406 void mc_dwarf_resolve_location(mc_location_t location,
407                                mc_expression_t expression,
408                                mc_object_info_t object_info,
409                                unw_cursor_t * c,
410                                void *frame_pointer_address,
411                                mc_snapshot_t snapshot, int process_index)
412 {
413   s_mc_expression_state_t state;
414   memset(&state, 0, sizeof(s_mc_expression_state_t));
415   state.frame_base = frame_pointer_address;
416   state.cursor = c;
417   state.snapshot = snapshot;
418   state.object_info = object_info;
419   state.process_index = process_index;
420
421   if (expression->size >= 1
422     && expression->ops[0].atom >=DW_OP_reg0 && expression->ops[0].atom <= DW_OP_reg31) {
423     int dwarf_register = expression->ops[0].atom - DW_OP_reg0;
424     xbt_assert(c, "Missing frame context for register operation DW_OP_reg%i",
425       dwarf_register);
426     location->memory_location = NULL;
427     location->cursor = c;
428     location->register_id = mc_dwarf_register_to_libunwind(dwarf_register);
429     return;
430   }
431
432   if (mc_dwarf_execute_expression(expression->size, expression->ops, &state))
433     xbt_die("Error evaluating DWARF expression");
434   if (state.stack_size == 0)
435     xbt_die("No value on the stack");
436   else {
437     location->memory_location = (void*) state.stack[state.stack_size - 1];
438     location->cursor = NULL;
439     location->register_id = 0;
440   }
441 }
442
443 static mc_expression_t mc_find_expression(mc_location_list_t locations, unw_word_t ip) {
444   for (size_t i = 0; i != locations->size; ++i) {
445     mc_expression_t expression = locations->locations + i;
446     if ((expression->lowpc == NULL && expression->highpc == NULL)
447         || (ip && ip >= (unw_word_t) expression->lowpc
448             && ip < (unw_word_t) expression->highpc)) {
449       return expression;
450     }
451   }
452   return NULL;
453 }
454
455 void mc_dwarf_resolve_locations(mc_location_t location,
456                                      mc_location_list_t locations,
457                                      mc_object_info_t object_info,
458                                      unw_cursor_t * c,
459                                      void *frame_pointer_address,
460                                      mc_snapshot_t snapshot, int process_index)
461 {
462
463   unw_word_t ip = 0;
464   if (c) {
465     if (unw_get_reg(c, UNW_REG_IP, &ip))
466       xbt_die("Could not resolve IP");
467   }
468
469   mc_expression_t expression = mc_find_expression(locations, ip);
470   if (expression) {
471     mc_dwarf_resolve_location(location,
472                               expression, object_info, c,
473                               frame_pointer_address, snapshot, process_index);
474   } else {
475     xbt_die("Could not resolve location");
476   }
477 }
478
479 /** \brief Find the frame base of a given frame
480  *
481  *  \param frame
482  *  \param unw_cursor
483  */
484 void *mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info,
485                          unw_cursor_t * unw_cursor)
486 {
487   s_mc_location_t location;
488   mc_dwarf_resolve_locations(&location,
489                              &frame->frame_base, object_info,
490                              unw_cursor, NULL, NULL, -1);
491   switch(mc_get_location_type(&location)) {
492   case MC_LOCATION_TYPE_ADDRESS:
493     return location.memory_location;
494
495   case MC_LOCATION_TYPE_REGISTER: {
496       // This is a special case.
497       // The register if not the location of the frame base
498       // (a frame base cannot be located in a register)
499       // Instead, DWARF defines this to mean that the register
500       // contains the address of the frame base.
501       unw_word_t word;
502       unw_get_reg(location.cursor, location.register_id, &word);
503       return (void*) word;
504     }
505
506   default:
507     xbt_die("Cannot handle non-address frame base");
508     return NULL; // Unreachable
509   }
510 }
511
512 void mc_dwarf_expression_clear(mc_expression_t expression)
513 {
514   free(expression->ops);
515   expression->ops = NULL;
516   expression->size = 0;
517   expression->lowpc = NULL;
518   expression->highpc = NULL;
519 }
520
521 void mc_dwarf_location_list_clear(mc_location_list_t list)
522 {
523   for (size_t i = 0; i != list->size; ++i) {
524     mc_dwarf_expression_clear(list->locations + i);
525   }
526   free(list->locations);
527   list->locations = NULL;
528   list->size = 0;
529 }
530
531 void mc_dwarf_expression_init(mc_expression_t expression, size_t len,
532                               Dwarf_Op * ops)
533 {
534   expression->lowpc = NULL;
535   expression->highpc = NULL;
536   expression->size = len;
537   expression->ops = xbt_malloc(len * sizeof(Dwarf_Op));
538   memcpy(expression->ops, ops, len * sizeof(Dwarf_Op));
539 }
540
541 void mc_dwarf_location_list_init_from_expression(mc_location_list_t target,
542                                                  size_t len, Dwarf_Op * ops)
543 {
544   target->size = 1;
545   target->locations = (mc_expression_t) xbt_malloc(sizeof(s_mc_expression_t));
546   mc_dwarf_expression_init(target->locations, len, ops);
547 }
548
549 void mc_dwarf_location_list_init(mc_location_list_t list, mc_object_info_t info,
550                                  Dwarf_Die * die, Dwarf_Attribute * attr)
551 {
552   if (list->locations) {
553     mc_dwarf_location_list_clear(list);
554   }
555   list->size = 0;
556
557   ptrdiff_t offset = 0;
558   Dwarf_Addr base, start, end;
559   Dwarf_Op *ops;
560   size_t len;
561
562   while (1) {
563
564     offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
565     if (offset == 0)
566       return;
567     else if (offset == -1)
568       xbt_die("Error while loading location list");
569
570     int i = list->size;
571     list->size++;
572     list->locations =
573         (mc_expression_t) realloc(list->locations,
574                                   list->size * sizeof(s_mc_expression_t));
575     mc_expression_t expression = list->locations + i;
576     expression->ops = NULL;
577     mc_dwarf_expression_init(expression, len, ops);
578
579     void *base =
580         info->
581         flags & MC_OBJECT_INFO_EXECUTABLE ? 0 : MC_object_base_address(info);
582     // If start == 0, this is not a location list:
583     expression->lowpc = start == 0 ? NULL : (char *) base + start;
584     expression->highpc = start == 0 ? NULL : (char *) base + end;
585   }
586
587 }