X-Git-Url: http://bilbo.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/dc9d4601416c48fbfed05be80d69cb7fd0d56794..2c1245acbee0af3cd92adf3991575ff8c2f490ad:/src/mc/mc_dwarf_expression.c diff --git a/src/mc/mc_dwarf_expression.c b/src/mc/mc_dwarf_expression.c index a73ac2f52a..e92da2acdc 100644 --- a/src/mc/mc_dwarf_expression.c +++ b/src/mc/mc_dwarf_expression.c @@ -1,3 +1,8 @@ +/* Copyright (c) 2014. The SimGrid Team. + * All rights reserved. */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ #include #include @@ -15,6 +20,45 @@ static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value) { return 0; } +static int mc_dwarf_register_to_libunwind(int dwarf_register) { + #if defined(UNW_TARGET_X86_64) + // It seems for this arch, DWARF and libunwind agree in the numbering: + return dwarf_register; + #elif defined(UNW_TARGET_X86) + // Could't find the authoritative source of information for this. + // This is inspired from http://source.winehq.org/source/dlls/dbghelp/cpu_i386.c#L517. + switch(dwarf_register) { + case 0: return UNW_X86_EAX; + case 1: return UNW_X86_ECX; + case 2: return UNW_X86_EDX; + case 3: return UNW_X86_EBX; + case 4: return UNW_X86_ESP; + case 5: return UNW_X86_EBP; + case 6: return UNW_X86_ESI; + case 7: return UNW_X86_EDI; + case 8: return UNW_X86_EIP; + case 9: return UNW_X86_EFLAGS; + case 10: return UNW_X86_CS; + case 11: return UNW_X86_SS; + case 12: return UNW_X86_DS; + case 13: return UNW_X86_ES; + case 14: return UNW_X86_FS; + case 15: return UNW_X86_GS; + case 16: return UNW_X86_ST0; + case 17: return UNW_X86_ST1; + case 18: return UNW_X86_ST2; + case 19: return UNW_X86_ST3; + case 20: return UNW_X86_ST4; + case 21: return UNW_X86_ST5; + case 22: return UNW_X86_ST6; + case 23: return UNW_X86_ST7; + default: xbt_die("Bad/unknown register number."); + } + #else + #error This architecture is not supported yet. + #endif +} + int mc_dwarf_execute_expression( size_t n, const Dwarf_Op* ops, mc_expression_state_t state) { for(int i=0; i!=n; ++i) { @@ -34,7 +78,7 @@ int mc_dwarf_execute_expression( case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23: case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31:{ - int register_id = op->atom - DW_OP_breg0; + int register_id = mc_dwarf_register_to_libunwind(op->atom - DW_OP_breg0); unw_word_t res; if(!state->cursor) return MC_EXPRESSION_E_MISSING_STACK_CONTEXT; @@ -43,6 +87,26 @@ int mc_dwarf_execute_expression( break; } + // Push the CFA (Canonical Frame Addresse): + case DW_OP_call_frame_cfa: + { + // UNW_X86_64_CFA does not return the CFA DWARF expects + // (it is a synonym for UNW_X86_64_RSP) so copy the cursor, + // unwind it once in order to find the parent SP: + + if(!state->cursor) + return MC_EXPRESSION_E_MISSING_STACK_CONTEXT; + + // Get frame: + unw_cursor_t cursor = *(state->cursor); + unw_step(&cursor); + + unw_word_t res; + unw_get_reg(&cursor, UNW_TDEP_SP, &res); + error = mc_dwarf_push_value(state, res); + break; + } + // Frame base: case DW_OP_fbreg: @@ -53,6 +117,7 @@ int mc_dwarf_execute_expression( break; } + // Constants: case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3: @@ -67,6 +132,14 @@ int mc_dwarf_execute_expression( break; 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); + break; + case DW_OP_const1u: case DW_OP_const2u: case DW_OP_const4u: @@ -204,9 +277,19 @@ int mc_dwarf_execute_expression( // Dereference: case DW_OP_deref_size: - case DW_OP_deref: return MC_EXPRESSION_E_UNSUPPORTED_OPERATION; + case DW_OP_deref: + if(state->stack_size==0) + return MC_EXPRESSION_E_STACK_UNDERFLOW; + { + // Computed address: + uintptr_t address = (uintptr_t) state->stack[state->stack_size-1]; + uintptr_t* p = (uintptr_t*)mc_translate_address(address, state->snapshot); + state->stack[state->stack_size-1] = *p; + } + break; + // Not handled: default: return MC_EXPRESSION_E_UNSUPPORTED_OPERATION; @@ -222,17 +305,116 @@ int mc_dwarf_execute_expression( /** \brief Resolve a location expression * \deprecated Use mc_dwarf_resolve_expression */ -Dwarf_Off mc_dwarf_resolve_location(mc_expression_t expression, unw_cursor_t* c, void* frame_pointer_address) { +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) { 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.object_info = object_info; 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 (Dwarf_Off) state.stack[state.stack_size-1]; + return state.stack[state.stack_size-1]; +} + +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) { + + unw_word_t ip; + 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); + } + } + xbt_die("Could not resolve location"); +} + +/** \brief Find the frame base of a given frame + * + * \param frame + * \param unw_cursor + */ +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); +} + +void mc_dwarf_expression_clear(mc_expression_t expression) { + free(expression->ops); + expression->ops = NULL; + expression->size = 0; + expression->lowpc = NULL; + expression->highpc = NULL; +} + +void mc_dwarf_location_list_clear(mc_location_list_t list) { + for(size_t i=0; i!=list->size; ++i) { + mc_dwarf_expression_clear(list->locations + i); + } + free(list->locations); + list->locations = NULL; + list->size = 0; +} + +void mc_dwarf_expression_init(mc_expression_t expression, size_t len, Dwarf_Op* ops) { + if(expression->ops) { + free(expression->ops); + } + expression->lowpc = NULL; + expression->highpc = NULL; + expression->size = len; + expression->ops = xbt_malloc(len*sizeof(Dwarf_Op)); + memcpy(expression->ops, ops, len*sizeof(Dwarf_Op)); +} + +void mc_dwarf_location_list_init_from_expression(mc_location_list_t target, size_t len, Dwarf_Op* ops) { + if(target->locations) { + mc_dwarf_location_list_clear(target); + } + target->size = 1; + target->locations = (mc_expression_t) xbt_malloc(sizeof(s_mc_expression_t)); + mc_dwarf_expression_init(target->locations, len, ops); } +void mc_dwarf_location_list_init(mc_location_list_t list, mc_object_info_t info, Dwarf_Die* die, Dwarf_Attribute* attr) { + if(list->locations) { + mc_dwarf_location_list_clear(list); + } + list->size = 0; + + ptrdiff_t offset = 0; + Dwarf_Addr base, start, end; + Dwarf_Op *ops; + size_t len; + + while (1) { + + offset = dwarf_getlocations(attr, offset, &base, &start, &end, &ops, &len); + if (offset==0) + return; + else if (offset==-1) + xbt_die("Error while loading location list"); + + int i = list->size; + list->size++; + list->locations = (mc_expression_t) realloc(list->locations, list->size*sizeof(s_mc_expression_t)); + mc_expression_t expression = list->locations + i; + expression->ops = NULL; + mc_dwarf_expression_init(expression, len, ops); + + void* base = info->flags & MC_OBJECT_INFO_EXECUTABLE ? 0 : MC_object_base_address(info); + // If start == 0, this is not a location list: + expression->lowpc = start == 0 ? NULL : (char*) base + start; + expression->highpc = start == 0 ? NULL : (char*) base + end; + } + +}