Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
92570ca9a8591e09a8a17be420f450bce2262018
[simgrid.git] / src / mc / mc_dwarf_expression.c
1
2 #include <stdint.h>
3 #include <stdarg.h>
4
5 #include <dwarf.h>
6 #include <elfutils/libdw.h>
7
8 #include "mc_private.h"
9
10 static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value) {
11   if(state->stack_size>=MC_EXPRESSION_STACK_SIZE)
12     return MC_EXPRESSION_E_STACK_OVERFLOW;
13
14   state->stack[state->stack_size++] = value;
15   return 0;
16 }
17
18 int mc_dwarf_execute_expression(
19   size_t n, const Dwarf_Op* ops, mc_expression_state_t state) {
20   for(int i=0; i!=n; ++i) {
21     int error = 0;
22     const Dwarf_Op* op = ops + i;
23     uint8_t atom = op->atom;
24
25     switch (atom) {
26
27     // Registers:
28
29     case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3:
30     case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7:
31     case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11:
32     case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15:
33     case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19:
34     case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23:
35     case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27:
36     case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31:{
37         int register_id = op->atom - DW_OP_breg0;
38         unw_word_t res;
39         if(!state->cursor)
40           return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
41         unw_get_reg(state->cursor, register_id, &res);
42         error = mc_dwarf_push_value(state, res + op->number);
43         break;
44       }
45
46     // Push the CFA (Canonical Frame Addresse):
47     case DW_OP_call_frame_cfa:
48     {
49       // UNW_X86_64_CFA does not return the CFA DWARF expects
50       // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
51       // unwind it once in order to find the parent SP:
52
53       if(!state->cursor)
54         return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
55
56       // Get frame:
57       unw_cursor_t cursor = *(state->cursor);
58       unw_step(&cursor);
59
60       unw_word_t res;
61       unw_get_reg(&cursor, UNW_TDEP_SP, &res);
62       error = mc_dwarf_push_value(state, res);
63       break;
64     }
65
66     // Frame base:
67
68     case DW_OP_fbreg:
69       {
70         if(!state->frame_base)
71           return MC_EXPRESSION_E_MISSING_FRAME_BASE;
72         error = mc_dwarf_push_value(state, ((uintptr_t)state->frame_base) + op->number);
73         break;
74       }
75
76
77     // Constants:
78
79     case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3:
80     case DW_OP_lit4: case DW_OP_lit5: case DW_OP_lit6: case DW_OP_lit7:
81     case DW_OP_lit8: case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11:
82     case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: case DW_OP_lit15:
83     case DW_OP_lit16: case DW_OP_lit17: case DW_OP_lit18: case DW_OP_lit19:
84     case DW_OP_lit20: case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23:
85     case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: case DW_OP_lit27:
86     case DW_OP_lit28: case DW_OP_lit29: case DW_OP_lit30: case DW_OP_lit31:
87       error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
88       break;
89
90     case DW_OP_addr:
91     case DW_OP_const1u:
92     case DW_OP_const2u:
93     case DW_OP_const4u:
94     case DW_OP_const8u:
95     case DW_OP_const1s:
96     case DW_OP_const2s:
97     case DW_OP_const4s:
98     case DW_OP_const8s:
99     case DW_OP_constu:
100     case DW_OP_consts:
101       if(state->stack_size==MC_EXPRESSION_STACK_SIZE)
102         return MC_EXPRESSION_E_STACK_OVERFLOW;
103       error = mc_dwarf_push_value(state, op->number);
104       break;
105
106     // Stack manipulation:
107
108     // Push the value at the top of the stack:
109     case DW_OP_dup:
110       if(state->stack_size==0)
111         return MC_EXPRESSION_E_STACK_UNDERFLOW;
112       else
113         error = mc_dwarf_push_value(state, state->stack[state->stack_size-1]);
114       break;
115
116     case DW_OP_drop:
117       if(state->stack_size==0)
118         return MC_EXPRESSION_E_STACK_UNDERFLOW;
119       else
120         state->stack_size--;
121       break;
122
123     case DW_OP_swap:
124       if(state->stack_size<2)
125         return MC_EXPRESSION_E_STACK_UNDERFLOW;
126       {
127         uintptr_t temp = state->stack[state->stack_size-2];
128         state->stack[state->stack_size-2] = state->stack[state->stack_size-1];
129         state->stack[state->stack_size-1] = temp;
130       }
131       break;
132
133     case DW_OP_over:
134       if(state->stack_size<2)
135         return MC_EXPRESSION_E_STACK_UNDERFLOW;
136       error = mc_dwarf_push_value(state, state->stack[state->stack_size-2]);
137       break;
138
139     // Operations:
140
141     case DW_OP_plus:
142       if(state->stack_size<2)
143         return MC_EXPRESSION_E_STACK_UNDERFLOW;
144       {
145         uintptr_t result = state->stack[state->stack_size-2] + state->stack[state->stack_size-1];
146         state->stack[state->stack_size-2] = result;
147         state->stack_size--;
148       }
149       break;
150
151     case DW_OP_mul:
152       if(state->stack_size<2)
153         return MC_EXPRESSION_E_STACK_UNDERFLOW;
154       {
155         uintptr_t result = state->stack[state->stack_size-2] - state->stack[state->stack_size-1];
156         state->stack[state->stack_size-2] = result;
157         state->stack_size--;
158       }
159       break;
160
161     case DW_OP_plus_uconst:
162       if(state->stack_size==0)
163         return MC_EXPRESSION_E_STACK_UNDERFLOW;
164       state->stack[state->stack_size-1] += op->number;
165       break;
166
167     case DW_OP_not:
168       if(state->stack_size==0)
169         return MC_EXPRESSION_E_STACK_UNDERFLOW;
170       state->stack[state->stack_size-1] = ~state->stack[state->stack_size-1];
171       break;
172
173     case DW_OP_neg:
174       if(state->stack_size==0)
175         return MC_EXPRESSION_E_STACK_UNDERFLOW;
176       {
177         intptr_t value = state->stack[state->stack_size-1];
178         if(value<0) value = -value;
179         state->stack[state->stack_size-1] = value;
180       }
181       break;
182
183     case DW_OP_minus:
184       if(state->stack_size<2)
185         return MC_EXPRESSION_E_STACK_UNDERFLOW;
186       {
187         uintptr_t result = state->stack[state->stack_size-2] - state->stack[state->stack_size-1];
188         state->stack[state->stack_size-2] = result;
189         state->stack_size--;
190       }
191       break;
192
193     case DW_OP_and:
194       if(state->stack_size<2)
195         return MC_EXPRESSION_E_STACK_UNDERFLOW;
196       {
197         uintptr_t result = state->stack[state->stack_size-2] & state->stack[state->stack_size-1];
198         state->stack[state->stack_size-2] = result;
199         state->stack_size--;
200       }
201       break;
202
203     case DW_OP_or:
204       if(state->stack_size<2)
205         return MC_EXPRESSION_E_STACK_UNDERFLOW;
206       {
207         uintptr_t result = state->stack[state->stack_size-2] | state->stack[state->stack_size-1];
208         state->stack[state->stack_size-2] = result;
209         state->stack_size--;
210       }
211       break;
212
213     case DW_OP_xor:
214       if(state->stack_size<2)
215         return MC_EXPRESSION_E_STACK_UNDERFLOW;
216       {
217         uintptr_t result = state->stack[state->stack_size-2] ^ state->stack[state->stack_size-1];
218         state->stack[state->stack_size-2] = result;
219         state->stack_size--;
220       }
221       break;
222
223     case DW_OP_nop:
224       break;
225
226     // Dereference:
227     case DW_OP_deref_size:
228       return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
229
230     case DW_OP_deref:
231       if(state->stack_size==0)
232         return MC_EXPRESSION_E_STACK_UNDERFLOW;
233       {
234         // Computed address:
235         uintptr_t address = (uintptr_t) state->stack[state->stack_size-1];
236         uintptr_t* p = (uintptr_t*)mc_translate_address(address, state->snapshot);
237         state->stack[state->stack_size-1] = *p;
238       }
239       break;
240
241     // Not handled:
242     default:
243      return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
244     }
245
246     if(error) return error;
247   }
248   return 0;
249 }
250
251 // ***** Location
252
253 /** \brief Resolve a location expression
254  *  \deprecated Use mc_dwarf_resolve_expression
255  */
256 Dwarf_Off mc_dwarf_resolve_location(mc_expression_t expression, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot) {
257   s_mc_expression_state_t state;
258   memset(&state, 0, sizeof(s_mc_expression_state_t));
259   state.frame_base = frame_pointer_address;
260   state.cursor = c;
261   state.snapshot = snapshot;
262
263   if(mc_dwarf_execute_expression(expression->size, expression->ops, &state))
264     xbt_die("Error evaluating DWARF expression");
265   if(state.stack_size==0)
266     xbt_die("No value on the stack");
267   else
268     return (Dwarf_Off) state.stack[state.stack_size-1];
269 }
270
271 Dwarf_Off mc_dwarf_resolve_locations(mc_location_list_t locations, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot) {
272
273   unw_word_t ip;
274   if(c) {
275     if(unw_get_reg(c, UNW_REG_IP, &ip))
276       xbt_die("Could not resolve IP");
277   }
278
279   for(size_t i=0; i!=locations->size; ++i) {
280     mc_expression_t expression = locations->locations + i;
281     if( (expression->lowpc==NULL && expression->highpc==NULL)
282       || (c && ip >= (unw_word_t) expression->lowpc && ip < (unw_word_t) expression->highpc)) {
283       return mc_dwarf_resolve_location(expression, c, frame_pointer_address, snapshot);
284     }
285   }
286   xbt_die("Could not resolve location");
287 }
288
289 /** \brief Find the frame base of a given frame
290  *
291  *  \param frame
292  *  \param unw_cursor
293  */
294 void* mc_find_frame_base(dw_frame_t frame, unw_cursor_t* unw_cursor) {
295   return (void*) mc_dwarf_resolve_locations(&frame->frame_base, unw_cursor, NULL, NULL);
296 }
297
298 void mc_dwarf_expression_clear(mc_expression_t expression) {
299   free(expression->ops);
300   expression->ops = NULL;
301   expression->size = 0;
302   expression->lowpc = NULL;
303   expression->highpc = NULL;
304 }
305
306 void mc_dwarf_location_list_clear(mc_location_list_t list) {
307   for(size_t i=0; i!=list->size; ++i) {
308     mc_dwarf_expression_clear(list->locations + i);
309   }
310   free(list->locations);
311   list->locations = NULL;
312   list->size = 0;
313 }
314
315 void mc_dwarf_expression_init(mc_expression_t expression, size_t len, Dwarf_Op* ops) {
316   if(expression->ops) {
317     free(expression->ops);
318   }
319   expression->lowpc = NULL;
320   expression->highpc = NULL;
321   expression->size = len;
322   expression->ops = xbt_malloc(len*sizeof(Dwarf_Op));
323   memcpy(expression->ops, ops, len*sizeof(Dwarf_Op));
324 }
325
326 void mc_dwarf_location_list_init_from_expression(mc_location_list_t target, size_t len, Dwarf_Op* ops) {
327   if(target->locations) {
328     mc_dwarf_location_list_clear(target);
329   }
330   target->size = 1;
331   target->locations = (mc_expression_t) xbt_malloc(sizeof(s_mc_expression_t));
332   mc_dwarf_expression_init(target->locations, len, ops);
333 }
334
335 void mc_dwarf_location_list_init(mc_location_list_t list, mc_object_info_t info, Dwarf_Die* die, Dwarf_Attribute* attr) {
336   if(list->locations) {
337     mc_dwarf_location_list_clear(list);
338   }
339   list->size = 0;
340
341   ptrdiff_t offset = 0;
342   Dwarf_Addr base, start, end;
343   Dwarf_Op *ops;
344   size_t len;
345
346   while (1) {
347
348     offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
349     if (offset==0)
350       return;
351     else if (offset==-1)
352       xbt_die("Error while loading location list");
353
354     int i = list->size;
355     list->size++;
356     list->locations = (mc_expression_t) realloc(list->locations, list->size*sizeof(s_mc_expression_t));
357     mc_expression_t expression = list->locations + i;
358
359     void* base = info->flags & MC_OBJECT_INFO_EXECUTABLE ? 0 : MC_object_base_address(info);
360     mc_dwarf_expression_init(expression, len, ops);
361
362     // If start == 0, this is not a location list:
363     expression->lowpc = start == 0 ? NULL : (char*) base + start;
364     expression->highpc = start == 0 ? NULL : (char*) base + end;
365   }
366
367 }