#include <dwarf.h>
#include <elfutils/libdw.h>
+#include "mc_object_info.h"
#include "mc_private.h"
static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value)
return 0;
}
+/** Convert a DWARF register into a libunwind register
+ *
+ * DWARF and libunwind does not use the same convention for numbering the
+ * registers on some architectures. The function makes the necessary
+ * convertion.
+ */
static int mc_dwarf_register_to_libunwind(int dwarf_register)
{
#if defined(UNW_TARGET_X86_64)
xbt_die("Bad/unknown register number.");
}
#else
-#error This architecture is not supported yet.
+#error This architecture is not supported yet for DWARF expression evaluation.
#endif
}
{
if (!state->frame_base)
return MC_EXPRESSION_E_MISSING_FRAME_BASE;
- error =
- mc_dwarf_push_value(state,
- ((uintptr_t) state->frame_base) + op->number);
+ uintptr_t fb = ((uintptr_t) state->frame_base) + op->number;
+ error = mc_dwarf_push_value(state, fb);
break;
}
- // Constants:
+ // ***** Constants:
+ // Short constant literals:
+ // DW_OP_lit15 pushed the 15 on the stack.
case DW_OP_lit0:
case DW_OP_lit1:
case DW_OP_lit2:
error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
break;
+ // Address from the base address of this ELF object.
+ // Push the address on the stack (base_address + argument).
case DW_OP_addr:
if (!state->object_info)
return MC_EXPRESSION_E_NO_BASE_ADDRESS;
if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
return MC_EXPRESSION_E_STACK_OVERFLOW;
- error = mc_dwarf_push_value(state,
- (Dwarf_Off) (uintptr_t)
- MC_object_base_address(state->object_info) +
- op->number);
+ Dwarf_Off addr = (Dwarf_Off) (uintptr_t)
+ MC_object_base_address(state->object_info) + op->number;
+ error = mc_dwarf_push_value(state, addr);
break;
+ // General constants:
+ // Push the constant argument on the stack.
case DW_OP_const1u:
case DW_OP_const2u:
case DW_OP_const4u:
error = mc_dwarf_push_value(state, op->number);
break;
- // Stack manipulation:
+ // ***** Stack manipulation:
- // Push the value at the top of the stack:
+ // Push another copy/duplicate the value at the top of the stack:
case DW_OP_dup:
if (state->stack_size == 0)
return MC_EXPRESSION_E_STACK_UNDERFLOW;
error = mc_dwarf_push_value(state, state->stack[state->stack_size - 1]);
break;
+ // Pop/drop the top of the stack:
case DW_OP_drop:
if (state->stack_size == 0)
return MC_EXPRESSION_E_STACK_UNDERFLOW;
state->stack_size--;
break;
+ // Swap the two top-most value of the stack:
case DW_OP_swap:
if (state->stack_size < 2)
return MC_EXPRESSION_E_STACK_UNDERFLOW;
}
break;
+ // Duplicate the value under the top of the stack:
case DW_OP_over:
if (state->stack_size < 2)
return MC_EXPRESSION_E_STACK_UNDERFLOW;
error = mc_dwarf_push_value(state, state->stack[state->stack_size - 2]);
break;
- // Operations:
+ // ***** Operations:
+ // Those usually take the top of the stack and the next value as argument
+ // and replace the top of the stack with the computed value
+ // (stack.top() += stack.before_top()).
case DW_OP_plus:
if (state->stack_size < 2)
case DW_OP_nop:
break;
- // Dereference:
+ // ***** Deference (memory fetch)
+
case DW_OP_deref_size:
return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
{
// Computed address:
uintptr_t address = (uintptr_t) state->stack[state->stack_size - 1];
- uintptr_t temp;
- uintptr_t* res = (uintptr_t*) mc_snapshot_read((void*) address, state->snapshot, state->process_index, &temp, sizeof(uintptr_t));
- state->stack[state->stack_size - 1] = *res;
+ if (!state->address_space)
+ xbt_die("Missing address space");
+ MC_address_space_read(
+ state->address_space, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+ &state->stack[state->stack_size - 1], (const void*) address,
+ sizeof(uintptr_t), state->process_index);
}
break;
/** \brief Resolve a location expression
* \deprecated Use mc_dwarf_resolve_expression
*/
-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, int process_index)
+void mc_dwarf_resolve_location(mc_location_t location,
+ mc_expression_t expression,
+ mc_object_info_t object_info,
+ unw_cursor_t * c,
+ void *frame_pointer_address,
+ mc_address_space_t address_space, int process_index)
{
s_mc_expression_state_t state;
memset(&state, 0, sizeof(s_mc_expression_state_t));
state.frame_base = frame_pointer_address;
state.cursor = c;
- state.snapshot = snapshot;
+ state.address_space = address_space;
state.object_info = object_info;
state.process_index = process_index;
+ if (expression->size >= 1
+ && expression->ops[0].atom >=DW_OP_reg0 && expression->ops[0].atom <= DW_OP_reg31) {
+ int dwarf_register = expression->ops[0].atom - DW_OP_reg0;
+ xbt_assert(c, "Missing frame context for register operation DW_OP_reg%i",
+ dwarf_register);
+ location->memory_location = NULL;
+ location->cursor = c;
+ location->register_id = mc_dwarf_register_to_libunwind(dwarf_register);
+ return;
+ }
+
if (mc_dwarf_execute_expression(expression->size, expression->ops, &state))
xbt_die("Error evaluating DWARF expression");
if (state.stack_size == 0)
xbt_die("No value on the stack");
- else
- return state.stack[state.stack_size - 1];
+ else {
+ location->memory_location = (void*) state.stack[state.stack_size - 1];
+ location->cursor = NULL;
+ location->register_id = 0;
+ }
}
-uintptr_t mc_dwarf_resolve_locations(mc_location_list_t locations,
+static mc_expression_t mc_find_expression(mc_location_list_t locations, unw_word_t ip) {
+ for (size_t i = 0; i != locations->size; ++i) {
+ mc_expression_t expression = locations->locations + i;
+ if ((expression->lowpc == NULL && expression->highpc == NULL)
+ || (ip && ip >= (unw_word_t) expression->lowpc
+ && ip < (unw_word_t) expression->highpc)) {
+ return expression;
+ }
+ }
+ return NULL;
+}
+
+void mc_dwarf_resolve_locations(mc_location_t location,
+ mc_location_list_t locations,
mc_object_info_t object_info,
unw_cursor_t * c,
void *frame_pointer_address,
- mc_snapshot_t snapshot, int process_index)
+ mc_address_space_t address_space, int process_index)
{
- unw_word_t ip;
+ unw_word_t ip = 0;
if (c) {
if (unw_get_reg(c, UNW_REG_IP, &ip))
xbt_die("Could not resolve IP");
}
- for (size_t i = 0; i != locations->size; ++i) {
- mc_expression_t expression = locations->locations + i;
- if ((expression->lowpc == NULL && expression->highpc == NULL)
- || (c && ip >= (unw_word_t) expression->lowpc
- && ip < (unw_word_t) expression->highpc)) {
- return mc_dwarf_resolve_location(expression, object_info, c,
- frame_pointer_address, snapshot, process_index);
- }
+ mc_expression_t expression = mc_find_expression(locations, ip);
+ if (expression) {
+ mc_dwarf_resolve_location(location,
+ expression, object_info, c,
+ frame_pointer_address, address_space, process_index);
+ } else {
+ xbt_die("Could not resolve location");
}
- xbt_die("Could not resolve location");
}
/** \brief Find the frame base of a given frame
void *mc_find_frame_base(dw_frame_t frame, mc_object_info_t object_info,
unw_cursor_t * unw_cursor)
{
- return (void *) mc_dwarf_resolve_locations(&frame->frame_base, object_info,
- unw_cursor, NULL, NULL, -1);
+ s_mc_location_t location;
+ mc_dwarf_resolve_locations(&location,
+ &frame->frame_base, object_info,
+ unw_cursor, NULL, NULL, -1);
+ switch(mc_get_location_type(&location)) {
+ case MC_LOCATION_TYPE_ADDRESS:
+ return location.memory_location;
+
+ case MC_LOCATION_TYPE_REGISTER: {
+ // This is a special case.
+ // The register if not the location of the frame base
+ // (a frame base cannot be located in a register)
+ // Instead, DWARF defines this to mean that the register
+ // contains the address of the frame base.
+ unw_word_t word;
+ unw_get_reg(location.cursor, location.register_id, &word);
+ return (void*) word;
+ }
+
+ default:
+ xbt_die("Cannot handle non-address frame base");
+ return NULL; // Unreachable
+ }
}
void mc_dwarf_expression_clear(mc_expression_t expression)