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_private.h"
16 static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value)
18 if (state->stack_size >= MC_EXPRESSION_STACK_SIZE)
19 return MC_EXPRESSION_E_STACK_OVERFLOW;
21 state->stack[state->stack_size++] = value;
25 /** Convert a DWARF register into a libunwind register
27 * DWARF and libunwind does not use the same convention for numbering the
28 * registers on some architectures. The function makes the necessary
31 static int mc_dwarf_register_to_libunwind(int dwarf_register)
33 #if defined(UNW_TARGET_X86_64)
34 // It seems for this arch, DWARF and libunwind agree in the numbering:
35 return dwarf_register;
36 #elif defined(UNW_TARGET_X86)
37 // Could't find the authoritative source of information for this.
38 // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517.
39 switch (dwarf_register) {
59 return UNW_X86_EFLAGS;
89 xbt_die("Bad/unknown register number.");
92 #error This architecture is not supported yet for DWARF expression evaluation.
96 int mc_dwarf_execute_expression(size_t n, const Dwarf_Op * ops,
97 mc_expression_state_t state)
99 for (int i = 0; i != n; ++i) {
101 const Dwarf_Op *op = ops + i;
102 uint8_t atom = op->atom;
141 mc_dwarf_register_to_libunwind(op->atom - DW_OP_breg0);
144 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
145 unw_get_reg(state->cursor, register_id, &res);
146 error = mc_dwarf_push_value(state, res + op->number);
150 // Push the CFA (Canonical Frame Addresse):
151 case DW_OP_call_frame_cfa:
153 // UNW_X86_64_CFA does not return the CFA DWARF expects
154 // (it is a synonym for UNW_X86_64_RSP) so copy the cursor,
155 // unwind it once in order to find the parent SP:
158 return MC_EXPRESSION_E_MISSING_STACK_CONTEXT;
161 unw_cursor_t cursor = *(state->cursor);
165 unw_get_reg(&cursor, UNW_TDEP_SP, &res);
166 error = mc_dwarf_push_value(state, res);
174 if (!state->frame_base)
175 return MC_EXPRESSION_E_MISSING_FRAME_BASE;
176 uintptr_t fb = ((uintptr_t) state->frame_base) + op->number;
177 error = mc_dwarf_push_value(state, fb);
184 // Short constant literals:
185 // DW_OP_lit15 pushed the 15 on the stack.
218 error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
221 // Address from the base address of this ELF object.
222 // Push the address on the stack (base_address + argument).
224 if (!state->object_info)
225 return MC_EXPRESSION_E_NO_BASE_ADDRESS;
226 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
227 return MC_EXPRESSION_E_STACK_OVERFLOW;
228 Dwarf_Off addr = (Dwarf_Off) (uintptr_t)
229 MC_object_base_address(state->object_info) + op->number;
230 error = mc_dwarf_push_value(state, addr);
233 // General constants:
234 // Push the constant argument on the stack.
245 if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
246 return MC_EXPRESSION_E_STACK_OVERFLOW;
247 error = mc_dwarf_push_value(state, op->number);
250 // ***** Stack manipulation:
252 // Push another copy/duplicate the value at the top of the stack:
254 if (state->stack_size == 0)
255 return MC_EXPRESSION_E_STACK_UNDERFLOW;
257 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 1]);
260 // Pop/drop the top of the stack:
262 if (state->stack_size == 0)
263 return MC_EXPRESSION_E_STACK_UNDERFLOW;
268 // Swap the two top-most value of the stack:
270 if (state->stack_size < 2)
271 return MC_EXPRESSION_E_STACK_UNDERFLOW;
273 uintptr_t temp = state->stack[state->stack_size - 2];
274 state->stack[state->stack_size - 2] =
275 state->stack[state->stack_size - 1];
276 state->stack[state->stack_size - 1] = temp;
280 // Duplicate the value under the top of the stack:
282 if (state->stack_size < 2)
283 return MC_EXPRESSION_E_STACK_UNDERFLOW;
284 error = mc_dwarf_push_value(state, state->stack[state->stack_size - 2]);
288 // Those usually take the top of the stack and the next value as argument
289 // and replace the top of the stack with the computed value
290 // (stack.top() += stack.before_top()).
293 if (state->stack_size < 2)
294 return MC_EXPRESSION_E_STACK_UNDERFLOW;
297 state->stack[state->stack_size - 2] +
298 state->stack[state->stack_size - 1];
299 state->stack[state->stack_size - 2] = result;
305 if (state->stack_size < 2)
306 return MC_EXPRESSION_E_STACK_UNDERFLOW;
309 state->stack[state->stack_size - 2] -
310 state->stack[state->stack_size - 1];
311 state->stack[state->stack_size - 2] = result;
316 case DW_OP_plus_uconst:
317 if (state->stack_size == 0)
318 return MC_EXPRESSION_E_STACK_UNDERFLOW;
319 state->stack[state->stack_size - 1] += op->number;
323 if (state->stack_size == 0)
324 return MC_EXPRESSION_E_STACK_UNDERFLOW;
325 state->stack[state->stack_size - 1] =
326 ~state->stack[state->stack_size - 1];
330 if (state->stack_size == 0)
331 return MC_EXPRESSION_E_STACK_UNDERFLOW;
333 intptr_t value = state->stack[state->stack_size - 1];
336 state->stack[state->stack_size - 1] = value;
341 if (state->stack_size < 2)
342 return MC_EXPRESSION_E_STACK_UNDERFLOW;
345 state->stack[state->stack_size - 2] -
346 state->stack[state->stack_size - 1];
347 state->stack[state->stack_size - 2] = result;
353 if (state->stack_size < 2)
354 return MC_EXPRESSION_E_STACK_UNDERFLOW;
357 state->stack[state->stack_size -
358 2] & state->stack[state->stack_size - 1];
359 state->stack[state->stack_size - 2] = result;
365 if (state->stack_size < 2)
366 return MC_EXPRESSION_E_STACK_UNDERFLOW;
369 state->stack[state->stack_size -
370 2] | state->stack[state->stack_size - 1];
371 state->stack[state->stack_size - 2] = result;
377 if (state->stack_size < 2)
378 return MC_EXPRESSION_E_STACK_UNDERFLOW;
381 state->stack[state->stack_size -
382 2] ^ state->stack[state->stack_size - 1];
383 state->stack[state->stack_size - 2] = result;
391 // ***** Deference (memory fetch)
393 case DW_OP_deref_size:
394 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
397 if (state->stack_size == 0)
398 return MC_EXPRESSION_E_STACK_UNDERFLOW;
401 uintptr_t address = (uintptr_t) state->stack[state->stack_size - 1];
403 if (state->address_space) {
405 const uintptr_t* res = (uintptr_t*) MC_address_space_read(
406 state->address_space, MC_ADDRESS_SPACE_READ_FLAGS_LAZY,
407 &temp, (const void*) address, sizeof(uintptr_t), state->process_index);
411 // TODO, use a mc_process representing the current process instead of this
412 value = *(const uintptr_t*) address;
414 state->stack[state->stack_size - 1] = value;
420 return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
431 /** \brief Resolve a location expression
432 * \deprecated Use mc_dwarf_resolve_expression
434 void mc_dwarf_resolve_location(mc_location_t location,
435 mc_expression_t expression,
436 mc_object_info_t object_info,
438 void *frame_pointer_address,
439 mc_address_space_t address_space, int process_index)
441 s_mc_expression_state_t state;
442 memset(&state, 0, sizeof(s_mc_expression_state_t));
443 state.frame_base = frame_pointer_address;
445 state.address_space = address_space;
446 state.object_info = object_info;
447 state.process_index = process_index;
449 if (expression->size >= 1
450 && expression->ops[0].atom >=DW_OP_reg0 && expression->ops[0].atom <= DW_OP_reg31) {
451 int dwarf_register = expression->ops[0].atom - DW_OP_reg0;
452 xbt_assert(c, "Missing frame context for register operation DW_OP_reg%i",
454 location->memory_location = NULL;
455 location->cursor = c;
456 location->register_id = mc_dwarf_register_to_libunwind(dwarf_register);
460 if (mc_dwarf_execute_expression(expression->size, expression->ops, &state))
461 xbt_die("Error evaluating DWARF expression");
462 if (state.stack_size == 0)
463 xbt_die("No value on the stack");
465 location->memory_location = (void*) state.stack[state.stack_size - 1];
466 location->cursor = NULL;
467 location->register_id = 0;
471 static mc_expression_t mc_find_expression(mc_location_list_t locations, unw_word_t ip) {
472 for (size_t i = 0; i != locations->size; ++i) {
473 mc_expression_t expression = locations->locations + i;
474 if ((expression->lowpc == NULL && expression->highpc == NULL)
475 || (ip && ip >= (unw_word_t) expression->lowpc
476 && ip < (unw_word_t) expression->highpc)) {
483 void mc_dwarf_resolve_locations(mc_location_t location,
484 mc_location_list_t locations,
485 mc_object_info_t object_info,
487 void *frame_pointer_address,
488 mc_address_space_t address_space, int process_index)
493 if (unw_get_reg(c, UNW_REG_IP, &ip))
494 xbt_die("Could not resolve IP");
497 mc_expression_t expression = mc_find_expression(locations, ip);
499 mc_dwarf_resolve_location(location,
500 expression, object_info, c,
501 frame_pointer_address, address_space, process_index);
503 xbt_die("Could not resolve location");
507 /** \brief Find the frame base of a given frame
512 void *mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info,
513 unw_cursor_t * unw_cursor)
515 s_mc_location_t location;
516 mc_dwarf_resolve_locations(&location,
517 &frame->frame_base, object_info,
518 unw_cursor, NULL, NULL, -1);
519 switch(mc_get_location_type(&location)) {
520 case MC_LOCATION_TYPE_ADDRESS:
521 return location.memory_location;
523 case MC_LOCATION_TYPE_REGISTER: {
524 // This is a special case.
525 // The register if not the location of the frame base
526 // (a frame base cannot be located in a register)
527 // Instead, DWARF defines this to mean that the register
528 // contains the address of the frame base.
530 unw_get_reg(location.cursor, location.register_id, &word);
535 xbt_die("Cannot handle non-address frame base");
536 return NULL; // Unreachable
540 void mc_dwarf_expression_clear(mc_expression_t expression)
542 free(expression->ops);
543 expression->ops = NULL;
544 expression->size = 0;
545 expression->lowpc = NULL;
546 expression->highpc = NULL;
549 void mc_dwarf_location_list_clear(mc_location_list_t list)
551 for (size_t i = 0; i != list->size; ++i) {
552 mc_dwarf_expression_clear(list->locations + i);
554 free(list->locations);
555 list->locations = NULL;
559 void mc_dwarf_expression_init(mc_expression_t expression, size_t len,
562 expression->lowpc = NULL;
563 expression->highpc = NULL;
564 expression->size = len;
565 expression->ops = xbt_malloc(len * sizeof(Dwarf_Op));
566 memcpy(expression->ops, ops, len * sizeof(Dwarf_Op));
569 void mc_dwarf_location_list_init_from_expression(mc_location_list_t target,
570 size_t len, Dwarf_Op * ops)
573 target->locations = (mc_expression_t) xbt_malloc(sizeof(s_mc_expression_t));
574 mc_dwarf_expression_init(target->locations, len, ops);
577 void mc_dwarf_location_list_init(mc_location_list_t list, mc_object_info_t info,
578 Dwarf_Die * die, Dwarf_Attribute * attr)
580 if (list->locations) {
581 mc_dwarf_location_list_clear(list);
585 ptrdiff_t offset = 0;
586 Dwarf_Addr base, start, end;
592 offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len);
595 else if (offset == -1)
596 xbt_die("Error while loading location list");
601 (mc_expression_t) realloc(list->locations,
602 list->size * sizeof(s_mc_expression_t));
603 mc_expression_t expression = list->locations + i;
604 expression->ops = NULL;
605 mc_dwarf_expression_init(expression, len, ops);
609 flags & MC_OBJECT_INFO_EXECUTABLE ? 0 : MC_object_base_address(info);
610 // If start == 0, this is not a location list:
611 expression->lowpc = start == 0 ? NULL : (char *) base + start;
612 expression->highpc = start == 0 ? NULL : (char *) base + end;