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_object_info.h"
14 #include "mc_snapshot.h"
15 #include "mc_private.h"
17 static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value)
19 if (state->stack_size >= MC_EXPRESSION_STACK_SIZE)
20 return MC_EXPRESSION_E_STACK_OVERFLOW;
22 state->stack[state->stack_size++] = value;
26 /** Convert a DWARF register into a libunwind register
28 * DWARF and libunwind does not use the same convention for numbering the
29 * registers on some architectures. The function makes the necessary
32 static int mc_dwarf_register_to_libunwind(int dwarf_register)
34 #if defined(UNW_TARGET_X86_64)
35 // It seems for this arch, DWARF and libunwind agree in the numbering:
36 return dwarf_register;
37 #elif defined(UNW_TARGET_X86)
38 // Could't find the authoritative source of information for this.
39 // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517.
40 switch (dwarf_register) {
60 return UNW_X86_EFLAGS;
90 xbt_die("Bad/unknown register number.");
93 #error This architecture is not supported yet for DWARF expression evaluation.
97 int mc_dwarf_execute_expression(size_t n, const Dwarf_Op * ops,
98 mc_expression_state_t state)
100 for (int i = 0; i != n; ++i) {
102 const Dwarf_Op *op = ops + i;
103 uint8_t atom = op->atom;
142 mc_dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
145 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
146 unw_get_reg(state->cursor, register_id, &res);
147 error = mc_dwarf_push_value(state, res + op->number);
151 // Push the CFA (Canonical Frame Addresse):
152 case DW_OP_call_frame_cfa:
154 // UNW_X86_64_CFA does not return the CFA DWARF expects
155 // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
156 // unwind it once in order to find the parent SP:
159 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
162 unw_cursor_t cursor = *(state->cursor);
166 unw_get_reg(&cursor, UNW_TDEP_SP, &res);
167 error = mc_dwarf_push_value(state, res);
175 if (!state->frame_base)
176 return MC_EXPRESSION_E_MISSING_FRAME_BASE;
177 uintptr_t fb = ((uintptr_t) state->frame_base) + op->number;
178 error = mc_dwarf_push_value(state, fb);
185 // Short constant literals:
186 // DW_OP_lit15 pushed the 15 on the stack.
219 error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
222 // Address from the base address of this ELF object.
223 // Push the address on the stack (base_address + argument).
225 if (!state->object_info)
226 return MC_EXPRESSION_E_NO_BASE_ADDRESS;
227 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
228 return MC_EXPRESSION_E_STACK_OVERFLOW;
229 Dwarf_Off addr = (Dwarf_Off) (uintptr_t)
230 MC_object_base_address(state->object_info) + op->number;
231 error = mc_dwarf_push_value(state, addr);
234 // General constants:
235 // Push the constant argument on the stack.
246 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
247 return MC_EXPRESSION_E_STACK_OVERFLOW;
248 error = mc_dwarf_push_value(state, op->number);
251 // ***** Stack manipulation:
253 // Push another copy/duplicate the value at the top of the stack:
255 if (state->stack_size == 0)
256 return MC_EXPRESSION_E_STACK_UNDERFLOW;
258 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 1]);
261 // Pop/drop the top of the stack:
263 if (state->stack_size == 0)
264 return MC_EXPRESSION_E_STACK_UNDERFLOW;
269 // Swap the two top-most value of the stack:
271 if (state->stack_size < 2)
272 return MC_EXPRESSION_E_STACK_UNDERFLOW;
274 uintptr_t temp = state->stack[state->stack_size - 2];
275 state->stack[state->stack_size - 2] =
276 state->stack[state->stack_size - 1];
277 state->stack[state->stack_size - 1] = temp;
281 // Duplicate the value under the top of the stack:
283 if (state->stack_size < 2)
284 return MC_EXPRESSION_E_STACK_UNDERFLOW;
285 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 2]);
289 // Those usually take the top of the stack and the next value as argument
290 // and replace the top of the stack with the computed value
291 // (stack.top() += stack.before_top()).
294 if (state->stack_size < 2)
295 return MC_EXPRESSION_E_STACK_UNDERFLOW;
298 state->stack[state->stack_size - 2] +
299 state->stack[state->stack_size - 1];
300 state->stack[state->stack_size - 2] = result;
306 if (state->stack_size < 2)
307 return MC_EXPRESSION_E_STACK_UNDERFLOW;
310 state->stack[state->stack_size - 2] -
311 state->stack[state->stack_size - 1];
312 state->stack[state->stack_size - 2] = result;
317 case DW_OP_plus_uconst:
318 if (state->stack_size == 0)
319 return MC_EXPRESSION_E_STACK_UNDERFLOW;
320 state->stack[state->stack_size - 1] += op->number;
324 if (state->stack_size == 0)
325 return MC_EXPRESSION_E_STACK_UNDERFLOW;
326 state->stack[state->stack_size - 1] =
327 ~state->stack[state->stack_size - 1];
331 if (state->stack_size == 0)
332 return MC_EXPRESSION_E_STACK_UNDERFLOW;
334 intptr_t value = state->stack[state->stack_size - 1];
337 state->stack[state->stack_size - 1] = value;
342 if (state->stack_size < 2)
343 return MC_EXPRESSION_E_STACK_UNDERFLOW;
346 state->stack[state->stack_size - 2] -
347 state->stack[state->stack_size - 1];
348 state->stack[state->stack_size - 2] = result;
354 if (state->stack_size < 2)
355 return MC_EXPRESSION_E_STACK_UNDERFLOW;
358 state->stack[state->stack_size -
359 2] & state->stack[state->stack_size - 1];
360 state->stack[state->stack_size - 2] = result;
366 if (state->stack_size < 2)
367 return MC_EXPRESSION_E_STACK_UNDERFLOW;
370 state->stack[state->stack_size -
371 2] | state->stack[state->stack_size - 1];
372 state->stack[state->stack_size - 2] = result;
378 if (state->stack_size < 2)
379 return MC_EXPRESSION_E_STACK_UNDERFLOW;
382 state->stack[state->stack_size -
383 2] ^ state->stack[state->stack_size - 1];
384 state->stack[state->stack_size - 2] = result;
392 // ***** Deference (memory fetch)
394 case DW_OP_deref_size:
395 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
398 if (state->stack_size == 0)
399 return MC_EXPRESSION_E_STACK_UNDERFLOW;
402 uintptr_t address = (uintptr_t) state->stack[state->stack_size - 1];
404 uintptr_t* res = (uintptr_t*) mc_snapshot_read((void*) address, state->snapshot, state->process_index, &temp, sizeof(uintptr_t));
405 state->stack[state->stack_size - 1] = *res;
411 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
422 /** \brief Resolve a location expression
423 * \deprecated Use mc_dwarf_resolve_expression
425 void mc_dwarf_resolve_location(mc_location_t location,
426 mc_expression_t expression,
427 mc_object_info_t object_info,
429 void *frame_pointer_address,
430 mc_snapshot_t snapshot, int process_index)
432 s_mc_expression_state_t state;
433 memset(&state, 0, sizeof(s_mc_expression_state_t));
434 state.frame_base = frame_pointer_address;
436 state.snapshot = snapshot;
437 state.object_info = object_info;
438 state.process_index = process_index;
440 if (expression->size >= 1
441 && expression->ops[0].atom >=DW_OP_reg0 && expression->ops[0].atom <= DW_OP_reg31) {
442 int dwarf_register = expression->ops[0].atom - DW_OP_reg0;
443 xbt_assert(c, "Missing frame context for register operation DW_OP_reg%i",
445 location->memory_location = NULL;
446 location->cursor = c;
447 location->register_id = mc_dwarf_register_to_libunwind(dwarf_register);
451 if (mc_dwarf_execute_expression(expression->size, expression->ops, &state))
452 xbt_die("Error evaluating DWARF expression");
453 if (state.stack_size == 0)
454 xbt_die("No value on the stack");
456 location->memory_location = (void*) state.stack[state.stack_size - 1];
457 location->cursor = NULL;
458 location->register_id = 0;
462 static mc_expression_t mc_find_expression(mc_location_list_t locations, unw_word_t ip) {
463 for (size_t i = 0; i != locations->size; ++i) {
464 mc_expression_t expression = locations->locations + i;
465 if ((expression->lowpc == NULL && expression->highpc == NULL)
466 || (ip && ip >= (unw_word_t) expression->lowpc
467 && ip < (unw_word_t) expression->highpc)) {
474 void mc_dwarf_resolve_locations(mc_location_t location,
475 mc_location_list_t locations,
476 mc_object_info_t object_info,
478 void *frame_pointer_address,
479 mc_snapshot_t snapshot, int process_index)
484 if (unw_get_reg(c, UNW_REG_IP, &ip))
485 xbt_die("Could not resolve IP");
488 mc_expression_t expression = mc_find_expression(locations, ip);
490 mc_dwarf_resolve_location(location,
491 expression, object_info, c,
492 frame_pointer_address, snapshot, process_index);
494 xbt_die("Could not resolve location");
498 /** \brief Find the frame base of a given frame
503 void *mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info,
504 unw_cursor_t * unw_cursor)
506 s_mc_location_t location;
507 mc_dwarf_resolve_locations(&location,
508 &frame->frame_base, object_info,
509 unw_cursor, NULL, NULL, -1);
510 switch(mc_get_location_type(&location)) {
511 case MC_LOCATION_TYPE_ADDRESS:
512 return location.memory_location;
514 case MC_LOCATION_TYPE_REGISTER: {
515 // This is a special case.
516 // The register if not the location of the frame base
517 // (a frame base cannot be located in a register)
518 // Instead, DWARF defines this to mean that the register
519 // contains the address of the frame base.
521 unw_get_reg(location.cursor, location.register_id, &word);
526 xbt_die("Cannot handle non-address frame base");
527 return NULL; // Unreachable
531 void mc_dwarf_expression_clear(mc_expression_t expression)
533 free(expression->ops);
534 expression->ops = NULL;
535 expression->size = 0;
536 expression->lowpc = NULL;
537 expression->highpc = NULL;
540 void mc_dwarf_location_list_clear(mc_location_list_t list)
542 for (size_t i = 0; i != list->size; ++i) {
543 mc_dwarf_expression_clear(list->locations + i);
545 free(list->locations);
546 list->locations = NULL;
550 void mc_dwarf_expression_init(mc_expression_t expression, size_t len,
553 expression->lowpc = NULL;
554 expression->highpc = NULL;
555 expression->size = len;
556 expression->ops = xbt_malloc(len * sizeof(Dwarf_Op));
557 memcpy(expression->ops, ops, len * sizeof(Dwarf_Op));
560 void mc_dwarf_location_list_init_from_expression(mc_location_list_t target,
561 size_t len, Dwarf_Op * ops)
564 target->locations = (mc_expression_t) xbt_malloc(sizeof(s_mc_expression_t));
565 mc_dwarf_expression_init(target->locations, len, ops);
568 void mc_dwarf_location_list_init(mc_location_list_t list, mc_object_info_t info,
569 Dwarf_Die * die, Dwarf_Attribute * attr)
571 if (list->locations) {
572 mc_dwarf_location_list_clear(list);
576 ptrdiff_t offset = 0;
577 Dwarf_Addr base, start, end;
583 offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
586 else if (offset == -1)
587 xbt_die("Error while loading location list");
592 (mc_expression_t) realloc(list->locations,
593 list->size * sizeof(s_mc_expression_t));
594 mc_expression_t expression = list->locations + i;
595 expression->ops = NULL;
596 mc_dwarf_expression_init(expression, len, ops);
600 flags & MC_OBJECT_INFO_EXECUTABLE ? 0 : MC_object_base_address(info);
601 // If start == 0, this is not a location list:
602 expression->lowpc = start == 0 ? NULL : (char *) base + start;
603 expression->highpc = start == 0 ? NULL : (char *) base + end;