1 /* Copyright (c) 2014. The SimGrid Team.
2 * All rights reserved. */
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. */
11 #include <elfutils/libdw.h>
13 #include "mc_private.h"
15 static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value)
17 if (state->stack_size >= MC_EXPRESSION_STACK_SIZE)
18 return MC_EXPRESSION_E_STACK_OVERFLOW;
20 state->stack[state->stack_size++] = value;
24 static int mc_dwarf_register_to_libunwind(int dwarf_register)
26 #if defined(UNW_TARGET_X86_64)
27 // It seems for this arch, DWARF and libunwind agree in the numbering:
28 return dwarf_register;
29 #elif defined(UNW_TARGET_X86)
30 // Could't find the authoritative source of information for this.
31 // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517.
32 switch (dwarf_register) {
52 return UNW_X86_EFLAGS;
82 xbt_die("Bad/unknown register number.");
85 #error This architecture is not supported yet.
89 int mc_dwarf_execute_expression(size_t n, const Dwarf_Op * ops,
90 mc_expression_state_t state)
92 for (int i = 0; i != n; ++i) {
94 const Dwarf_Op *op = ops + i;
95 uint8_t atom = op->atom;
134 mc_dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
137 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
138 unw_get_reg(state->cursor, register_id, &res);
139 error = mc_dwarf_push_value(state, res + op->number);
143 // Push the CFA (Canonical Frame Addresse):
144 case DW_OP_call_frame_cfa:
146 // UNW_X86_64_CFA does not return the CFA DWARF expects
147 // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
148 // unwind it once in order to find the parent SP:
151 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
154 unw_cursor_t cursor = *(state->cursor);
158 unw_get_reg(&cursor, UNW_TDEP_SP, &res);
159 error = mc_dwarf_push_value(state, res);
167 if (!state->frame_base)
168 return MC_EXPRESSION_E_MISSING_FRAME_BASE;
170 mc_dwarf_push_value(state,
171 ((uintptr_t) state->frame_base) + op->number);
210 error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
214 if (!state->object_info)
215 return MC_EXPRESSION_E_NO_BASE_ADDRESS;
216 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
217 return MC_EXPRESSION_E_STACK_OVERFLOW;
218 error = mc_dwarf_push_value(state,
219 (Dwarf_Off) (uintptr_t)
220 MC_object_base_address(state->object_info) +
234 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
235 return MC_EXPRESSION_E_STACK_OVERFLOW;
236 error = mc_dwarf_push_value(state, op->number);
239 // Stack manipulation:
241 // Push the value at the top of the stack:
243 if (state->stack_size == 0)
244 return MC_EXPRESSION_E_STACK_UNDERFLOW;
246 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 1]);
250 if (state->stack_size == 0)
251 return MC_EXPRESSION_E_STACK_UNDERFLOW;
257 if (state->stack_size < 2)
258 return MC_EXPRESSION_E_STACK_UNDERFLOW;
260 uintptr_t temp = state->stack[state->stack_size - 2];
261 state->stack[state->stack_size - 2] =
262 state->stack[state->stack_size - 1];
263 state->stack[state->stack_size - 1] = temp;
268 if (state->stack_size < 2)
269 return MC_EXPRESSION_E_STACK_UNDERFLOW;
270 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 2]);
276 if (state->stack_size < 2)
277 return MC_EXPRESSION_E_STACK_UNDERFLOW;
280 state->stack[state->stack_size - 2] +
281 state->stack[state->stack_size - 1];
282 state->stack[state->stack_size - 2] = result;
288 if (state->stack_size < 2)
289 return MC_EXPRESSION_E_STACK_UNDERFLOW;
292 state->stack[state->stack_size - 2] -
293 state->stack[state->stack_size - 1];
294 state->stack[state->stack_size - 2] = result;
299 case DW_OP_plus_uconst:
300 if (state->stack_size == 0)
301 return MC_EXPRESSION_E_STACK_UNDERFLOW;
302 state->stack[state->stack_size - 1] += op->number;
306 if (state->stack_size == 0)
307 return MC_EXPRESSION_E_STACK_UNDERFLOW;
308 state->stack[state->stack_size - 1] =
309 ~state->stack[state->stack_size - 1];
313 if (state->stack_size == 0)
314 return MC_EXPRESSION_E_STACK_UNDERFLOW;
316 intptr_t value = state->stack[state->stack_size - 1];
319 state->stack[state->stack_size - 1] = value;
324 if (state->stack_size < 2)
325 return MC_EXPRESSION_E_STACK_UNDERFLOW;
328 state->stack[state->stack_size - 2] -
329 state->stack[state->stack_size - 1];
330 state->stack[state->stack_size - 2] = result;
336 if (state->stack_size < 2)
337 return MC_EXPRESSION_E_STACK_UNDERFLOW;
340 state->stack[state->stack_size -
341 2] & state->stack[state->stack_size - 1];
342 state->stack[state->stack_size - 2] = result;
348 if (state->stack_size < 2)
349 return MC_EXPRESSION_E_STACK_UNDERFLOW;
352 state->stack[state->stack_size -
353 2] | state->stack[state->stack_size - 1];
354 state->stack[state->stack_size - 2] = result;
360 if (state->stack_size < 2)
361 return MC_EXPRESSION_E_STACK_UNDERFLOW;
364 state->stack[state->stack_size -
365 2] ^ state->stack[state->stack_size - 1];
366 state->stack[state->stack_size - 2] = result;
375 case DW_OP_deref_size:
376 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
379 if (state->stack_size == 0)
380 return MC_EXPRESSION_E_STACK_UNDERFLOW;
383 uintptr_t address = (uintptr_t) state->stack[state->stack_size - 1];
385 uintptr_t* res = (uintptr_t*) mc_snapshot_read((void*) address, state->snapshot, state->process_index, &temp, sizeof(uintptr_t));
386 state->stack[state->stack_size - 1] = *res;
392 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
403 /** \brief Resolve a location expression
404 * \deprecated Use mc_dwarf_resolve_expression
406 uintptr_t mc_dwarf_resolve_location(mc_expression_t expression,
407 mc_object_info_t object_info,
409 void *frame_pointer_address,
410 mc_snapshot_t snapshot, int process_index)
412 s_mc_expression_state_t state;
413 memset(&state, 0, sizeof(s_mc_expression_state_t));
414 state.frame_base = frame_pointer_address;
416 state.snapshot = snapshot;
417 state.object_info = object_info;
418 state.process_index = process_index;
420 if (mc_dwarf_execute_expression(expression->size, expression->ops, &state))
421 xbt_die("Error evaluating DWARF expression");
422 if (state.stack_size == 0)
423 xbt_die("No value on the stack");
425 return state.stack[state.stack_size - 1];
428 uintptr_t mc_dwarf_resolve_locations(mc_location_list_t locations,
429 mc_object_info_t object_info,
431 void *frame_pointer_address,
432 mc_snapshot_t snapshot, int process_index)
437 if (unw_get_reg(c, UNW_REG_IP, &ip))
438 xbt_die("Could not resolve IP");
441 for (size_t i = 0; i != locations->size; ++i) {
442 mc_expression_t expression = locations->locations + i;
443 if ((expression->lowpc == NULL && expression->highpc == NULL)
444 || (c && ip >= (unw_word_t) expression->lowpc
445 && ip < (unw_word_t) expression->highpc)) {
446 return mc_dwarf_resolve_location(expression, object_info, c,
447 frame_pointer_address, snapshot, process_index);
450 xbt_die("Could not resolve location");
453 /** \brief Find the frame base of a given frame
458 void *mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info,
459 unw_cursor_t * unw_cursor)
461 return (void *) mc_dwarf_resolve_locations(&frame->frame_base, object_info,
462 unw_cursor, NULL, NULL, -1);
465 void mc_dwarf_expression_clear(mc_expression_t expression)
467 free(expression->ops);
468 expression->ops = NULL;
469 expression->size = 0;
470 expression->lowpc = NULL;
471 expression->highpc = NULL;
474 void mc_dwarf_location_list_clear(mc_location_list_t list)
476 for (size_t i = 0; i != list->size; ++i) {
477 mc_dwarf_expression_clear(list->locations + i);
479 free(list->locations);
480 list->locations = NULL;
484 void mc_dwarf_expression_init(mc_expression_t expression, size_t len,
487 expression->lowpc = NULL;
488 expression->highpc = NULL;
489 expression->size = len;
490 expression->ops = xbt_malloc(len * sizeof(Dwarf_Op));
491 memcpy(expression->ops, ops, len * sizeof(Dwarf_Op));
494 void mc_dwarf_location_list_init_from_expression(mc_location_list_t target,
495 size_t len, Dwarf_Op * ops)
498 target->locations = (mc_expression_t) xbt_malloc(sizeof(s_mc_expression_t));
499 mc_dwarf_expression_init(target->locations, len, ops);
502 void mc_dwarf_location_list_init(mc_location_list_t list, mc_object_info_t info,
503 Dwarf_Die * die, Dwarf_Attribute * attr)
505 if (list->locations) {
506 mc_dwarf_location_list_clear(list);
510 ptrdiff_t offset = 0;
511 Dwarf_Addr base, start, end;
517 offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
520 else if (offset == -1)
521 xbt_die("Error while loading location list");
526 (mc_expression_t) realloc(list->locations,
527 list->size * sizeof(s_mc_expression_t));
528 mc_expression_t expression = list->locations + i;
529 expression->ops = NULL;
530 mc_dwarf_expression_init(expression, len, ops);
534 flags & MC_OBJECT_INFO_EXECUTABLE ? 0 : MC_object_base_address(info);
535 // If start == 0, this is not a location list:
536 expression->lowpc = start == 0 ? NULL : (char *) base + start;
537 expression->highpc = start == 0 ? NULL : (char *) base + end;