Logo AND Algorithmique Numérique Distribuée

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