Logo AND Algorithmique Numérique Distribuée

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