Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] OOify DWARF stack/evaluation expression
[simgrid.git] / src / mc / DwarfExpression.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 #include "mc/DwarfExpression.hpp"
20
21 using simgrid::mc::remote;
22
23 namespace simgrid {
24 namespace dwarf {
25
26 evaluation_error::~evaluation_error() {}
27
28 }
29 }
30
31 extern "C" {
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 }
105
106 namespace simgrid {
107 namespace dwarf {
108
109 void execute(
110   const Dwarf_Op* ops, std::size_t n,
111   const ExpressionContext& context, ExpressionStack& stack)
112 {
113   for (size_t i = 0; i != n; ++i) {
114     const Dwarf_Op *op = ops + i;
115     std::uint8_t atom = op->atom;
116
117     switch (atom) {
118
119       // Registers:
120
121     case DW_OP_breg0:
122     case DW_OP_breg1:
123     case DW_OP_breg2:
124     case DW_OP_breg3:
125     case DW_OP_breg4:
126     case DW_OP_breg5:
127     case DW_OP_breg6:
128     case DW_OP_breg7:
129     case DW_OP_breg8:
130     case DW_OP_breg9:
131     case DW_OP_breg10:
132     case DW_OP_breg11:
133     case DW_OP_breg12:
134     case DW_OP_breg13:
135     case DW_OP_breg14:
136     case DW_OP_breg15:
137     case DW_OP_breg16:
138     case DW_OP_breg17:
139     case DW_OP_breg18:
140     case DW_OP_breg19:
141     case DW_OP_breg20:
142     case DW_OP_breg21:
143     case DW_OP_breg22:
144     case DW_OP_breg23:
145     case DW_OP_breg24:
146     case DW_OP_breg25:
147     case DW_OP_breg26:
148     case DW_OP_breg27:
149     case DW_OP_breg28:
150     case DW_OP_breg29:
151     case DW_OP_breg30:
152     case DW_OP_breg31:{
153         int register_id =
154             mc_dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
155         unw_word_t res;
156         if (!context.cursor)
157           throw evaluation_error("Missin stack context");
158         unw_get_reg(context.cursor, register_id, &res);
159         stack.push(res + op->number);
160         break;
161       }
162
163       // Push the CFA (Canonical Frame Addresse):
164     case DW_OP_call_frame_cfa:
165       {
166         // UNW_X86_64_CFA does not return the CFA DWARF expects
167         // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
168         // unwind it once in order to find the parent SP:
169
170         if (!context.cursor)
171           throw evaluation_error("Missint cursor");
172
173         // Get frame:
174         unw_cursor_t cursor = *(context.cursor);
175         unw_step(&cursor);
176
177         unw_word_t res;
178         unw_get_reg(&cursor, UNW_REG_SP, &res);
179         stack.push(res);
180         break;
181       }
182
183       // Frame base:
184
185     case DW_OP_fbreg:
186       stack.push((std::uintptr_t) context.frame_base + op->number);
187       break;
188
189       // ***** Constants:
190
191       // Short constant literals:
192       // DW_OP_lit15 pushed the 15 on the stack.
193     case DW_OP_lit0:
194     case DW_OP_lit1:
195     case DW_OP_lit2:
196     case DW_OP_lit3:
197     case DW_OP_lit4:
198     case DW_OP_lit5:
199     case DW_OP_lit6:
200     case DW_OP_lit7:
201     case DW_OP_lit8:
202     case DW_OP_lit9:
203     case DW_OP_lit10:
204     case DW_OP_lit11:
205     case DW_OP_lit12:
206     case DW_OP_lit13:
207     case DW_OP_lit14:
208     case DW_OP_lit15:
209     case DW_OP_lit16:
210     case DW_OP_lit17:
211     case DW_OP_lit18:
212     case DW_OP_lit19:
213     case DW_OP_lit20:
214     case DW_OP_lit21:
215     case DW_OP_lit22:
216     case DW_OP_lit23:
217     case DW_OP_lit24:
218     case DW_OP_lit25:
219     case DW_OP_lit26:
220     case DW_OP_lit27:
221     case DW_OP_lit28:
222     case DW_OP_lit29:
223     case DW_OP_lit30:
224     case DW_OP_lit31:
225       stack.push(atom - DW_OP_lit0);
226       break;
227
228       // Address from the base address of this ELF object.
229       // Push the address on the stack (base_address + argument).
230     case DW_OP_addr: {
231       if (!context.object_info)
232         throw evaluation_error("No base address");
233       Dwarf_Off addr = (Dwarf_Off) (std::uintptr_t)
234         context.object_info->base_address() + op->number;
235       stack.push(addr);
236       break;
237     }
238
239       // General constants:
240       // Push the constant argument on the stack.
241     case DW_OP_const1u:
242     case DW_OP_const2u:
243     case DW_OP_const4u:
244     case DW_OP_const8u:
245     case DW_OP_const1s:
246     case DW_OP_const2s:
247     case DW_OP_const4s:
248     case DW_OP_const8s:
249     case DW_OP_constu:
250     case DW_OP_consts:
251       stack.push(op->number);
252       break;
253
254       // ***** Stack manipulation:
255
256       // Push another copy/duplicate the value at the top of the stack:
257     case DW_OP_dup:
258       stack.dup();
259       break;
260
261       // Pop/drop the top of the stack:
262     case DW_OP_drop:
263       stack.pop();
264       break;
265
266       // Swap the two top-most value of the stack:
267     case DW_OP_swap:
268       std::swap(stack.top(), stack.top(1));
269       break;
270
271       // Duplicate the value under the top of the stack:
272     case DW_OP_over:
273       stack.push(stack.top(1));
274       break;
275
276       // ***** Operations:
277       // Those usually take the top of the stack and the next value as argument
278       // and replace the top of the stack with the computed value
279       // (stack.top() += stack.before_top()).
280
281     case DW_OP_plus:
282       stack.push(stack.pop() + stack.pop());
283       break;
284
285     case DW_OP_mul:
286       stack.push(stack.pop() * stack.pop());
287       break;
288
289     case DW_OP_plus_uconst:
290       stack.top() += op->number;
291       break;
292
293     case DW_OP_not:
294       stack.top() = ~stack.top();
295       break;
296
297     case DW_OP_neg:
298       stack.top() = - (intptr_t) stack.top();
299       break;
300
301     case DW_OP_minus:
302       stack.push(stack.pop() - stack.pop());
303       break;
304
305     case DW_OP_and:
306       stack.push(stack.pop() & stack.pop());
307       break;
308
309     case DW_OP_or:
310       stack.push(stack.pop() | stack.pop());
311       break;
312
313     case DW_OP_xor:
314       stack.push(stack.pop() ^ stack.pop());
315       break;
316
317     case DW_OP_nop:
318       break;
319
320       // ***** Deference (memory fetch)
321
322     case DW_OP_deref_size:
323       throw evaluation_error("Unsupported operation");
324
325     case DW_OP_deref:
326       // Computed address:
327       if (!context.address_space)
328         throw evaluation_error("Missing address space");
329       context.address_space->read_bytes(
330         &stack.top(), sizeof(uintptr_t), remote(stack.top()),
331         context.process_index);
332       break;
333
334       // Not handled:
335     default:
336       throw evaluation_error("Unsupported operation");
337     }
338
339   }
340 }
341
342 // ***** Location
343
344 /** \brief Resolve a location expression
345  *  \deprecated Use mc_dwarf_resolve_expression
346  */
347 void resolve_location(mc_location_t location,
348                       simgrid::dwarf::DwarfExpression const& expression,
349                       simgrid::mc::ObjectInformation* object_info,
350                       unw_cursor_t * c,
351                       void *frame_pointer_address,
352                       simgrid::mc::AddressSpace* address_space, int process_index)
353 {
354   simgrid::dwarf::ExpressionContext context;
355   context.frame_base = frame_pointer_address;
356   context.cursor = c;
357   context.address_space = address_space;
358   context.object_info = object_info;
359   context.process_index = process_index;
360
361   if (!expression.empty()
362       && expression[0].atom >= DW_OP_reg0
363       && expression[0].atom <= DW_OP_reg31) {
364     int dwarf_register = expression[0].atom - DW_OP_reg0;
365     xbt_assert(c,
366       "Missing frame context for register operation DW_OP_reg%i",
367       dwarf_register);
368     location->memory_location = NULL;
369     location->cursor = c;
370     location->register_id = mc_dwarf_register_to_libunwind(dwarf_register);
371     return;
372   }
373
374   simgrid::dwarf::ExpressionStack stack;
375   simgrid::dwarf::execute(expression, context, stack);
376
377   location->memory_location = (void*) stack.top();
378   location->cursor = NULL;
379   location->register_id = 0;
380 }
381
382 }
383 }
384
385 // TODO, move this in a method of LocationList
386 static simgrid::dwarf::DwarfExpression* mc_find_expression(
387     simgrid::mc::LocationList* locations, unw_word_t ip)
388 {
389   for (simgrid::mc::LocationListEntry& entry : *locations)
390     if (entry.valid_for_ip(ip))
391       return &entry.expression;
392   return nullptr;
393 }
394
395 extern "C" {
396
397 void mc_dwarf_resolve_locations(mc_location_t location,
398                                 simgrid::mc::LocationList* locations,
399                                 simgrid::mc::ObjectInformation* object_info,
400                                 unw_cursor_t * c,
401                                 void *frame_pointer_address,
402                                 simgrid::mc::AddressSpace* address_space,
403                                 int process_index)
404 {
405
406   unw_word_t ip = 0;
407   if (c) {
408     if (unw_get_reg(c, UNW_REG_IP, &ip))
409       xbt_die("Could not resolve IP");
410   }
411
412   simgrid::dwarf::DwarfExpression* expression =
413     mc_find_expression(locations, ip);
414   if (expression) {
415     simgrid::dwarf::resolve_location(location,
416                               *expression, object_info, c,
417                               frame_pointer_address, address_space, process_index);
418   } else {
419     xbt_die("Could not resolve location");
420   }
421 }
422
423 /** \brief Find the frame base of a given frame
424  *
425  *  \param frame
426  *  \param unw_cursor
427  */
428 void *mc_find_frame_base(simgrid::mc::Frame* frame, simgrid::mc::ObjectInformation* object_info,
429                          unw_cursor_t * unw_cursor)
430 {
431   s_mc_location_t location;
432   mc_dwarf_resolve_locations(&location,
433                              &frame->frame_base, object_info,
434                              unw_cursor, NULL, NULL, -1);
435   switch(mc_get_location_type(&location)) {
436   case MC_LOCATION_TYPE_ADDRESS:
437     return location.memory_location;
438
439   case MC_LOCATION_TYPE_REGISTER: {
440       // This is a special case.
441       // The register if not the location of the frame base
442       // (a frame base cannot be located in a register)
443       // Instead, DWARF defines this to mean that the register
444       // contains the address of the frame base.
445       unw_word_t word;
446       unw_get_reg(location.cursor, location.register_id, &word);
447       return (void*) word;
448     }
449
450   default:
451     xbt_die("Cannot handle non-address frame base");
452     return NULL; // Unreachable
453   }
454 }
455
456 void mc_dwarf_location_list_init(
457   simgrid::mc::LocationList* list, simgrid::mc::ObjectInformation* info,
458   Dwarf_Die * die, Dwarf_Attribute * attr)
459 {
460   list->clear();
461
462   std::ptrdiff_t offset = 0;
463   Dwarf_Addr base, start, end;
464   Dwarf_Op *ops;
465   std::size_t len;
466
467   while (1) {
468
469     offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
470     if (offset == 0)
471       return;
472     else if (offset == -1)
473       xbt_die("Error while loading location list");
474
475     simgrid::mc::LocationListEntry entry;
476     entry.expression = simgrid::dwarf::DwarfExpression(ops, ops + len);
477
478     void *base = info->base_address();
479     // If start == 0, this is not a location list:
480     entry.lowpc = start == 0 ? NULL : (char *) base + start;
481     entry.highpc = start == 0 ? NULL : (char *) base + end;
482
483     list->push_back(std::move(entry));
484   }
485
486 }
487
488 }