Logo AND Algorithmique Numérique Distribuée

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