Logo AND Algorithmique Numérique Distribuée

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