diff options
Diffstat (limited to 'agent')
28 files changed, 1645 insertions, 729 deletions
diff --git a/agent/agent.vcproj b/agent/agent.vcproj index f13dd7c6..786d1fd3 100644 --- a/agent/agent.vcproj +++ b/agent/agent.vcproj @@ -664,6 +664,14 @@ >
</File>
<File
+ RelativePath=".\tcf\services\dwarfecomp.c"
+ >
+ </File>
+ <File
+ RelativePath=".\tcf\services\dwarfecomp.h"
+ >
+ </File>
+ <File
RelativePath=".\tcf\services\dwarfexpr.c"
>
</File>
diff --git a/agent/cmake/build-gcc-debug.sh b/agent/cmake/build-gcc-debug.sh new file mode 100644 index 00000000..c75c3366 --- /dev/null +++ b/agent/cmake/build-gcc-debug.sh @@ -0,0 +1,5 @@ +#!/bin/sh
+[ -d gcc-debug ] || mkdir gcc-debug
+cd gcc-debug
+[ -f Makefile ] || cmake -DCMAKE_BUILD_TYPE=Debug -G "Unix Makefiles" ../..
+make $*
diff --git a/agent/tcf/framework/cpudefs.c b/agent/tcf/framework/cpudefs.c index 56442fd9..77f45e84 100644 --- a/agent/tcf/framework/cpudefs.c +++ b/agent/tcf/framework/cpudefs.c @@ -213,101 +213,134 @@ int id2register(const char * id, Context ** ctx, int * frame, RegisterDefinition return 0; } -static void stack_trace_error(void) { +static void location_expression_error(void) { str_exception(ERR_OTHER, "Invalid stack trace program"); } -uint64_t evaluate_stack_trace_commands(Context * ctx, StackFrame * frame, StackTracingCommandSequence * cmds) { - static uint64_t * stk = NULL; - static int stk_size = 0; +LocationExpressionState * evaluate_location_expression(Context * ctx, StackFrame * frame, + LocationExpressionCommand * cmds, unsigned cmd_cnt, + uint64_t * args, unsigned args_cnt) { + unsigned i; + unsigned stk_pos = 0; + unsigned stk_max = 0; + uint64_t * stk = NULL; + LocationExpressionState * state = (LocationExpressionState *)tmp_alloc_zero(sizeof(LocationExpressionState)); - int i; - int stk_pos = 0; - - for (i = 0; i < cmds->cmds_cnt; i++) { - StackTracingCommand * cmd = cmds->cmds + i; - if (stk_pos >= stk_size) { - stk_size += 4; - stk = (uint64_t *)loc_realloc(stk, sizeof(uint64_t) * stk_size); + state->ctx = ctx; + state->stack_frame = frame; + state->args = args; + state->args_cnt = args_cnt; + for (i = 0; i < cmd_cnt; i++) { + LocationExpressionCommand * cmd = cmds + i; + if (stk_pos >= stk_max) { + stk_max += 4; + stk = (uint64_t *)tmp_realloc(stk, sizeof(uint64_t) * stk_max); } switch (cmd->cmd) { case SFT_CMD_NUMBER: - stk[stk_pos++] = cmd->num; + stk[stk_pos++] = cmd->args.num; break; case SFT_CMD_REGISTER: - if (read_reg_value(frame, cmd->reg, stk + stk_pos) < 0) exception(errno); + if (read_reg_value(frame, cmd->args.reg, stk + stk_pos) < 0) exception(errno); stk_pos++; break; case SFT_CMD_FP: stk[stk_pos++] = frame->fp; break; case SFT_CMD_DEREF: - if (stk_pos < 1) stack_trace_error(); + if (stk_pos < 1) location_expression_error(); { size_t j; - size_t size = cmd->size; + size_t size = cmd->args.deref.size; uint64_t n = 0; uint8_t buf[8]; if (context_read_mem(ctx, (ContextAddress)stk[stk_pos - 1], buf, size) < 0) exception(errno); for (j = 0; j < size; j++) { - n = (n << 8) | buf[cmd->big_endian ? j : size - j - 1]; + n = (n << 8) | buf[cmd->args.deref.big_endian ? j : size - j - 1]; } stk[stk_pos - 1] = n; } break; case SFT_CMD_ADD: - if (stk_pos < 2) stack_trace_error(); + if (stk_pos < 2) location_expression_error(); stk[stk_pos - 2] = stk[stk_pos - 2] + stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_SUB: - if (stk_pos < 2) stack_trace_error(); + if (stk_pos < 2) location_expression_error(); stk[stk_pos - 2] = stk[stk_pos - 2] - stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_AND: - if (stk_pos < 2) stack_trace_error(); + if (stk_pos < 2) location_expression_error(); stk[stk_pos - 2] = stk[stk_pos - 2] & stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_OR: - if (stk_pos < 2) stack_trace_error(); + if (stk_pos < 2) location_expression_error(); stk[stk_pos - 2] = stk[stk_pos - 2] | stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_GE: - if (stk_pos < 2) stack_trace_error(); + if (stk_pos < 2) location_expression_error(); stk[stk_pos - 2] = stk[stk_pos - 2] >= stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_GT: - if (stk_pos < 2) stack_trace_error(); + if (stk_pos < 2) location_expression_error(); stk[stk_pos - 2] = stk[stk_pos - 2] > stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_LE: - if (stk_pos < 2) stack_trace_error(); + if (stk_pos < 2) location_expression_error(); stk[stk_pos - 2] = stk[stk_pos - 2] <= stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_LT: - if (stk_pos < 2) stack_trace_error(); + if (stk_pos < 2) location_expression_error(); stk[stk_pos - 2] = stk[stk_pos - 2] < stk[stk_pos - 1]; stk_pos--; break; case SFT_CMD_SHL: - if (stk_pos < 2) stack_trace_error(); + if (stk_pos < 2) location_expression_error(); stk[stk_pos - 2] <<= stk[stk_pos - 1]; stk_pos--; break; + case SFT_CMD_SHR: + if (stk_pos < 2) location_expression_error(); + stk[stk_pos - 2] >>= stk[stk_pos - 1]; + stk_pos--; + break; + case SFT_CMD_ARG: + if (cmd->args.arg_no >= args_cnt) location_expression_error(); + stk[stk_pos++] = args[cmd->args.arg_no]; + break; + case SFT_CMD_USER: + state->stk = stk; + state->stk_pos = stk_pos; + state->stk_max = stk_max; + state->reg_id_scope = cmd->args.user.reg_id_scope; + state->code = cmd->args.user.code_addr; + state->code_len = cmd->args.user.code_size; + state->code_pos = 0; + state->addr_size = cmd->args.user.addr_size; + state->big_endian = cmd->args.user.big_endian; + state->client_op = NULL; + if (cmd->args.user.func(state) < 0) exception(errno); + stk_max = state->stk_max; + stk_pos = state->stk_pos; + stk = state->stk; + break; default: - stack_trace_error(); + location_expression_error(); break; } } - if (stk_pos == 0) stack_trace_error(); - return stk[stk_pos - 1]; + state->stk = stk; + state->stk_pos = stk_pos; + state->stk_max = stk_max; + return state; } #endif /* ENABLE_DebugContext */ diff --git a/agent/tcf/framework/cpudefs.h b/agent/tcf/framework/cpudefs.h index 4040b657..55fa7254 100644 --- a/agent/tcf/framework/cpudefs.h +++ b/agent/tcf/framework/cpudefs.h @@ -71,7 +71,14 @@ struct RegisterDefinition { const char * role; /* the role the register plays in a program execution */ }; -/* Stack tracing command codes */ +typedef struct RegisterIdScope { + uint16_t machine; + uint8_t os_abi; + uint8_t big_endian; + uint8_t id_type; +} RegisterIdScope; + +/* Location expression command codes */ #define SFT_CMD_NUMBER 1 #define SFT_CMD_REGISTER 2 #define SFT_CMD_FP 3 @@ -85,32 +92,73 @@ struct RegisterDefinition { #define SFT_CMD_LE 11 #define SFT_CMD_LT 12 #define SFT_CMD_SHL 13 +#define SFT_CMD_SHR 14 +#define SFT_CMD_ARG 15 +#define SFT_CMD_USER 16 -/* Stack tracing command */ -typedef struct StackTracingCommand { - int cmd; - int64_t num; - size_t size; +typedef struct LocationPiece { int big_endian; + ContextAddress addr; RegisterDefinition * reg; -} StackTracingCommand; - -/* Stack tracing command sequence */ -typedef struct StackTracingCommandSequence { - RegisterDefinition * reg; - int cmds_cnt; - int cmds_max; - StackTracingCommand cmds[1]; -} StackTracingCommandSequence; + void * value; + size_t size; + unsigned bit_offs; + unsigned bit_size; +} LocationPiece; -/* Complete stack tracing info for a range of instruction addresses */ -typedef struct StackTracingInfo { - ContextAddress addr; - ContextAddress size; - StackTracingCommandSequence * fp; - StackTracingCommandSequence ** regs; - int reg_cnt; -} StackTracingInfo; +typedef struct LocationExpressionState { + /* Evaluation context */ + Context * ctx; + struct StackFrame * stack_frame; + RegisterIdScope reg_id_scope; + int big_endian; + size_t addr_size; + uint64_t * args; + unsigned args_cnt; + + /* Code to execute */ + uint8_t * code; + size_t code_pos; + size_t code_len; + + /* Client callback */ + void (*client_op)(uint8_t op); + + /* Result */ + LocationPiece * pieces; + unsigned pieces_cnt; + unsigned pieces_max; + + /* Evaluation stack */ + unsigned stk_pos; + unsigned stk_max; + uint64_t * stk; +} LocationExpressionState; + +typedef struct LocationExpressionCommand LocationExpressionCommand; +typedef int LocationExpressionCallback(LocationExpressionState *); + +/* Location expression command */ +struct LocationExpressionCommand { + int cmd; + union { + int64_t num; + RegisterDefinition * reg; + struct { + size_t size; + int big_endian; + } deref; + struct { + LocationExpressionCallback * func; + RegisterIdScope reg_id_scope; + uint8_t * code_addr; + size_t code_size; + size_t addr_size; + int big_endian; + } user; + unsigned arg_no; + } args; +}; #define STACK_BOTTOM_FRAME 0 #define STACK_NO_FRAME (-1) @@ -118,19 +166,13 @@ typedef struct StackTracingInfo { typedef struct StackFrame { int is_top_frame; + int is_walked; /* Data collected by: 0 - crawl, 1 - walk */ int has_reg_data; Context * ctx; ContextAddress fp; /* frame address */ RegisterData * regs; /* register values */ } StackFrame; -typedef struct RegisterIdScope { - uint16_t machine; - uint8_t os_abi; - uint8_t big_endian; - uint8_t id_type; -} RegisterIdScope; - /* Return array of CPU register definitions. Last item in the array has name == NULL */ extern RegisterDefinition * get_reg_definitions(Context * ctx); @@ -186,8 +228,10 @@ extern uint8_t * get_break_instruction(Context * ctx, size_t * size); */ extern int crawl_stack_frame(StackFrame * frame, StackFrame * down); -/* Execute stack tracing command sequence */ -extern uint64_t evaluate_stack_trace_commands(Context * ctx, StackFrame * frame, StackTracingCommandSequence * cmds); +/* Execute location expression */ +extern LocationExpressionState * evaluate_location_expression(Context * ctx, StackFrame * frame, + LocationExpressionCommand * cmds, unsigned cmds_cnt, + uint64_t * args, unsigned args_cnt); #endif /* ENABLE_DebugContext */ diff --git a/agent/tcf/main/test.c b/agent/tcf/main/test.c index 47a62cb9..974d4e27 100644 --- a/agent/tcf/main/test.c +++ b/agent/tcf/main/test.c @@ -59,6 +59,7 @@ public: int tcf_cpp_test_class::s_int = 1; int tcf_cpp_test_class::tcf_cpp_test_class_nested::s_int = 2; tcf_cpp_test_class_extension * tcf_cpp_text_ce = (tcf_cpp_test_class_extension *)3; +int tcf_cpp_test_class_extension::* tcf_cpp_test_member_ptr = &tcf_cpp_test_class_extension::f_int; extern "C" { diff --git a/agent/tcf/services/dwarf.h b/agent/tcf/services/dwarf.h index 7df3f5c5..20a47e2b 100644 --- a/agent/tcf/services/dwarf.h +++ b/agent/tcf/services/dwarf.h @@ -206,7 +206,17 @@ #define AT_call_file 0x0058 /* v3 */ #define AT_call_line 0x0059 /* v3 */ #define AT_description 0x005a /* v3 */ +#define AT_object_pointer 0x0064 /* v3 */ #define AT_endianity 0x0065 /* v3 */ +#define AT_elemental 0x0066 /* v3 */ +#define AT_pure 0x0067 /* v3 */ +#define AT_recursive 0x0068 /* v3 */ +#define AT_signature 0x0069 /* v4 */ +#define AT_main_subprogram 0x006a /* v4 */ +#define AT_data_bit_offset 0x006b /* v4 */ +#define AT_const_expr 0x006c /* v4 */ +#define AT_enum_class 0x006d /* v4 */ +#define AT_linkage_name 0x006e /* v4 */ #define AT_lo_user_v1 0x0200 #define AT_hi_user_v1 0x03ff #define AT_push_mask 0x0220 diff --git a/agent/tcf/services/dwarfcache.c b/agent/tcf/services/dwarfcache.c index 15cd804e..73c8e13e 100644 --- a/agent/tcf/services/dwarfcache.c +++ b/agent/tcf/services/dwarfcache.c @@ -35,6 +35,13 @@ #define OBJ_HASH(Cache,ID) (((U4_T)(ID) + ((U4_T)(ID) >> 8)) % Cache->mObjectHashSize) +#define OBJECT_ARRAY_SIZE 128 + +typedef struct ObjectArray { + struct ObjectArray * mNext; + ObjectInfo mArray[OBJECT_ARRAY_SIZE]; +} ObjectArray; + typedef struct ObjectReference { ELF_Section * sec; ObjectInfo * obj; @@ -488,6 +495,11 @@ static void read_object_info(U2_T Tag, U2_T Attr, U2_T Form) { add_object_reference(dio_gFormSection, add_object_info((ContextAddress)dio_gFormData), Info); Info->mFlags |= DOIF_abstract_origin; break; + case AT_extension: + dio_ChkRef(Form); + add_object_reference(dio_gFormSection, add_object_info((ContextAddress)dio_gFormData), Info); + Info->mFlags |= DOIF_extension; + break; case AT_low_pc: dio_ChkAddr(Form); Info->u.mAddr.mLowPC = (ContextAddress)dio_gFormData; @@ -586,12 +598,18 @@ static void read_object_refs(void) { } if (ref.obj != NULL) { assert(ref.org->mTag != 0); + if (ref.obj->mFlags & DOIF_specification) ref.org->mDefinition = ref.obj; if (ref.obj->mName == NULL) ref.obj->mName = ref.org->mName; if (ref.obj->mType == NULL) ref.obj->mType = ref.org->mType; - ref.obj->mFlags |= ref.org->mFlags & ~DOIF_children_loaded; - assert(ref.obj->mDefinition == NULL); - ref.obj->mDefinition = ref.org->mDefinition; - ref.org->mDefinition = ref.obj; + ref.obj->mFlags |= ref.org->mFlags & ~(DOIF_children_loaded | DOIF_declaration | DOIF_specification); + if (ref.obj->mFlags & DOIF_external) { + ObjectInfo * cls = ref.org; + while (cls->mParent != NULL && + (cls->mParent->mTag == TAG_class_type || cls->mParent->mTag == TAG_structure_type)) { + cls = cls->mParent; + } + cls->mFlags |= DOIF_external; + } } } sObjRefsPos = 0; @@ -773,7 +791,7 @@ static void create_pub_names(ELF_Section * debug_info, PubNamesTable * tbl) { while (unit != NULL) { ObjectInfo * obj = get_dwarf_children(unit); while (obj != NULL) { - if (obj->mFlags & DOIF_external) { + if ((obj->mFlags & DOIF_external) && obj->mDefinition == NULL) { unsigned h; PubNamesInfo * info = NULL; if (tbl->mCnt >= tbl->mMax) { @@ -926,10 +944,12 @@ static void * gop_gFormDataAddr = NULL; static ELF_Section * gop_gFormSection = NULL; static U8_T gop_gSpecification = 0; static U8_T gop_gAbstractOrigin = 0; +static U8_T gop_gExtension = 0; static void get_object_property_callback(U2_T Tag, U2_T Attr, U2_T Form) { if (Attr == AT_specification_v2) gop_gSpecification = dio_gFormData; if (Attr == AT_abstract_origin) gop_gAbstractOrigin = dio_gFormData; + if (Attr == AT_extension) gop_gExtension = dio_gFormData; if (Attr != gop_gAttr) return; gop_gForm = Form; gop_gFormData = dio_gFormData; @@ -941,8 +961,7 @@ static void get_object_property_callback(U2_T Tag, U2_T Attr, U2_T Form) { U8_T get_numeric_property_value(PropertyValue * Value) { U8_T Res = 0; - if (Value->mPieces != NULL || Value->mRegister != NULL || - (Value->mAddr != NULL && Value->mForm == FORM_EXPR_VALUE)) { + if (Value->mPieces != NULL) { str_exception(ERR_INV_DWARF, "Constant DWARF attribute value expected"); } else if (Value->mAddr != NULL) { @@ -958,7 +977,7 @@ U8_T get_numeric_property_value(PropertyValue * Value) { return Res; } -static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Obj, U2_T Attr, PropertyValue * Value) { +void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Obj, U2_T Attr, PropertyValue * Value) { memset(Value, 0, sizeof(PropertyValue)); Value->mContext = Ctx; @@ -1038,11 +1057,13 @@ static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Ob gop_gForm = 0; gop_gSpecification = 0; gop_gAbstractOrigin = 0; + gop_gExtension = 0; dio_ReadEntry(get_object_property_callback, gop_gAttr); dio_ExitSection(); if (gop_gForm != 0) break; if (gop_gSpecification != 0) dio_EnterSection(&sCompUnit->mDesc, sDebugSection, gop_gSpecification - sDebugSection->addr); else if (gop_gAbstractOrigin != 0) dio_EnterSection(&sCompUnit->mDesc, sDebugSection, gop_gAbstractOrigin - sDebugSection->addr); + else if (gop_gExtension != 0) dio_EnterSection(&sCompUnit->mDesc, sDebugSection, gop_gExtension - sDebugSection->addr); else break; } @@ -1054,7 +1075,7 @@ static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Ob case FORM_REF4 : case FORM_REF8 : case FORM_REF_UDATA : - if (Attr == AT_import || Attr == AT_specification_v2) { + if (Attr == AT_import || Attr == AT_specification_v2 || Attr == AT_constaining_type) { Value->mValue = gop_gFormData; } else { @@ -1062,12 +1083,13 @@ static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Ob ObjectInfo * RefObj = find_object(sCache, (ContextAddress)gop_gFormData); if (RefObj == NULL) exception(ERR_INV_DWARF); - read_and_evaluate_dwarf_object_property(Ctx, Frame, 0, RefObj, AT_location, &ValueAddr); - if (ValueAddr.mRegister != NULL) { + read_and_evaluate_dwarf_object_property(Ctx, Frame, RefObj, AT_location, &ValueAddr); + if (ValueAddr.mPieceCnt == 1 && ValueAddr.mPieces[0].reg != NULL && ValueAddr.mPieces[0].bit_size == 0) { static U1_T Buf[8]; StackFrame * Frame = NULL; + RegisterDefinition * Register = ValueAddr.mPieces[0].reg; if (get_frame_info(ValueAddr.mContext, ValueAddr.mFrame, &Frame) < 0) exception(errno); - if (read_reg_bytes(Frame, ValueAddr.mRegister, 0, ValueAddr.mRegister->size, Buf) < 0) exception(errno); + if (read_reg_bytes(Frame, Register, 0, Register->size, Buf) < 0) exception(errno); Value->mAddr = Buf; Value->mSize = ValueAddr.mSize; Value->mBigEndian = ValueAddr.mBigEndian; @@ -1075,14 +1097,13 @@ static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Ob else { static U1_T Buf[8]; PropertyValue ValueSize; - ContextAddress Addr; size_t Size; - Addr = (ContextAddress)get_numeric_property_value(&ValueAddr); - read_and_evaluate_dwarf_object_property(Ctx, Frame, Addr, RefObj, AT_byte_size, &ValueSize); + dwarf_expression_obj_addr = get_numeric_property_value(&ValueAddr); + read_and_evaluate_dwarf_object_property(Ctx, Frame, RefObj, AT_byte_size, &ValueSize); Size = (size_t)get_numeric_property_value(&ValueSize); if (Size < 1 || Size > sizeof(Buf)) exception(ERR_INV_DATA_TYPE); - if (context_read_mem(Ctx, Addr, Buf, Size) < 0) exception(errno); + if (context_read_mem(Ctx, (ContextAddress)dwarf_expression_obj_addr, Buf, Size) < 0) exception(errno); Value->mAddr = Buf; Value->mSize = Size; } @@ -1126,7 +1147,7 @@ static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Ob } if (Obj->mTag == TAG_ptr_to_member_type) { Value->mForm = FORM_UDATA; - Value->mValue = sCompUnit->mDesc.mAddressSize * 2; + Value->mValue = sCompUnit->mDesc.mAddressSize; break; } if (Obj->mTag == TAG_structure_type || Obj->mTag == TAG_class_type || Obj->mTag == TAG_union_type) { @@ -1137,7 +1158,7 @@ static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Ob ObjectInfo * d = c; while (d->mTag == TAG_imported_declaration) { PropertyValue v; - read_and_evaluate_dwarf_object_property(Ctx, Frame, 0, d, AT_import, &v); + read_and_evaluate_dwarf_object_property(Ctx, Frame, d, AT_import, &v); d = find_object( (DWARFCache *)Obj->mCompUnit->mFile->dwarf_dt_cache, (ContextAddress)get_numeric_property_value(&v)); @@ -1151,6 +1172,14 @@ static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Ob case TAG_typedef: case TAG_subprogram: case TAG_template_type_param: + case TAG_class_type: + case TAG_structure_type: + case TAG_union_type: + case TAG_enumeration_type: + break; + case TAG_member: + if (d->mFlags & DOIF_external) break; + OK = 0; break; default: OK = 0; @@ -1160,6 +1189,7 @@ static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Ob } if (OK) { Value->mForm = FORM_UDATA; + Value->mAddr = 0; Value->mValue = 0; break; } @@ -1173,16 +1203,36 @@ static void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Ob sDebugSection = NULL; } -void read_and_evaluate_dwarf_object_property(Context * Ctx, int Frame, U8_T Base, ObjectInfo * Obj, U2_T Attr, PropertyValue * Value) { +void read_and_evaluate_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Obj, U2_T Attr, PropertyValue * Value) { read_dwarf_object_property(Ctx, Frame, Obj, Attr, Value); assert(Value->mContext == Ctx); assert(Value->mFrame == Frame); assert(Value->mObject == Obj); assert(Value->mAttr == Attr); if (Value->mForm == FORM_EXPRLOC) { - dwarf_evaluate_expression(Base, Value); + dwarf_evaluate_expression(Value); + } + else if (Attr == AT_data_member_location) { + switch (Value->mForm) { + case FORM_DATA1 : + case FORM_DATA4 : + case FORM_DATA8 : + case FORM_SDATA : + case FORM_UDATA : + Value->mValue = dwarf_expression_obj_addr + get_numeric_property_value(Value); + Value->mForm = FORM_UDATA; + Value->mAddr = NULL; + Value->mSize = 0; + break; + case FORM_BLOCK1 : + case FORM_BLOCK2 : + case FORM_BLOCK4 : + case FORM_BLOCK : + dwarf_evaluate_expression(Value); + break; + } } - else if (Attr == AT_location || Attr == AT_data_member_location || Attr == AT_string_length || Attr == AT_frame_base) { + else if (Attr == AT_location || Attr == AT_string_length || Attr == AT_frame_base || Attr == AT_use_location) { switch (Value->mForm) { case FORM_DATA4 : case FORM_DATA8 : @@ -1190,7 +1240,7 @@ void read_and_evaluate_dwarf_object_property(Context * Ctx, int Frame, U8_T Base case FORM_BLOCK2 : case FORM_BLOCK4 : case FORM_BLOCK : - dwarf_evaluate_expression(Base, Value); + dwarf_evaluate_expression(Value); break; } } @@ -1200,7 +1250,7 @@ void read_and_evaluate_dwarf_object_property(Context * Ctx, int Frame, U8_T Base case FORM_BLOCK2 : case FORM_BLOCK4 : case FORM_BLOCK : - dwarf_evaluate_expression(Base, Value); + dwarf_evaluate_expression(Value); break; } } @@ -1599,8 +1649,9 @@ UnitAddressRange * find_comp_unit_addr_range(DWARFCache * cache, ContextAddress first = rp->mAddr + rp->mSize <= addr_min; } if (first) return rk; + h = k; } - if (rk->mAddr >= addr_min) h = k; + else if (rk->mAddr >= addr_min) h = k; else l = k + 1; } return NULL; diff --git a/agent/tcf/services/dwarfcache.h b/agent/tcf/services/dwarfcache.h index 1714881d..e4a357bc 100644 --- a/agent/tcf/services/dwarfcache.h +++ b/agent/tcf/services/dwarfcache.h @@ -28,9 +28,9 @@ #if ENABLE_ELF && ENABLE_DebugContext +#include <tcf/framework/errors.h> #include <tcf/services/tcf_elf.h> #include <tcf/services/dwarfio.h> -#include <tcf/framework/errors.h> #ifndef ENABLE_DWARF_LAZY_LOAD # define ENABLE_DWARF_LAZY_LOAD 1 @@ -40,9 +40,7 @@ typedef struct FileInfo FileInfo; typedef struct ObjectInfo ObjectInfo; typedef struct PubNamesInfo PubNamesInfo; typedef struct PubNamesTable PubNamesTable; -typedef struct ObjectArray ObjectArray; typedef struct SymbolInfo SymbolInfo; -typedef struct PropertyValuePiece PropertyValuePiece; typedef struct PropertyValue PropertyValue; typedef struct LineNumbersState LineNumbersState; typedef struct CompUnit CompUnit; @@ -52,8 +50,8 @@ typedef struct FrameInfoRange FrameInfoRange; typedef struct DWARFCache DWARFCache; struct FileInfo { - char * mName; - char * mDir; + const char * mName; + const char * mDir; U4_T mModTime; U4_T mSize; unsigned mNameHash; @@ -71,7 +69,8 @@ struct FileInfo { #define DOIF_artificial 0x0004 #define DOIF_specification 0x0008 #define DOIF_abstract_origin 0x0010 -#define DOIF_children_loaded 0x0020 +#define DOIF_extension 0x0020 +#define DOIF_children_loaded 0x0040 struct ObjectInfo { @@ -89,7 +88,7 @@ struct ObjectInfo { U2_T mFlags; CompUnit * mCompUnit; ObjectInfo * mType; - char * mName; + const char * mName; union { U2_T mFundType; @@ -117,13 +116,6 @@ struct ObjectInfo { } u; }; -#define OBJECT_ARRAY_SIZE 128 - -struct ObjectArray { - ObjectArray * mNext; - ObjectInfo mArray[OBJECT_ARRAY_SIZE]; -}; - struct PubNamesInfo { unsigned mNext; ContextAddress mID; @@ -136,15 +128,6 @@ struct PubNamesTable { unsigned mMax; }; -struct PropertyValuePiece { - int mBigEndian; - ContextAddress mAddress; - RegisterDefinition * mRegister; - U1_T * mValue; - U4_T mBitOffset; - U4_T mBitSize; -}; - struct PropertyValue { Context * mContext; int mFrame; @@ -155,8 +138,7 @@ struct PropertyValue { U1_T * mAddr; size_t mSize; int mBigEndian; - RegisterDefinition * mRegister; - PropertyValuePiece * mPieces; + LocationPiece * mPieces; U4_T mPieceCnt; }; @@ -244,7 +226,7 @@ struct DWARFCache { ELF_Section * mEHFrame; ObjectInfo ** mObjectHash; unsigned mObjectHashSize; - ObjectArray * mObjectList; + struct ObjectArray * mObjectList; unsigned mObjectArrayPos; UnitAddressRange * mAddrRanges; unsigned mAddrRangesCnt; @@ -288,10 +270,16 @@ extern ObjectInfo * find_object(DWARFCache * cache, ContextAddress ID); extern UnitAddressRange * find_comp_unit_addr_range(DWARFCache * cache, ContextAddress addr_min, ContextAddress addr_max); /* + * Read a property of a DWARF object, perform ELF relocations if any. + * FORM_ADDR values are mapped to run-time address space. + */ +extern void read_dwarf_object_property(Context * Ctx, int Frame, ObjectInfo * Obj, U2_T Attr, PropertyValue * Value); + +/* * Read and evaluate a property of a DWARF object, perform ELF relocations if any. * FORM_ADDR values are mapped to run-time address space. */ -extern void read_and_evaluate_dwarf_object_property(Context * ctx, int frame, U8_T base, ObjectInfo * obj, U2_T attr_tag, PropertyValue * value); +extern void read_and_evaluate_dwarf_object_property(Context * ctx, int frame, ObjectInfo * obj, U2_T attr_tag, PropertyValue * value); /* * Convert PropertyValue to a number. diff --git a/agent/tcf/services/dwarfecomp.c b/agent/tcf/services/dwarfecomp.c new file mode 100644 index 00000000..53beba42 --- /dev/null +++ b/agent/tcf/services/dwarfecomp.c @@ -0,0 +1,346 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ + +/* + * Transformation of DWARF expressions to a portable form. + * + * Functions in this module use exceptions to report errors, see exceptions.h + */ + +#include <tcf/config.h> + +#if ENABLE_ELF && ENABLE_DebugContext + +#include <assert.h> +#include <tcf/framework/myalloc.h> +#include <tcf/framework/exceptions.h> +#include <tcf/services/dwarf.h> +#include <tcf/services/dwarfecomp.h> + +static U1_T * buf = NULL; +static size_t buf_pos = 0; +static size_t buf_max = 0; +static DWARFExpressionInfo * expr = NULL; +static size_t expr_pos = 0; +static Context * expr_ctx = NULL; +static U8_T expr_ip = 0; + +static void add(unsigned n) { + if (buf_pos >= buf_max) { + buf_max *= 2; + buf = (U1_T *)tmp_realloc(buf, buf_max); + } + buf[buf_pos++] = (U1_T)n; +} + +static void copy(size_t n) { + while (n > 0) { + if (expr_pos >= expr->expr_size) exception(ERR_INV_DWARF); + add(expr->expr_addr[expr_pos++]); + n--; + } +} + +static void copy_leb128(void) { + for (;;) { + U1_T n = expr->expr_addr[expr_pos++]; + add(n); + if ((n & 0x80) == 0) break; + } +} + +static void add_uleb128(U8_T x) { + for (;;) { + U1_T n = (U1_T)(x & 0x7Fu); + x = x >> 7; + if (x == 0) { + add(n); + break; + } + add(n | 0x80u); + } +} + +#if 0 +/* Not used yet */ +static void add_sleb128(I8_T x) { + for (;;) { + U1_T n = (U1_T)(x & 0x7Fu); + x = x >> 7; + if (x == 0 || (x == 0xFFu && (n & 0x40))) { + add(n); + break; + } + add(n | 0x80u); + } +} +#endif + +static void add_expression(DWARFExpressionInfo * info); + +static void op_addr(void) { + ContextAddress addr = 0; + ELF_Section * section = NULL; + U8_T pos = 0; + + expr_pos++; + pos = expr->expr_addr + expr_pos - (U1_T *)expr->section->data; + dio_EnterSection(&expr->unit->mDesc, expr->section, pos); + addr = (ContextAddress)dio_ReadAddress(§ion); + expr_pos += (size_t)(dio_GetPos() - pos); + dio_ExitSection(); + addr = elf_map_to_run_time_address(expr_ctx, expr->unit->mFile, section, addr); + if (errno) str_exception(errno, "Cannot get object run-time address"); + add(OP_constu); + add_uleb128(addr); +} + +static void op_fbreg(void) { + PropertyValue fp; + DWARFExpressionInfo info; + ObjectInfo * parent = get_parent_function(expr->object); + + expr_pos++; + memset(&fp, 0, sizeof(fp)); + if (parent == NULL) str_exception(ERR_INV_DWARF, "OP_fbreg: no parent function"); + read_dwarf_object_property(expr_ctx, STACK_NO_FRAME, parent, AT_frame_base, &fp); + dwarf_find_expression(&fp, expr_ip, &info); + switch (*info.expr_addr) { + case OP_reg: + add(OP_basereg); + { + unsigned i = 1; + while (i < info.unit->mDesc.mAddressSize + 1u) { + add(info.expr_addr[i++]); + } + } + copy_leb128(); + return; + case OP_regx: + add(OP_bregx); + { + unsigned i = 1; + for (;;) { + U1_T n = info.expr_addr[i++]; + add(n); + if ((n & 0x80) == 0) break; + } + } + copy_leb128(); + return; + case OP_reg0: + case OP_reg1: + case OP_reg2: + case OP_reg3: + case OP_reg4: + case OP_reg5: + case OP_reg6: + case OP_reg7: + case OP_reg8: + case OP_reg9: + case OP_reg10: + case OP_reg11: + case OP_reg12: + case OP_reg13: + case OP_reg14: + case OP_reg15: + case OP_reg16: + case OP_reg17: + case OP_reg18: + case OP_reg19: + case OP_reg20: + case OP_reg21: + case OP_reg22: + case OP_reg23: + case OP_reg24: + case OP_reg25: + case OP_reg26: + case OP_reg27: + case OP_reg28: + case OP_reg29: + case OP_reg30: + case OP_reg31: + add(OP_breg0 + (*info.expr_addr - OP_reg0)); + copy_leb128(); + return; + } + add_expression(&info); + add(OP_consts); + copy_leb128(); + add(OP_add); +} + +static void add_expression(DWARFExpressionInfo * info) { + DWARFExpressionInfo * org_expr = expr; + size_t org_expr_pos = expr_pos; + + if (expr != NULL && info->code_size) { + if (expr->code_size) { + if (info->code_addr > expr->code_addr) { + U8_T d = info->code_addr - expr->code_addr; + assert(expr->code_size > d); + expr->code_addr += d; + expr->code_size -= d; + } + if (info->code_addr + info->code_size < expr->code_addr + expr->code_size) { + U8_T d = (expr->code_addr + expr->code_size) - (info->code_addr + info->code_size); + assert(expr->code_size > d); + expr->code_size -= d; + } + } + else { + expr->code_addr = info->code_addr; + expr->code_size = info->code_size; + } + } + + expr = info; + expr_pos = 0; + while (expr_pos < info->expr_size) { + U1_T op = info->expr_addr[expr_pos]; + switch (op) { + case OP_const1u: + case OP_const1s: + case OP_pick: + case OP_deref_size: + case OP_xderef_size: + copy(2); + break; + case OP_const: + case OP_reg: + case OP_basereg: + copy(1 + info->unit->mDesc.mAddressSize); + break; + case OP_const2u: + case OP_const2s: + copy(3); + break; + case OP_const4u: + case OP_const4s: + copy(5); + break; + case OP_const8u: + case OP_const8s: + copy(9); + break; + case OP_constu: + case OP_consts: + case OP_plus_uconst: + case OP_regx: + case OP_breg0: + case OP_breg1: + case OP_breg2: + case OP_breg3: + case OP_breg4: + case OP_breg5: + case OP_breg6: + case OP_breg7: + case OP_breg8: + case OP_breg9: + case OP_breg10: + case OP_breg11: + case OP_breg12: + case OP_breg13: + case OP_breg14: + case OP_breg15: + case OP_breg16: + case OP_breg17: + case OP_breg18: + case OP_breg19: + case OP_breg20: + case OP_breg21: + case OP_breg22: + case OP_breg23: + case OP_breg24: + case OP_breg25: + case OP_breg26: + case OP_breg27: + case OP_breg28: + case OP_breg29: + case OP_breg30: + case OP_breg31: + case OP_piece: + add(op); + expr_pos++; + copy_leb128(); + break; + case OP_bra: + case OP_skip: + str_exception(ERR_UNSUPPORTED, "OP_bra/OP_skip not supported yet"); + break; + case OP_bregx: + case OP_bit_piece: + add(op); + expr_pos++; + copy_leb128(); + copy_leb128(); + break; + case OP_implicit_value: + { + unsigned i = 0; + size_t j = expr_pos + 1u; + size_t size = 0; + for (;; i += 7) { + U1_T n = info->expr_addr[j++]; + size |= (n & 0x7Fu) << i; + if ((n & 0x80) == 0) break; + } + copy(j + size - expr_pos); + } + break; + case OP_fbreg: + op_fbreg(); + break; + case OP_addr: + op_addr(); + break; + case OP_form_tls_address: + case OP_GNU_push_tls_address: + case OP_GNU_implicit_pointer: + case OP_call2: + case OP_call4: + case OP_call_ref: + str_fmt_exception(ERR_OTHER, "Unsupported DWARF expression op 0x%02x", op); + break; + default: + add(op); + expr_pos++; + break; + } + } + expr = org_expr; + expr_pos = org_expr_pos; +} + +void dwarf_transform_expression(Context * ctx, ContextAddress ip, DWARFExpressionInfo * info) { + buf_pos = 0; + buf_max = info->expr_size * 2; + buf = (U1_T *)tmp_alloc(buf_max); + expr_ctx = ctx; + expr_ip = ip; + expr = NULL; + add_expression(info); + info->expr_addr = buf; + info->expr_size = buf_pos; + buf_pos = 0; + buf_max = 0; + buf = NULL; + expr = NULL; + expr_pos = 0; + expr_ctx = NULL; + expr_ip = 0; +} + +#endif diff --git a/agent/tcf/services/dwarfecomp.h b/agent/tcf/services/dwarfecomp.h new file mode 100644 index 00000000..612f54af --- /dev/null +++ b/agent/tcf/services/dwarfecomp.h @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v1.0 which accompany this distribution. + * The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * You may elect to redistribute this code under either of these licenses. + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ + +/* + * Transformation of DWARF expressions to a portable form. + * + * Functions in this module use exceptions to report errors, see exceptions.h + */ +#ifndef D_dwarfecomp +#define D_dwarfecomp + +#include <tcf/config.h> + +#if ENABLE_ELF && ENABLE_DebugContext + +#include <tcf/services/dwarfexpr.h> + +extern void dwarf_transform_expression(Context * ctx, ContextAddress ip, DWARFExpressionInfo * info); + +#endif /* ENABLE_ELF && ENABLE_DebugContext */ + +#endif /* D_dwarfecomp */ diff --git a/agent/tcf/services/dwarfexpr.c b/agent/tcf/services/dwarfexpr.c index 27145c4b..a9291cfd 100644 --- a/agent/tcf/services/dwarfexpr.c +++ b/agent/tcf/services/dwarfexpr.c @@ -35,23 +35,23 @@ #include <tcf/services/elf-loader.h> #include <tcf/services/vm.h> -static VMState * sState = NULL; +U8_T dwarf_expression_obj_addr = 0; +U8_T dwarf_expression_pm_value = 0; + +static int sStackFrame = 0; +static LocationExpressionState * sState = NULL; static ELF_Section * sSection = NULL; static U8_T sSectionOffs = 0; static PropertyValue * sValue = NULL; -static PropertyValuePiece * sValuePieces = NULL; -static U4_T sValuePiecesCnt = 0; -static U4_T sValuePiecesMax = 0; - -static PropertyValuePiece * add_piece(void) { - PropertyValuePiece * Piece; - if (sValuePiecesCnt >= sValuePiecesMax) { - sValuePiecesMax += 8; - sValuePieces = (PropertyValuePiece *)tmp_realloc(sValuePieces, - sizeof(PropertyValuePiece) * sValuePiecesMax); + +static LocationPiece * add_piece(void) { + LocationPiece * Piece = NULL; + if (sState->pieces_cnt >= sState->pieces_max) { + sState->pieces_max += 4; + sState->pieces = (LocationPiece *)tmp_realloc(sState->pieces, sState->pieces_max * sizeof(LocationPiece)); } - Piece = sValuePieces + sValuePiecesCnt++; - memset(Piece, 0, sizeof(PropertyValuePiece)); + Piece = sState->pieces + sState->pieces_cnt++; + memset(Piece, 0, sizeof(LocationPiece)); return Piece; } @@ -62,7 +62,7 @@ static StackFrame * get_stack_frame(PropertyValue * sValue) { return Info; } -static ObjectInfo * get_parent_function(ObjectInfo * Info) { +ObjectInfo * get_parent_function(ObjectInfo * Info) { while (Info != NULL) { switch (Info->mTag) { case TAG_global_subroutine: @@ -96,10 +96,11 @@ static U8_T get_fbreg(void) { if (Parent == NULL) str_exception(ERR_INV_DWARF, "OP_fbreg: no parent function"); memset(&FP, 0, sizeof(FP)); - read_and_evaluate_dwarf_object_property(sState->ctx, sState->stack_frame, 0, Parent, AT_frame_base, &FP); + read_and_evaluate_dwarf_object_property(sState->ctx, sStackFrame, Parent, AT_frame_base, &FP); + assert(get_stack_frame(&FP) == sState->stack_frame); - if (FP.mRegister != NULL) { - if (read_reg_value(get_stack_frame(&FP), FP.mRegister, &addr) < 0) exception(errno); + if (FP.mPieceCnt == 1 && FP.mPieces[0].reg != NULL && FP.mPieces[0].bit_size == 0) { + if (read_reg_value(sState->stack_frame, FP.mPieces[0].reg, &addr) < 0) exception(errno); } else { addr = get_numeric_property_value(&FP); @@ -130,58 +131,44 @@ static void evaluate_implicit_pointer(void) { U8_T DioPos = dio_GetPos(); if (Info == NULL) str_exception(ERR_INV_DWARF, "OP_GNU_implicit_pointer: invalid object reference"); memset(&FP, 0, sizeof(FP)); - read_and_evaluate_dwarf_object_property(sState->ctx, sState->stack_frame, 0, Info, sValue->mAttr, &FP); + read_and_evaluate_dwarf_object_property(sState->ctx, sStackFrame, Info, sValue->mAttr, &FP); if (FP.mPieces != NULL) { U4_T Cnt = 0; U4_T BitOffset = 0; while (Cnt < FP.mPieceCnt) { - PropertyValuePiece * OrgPiece = FP.mPieces + Cnt++; - if (BitOffset + OrgPiece->mBitSize > Offset * 8) { - PropertyValuePiece * Piece = add_piece(); + LocationPiece * OrgPiece = FP.mPieces + Cnt++; + if (OrgPiece->bit_size == 0) OrgPiece->bit_size = OrgPiece->size * 8; + if (BitOffset + OrgPiece->bit_size > Offset * 8) { + LocationPiece * Piece = add_piece(); *Piece = *OrgPiece; if (BitOffset < Offset * 8) { - Piece->mBitOffset += Offset * 8 - BitOffset; - Piece->mBitSize -= Offset * 8 - BitOffset; + Piece->bit_offs += Offset * 8 - BitOffset; + Piece->bit_size -= Offset * 8 - BitOffset; } } - BitOffset += OrgPiece->mBitSize; + BitOffset += OrgPiece->bit_size; } } - else if (FP.mRegister != NULL) { - PropertyValuePiece * Piece = add_piece(); - if (Offset > FP.mRegister->size) str_exception(ERR_INV_DWARF, "Invalid OP_GNU_implicit_pointer"); - Piece->mBigEndian = FP.mRegister->big_endian; - Piece->mRegister = FP.mRegister; - Piece->mBitOffset = Offset * 8; - Piece->mBitSize = (FP.mRegister->size - Offset) * 8; - } - else if (FP.mAddr != NULL) { - PropertyValuePiece * Piece = add_piece(); - if (Offset > FP.mSize) str_exception(ERR_INV_DWARF, "Invalid OP_GNU_implicit_pointer"); - Piece->mBigEndian = FP.mBigEndian; - Piece->mValue = FP.mAddr; - Piece->mBitOffset = Offset * 8; - Piece->mBitSize = (FP.mSize - Offset) * 8; - } else { - PropertyValuePiece * Piece = add_piece(); + LocationPiece * Piece = add_piece(); if (Offset > sizeof(FP.mValue)) str_exception(ERR_INV_DWARF, "Invalid OP_GNU_implicit_pointer"); - Piece->mBigEndian = big_endian_host(); - Piece->mValue = (U1_T *)tmp_alloc(sizeof(FP.mValue)); - Piece->mBitOffset = Offset * 8; - Piece->mBitSize = (sizeof(FP.mValue) - Offset) * 8; + Piece->big_endian = big_endian_host(); + Piece->size = sizeof(FP.mValue); + Piece->value = (U1_T *)tmp_alloc(sizeof(FP.mValue)); + Piece->bit_offs = Offset * 8; + Piece->bit_size = (sizeof(FP.mValue) - Offset) * 8; } dio_EnterSection(&Unit->mDesc, sSection, DioPos); } static void client_op(uint8_t op) { - dio_SetPos(sSectionOffs + sState->code_pos); + dio_EnterSection(&sValue->mObject->mCompUnit->mDesc, sSection, sSectionOffs + sState->code_pos); switch (op) { case OP_addr: sState->stk[sState->stk_pos++] = read_address(); break; case OP_fbreg: - if (sState->stack_frame == STACK_NO_FRAME) str_exception(ERR_INV_CONTEXT, "Invalid stack frame"); + if (sState->stack_frame == NULL) str_exception(ERR_INV_CONTEXT, "Invalid stack frame"); sState->stk[sState->stk_pos++] = get_fbreg(); break; case OP_form_tls_address: @@ -207,163 +194,135 @@ static void client_op(uint8_t op) { str_fmt_exception(ERR_UNSUPPORTED, "Unsupported DWARF expression op 0x%02x", op); } sState->code_pos = (size_t)(dio_GetPos() - sSectionOffs); + dio_ExitSection(); } -static void evaluate_expression(ELF_Section * Section, U1_T * Buf, size_t Size) { - int error = 0; - CompUnit * Unit = sValue->mObject->mCompUnit; +void dwarf_find_expression(PropertyValue * Value, U8_T IP, DWARFExpressionInfo * Info) { + CompUnit * Unit = Value->mObject->mCompUnit; - sState->code = Buf; - sState->code_len = Size; - sState->code_pos = 0; - sSection = Section; - sSectionOffs = Buf - (U1_T *)Section->data; - dio_EnterSection(&Unit->mDesc, sSection, sSectionOffs); - if (evaluate_vm_expression(sState) < 0) error = errno; - if (!error && sState->piece_bits) { - while (!error) { - PropertyValuePiece * Piece = add_piece(); - if (sState->reg) { - Piece->mRegister = sState->reg; - Piece->mBigEndian = sState->reg->big_endian; + memset(Info, 0, sizeof(DWARFExpressionInfo)); + Info->object = Value->mObject; + Info->unit = Unit; + + if (Value->mAddr == NULL || Value->mSize == 0) str_exception(ERR_INV_DWARF, "Invalid format of location expression"); + + if (Value->mForm == FORM_DATA4 || Value->mForm == FORM_DATA8) { + U8_T Base = 0; + U8_T Offset = 0; + U8_T AddrMax = ~(U8_T)0; + DWARFCache * Cache = (DWARFCache *)Unit->mFile->dwarf_dt_cache; + + assert(Cache->magic == DWARF_CACHE_MAGIC); + if (Cache->mDebugLoc == NULL) str_exception(ERR_INV_DWARF, "Missing .debug_loc section"); + dio_EnterSection(&Unit->mDesc, Unit->mDesc.mSection, Value->mAddr - (U1_T *)Unit->mDesc.mSection->data); + Offset = dio_ReadUX(Value->mSize); + dio_ExitSection(); + Base = Unit->mLowPC; + if (Unit->mDesc.mAddressSize < 8) AddrMax = ((U8_T)1 << Unit->mDesc.mAddressSize * 8) - 1; + dio_EnterSection(&Unit->mDesc, Cache->mDebugLoc, Offset); + for (;;) { + ELF_Section * S0 = NULL; + ELF_Section * S1 = NULL; + U8_T Addr0 = dio_ReadAddress(&S0); + U8_T Addr1 = dio_ReadAddress(&S1); + if (S0 == NULL) S0 = Unit->mTextSection; + if (S1 == NULL) S1 = Unit->mTextSection; + if (Addr0 == AddrMax) { + Base = Addr1; } - else if (sState->value_addr) { - Piece->mValue = (U1_T *)sState->value_addr; - if (sState->value_size * 8 < sState->piece_bits) str_exception(ERR_INV_DWARF, "Invalid object piece size"); - Piece->mBigEndian = sState->big_endian; + else if (Addr0 == 0 && Addr1 == 0) { + break; } - else if (sState->stk_pos == 0) { - /* An empty location description represents a piece or all of an object that is - * present in the source but not in the object code (perhaps due to optimization). */ - size_t size = (sState->piece_bits + 7) / 8; - Piece->mValue = (U1_T *)tmp_alloc_zero(size); + else if (S0 != S1 || Addr0 > Addr1) { + str_exception(ERR_INV_DWARF, "Invalid .debug_loc section"); } else { - Piece->mAddress = (ContextAddress)sState->stk[--sState->stk_pos]; - Piece->mBigEndian = sState->big_endian; + U2_T Size = dio_ReadU2(); + U8_T RTAddr0 = elf_map_to_run_time_address(Value->mContext, Unit->mFile, S0, (ContextAddress)(Base + Addr0)); + U8_T RTAddr1 = Addr1 - Addr0 + RTAddr0; + if (RTAddr0 != 0 && IP >= RTAddr0 && IP < RTAddr1) { + Info->code_addr = RTAddr0; + Info->code_size = RTAddr1 - RTAddr0; + Info->section = Cache->mDebugLoc; + Info->expr_addr = dio_GetDataPtr(); + Info->expr_size = Size; + dio_ExitSection(); + return; + } + dio_Skip(Size); } - Piece->mBitOffset = sState->piece_offs; - Piece->mBitSize = sState->piece_bits; - if (sState->stk_pos != 0) str_exception(ERR_INV_DWARF, "Invalid DWARF expression stack"); - if (sState->code_pos >= sState->code_len) break; - if (evaluate_vm_expression(sState) < 0) error = errno; } + dio_ExitSection(); + str_exception(ERR_OTHER, "Object is not available at this location in the code"); } - dio_ExitSection(); - assert(error || sState->code_pos == sState->code_len); - if (error) exception(error); -} - -static void evaluate_location(void) { - U8_T IP = 0; - U8_T Offset = 0; - U8_T Base = 0; - CompUnit * Unit = sValue->mObject->mCompUnit; - DWARFCache * Cache = (DWARFCache *)Unit->mFile->dwarf_dt_cache; - U8_T AddrMax = ~(U8_T)0; - - assert(Cache->magic == DWARF_CACHE_MAGIC); - if (Cache->mDebugLoc == NULL) str_exception(ERR_INV_DWARF, "Missing .debug_loc section"); - dio_EnterSection(&Unit->mDesc, Unit->mDesc.mSection, sValue->mAddr - (U1_T *)Unit->mDesc.mSection->data); - Offset = dio_ReadUX(sValue->mSize); - dio_ExitSection(); - Base = Unit->mLowPC; - if (Unit->mDesc.mAddressSize < 8) AddrMax = ((U8_T)1 << Unit->mDesc.mAddressSize * 8) - 1; - if (read_reg_value(get_stack_frame(sValue), get_PC_definition(sValue->mContext), &IP) < 0) exception(errno); - dio_EnterSection(&Unit->mDesc, Cache->mDebugLoc, Offset); - for (;;) { - ELF_Section * S0 = NULL; - ELF_Section * S1 = NULL; - U8_T Addr0 = dio_ReadAddress(&S0); - U8_T Addr1 = dio_ReadAddress(&S1); - if (S0 == NULL) S0 = Unit->mTextSection; - if (S1 == NULL) S1 = Unit->mTextSection; - if (Addr0 == AddrMax) { - Base = Addr1; - } - else if (Addr0 == 0 && Addr1 == 0) { - break; - } - else if (S0 != S1 || Addr0 > Addr1) { - str_exception(ERR_INV_DWARF, "Invalid .debug_loc section"); - } - else { - U2_T Size = dio_ReadU2(); - U8_T RTAddr0 = elf_map_to_run_time_address(sValue->mContext, Unit->mFile, S0, (ContextAddress)(Base + Addr0)); - U8_T RTAddr1 = Addr1 - Addr0 + RTAddr0; - if (RTAddr0 != 0 && IP >= RTAddr0 && IP < RTAddr1) { - U1_T * Buf = dio_GetDataPtr(); - dio_ExitSection(); - evaluate_expression(Cache->mDebugLoc, Buf, Size); - return; - } - dio_Skip(Size); - } + else { + Info->section = Unit->mDesc.mSection; + Info->expr_addr = Value->mAddr; + Info->expr_size = Value->mSize; } - dio_ExitSection(); - str_exception(ERR_OTHER, "Object is not available at this location in the code"); } -void dwarf_evaluate_expression(U8_T BaseAddress, PropertyValue * v) { +void dwarf_evaluate_expression(PropertyValue * v) { CompUnit * Unit = v->mObject->mCompUnit; - VMState * OrgState = sState; + LocationExpressionState * OrgState = sState; ELF_Section * OrgSection = sSection; U8_T OrgSectionOffs = sSectionOffs; PropertyValue * OrgValue = sValue; - PropertyValuePiece * OrgValuePieces = sValuePieces; - U4_T OrgValuePiecesCnt = sValuePiecesCnt; - U4_T OrgValuePiecesMax = sValuePiecesMax; + DWARFExpressionInfo Info; + U8_T IP = 0; + U8_T args[2]; sValue = v; - sValuePieces = NULL; - sValuePiecesCnt = 0; - sValuePiecesMax = 0; - sState = (VMState *)tmp_alloc_zero(sizeof(VMState)); + sStackFrame = sValue->mFrame; + sState = (LocationExpressionState *)tmp_alloc_zero(sizeof(LocationExpressionState)); + sState->stk = (U8_T *)tmp_alloc(sizeof(U8_T) * (sState->stk_max = 8)); sState->ctx = sValue->mContext; + sState->stack_frame = get_stack_frame(v); sState->addr_size = Unit->mDesc.mAddressSize; sState->big_endian = Unit->mFile->big_endian; - sState->stack_frame = sValue->mFrame; sState->reg_id_scope = Unit->mRegIdScope; - sState->object_address = BaseAddress; + sState->args = args; sState->client_op = client_op; + args[0] = dwarf_expression_obj_addr; + args[1] = dwarf_expression_pm_value; if (sValue->mAttr == AT_data_member_location) { - sState->stk = (U8_T *)tmp_alloc(sizeof(U8_T) * (sState->stk_max = 8)); - sState->stk[sState->stk_pos++] = BaseAddress; + sState->stk[sState->stk_pos++] = dwarf_expression_obj_addr; + sState->args_cnt = 1; + } + if (sValue->mAttr == AT_use_location) { + sState->stk[sState->stk_pos++] = dwarf_expression_pm_value; + sState->stk[sState->stk_pos++] = dwarf_expression_obj_addr; + sState->args_cnt = 2; } - if (sValue->mRegister != NULL || sValue->mAddr == NULL || sValue->mSize == 0) { + if (sValue->mPieces != NULL || sValue->mAddr == NULL || sValue->mSize == 0) { str_exception(ERR_INV_DWARF, "Invalid DWARF expression reference"); } if (sValue->mForm == FORM_DATA4 || sValue->mForm == FORM_DATA8) { if (sValue->mFrame == STACK_NO_FRAME) str_exception(ERR_INV_CONTEXT, "Need stack frame"); - evaluate_location(); - } - else { - evaluate_expression(Unit->mDesc.mSection, sValue->mAddr, sValue->mSize); + if (read_reg_value(sState->stack_frame, get_PC_definition(sValue->mContext), &IP) < 0) exception(errno); } + dwarf_find_expression(sValue, IP, &Info); + sState->code = Info.expr_addr; + sState->code_len = Info.expr_size; + sState->code_pos = 0; + sSection = Info.section; + sSectionOffs = Info.expr_addr - (U1_T *)sSection->data; + if (evaluate_vm_expression(sState) < 0) exception(errno); + assert(sState->code_pos == sState->code_len); + sValue->mForm = FORM_EXPR_VALUE; sValue->mAddr = NULL; sValue->mValue = 0; sValue->mSize = 0; sValue->mBigEndian = sState->big_endian; - sValue->mRegister = NULL; sValue->mPieces = NULL; sValue->mPieceCnt = 0; - if (sValuePieces) { - sValue->mPieces = sValuePieces; - sValue->mPieceCnt = sValuePiecesCnt; - } - else if (sState->reg) { - sValue->mSize = sState->reg->size; - sValue->mBigEndian = sState->reg->big_endian; - sValue->mRegister = sState->reg; - } - else if (sState->value_addr) { - sValue->mAddr = (U1_T *)sState->value_addr; - sValue->mSize = sState->value_size; - sValue->mBigEndian = sState->big_endian; + if (sState->pieces_cnt) { + sValue->mPieces = sState->pieces; + sValue->mPieceCnt = sState->pieces_cnt; } else { sValue->mValue = sState->stk[--sState->stk_pos]; @@ -377,9 +336,6 @@ void dwarf_evaluate_expression(U8_T BaseAddress, PropertyValue * v) { sSection = OrgSection; sSectionOffs = OrgSectionOffs; sValue = OrgValue; - sValuePieces = OrgValuePieces; - sValuePiecesCnt = OrgValuePiecesCnt; - sValuePiecesMax = OrgValuePiecesMax; } #endif /* ENABLE_ELF && ENABLE_DebugContext */ diff --git a/agent/tcf/services/dwarfexpr.h b/agent/tcf/services/dwarfexpr.h index 1ebbd484..c40a8ce5 100644 --- a/agent/tcf/services/dwarfexpr.h +++ b/agent/tcf/services/dwarfexpr.h @@ -30,7 +30,22 @@ /* PropertyValue format for expresson evaluation results */ #define FORM_EXPR_VALUE 0x00ff -extern void dwarf_evaluate_expression(U8_T base, PropertyValue * value); +extern U8_T dwarf_expression_obj_addr; +extern U8_T dwarf_expression_pm_value; + +typedef struct DWARFExpressionInfo { + U8_T code_addr; + U8_T code_size; + CompUnit * unit; + ObjectInfo * object; + ELF_Section * section; + U1_T * expr_addr; + size_t expr_size; +} DWARFExpressionInfo; + +extern ObjectInfo * get_parent_function(ObjectInfo * info); +extern void dwarf_find_expression(PropertyValue * Value, U8_T IP, DWARFExpressionInfo * info); +extern void dwarf_evaluate_expression(PropertyValue * value); #endif /* ENABLE_ELF && ENABLE_DebugContext */ diff --git a/agent/tcf/services/dwarfframe.c b/agent/tcf/services/dwarfframe.c index d2fb540d..72b6851b 100644 --- a/agent/tcf/services/dwarfframe.c +++ b/agent/tcf/services/dwarfframe.c @@ -109,15 +109,15 @@ static StackFrameRules rules; U8_T dwarf_stack_trace_addr = 0; U8_T dwarf_stack_trace_size = 0; -StackTracingCommandSequence * dwarf_stack_trace_fp = NULL; +StackFrameRegisterLocation * dwarf_stack_trace_fp = NULL; int dwarf_stack_trace_regs_cnt = 0; -StackTracingCommandSequence ** dwarf_stack_trace_regs = NULL; +StackFrameRegisterLocation ** dwarf_stack_trace_regs = NULL; static int trace_regs_max = 0; -static int trace_cmds_max = 0; -static int trace_cmds_cnt = 0; -static StackTracingCommand * trace_cmds = NULL; +static unsigned trace_cmds_max = 0; +static unsigned trace_cmds_cnt = 0; +static LocationExpressionCommand * trace_cmds = NULL; static RegisterRules * get_reg(StackFrameRegisters * regs, int reg) { while (reg >= regs->regs_max) { @@ -423,11 +423,11 @@ static void exec_stack_frame_instruction(void) { } } -static StackTracingCommand * add_command(int op) { - StackTracingCommand * cmd = NULL; +static LocationExpressionCommand * add_command(int op) { + LocationExpressionCommand * cmd = NULL; if (trace_cmds_cnt >= trace_cmds_max) { trace_cmds_max += 16; - trace_cmds = (StackTracingCommand *)loc_realloc(trace_cmds, trace_cmds_max * sizeof(StackTracingCommand)); + trace_cmds = (LocationExpressionCommand *)loc_realloc(trace_cmds, trace_cmds_max * sizeof(LocationExpressionCommand)); } cmd = trace_cmds + trace_cmds_cnt++; memset(cmd, 0, sizeof(*cmd)); @@ -435,15 +435,15 @@ static StackTracingCommand * add_command(int op) { return cmd; } -static void add_command_sequence(StackTracingCommandSequence ** ptr, RegisterDefinition * reg) { - StackTracingCommandSequence * seq = *ptr; +static void add_command_sequence(StackFrameRegisterLocation ** ptr, RegisterDefinition * reg) { + StackFrameRegisterLocation * seq = *ptr; if (seq == NULL || seq->cmds_max < trace_cmds_cnt) { - *ptr = seq = (StackTracingCommandSequence *)loc_realloc(seq, sizeof(StackTracingCommandSequence) + (trace_cmds_cnt - 1) * sizeof(StackTracingCommand)); + *ptr = seq = (StackFrameRegisterLocation *)loc_realloc(seq, sizeof(StackFrameRegisterLocation) + (trace_cmds_cnt - 1) * sizeof(LocationExpressionCommand)); seq->cmds_max = trace_cmds_cnt; } seq->reg = reg; seq->cmds_cnt = trace_cmds_cnt; - memcpy(seq->cmds, trace_cmds, trace_cmds_cnt * sizeof(StackTracingCommand)); + memcpy(seq->cmds, trace_cmds, trace_cmds_cnt * sizeof(LocationExpressionCommand)); } static void add_dwarf_expression_commands(U8_T cmds_offs, U4_T cmds_size) { @@ -459,52 +459,52 @@ static void add_dwarf_expression_commands(U8_T cmds_offs, U4_T cmds_size) { ContextAddress rt_addr = elf_map_to_run_time_address( rules.ctx, rules.section->file, section, (ContextAddress)lt_addr); if (errno) str_exception(ERR_INV_DWARF, "Cannot get object run-time address"); - add_command(SFT_CMD_NUMBER)->num = rt_addr; + add_command(SFT_CMD_NUMBER)->args.num = rt_addr; } break; case OP_deref: { - StackTracingCommand * cmd = add_command(SFT_CMD_DEREF); - cmd->size = rules.address_size; - cmd->big_endian = rules.section->file->big_endian; + LocationExpressionCommand * cmd = add_command(SFT_CMD_DEREF); + cmd->args.deref.size = rules.address_size; + cmd->args.deref.big_endian = rules.section->file->big_endian; } break; case OP_deref_size: { - StackTracingCommand * cmd = add_command(SFT_CMD_DEREF); - cmd->size = dio_ReadU1(); - cmd->big_endian = rules.section->file->big_endian; + LocationExpressionCommand * cmd = add_command(SFT_CMD_DEREF); + cmd->args.deref.size = dio_ReadU1(); + cmd->args.deref.big_endian = rules.section->file->big_endian; } break; case OP_const1u: - add_command(SFT_CMD_NUMBER)->num = dio_ReadU1(); + add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU1(); break; case OP_const1s: - add_command(SFT_CMD_NUMBER)->num = (I1_T)dio_ReadU1(); + add_command(SFT_CMD_NUMBER)->args.num = (I1_T)dio_ReadU1(); break; case OP_const2u: - add_command(SFT_CMD_NUMBER)->num = dio_ReadU2(); + add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU2(); break; case OP_const2s: - add_command(SFT_CMD_NUMBER)->num = (I2_T)dio_ReadU2(); + add_command(SFT_CMD_NUMBER)->args.num = (I2_T)dio_ReadU2(); break; case OP_const4u: - add_command(SFT_CMD_NUMBER)->num = dio_ReadU4(); + add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU4(); break; case OP_const4s: - add_command(SFT_CMD_NUMBER)->num = (I4_T)dio_ReadU4(); + add_command(SFT_CMD_NUMBER)->args.num = (I4_T)dio_ReadU4(); break; case OP_const8u: - add_command(SFT_CMD_NUMBER)->num = dio_ReadU8(); + add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU8(); break; case OP_const8s: - add_command(SFT_CMD_NUMBER)->num = (I8_T)dio_ReadU8(); + add_command(SFT_CMD_NUMBER)->args.num = (I8_T)dio_ReadU8(); break; case OP_constu: - add_command(SFT_CMD_NUMBER)->num = dio_ReadU8LEB128(); + add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU8LEB128(); break; case OP_consts: - add_command(SFT_CMD_NUMBER)->num = dio_ReadS8LEB128(); + add_command(SFT_CMD_NUMBER)->args.num = dio_ReadS8LEB128(); break; case OP_and: add_command(SFT_CMD_AND); @@ -519,7 +519,7 @@ static void add_dwarf_expression_commands(U8_T cmds_offs, U4_T cmds_size) { add_command(SFT_CMD_ADD); break; case OP_plus_uconst: - add_command(SFT_CMD_NUMBER)->num = dio_ReadU8LEB128(); + add_command(SFT_CMD_NUMBER)->args.num = dio_ReadU8LEB128(); add_command(SFT_CMD_ADD); break; case OP_ge: @@ -569,7 +569,7 @@ static void add_dwarf_expression_commands(U8_T cmds_offs, U4_T cmds_size) { case OP_lit29: case OP_lit30: case OP_lit31: - add_command(SFT_CMD_NUMBER)->num = op - OP_lit0; + add_command(SFT_CMD_NUMBER)->args.num = op - OP_lit0; break; case OP_breg0: case OP_breg1: @@ -607,9 +607,9 @@ static void add_dwarf_expression_commands(U8_T cmds_offs, U4_T cmds_size) { I8_T offs = dio_ReadS8LEB128(); RegisterDefinition * def = get_reg_by_id(rules.ctx, op - OP_breg0, &rules.reg_id_scope); if (def == NULL) str_exception(errno, "Cannot read DWARF frame info"); - add_command(SFT_CMD_REGISTER)->reg = def; + add_command(SFT_CMD_REGISTER)->args.reg = def; if (offs != 0) { - add_command(SFT_CMD_NUMBER)->num = offs; + add_command(SFT_CMD_NUMBER)->args.num = offs; add_command(SFT_CMD_ADD); } } @@ -631,24 +631,24 @@ static void generate_register_commands(RegisterRules * reg, RegisterDefinition * case RULE_OFFSET: add_command(SFT_CMD_FP); if (reg->offset != 0) { - add_command(SFT_CMD_NUMBER)->num = reg->offset; + add_command(SFT_CMD_NUMBER)->args.num = reg->offset; add_command(SFT_CMD_ADD); } if (reg->rule == RULE_OFFSET) { - StackTracingCommand * cmd = add_command(SFT_CMD_DEREF); - cmd->size = dst_reg_def->size; - if (cmd->size > rules.address_size) cmd->size = rules.address_size; - cmd->big_endian = rules.section->file->big_endian; + LocationExpressionCommand * cmd = add_command(SFT_CMD_DEREF); + cmd->args.deref.size = dst_reg_def->size; + if (cmd->args.deref.size > rules.address_size) cmd->args.deref.size = rules.address_size; + cmd->args.deref.big_endian = rules.section->file->big_endian; } break; case RULE_SAME_VALUE: if (src_reg_def == NULL) return; - add_command(SFT_CMD_REGISTER)->reg = src_reg_def; + add_command(SFT_CMD_REGISTER)->args.reg = src_reg_def; break; case RULE_REGISTER: { RegisterDefinition * src_sef = get_reg_by_id(rules.ctx, reg->offset, &rules.reg_id_scope); - if (src_sef != NULL) add_command(SFT_CMD_REGISTER)->reg = src_sef; + if (src_sef != NULL) add_command(SFT_CMD_REGISTER)->args.reg = src_sef; } break; case RULE_EXPRESSION: @@ -656,10 +656,10 @@ static void generate_register_commands(RegisterRules * reg, RegisterDefinition * add_command(SFT_CMD_FP); add_dwarf_expression_commands(reg->expression, reg->offset); if (reg->rule == RULE_EXPRESSION) { - StackTracingCommand * cmd = add_command(SFT_CMD_DEREF); - cmd->size = dst_reg_def->size; - if (cmd->size > rules.address_size) cmd->size = rules.address_size; - cmd->big_endian = rules.section->file->big_endian; + LocationExpressionCommand * cmd = add_command(SFT_CMD_DEREF); + cmd->args.deref.size = dst_reg_def->size; + if (cmd->args.deref.size > rules.address_size) cmd->args.deref.size = rules.address_size; + cmd->args.deref.big_endian = rules.section->file->big_endian; } break; default: @@ -669,7 +669,7 @@ static void generate_register_commands(RegisterRules * reg, RegisterDefinition * if (dwarf_stack_trace_regs_cnt >= trace_regs_max) { int i; trace_regs_max += 16; - dwarf_stack_trace_regs = (StackTracingCommandSequence **)loc_realloc(dwarf_stack_trace_regs, trace_regs_max * sizeof(StackTracingCommandSequence *)); + dwarf_stack_trace_regs = (StackFrameRegisterLocation **)loc_realloc(dwarf_stack_trace_regs, trace_regs_max * sizeof(StackFrameRegisterLocation *)); for (i = dwarf_stack_trace_regs_cnt; i < trace_regs_max; i++) dwarf_stack_trace_regs[i] = NULL; } if (trace_cmds_cnt == 0) return; @@ -699,9 +699,9 @@ static void generate_commands(void) { case RULE_OFFSET: reg_def = get_reg_by_id(rules.ctx, rules.cfa_register, &rules.reg_id_scope); if (reg_def != NULL) { - add_command(SFT_CMD_REGISTER)->reg = reg_def; + add_command(SFT_CMD_REGISTER)->args.reg = reg_def; if (rules.cfa_offset != 0) { - add_command(SFT_CMD_NUMBER)->num = rules.cfa_offset; + add_command(SFT_CMD_NUMBER)->args.num = rules.cfa_offset; add_command(SFT_CMD_ADD); } } @@ -1012,7 +1012,7 @@ void get_dwarf_stack_frame_info(Context * ctx, ELF_File * file, ELF_Section * te dwarf_stack_trace_regs_cnt = 0; if (dwarf_stack_trace_fp == NULL) { - dwarf_stack_trace_fp = (StackTracingCommandSequence *)loc_alloc_zero(sizeof(StackTracingCommandSequence)); + dwarf_stack_trace_fp = (StackFrameRegisterLocation *)loc_alloc_zero(sizeof(StackFrameRegisterLocation)); dwarf_stack_trace_fp->cmds_max = 1; } dwarf_stack_trace_fp->cmds_cnt = 0; diff --git a/agent/tcf/services/dwarfframe.h b/agent/tcf/services/dwarfframe.h index 48a0c2f7..3cddbfdb 100644 --- a/agent/tcf/services/dwarfframe.h +++ b/agent/tcf/services/dwarfframe.h @@ -26,8 +26,8 @@ #if ENABLE_ELF && ENABLE_DebugContext -#include <tcf/framework/context.h> #include <tcf/services/dwarfcache.h> +#include <tcf/services/symbols.h> /* * Lookup stack tracing information in ELF file, in .debug_frame and .eh_frame sections. @@ -46,10 +46,10 @@ extern void get_dwarf_stack_frame_info(Context * ctx, ELF_File * file, ELF_Secti extern U8_T dwarf_stack_trace_addr; extern U8_T dwarf_stack_trace_size; -extern StackTracingCommandSequence * dwarf_stack_trace_fp; +extern StackFrameRegisterLocation * dwarf_stack_trace_fp; extern int dwarf_stack_trace_regs_cnt; -extern StackTracingCommandSequence ** dwarf_stack_trace_regs; +extern StackFrameRegisterLocation ** dwarf_stack_trace_regs; #endif /* ENABLE_ELF && ENABLE_DebugContext */ diff --git a/agent/tcf/services/dwarfio.c b/agent/tcf/services/dwarfio.c index 34ee2c8b..ee3d477e 100644 --- a/agent/tcf/services/dwarfio.c +++ b/agent/tcf/services/dwarfio.c @@ -209,7 +209,7 @@ U4_T dio_ReadULEB128(void) { int i = 0; for (;; i += 7) { U1_T n = dio_ReadU1(); - Res |= (n & 0x7Fu) << i; + Res |= (U4_T)(n & 0x7Fu) << i; if ((n & 0x80) == 0) break; } return Res; @@ -220,9 +220,9 @@ I4_T dio_ReadSLEB128(void) { int i = 0; for (;; i += 7) { U1_T n = dio_ReadU1(); - Res |= (n & 0x7Fu) << i; + Res |= (U4_T)(n & 0x7Fu) << i; if ((n & 0x80) == 0) { - Res |= -(n & 0x40) << i; + Res |= -(I4_T)(n & 0x40) << i; break; } } @@ -234,7 +234,7 @@ U8_T dio_ReadU8LEB128(void) { int i = 0; for (;; i += 7) { U1_T n = dio_ReadU1(); - Res |= (n & 0x7Fu) << i; + Res |= (U8_T)(n & 0x7Fu) << i; if ((n & 0x80) == 0) break; } return Res; @@ -245,9 +245,9 @@ I8_T dio_ReadS8LEB128(void) { int i = 0; for (;; i += 7) { U1_T n = dio_ReadU1(); - Res |= (n & 0x7Fu) << i; + Res |= (U8_T)(n & 0x7Fu) << i; if ((n & 0x80) == 0) { - Res |= -(n & 0x40) << i; + Res |= -(I8_T)(n & 0x40) << i; break; } } @@ -507,6 +507,7 @@ int dio_ReadEntry(DIO_EntryCallBack CallBack, U2_T TargetAttr) { case AT_specification_v1: case AT_specification_v2: case AT_abstract_origin: + case AT_extension: break; default: switch (Form) { @@ -757,6 +758,7 @@ void dio_ChkBlock(U2_T Form, U1_T ** Buf, size_t * Size) { case FORM_DATA2 : case FORM_DATA4 : case FORM_DATA8 : + case FORM_EXPRLOC : case FORM_SEC_OFFSET: assert(dio_gFormDataAddr >= sSection->data); assert((U1_T *)dio_gFormDataAddr < (U1_T *)sSection->data + sSection->size); diff --git a/agent/tcf/services/elf-loader.c b/agent/tcf/services/elf-loader.c index 627741b0..7bb573d7 100644 --- a/agent/tcf/services/elf-loader.c +++ b/agent/tcf/services/elf-loader.c @@ -198,7 +198,7 @@ static ContextAddress find_module(Context * ctx, ELF_File * exe_file, ELF_File * else if (strcmp(name, "l_tls_modid") == 0) offs_l_tls_modid = offs; } if (offs_l_addr == 0 || offs_l_next == 0 || offs_l_tls_modid == 0) - str_exception(errno, "Invalid 'link_map' fields"); + str_exception(ERR_OTHER, "Invalid 'link_map' fields"); while (link != 0) { ContextAddress l_tls_modid = 0; if (elf_read_memory_word(ctx, exe_file, link + offs_l_tls_modid, &l_tls_modid) < 0) exception(errno); diff --git a/agent/tcf/services/expressions.c b/agent/tcf/services/expressions.c index 6ba8b326..40b4852a 100644 --- a/agent/tcf/services/expressions.c +++ b/agent/tcf/services/expressions.c @@ -72,6 +72,8 @@ #define SY_SIZEOF 279 #define SY_NAME 280 #define SY_SCOPE 281 +#define SY_PM_D 282 +#define SY_PM_R 283 #define MODE_NORMAL 0 #define MODE_TYPE 1 @@ -289,7 +291,14 @@ static void next_sy(void) { case ';': case '?': case ',': + text_sy = ch; + return; case '.': + if (text_ch == '*') { + next_ch(); + text_sy = SY_PM_D; + return; + } text_sy = ch; return; case ':': @@ -303,6 +312,11 @@ static void next_sy(void) { case '-': if (text_ch == '>') { next_ch(); + if (text_ch == '*') { + next_ch(); + text_sy = SY_PM_R; + return; + } text_sy = SY_REF; return; } @@ -1156,14 +1170,33 @@ static void op_deref(int mode, Value * v) { } #if ENABLE_Symbols -static void find_field(Symbol * sym, ContextAddress offs, const char * name, Symbol ** res, ContextAddress * res_offs) { +static void evaluate_symbol_address(Symbol * sym, ContextAddress obj_addr, ContextAddress index, ContextAddress * addr) { + LocationExpressionState * state = NULL; + LocationInfo * loc_info = NULL; + StackFrame * stk_info = NULL; + uint64_t args[2]; + + args[0] = obj_addr; + args[1] = index; + if (get_location_info(sym, &loc_info) < 0) { + error(errno, "Cannot get symbol location expression"); + } + if (get_frame_info(expression_context, expression_frame, &stk_info) < 0) { + error(errno, "Cannot get stack frame info"); + } + state = evaluate_location_expression(expression_context, stk_info, loc_info->cmds, loc_info->cmds_cnt, args, 2); + if (state->stk_pos != 1) error(ERR_INV_EXPRESSION, "Cannot evaluate symbol address"); + *addr = (ContextAddress)state->stk[0]; +} + +static void find_field(Symbol * class_sym, ContextAddress obj_addr, const char * name, const char * id, Symbol ** field_sym, ContextAddress * field_addr) { Symbol ** children = NULL; Symbol ** inheritance = NULL; int count = 0; int h = 0; int i; - if (get_symbol_children(sym, &children, &count) < 0) { + if (get_symbol_children(class_sym, &children, &count) < 0) { error(errno, "Cannot retrieve field list"); } for (i = 0; i < count; i++) { @@ -1175,19 +1208,17 @@ static void find_field(Symbol * sym, ContextAddress offs, const char * name, Sym if (inheritance == NULL) inheritance = (Symbol **)tmp_alloc(sizeof(Symbol *) * count); inheritance[h++] = children[i]; } - else if (strcmp(s, name) == 0) { - *res = children[i]; - *res_offs = offs; + else if (name != NULL ? strcmp(s, name) == 0 : strcmp(symbol2id(children[i]), id) == 0) { + evaluate_symbol_address(children[i], obj_addr, 0, field_addr); + *field_sym = children[i]; return; } } for (i = 0; i < h; i++) { ContextAddress x = 0; - if (get_symbol_offset(inheritance[i], &x) < 0) { - error(errno, "Cannot retrieve field offset"); - } - find_field(inheritance[i], offs + x, name, res, res_offs); - if (*res != NULL) return; + evaluate_symbol_address(inheritance[i], obj_addr, 0, &x); + find_field(inheritance[i], x, name, id, field_sym, field_addr); + if (*field_sym != NULL) return; } } #endif @@ -1195,6 +1226,7 @@ static void find_field(Symbol * sym, ContextAddress offs, const char * name, Sym static void op_field(int mode, Value * v) { char * id = NULL; char * name = NULL; + if (!v->remote) error(ERR_INV_EXPRESSION, "L-value expected"); if (text_sy == SY_ID) id = (char *)text_val.value; else if (text_sy == SY_NAME) name = (char *)text_val.value; else error(ERR_INV_EXPRESSION, "Field name expected"); @@ -1204,59 +1236,31 @@ static void op_field(int mode, Value * v) { #if ENABLE_Symbols Symbol * sym = NULL; int sym_class = 0; - ContextAddress size = 0; - ContextAddress offs = 0; + ContextAddress addr = 0; - if (id != NULL) { - if (id2symbol(id, &sym) < 0) error(errno, "Invalid field ID"); - } - else { - find_field(v->type, 0, name, &sym, &offs); - } + find_field(v->type, v->address, name, id, &sym, &addr); if (sym == NULL) { - error(ERR_SYM_NOT_FOUND, "Symbol not found"); + error(ERR_SYM_NOT_FOUND, "Invalid field name or ID"); } if (get_symbol_class(sym, &sym_class) < 0) { error(errno, "Cannot retrieve symbol class"); } if (sym_class == SYM_CLASS_FUNCTION) { - ContextAddress word = 0; v->type_class = TYPE_CLASS_CARDINAL; get_symbol_type(sym, &v->type); if (v->type != NULL) get_array_symbol(v->type, 0, &v->type); - if (mode == MODE_NORMAL && get_symbol_address(sym, &word) < 0) { - error(errno, "Cannot retrieve symbol address"); - } - set_ctx_word_value(v, word); + set_ctx_word_value(v, addr); v->function = 1; } else { - ContextAddress x = 0; - if (sym_class != SYM_CLASS_REFERENCE) { - error(ERR_UNSUPPORTED, "Invalid symbol class"); - } + ContextAddress size = 0; if (get_symbol_size(sym, &size) < 0) { error(errno, "Cannot retrieve field size"); } - if (get_symbol_offset(sym, &x) < 0) { - error(errno, "Cannot retrieve field offset"); - } - offs += x; - if (v->sym != NULL && v->size == 0 && get_symbol_size(v->sym, &v->size) < 0) { - error(errno, "Cannot retrieve symbol size"); - } - if (offs + size > v->size) { - error(ERR_INV_EXPRESSION, "Invalid field offset and/or size"); - } - if (v->remote) { - if (mode != MODE_TYPE) v->address += offs; - } - else { - v->value = (uint8_t *)v->value + offs; - } + v->address = addr; + v->size = size; v->sym = NULL; v->reg = NULL; - v->size = size; if (get_symbol_type(sym, &v->type) < 0) { error(errno, "Cannot retrieve symbol type"); } @@ -1641,13 +1645,50 @@ static void unary_expression(int mode, Value * v) { #endif } -static void multiplicative_expression(int mode, Value * v) { +static void pm_expression(int mode, Value * v) { unary_expression(mode, v); - while (text_sy == '*' || text_sy == '/' || text_sy == '%') { +#if ENABLE_Symbols + while (text_sy == SY_PM_D || text_sy == SY_PM_R) { Value x; int sy = text_sy; next_sy(); unary_expression(mode, &x); + if (x.type == NULL || x.type_class != TYPE_CLASS_MEMBER_PTR) { + error(ERR_INV_EXPRESSION, "Invalid type: pointer to member expected"); + } + if (mode != MODE_SKIP) { + ContextAddress obj = 0; + ContextAddress ptr = 0; + ContextAddress addr = 0; + if (sy == SY_PM_D) { + if (!v->remote) error(ERR_INV_EXPRESSION, "L-value expected"); + obj = v->address; + } + else { + obj = (ContextAddress)to_uns(mode, v); + } + ptr = (ContextAddress)to_uns(mode, &x); + evaluate_symbol_address(x.type, obj, ptr, &addr); + set_ctx_word_value(v, addr); + v->constant = 0; + if (get_symbol_base_type(x.type, &v->type) < 0) { + error(ERR_INV_EXPRESSION, "Cannot get pointed type"); + } + if (get_symbol_type_class(x.type, &v->type_class) < 0) { + error(ERR_INV_EXPRESSION, "Cannot get pointed type class"); + } + } + } +#endif +} + +static void multiplicative_expression(int mode, Value * v) { + pm_expression(mode, v); + while (text_sy == '*' || text_sy == '/' || text_sy == '%') { + Value x; + int sy = text_sy; + next_sy(); + pm_expression(mode, &x); if (mode != MODE_SKIP) { if (!is_number(v) || !is_number(&x)) { error(ERR_INV_EXPRESSION, "Numeric types expected"); diff --git a/agent/tcf/services/linenumbers.h b/agent/tcf/services/linenumbers.h index fa4d5141..75519e67 100644 --- a/agent/tcf/services/linenumbers.h +++ b/agent/tcf/services/linenumbers.h @@ -26,8 +26,8 @@ #include <tcf/framework/context.h> typedef struct CodeArea { - char * directory; - char * file; + const char * directory; + const char * file; uint32_t file_mtime; uint32_t file_size; ContextAddress start_address; diff --git a/agent/tcf/services/linenumbers_elf.c b/agent/tcf/services/linenumbers_elf.c index 3415f932..37e22a0e 100644 --- a/agent/tcf/services/linenumbers_elf.c +++ b/agent/tcf/services/linenumbers_elf.c @@ -42,7 +42,7 @@ #include <tcf/services/stacktrace.h> #include <tcf/services/pathmap.h> -static int is_absolute_path(char * fnm) { +static int is_absolute_path(const char * fnm) { if (fnm[0] == '/') return 1; if (fnm[0] == '\\') return 1; if (fnm[0] != 0 && fnm[1] == ':') { @@ -52,7 +52,7 @@ static int is_absolute_path(char * fnm) { return 0; } -static int compare_path(Channel * chnl, Context * ctx, char * file, char * pwd, char * dir, char * name) { +static int compare_path(Channel * chnl, Context * ctx, const char * file, const char * pwd, const char * dir, const char * name) { int i, j; char buf[FILE_PATH_SIZE]; char * full_name = NULL; @@ -61,7 +61,7 @@ static int compare_path(Channel * chnl, Context * ctx, char * file, char * pwd, if (name == NULL) return 0; if (is_absolute_path(name)) { - full_name = name; + full_name = (char *)name; } else if (dir != NULL && is_absolute_path(dir)) { snprintf(full_name = buf, sizeof(buf), "%s/%s", dir, name); @@ -73,7 +73,7 @@ static int compare_path(Channel * chnl, Context * ctx, char * file, char * pwd, snprintf(full_name = buf, sizeof(buf), "%s/%s", pwd, name); } else { - full_name = name; + full_name = (char *)name; } full_name = canonic_path_map_file_name(full_name); #if SERVICE_PathMap @@ -81,6 +81,11 @@ static int compare_path(Channel * chnl, Context * ctx, char * file, char * pwd, full_name = apply_path_map(chnl, ctx, buf, PATH_MAP_TO_CLIENT); if (full_name != buf) full_name = canonic_path_map_file_name(full_name); #endif + while (file[0] == '.') { + if (file[1] == '.' && file[2] == '/') file += 3; + else if (file[1] == '/') file += 2; + else break; + } i = strlen(file); j = strlen(full_name); return i <= j && strcmp(file, full_name + j - i) == 0; @@ -97,18 +102,28 @@ static LineNumbersState * get_next_in_text(CompUnit * unit, LineNumbersState * s return next; } +static LineNumbersState * get_next_in_code(CompUnit * unit, LineNumbersState * state) { + LineNumbersState * next = state + 1; + if (next >= unit->mStates + unit->mStatesCnt) return NULL; + if (state->mFlags & LINE_EndSequence) return NULL; + return next; +} + static void call_client(CompUnit * unit, LineNumbersState * state, ContextAddress state_addr, LineNumbersCallBack * client, void * args) { CodeArea area; - LineNumbersState * next = get_next_in_text(unit, state); + LineNumbersState * code_next = get_next_in_code(unit, state); + LineNumbersState * text_next = get_next_in_text(unit, state); FileInfo * file_info = unit->mFiles + state->mFile; - if (state->mAddress >= (state + 1)->mAddress) return; + if (code_next == NULL) return; + if (state->mAddress >= code_next->mAddress) return; + memset(&area, 0, sizeof(area)); area.start_line = state->mLine; area.start_column = state->mColumn; - area.end_line = next ? next->mLine : state->mLine; - area.end_column = next ? next->mColumn : 0; + area.end_line = text_next ? text_next->mLine : state->mLine + 1; + area.end_column = text_next ? text_next->mColumn : 0; area.directory = unit->mDir; if (state->mFileName != NULL) { @@ -130,8 +145,8 @@ static void call_client(CompUnit * unit, LineNumbersState * state, area.file_mtime = file_info->mModTime; area.file_size = file_info->mSize; area.start_address = state_addr; - area.end_address = (state + 1)->mAddress - state->mAddress + state_addr; - if (next != NULL) area.next_address = next->mAddress; + area.end_address = code_next->mAddress - state->mAddress + state_addr; + if (text_next != NULL) area.next_address = text_next->mAddress; area.isa = state->mISA; area.is_statement = (state->mFlags & LINE_IsStmt) != 0; area.basic_block = (state->mFlags & LINE_BasicBlock) != 0; @@ -146,7 +161,7 @@ static void unit_line_to_address(Context * ctx, CompUnit * unit, unsigned file, LineNumbersCallBack * client, void * args) { if (unit->mStatesCnt >= 2) { unsigned l = 0; - unsigned h = unit->mStatesCnt - 1; + unsigned h = unit->mStatesCnt; while (l < h) { unsigned k = (h + l) / 2; LineNumbersState * state = unit->mStatesIndex[k]; @@ -162,20 +177,22 @@ static void unit_line_to_address(Context * ctx, CompUnit * unit, unsigned file, l = k + 1; } else { - unsigned i = k; - while (i > 0) { - LineNumbersState * prev = unit->mStatesIndex[i - 1]; + while (k > 0) { + LineNumbersState * prev = unit->mStatesIndex[k - 1]; if (prev->mFile != state->mFile) break; if (prev->mLine != state->mLine) break; if (prev->mColumn != state->mColumn) break; state = prev; - i--; + k--; } for (;;) { ContextAddress addr = elf_map_to_run_time_address(ctx, unit->mFile, unit->mTextSection, state->mAddress); if (errno == 0) call_client(unit, state, addr, client, args); - if (i == k) break; - state = unit->mStatesIndex[++i]; + if (++k >= unit->mStatesCnt) break; + state = unit->mStatesIndex[k]; + if (state->mFile > file) break; + if (state->mLine > line) break; + if (state->mColumn > column) break; } break; } @@ -252,12 +269,11 @@ int address_to_line(Context * ctx, ContextAddress addr0, ContextAddress addr1, L ContextAddress range_rt_addr = 0; UnitAddressRange * range = elf_find_unit(ctx, addr0, addr1, &range_rt_addr); if (range == NULL) break; - assert(range_rt_addr != 0); if (!range->mUnit->mLineInfoLoaded) load_line_numbers(range->mUnit); if (range->mUnit->mStatesCnt >= 2) { CompUnit * unit = range->mUnit; unsigned l = 0; - unsigned h = unit->mStatesCnt - 1; + unsigned h = unit->mStatesCnt; ContextAddress addr_min = addr0 - range_rt_addr + range->mAddr; ContextAddress addr_max = addr1 - range_rt_addr + range->mAddr; if (addr_min < range->mAddr) addr_min = range->mAddr; @@ -269,9 +285,8 @@ int address_to_line(Context * ctx, ContextAddress addr0, ContextAddress addr1, L h = k; } else { - LineNumbersState * next = state + 1; - assert(next->mAddress >= state->mAddress); - if (next->mAddress <= addr_min) { + LineNumbersState * next = get_next_in_code(unit, state); + if (next != NULL && next->mAddress <= addr_min) { l = k + 1; } else { @@ -279,17 +294,14 @@ int address_to_line(Context * ctx, ContextAddress addr0, ContextAddress addr1, L LineNumbersState * prev = unit->mStates + k - 1; if (state->mAddress <= addr_min) break; if (prev->mAddress >= addr_max) break; - next = state; state = prev; k--; } for (;;) { call_client(unit, state, state->mAddress - range->mAddr + range_rt_addr, client, args); - k++; - if (k >= unit->mStatesCnt - 1) break; + if (++k >= unit->mStatesCnt) break; state = unit->mStates + k; if (state->mAddress >= addr_max) break; - next = state + 1; } break; } diff --git a/agent/tcf/services/pathmap.c b/agent/tcf/services/pathmap.c index b3281c4a..bc8c020b 100644 --- a/agent/tcf/services/pathmap.c +++ b/agent/tcf/services/pathmap.c @@ -46,10 +46,13 @@ char * canonic_path_map_file_name(const char * fnm) { if (buf_pos > 0 && *fnm == '.' && (fnm[1] == '/' || fnm[1] == '\\')) { unsigned j = buf_pos - 1; if (j > 0 && buf[j - 1] != '/') { + buf[buf_pos] = 0; while (j > 0 && buf[j - 1] != '/') j--; - buf_pos = j; - fnm += 2; - continue; + if (strcmp(buf + j, "./") && strcmp(buf + j, "../")) { + buf_pos = j; + fnm += 2; + continue; + } } } } diff --git a/agent/tcf/services/stacktrace.c b/agent/tcf/services/stacktrace.c index 82fafeb8..d8035464 100644 --- a/agent/tcf/services/stacktrace.c +++ b/agent/tcf/services/stacktrace.c @@ -109,7 +109,7 @@ static void trace_stack(Context * ctx, StackTrace * stack) { break; } #endif - if (frame.fp == 0) { + if (frame.is_walked == 0) { trace(LOG_STACK, " *** frame info not available ***"); loc_free(down.regs); memset(&down, 0, sizeof(down)); diff --git a/agent/tcf/services/symbols.c b/agent/tcf/services/symbols.c index 214b7976..a563a227 100644 --- a/agent/tcf/services/symbols.c +++ b/agent/tcf/services/symbols.c @@ -26,6 +26,7 @@ #include <tcf/framework/cache.h> #include <tcf/services/stacktrace.h> #include <tcf/services/symbols.h> +#include <tcf/services/vm.h> static const char * SYMBOLS = "Symbols"; @@ -47,6 +48,7 @@ static void command_get_context_cache_client(void * x) { Symbol * type = NULL; Symbol * base = NULL; Symbol * index = NULL; + Symbol * container = NULL; int has_size = 0; int has_length = 0; int has_lower_bound = 0; @@ -75,6 +77,7 @@ static void command_get_context_cache_client(void * x) { get_symbol_type(sym, &type); get_symbol_base_type(sym, &base); get_symbol_index_type(sym, &index); + get_symbol_containing_type(sym, &container); has_size = get_symbol_size(sym, &size) == 0; has_length = get_symbol_length(sym, &length) == 0; if (has_length) { @@ -159,6 +162,13 @@ static void command_get_context_cache_client(void * x) { write_stream(&c->out, ','); } + if (container != NULL) { + json_write_string(&c->out, "ContainigTypeID"); + write_stream(&c->out, ':'); + json_write_string(&c->out, symbol2id(container)); + write_stream(&c->out, ','); + } + if (has_size) { json_write_string(&c->out, "Size"); write_stream(&c->out, ':'); @@ -586,28 +596,36 @@ typedef struct CommandFindFrameInfo { ContextAddress addr; } CommandFindFrameInfo; -static void write_commands(OutputStream * out, Context * ctx, StackTracingCommandSequence * seq) { +static void write_commands(OutputStream * out, Context * ctx, StackFrameRegisterLocation * seq) { if (seq != NULL) { - int i; + unsigned i; write_stream(out, '['); for (i = 0; i < seq->cmds_cnt; i++) { - StackTracingCommand * cmd = seq->cmds + i; + LocationExpressionCommand * cmd = seq->cmds + i; if (i > 0) write_stream(out, ','); json_write_long(out, cmd->cmd); switch (cmd->cmd) { case SFT_CMD_NUMBER: write_stream(out, ','); - json_write_int64(out, cmd->num); + json_write_int64(out, cmd->args.num); break; case SFT_CMD_REGISTER: write_stream(out, ','); - json_write_string(out, register2id(ctx, STACK_NO_FRAME, cmd->reg)); + json_write_string(out, register2id(ctx, STACK_NO_FRAME, cmd->args.reg)); break; case SFT_CMD_DEREF: write_stream(out, ','); - json_write_ulong(out, cmd->size); + json_write_ulong(out, cmd->args.deref.size); + write_stream(out, ','); + json_write_boolean(out, cmd->args.deref.big_endian); + break; + case SFT_CMD_USER: + write_stream(out, ','); + json_write_binary(out, cmd->args.user.code_addr, cmd->args.user.code_size); write_stream(out, ','); - json_write_boolean(out, cmd->big_endian); + /* TODO: SFT_CMD_USER parameters */ + write_stream(out, '{'); + write_stream(out, '}'); break; } } diff --git a/agent/tcf/services/symbols.h b/agent/tcf/services/symbols.h index 884699d2..aca6da0c 100644 --- a/agent/tcf/services/symbols.h +++ b/agent/tcf/services/symbols.h @@ -46,6 +46,7 @@ typedef struct Symbol Symbol; #define TYPE_CLASS_COMPOSITE 6 #define TYPE_CLASS_ENUMERATION 7 #define TYPE_CLASS_FUNCTION 8 +#define TYPE_CLASS_MEMBER_PTR 9 typedef uint32_t SYM_FLAGS; @@ -75,6 +76,35 @@ typedef uint32_t SYM_FLAGS; typedef void EnumerateSymbolsCallBack(void *, Symbol *); +#if ENABLE_DebugContext + +typedef struct LocationInfo { + ContextAddress addr; + ContextAddress size; + LocationExpressionCommand * cmds; + unsigned cmds_cnt; + unsigned cmds_max; +} LocationInfo; + +/* Stack tracing command sequence */ +typedef struct StackFrameRegisterLocation { + RegisterDefinition * reg; + unsigned cmds_cnt; + unsigned cmds_max; + LocationExpressionCommand cmds[1]; +} StackFrameRegisterLocation; + +/* Complete stack tracing info for a range of instruction addresses */ +typedef struct StackTracingInfo { + ContextAddress addr; + ContextAddress size; + StackFrameRegisterLocation * fp; + StackFrameRegisterLocation ** regs; + int reg_cnt; +} StackTracingInfo; + +#endif + #if ENABLE_Symbols /* @@ -119,7 +149,6 @@ extern const char * symbol2id(const Symbol * sym); */ extern int id2symbol(const char * id, Symbol ** sym); - /*************** Functions for retrieving symbol properties ***************************************/ /* * Each function retireves one particular attribute of an object or type. @@ -154,12 +183,16 @@ extern int get_symbol_name(const Symbol * sym, char ** name); /* Get value size of the type, in bytes */ extern int get_symbol_size(const Symbol * sym, ContextAddress * size); -/* Get base type ID */ +/* Get base type: pointer or member pointer - pointed object type, + * array - elements type, function - result type */ extern int get_symbol_base_type(const Symbol * sym, Symbol ** base_type); -/* Get array index type ID */ +/* Get array index type */ extern int get_symbol_index_type(const Symbol * sym, Symbol ** index_type); +/* Get containing type: field (member) or member pointer - parent structure */ +extern int get_symbol_containing_type(const Symbol * sym, Symbol ** containing_type); + /* Get array length (number of elements) */ extern int get_symbol_length(const Symbol * sym, ContextAddress * length); @@ -200,6 +233,9 @@ extern int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** */ extern ContextAddress is_plt_section(Context * ctx, ContextAddress addr); +/* Get object location expression */ +extern int get_location_info(const Symbol * sym, LocationInfo ** info); + /* * For given context and its registers in a stack frame, * compute stack frame location and next frame register values. diff --git a/agent/tcf/services/symbols_elf.c b/agent/tcf/services/symbols_elf.c index 785d87db..b4b34a7e 100644 --- a/agent/tcf/services/symbols_elf.c +++ b/agent/tcf/services/symbols_elf.c @@ -38,9 +38,11 @@ #include <tcf/services/dwarf.h> #include <tcf/services/dwarfcache.h> #include <tcf/services/dwarfexpr.h> +#include <tcf/services/dwarfecomp.h> #include <tcf/services/dwarfframe.h> #include <tcf/services/stacktrace.h> #include <tcf/services/symbols.h> +#include <tcf/services/vm.h> #if ENABLE_RCBP_TEST # include <tcf/main/test.h> #endif @@ -111,6 +113,12 @@ static struct BaseTypeAlias { #define SYMBOL_MAGIC 0x34875234 +/* This function is used for DWARF testing */ +extern ObjectInfo * get_symbol_object(Symbol * sym); +ObjectInfo * get_symbol_object(Symbol * sym) { + return sym->obj; +} + static Symbol * alloc_symbol(void) { Symbol * s = (Symbol *)tmp_alloc_zero(sizeof(Symbol)); s->magic = SYMBOL_MAGIC; @@ -207,6 +215,7 @@ static int is_frame_based_object(Symbol * sym) { case TAG_enumeration_type: case TAG_pointer_type: case TAG_reference_type: + case TAG_ptr_to_member_type: return 0; } break; @@ -369,7 +378,7 @@ static int get_num_prop(ObjectInfo * obj, U2_T at, U8_T * res) { PropertyValue v; if (!set_trap(&trap)) return 0; - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, at, &v); + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, obj, at, &v); *res = get_numeric_property_value(&v); clear_trap(&trap); return 1; @@ -395,7 +404,7 @@ static int check_in_range(ObjectInfo * obj, ContextAddress rt_offs, ContextAddre U8_T offs = 0; int res = 0; - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_ranges, &v); + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, obj, AT_ranges, &v); offs = get_numeric_property_value(&v); dio_EnterSection(&unit->mDesc, debug_ranges, offs); for (;;) { @@ -424,46 +433,49 @@ static int check_in_range(ObjectInfo * obj, ContextAddress rt_offs, ContextAddre return 0; } -static int map_to_sym_table(ObjectInfo * obj, Symbol ** sym); - /* If 'sym' represents a declaration, replace it with definition - if possible */ static ObjectInfo * find_definition(ObjectInfo * decl) { - Symbol * sym = NULL; if (decl == NULL) return NULL; if (!(decl->mFlags & DOIF_declaration)) return decl; if (decl->mDefinition != NULL) return decl->mDefinition; - if (map_to_sym_table(decl, &sym) && sym->obj != NULL) return sym->obj; return decl; } -static int find_in_object_tree(ObjectInfo * list, ContextAddress rt_offs, ContextAddress ip, const char * name, Symbol ** sym) { +static int find_in_object_tree(ObjectInfo * parent, ContextAddress rt_offs, ContextAddress ip, const char * name, Symbol ** sym) { Symbol * sym_imp = NULL; /* Imported from a namespace */ Symbol * sym_enu = NULL; /* Enumeration constant */ Symbol * sym_cur = NULL; /* Found in current scope */ Symbol * sym_base = NULL; /* Found in base class (inherited) */ Symbol * sym_this = NULL; /* Found in 'this' reference */ - ObjectInfo * obj = list; + ObjectInfo * obj = get_dwarf_children(parent); + U8_T obj_ptr = 0; + + if (parent->mTag == TAG_subprogram) get_num_prop(parent, AT_object_pointer, &obj_ptr); + while (obj != NULL) { if (obj->mName != NULL && !(obj->mFlags & DOIF_specification)) { if (strcmp(obj->mName, name) == 0) { object2symbol(obj, &sym_cur); } - if (sym_frame != STACK_NO_FRAME && (obj->mFlags & DOIF_artificial) && strcmp(obj->mName, "this") == 0) { - ObjectInfo * type = get_original_type(obj); - if ((type->mTag == TAG_pointer_type || type->mTag == TAG_mod_pointer) && type->mType != NULL) { - type = get_original_type(type->mType); - find_in_object_tree(get_dwarf_children(type), 0, 0, name, &sym_this); - if (sym_this != NULL) { - sym_this->ctx = sym_ctx; - sym_this->frame = sym_frame; - sym_this->var = obj; + if (parent->mTag == TAG_subprogram) { + if (obj->mID == obj_ptr || (obj_ptr == 0 && obj->mTag == TAG_formal_parameter && + (obj->mFlags & DOIF_artificial) && strcmp(obj->mName, "this") == 0)) { + ObjectInfo * type = get_original_type(obj); + if ((type->mTag == TAG_pointer_type || type->mTag == TAG_mod_pointer) && type->mType != NULL) { + type = get_original_type(type->mType); + find_in_object_tree(type, 0, 0, name, &sym_this); + if (sym_this != NULL) { + sym_this->ctx = sym_ctx; + sym_this->frame = sym_frame; + sym_this->var = obj; + } } } } } switch (obj->mTag) { case TAG_enumeration_type: - find_in_object_tree(get_dwarf_children(obj), 0, 0, name, &sym_enu); + find_in_object_tree(obj, 0, 0, name, &sym_enu); break; case TAG_global_subroutine: case TAG_inlined_subroutine: @@ -472,19 +484,19 @@ static int find_in_object_tree(ObjectInfo * list, ContextAddress rt_offs, Contex case TAG_entry_point: case TAG_lexical_block: if (ip != 0 && check_in_range(obj, rt_offs, ip)) { - if (find_in_object_tree(get_dwarf_children(obj), rt_offs, ip, name, sym)) return 1; + if (find_in_object_tree(obj, rt_offs, ip, name, sym)) return 1; } break; case TAG_inheritance: - find_in_object_tree(get_dwarf_children(obj->mType), 0, 0, name, &sym_base); + find_in_object_tree(obj->mType, 0, 0, name, &sym_base); break; case TAG_imported_module: { PropertyValue p; ObjectInfo * module; - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_import, &p); + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, obj, AT_import, &p); module = find_object(get_dwarf_cache(obj->mCompUnit->mFile), (ContextAddress)p.mValue); - if (module != NULL) find_in_object_tree(get_dwarf_children(module), 0, 0, name, &sym_imp); + if (module != NULL) find_in_object_tree(module, 0, 0, name, &sym_imp); } break; } @@ -495,7 +507,16 @@ static int find_in_object_tree(ObjectInfo * list, ContextAddress rt_offs, Contex if (*sym == NULL) *sym = sym_this; if (*sym == NULL) *sym = sym_enu; if (*sym == NULL) *sym = sym_imp; - if (*sym != NULL && sym_ip != 0) (*sym)->obj = find_definition((*sym)->obj); + + if (*sym == NULL && (parent->mFlags & DOIF_extension)) { + PropertyValue p; + ObjectInfo * name_space; + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, parent, AT_extension, &p); + name_space = find_object(get_dwarf_cache(obj->mCompUnit->mFile), (ContextAddress)p.mValue); + if (name_space != NULL) find_in_object_tree(name_space, 0, 0, name, &sym_imp); + } + + if (*sym != NULL) (*sym)->obj = find_definition((*sym)->obj); return *sym != NULL; } @@ -505,9 +526,9 @@ static int find_in_dwarf(const char * name, Symbol ** sym) { *sym = NULL; if (range != NULL) { CompUnit * unit = range->mUnit; - if (find_in_object_tree(get_dwarf_children(unit->mObject), rt_addr - range->mAddr, sym_ip, name, sym)) return 1; + if (find_in_object_tree(unit->mObject, rt_addr - range->mAddr, sym_ip, name, sym)) return 1; if (unit->mBaseTypes != NULL) { - if (find_in_object_tree(get_dwarf_children(unit->mBaseTypes->mObject), 0, 0, name, sym)) return 1; + if (find_in_object_tree(unit->mBaseTypes->mObject, 0, 0, name, sym)) return 1; } } return 0; @@ -813,7 +834,7 @@ int find_symbol_in_scope(Context * ctx, int frame, ContextAddress ip, Symbol * s DWARFCache * cache = get_dwarf_cache(get_dwarf_file(file)); UnitAddressRange * range = find_comp_unit_addr_range(cache, sym_ip, sym_ip); if (range != NULL) { - found = find_in_object_tree(get_dwarf_children(range->mUnit->mObject), 0, 0, name, res); + found = find_in_object_tree(range->mUnit->mObject, 0, 0, name, res); } if (!found) { found = find_by_name_in_sym_table(cache, name, res); @@ -834,7 +855,7 @@ int find_symbol_in_scope(Context * ctx, int frame, ContextAddress ip, Symbol * s if (!found && !error && scope != NULL && scope->obj != NULL) { Trap trap; if (set_trap(&trap)) { - found = find_in_object_tree(get_dwarf_children(scope->obj), 0, 0, name, res); + found = find_in_object_tree(scope->obj, 0, 0, name, res); clear_trap(&trap); } else { @@ -1000,7 +1021,6 @@ static void enumerate_local_vars(ObjectInfo * obj, int level, ContextAddress rt_ int enumerate_symbols(Context * ctx, int frame, EnumerateSymbolsCallBack * call_back, void * args) { Trap trap; if (!set_trap(&trap)) return -1; - if (frame == STACK_TOP_FRAME && (frame = get_top_frame(ctx)) < 0) exception(errno); if (get_sym_context(ctx, frame, 0) < 0) exception(errno); if (sym_ip != 0) { ContextAddress rt_addr = 0; @@ -1172,7 +1192,6 @@ ContextAddress is_plt_section(Context * ctx, ContextAddress addr) { int get_stack_tracing_info(Context * ctx, ContextAddress rt_addr, StackTracingInfo ** info) { /* TODO: no debug info exists for linux-gate.so, need to read stack tracing information from the kernel */ - /* TODO: support for separate debug info files */ ELF_File * file = NULL; ELF_Section * sec = NULL; ContextAddress lt_addr = 0; @@ -1226,16 +1245,23 @@ int get_next_stack_frame(StackFrame * frame, StackFrame * down) { Trap trap; if (set_trap(&trap)) { int i; - frame->fp = (ContextAddress)evaluate_stack_trace_commands(ctx, frame, info->fp); + LocationExpressionState * state; + state = evaluate_location_expression(ctx, frame, info->fp->cmds, info->fp->cmds_cnt, NULL, 0); + if (state->stk_pos != 1) str_exception(ERR_OTHER, "Invalid stack trace expression"); + frame->fp = (ContextAddress)state->stk[0]; + frame->is_walked = 1; for (i = 0; i < info->reg_cnt; i++) { int ok = 0; uint64_t v = 0; Trap trap_reg; if (set_trap(&trap_reg)) { /* If a saved register value cannot be evaluated - ignore it */ - v = evaluate_stack_trace_commands(ctx, frame, info->regs[i]); + state = evaluate_location_expression(ctx, frame, info->regs[i]->cmds, info->regs[i]->cmds_cnt, NULL, 0); + if (state->stk_pos == 1) { + v = state->stk[0]; + ok = 1; + } clear_trap(&trap_reg); - ok = 1; } if (ok && write_reg_value(down, info->regs[i]->reg, v) < 0) exception(errno); } @@ -1314,7 +1340,7 @@ static int map_to_sym_table(ObjectInfo * obj, Symbol ** sym) { if (set_trap(&trap)) { PropertyValue p; DWARFCache * cache = get_dwarf_cache(obj->mCompUnit->mFile); - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_MIPS_linkage_name, &p); + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, obj, AT_MIPS_linkage_name, &p); if (p.mAddr != NULL) found = find_by_name_in_sym_table(cache, (char *)p.mAddr, sym); clear_trap(&trap); } @@ -1322,8 +1348,77 @@ static int map_to_sym_table(ObjectInfo * obj, Symbol ** sym) { return found; } +static U8_T read_string_length(ObjectInfo * obj); + +static int get_object_size(ObjectInfo * obj, unsigned dimension, U8_T * byte_size, U8_T * bit_size) { + U8_T n = 0, m = 0; + obj = find_definition(obj); + if (get_num_prop(obj, AT_byte_size, &n)) { + *byte_size = n; + return 1; + } + if (get_num_prop(obj, AT_bit_size, &n)) { + *byte_size = (n + 7) / 8; + *bit_size = n; + return 1; + } + switch (obj->mTag) { + case TAG_enumerator: + case TAG_formal_parameter: + case TAG_unspecified_parameters: + case TAG_template_type_param: + case TAG_global_variable: + case TAG_local_variable: + case TAG_variable: + case TAG_inheritance: + case TAG_member: + case TAG_constant: + case TAG_const_type: + case TAG_volatile_type: + case TAG_restrict_type: + case TAG_shared_type: + case TAG_typedef: + if (obj->mType == NULL) return 0; + return get_object_size(obj->mType, 0, byte_size, bit_size); + case TAG_global_subroutine: + case TAG_subroutine: + case TAG_subprogram: + if (obj->u.mAddr.mHighPC > obj->u.mAddr.mLowPC) { + *byte_size = obj->u.mAddr.mHighPC - obj->u.mAddr.mLowPC; + return 1; + } + return 0; + case TAG_string_type: + *byte_size = read_string_length(obj); + return 1; + case TAG_array_type: + { + unsigned i = 0; + U8_T length = 1; + ObjectInfo * idx = get_dwarf_children(obj); + while (idx != NULL) { + if (i++ >= dimension) length *= get_array_index_length(idx); + idx = idx->mSibling; + } + if (get_num_prop(obj, AT_stride_size, &n)) { + *byte_size = (n * length + 7) / 8; + *bit_size = n * length; + return 1; + } + if (obj->mType == NULL) return 0; + if (!get_object_size(obj->mType, 0, &n, &m)) return 0; + if (m != 0) { + *byte_size = (m * length + 7) / 8; + *bit_size = m * length; + } + *byte_size = n * length; + } + return 1; + } + return 0; +} + static void read_object_value(PropertyValue * v, void ** value, size_t * size, int * big_endian) { - assert(v->mForm == FORM_EXPR_VALUE); if (v->mPieces != NULL) { U4_T n = 0; U1_T * bf = NULL; @@ -1331,27 +1426,27 @@ static void read_object_value(PropertyValue * v, void ** value, size_t * size, i U4_T bf_offs = 0; while (n < v->mPieceCnt) { U4_T i; - PropertyValuePiece * piece = v->mPieces + n++; - U4_T piece_size = (piece->mBitSize + 7) / 8; + LocationPiece * piece = v->mPieces + n++; + U4_T piece_size = piece->size ? piece->size : (piece->bit_offs + piece->bit_size + 7) / 8; + U4_T piece_bits = piece->bit_size ? piece->bit_size : piece->size * 8; U1_T * pbf = (U1_T *)tmp_alloc(piece_size); if (bf_size < bf_offs / 8 + piece_size + 1) { bf_size = bf_offs / 8 + piece_size + 1; bf = (U1_T *)tmp_realloc(bf, bf_size); } - if (piece->mRegister) { + if (piece->reg) { StackFrame * frame = NULL; - RegisterDefinition * def = piece->mRegister; if (get_frame_info(v->mContext, v->mFrame, &frame) < 0) exception(errno); - if (read_reg_bytes(frame, def, 0, piece_size, pbf) < 0) exception(errno); + if (read_reg_bytes(frame, piece->reg, 0, piece_size, pbf) < 0) exception(errno); } - else if (piece->mValue) { - memcpy(pbf, piece->mValue, piece_size); + else if (piece->value) { + memcpy(pbf, piece->value, piece_size); } else { - if (context_read_mem(v->mContext, piece->mAddress, pbf, piece_size) < 0) exception(errno); + if (context_read_mem(v->mContext, piece->addr, pbf, piece_size) < 0) exception(errno); } - if (!piece->mBigEndian != !v->mBigEndian) swap_bytes(pbf, piece_size); - for (i = piece->mBitOffset; i < piece->mBitOffset + piece->mBitSize; i++) { + if (!piece->big_endian != !v->mBigEndian) swap_bytes(pbf, piece_size); + for (i = piece->bit_offs; i < piece->bit_offs + piece_bits; i++) { if (pbf[i / 8] & (1u << (i % 8))) { bf[bf_offs / 8] |= (1u << (bf_offs % 8)); } @@ -1369,29 +1464,6 @@ static void read_object_value(PropertyValue * v, void ** value, size_t * size, i *size = bf_offs / 8; *big_endian = v->mBigEndian; } - else if (v->mRegister != NULL) { - StackFrame * frame = NULL; - RegisterDefinition * def = v->mRegister; - ContextAddress sym_size = 0; - ContextAddress bit_size = 0; - unsigned val_offs = 0; - unsigned val_size = 0; - U1_T * bf = NULL; - U8_T n = 0; - - if (get_num_prop(v->mObject, AT_byte_size, &n)) sym_size = (ContextAddress)n; - else if (get_num_prop(v->mObject, AT_bit_size, &n)) sym_size = ((bit_size = (ContextAddress)n) + 7) / 8; - else sym_size = def->size; - if (get_frame_info(v->mContext, v->mFrame, &frame) < 0) exception(errno); - val_size = def->size < sym_size ? (unsigned)def->size : (unsigned)sym_size; - if (def->big_endian) val_offs = (unsigned)def->size - val_size; - bf = (U1_T *)tmp_alloc(val_size); - if (read_reg_bytes(frame, def, val_offs, val_size, bf) < 0) exception(errno); - if (bit_size % 8 != 0) bf[bit_size / 8] &= (1 << (bit_size % 8)) - 1; - *value = bf; - *size = val_size; - *big_endian = def->big_endian; - } else if (v->mAddr != NULL) { *value = v->mAddr; *size = v->mSize; @@ -1399,19 +1471,17 @@ static void read_object_value(PropertyValue * v, void ** value, size_t * size, i } else { U1_T * bf = NULL; - size_t val_size = 0; - size_t bit_size = 0; - U8_T n = 0; + U8_T val_size = 0; + U8_T bit_size = 0; - if (get_num_prop(v->mObject, AT_byte_size, &n)) val_size = (size_t)n; - else if (get_num_prop(v->mObject, AT_bit_size, &n)) val_size = ((bit_size = (size_t)n) + 7) / 8; + if (get_object_size(v->mObject, 0, &val_size, &bit_size)) {} else if (v->mAttr == AT_string_length) val_size = v->mObject->mCompUnit->mDesc.mAddressSize; else str_exception(ERR_INV_DWARF, "Unknown object size"); - bf = (U1_T *)tmp_alloc(val_size); - if (context_read_mem(sym_ctx, (ContextAddress)v->mValue, bf, val_size) < 0) exception(errno); + bf = (U1_T *)tmp_alloc((size_t)val_size); + if (context_read_mem(sym_ctx, (ContextAddress)v->mValue, bf, (size_t)val_size) < 0) exception(errno); if (bit_size % 8 != 0) bf[bit_size / 8] &= (1 << (bit_size % 8)) - 1; *value = bf; - *size = val_size; + *size = (size_t)val_size; *big_endian = v->mBigEndian; } } @@ -1437,7 +1507,7 @@ static U8_T read_string_length(ObjectInfo * obj) { if (set_trap(&trap)) { PropertyValue v; - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_string_length, &v); + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, obj, AT_string_length, &v); len = read_cardinal_object_value(&v); clear_trap(&trap); return len; @@ -1446,7 +1516,7 @@ static U8_T read_string_length(ObjectInfo * obj) { exception(trap.error); } if (get_num_prop(obj, AT_byte_size, &len)) return len; - str_exception(ERR_INV_DWARF, "Unknown lemgth of a string type"); + str_exception(ERR_INV_DWARF, "Unknown length of a string type"); return 0; } @@ -1530,6 +1600,9 @@ int get_symbol_type_class(const Symbol * sym, int * type_class) { case TAG_mod_reference: *type_class = TYPE_CLASS_POINTER; return 0; + case TAG_ptr_to_member_type: + *type_class = TYPE_CLASS_MEMBER_PTR; + return 0; case TAG_class_type: case TAG_structure_type: case TAG_union_type: @@ -1653,7 +1726,7 @@ int get_symbol_name(const Symbol * sym, char ** name) { *name = (char *)constant_pseudo_symbols[(int)sym->length].name; } else if (sym->obj != NULL) { - *name = sym->obj->mName; + *name = (char *)sym->obj->mName; } else if (sym->tbl != NULL) { ELF_SymbolInfo info; @@ -1694,86 +1767,42 @@ int get_symbol_size(const Symbol * sym, ContextAddress * size) { if (unpack(sym) < 0) return -1; *size = 0; if (obj != NULL) { - Trap trap; int ok = 0; U8_T sz = 0; + U8_T n = 0; - if (!set_trap(&trap)) return -1; - if (sym->dimension == 0 && obj->mTag != TAG_string_type) { - ok = get_num_prop(obj, AT_byte_size, &sz); - } - if (!ok && sym->sym_class == SYM_CLASS_FUNCTION) { - if (obj->u.mAddr.mHighPC > obj->u.mAddr.mLowPC) { - ok = 1; - sz = obj->u.mAddr.mHighPC - obj->u.mAddr.mLowPC; - } - } - else if (!ok) { - ObjectInfo * ref = NULL; - if (sym->sym_class == SYM_CLASS_REFERENCE) { - ref = obj; - if (obj->mType != NULL) { - obj = obj->mType; - if (sym->dimension == 0) ok = get_num_prop(obj, AT_byte_size, &sz); - } - } - while (!ok && obj->mType != NULL) { - if (!is_modified_type(obj) && obj->mTag != TAG_enumeration_type) break; - obj = find_definition(obj->mType); - if (sym->dimension == 0) ok = get_num_prop(obj, AT_byte_size, &sz); - } - if (!ok && obj->mTag == TAG_array_type) { - unsigned i = 0; - U8_T length = 1; - ObjectInfo * elem_type = obj->mType; - ObjectInfo * idx = get_dwarf_children(obj); - while (idx != NULL) { - if (i++ >= sym->dimension) length *= get_array_index_length(idx); - idx = idx->mSibling; - } - ok = get_num_prop(obj, AT_stride_size, &sz); - if (ok) { - sz = (sz * length + 7) / 8; - } - else { - if (elem_type == NULL) str_exception(ERR_OTHER, "Unknown array element type"); - ok = get_num_prop(elem_type, AT_byte_size, &sz); - while (!ok && elem_type->mType != NULL) { - if (!is_modified_type(elem_type) && elem_type->mTag != TAG_enumeration_type) break; - elem_type = elem_type->mType; - ok = get_num_prop(elem_type, AT_byte_size, &sz); + ok = get_object_size(obj, sym->dimension, &sz, &n); + if (!ok && sym->sym_class == SYM_CLASS_REFERENCE) { + Trap trap; + if (set_trap(&trap)) { + PropertyValue v; + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, obj, AT_location, &v); + if (v.mPieces) { + U4_T i = 0, j = 0; + while (i < v.mPieceCnt) { + LocationPiece * p = v.mPieces + i++; + if (p->bit_size) j += p->bit_size; + else sz += p->size; } - if (ok) sz *= length; + sz += (j + 7) / 8; + ok = 1; } + clear_trap(&trap); } - if (!ok && obj->mTag == TAG_string_type) { - sz = read_string_length(obj); + } + if (!ok && sym->sym_class == SYM_CLASS_REFERENCE) { + Symbol * elf_sym = NULL; + ContextAddress elf_sym_size = 0; + if (map_to_sym_table(obj, &elf_sym) && get_symbol_size(elf_sym, &elf_sym_size) == 0) { + sz = elf_sym_size; ok = 1; } - if (!ok && ref && ref->mTag != TAG_member && ref->mTag != TAG_inheritance) { - Trap trap; - if (set_trap(&trap)) { - PropertyValue v; - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, ref, AT_location, &v); - if (v.mRegister) { - sz = v.mRegister->size; - ok = 1; - } - clear_trap(&trap); - } - } - if (!ok && ref != NULL) { - Symbol * elf_sym = NULL; - ContextAddress elf_sym_size = 0; - if (map_to_sym_table(ref, &elf_sym) && get_symbol_size(elf_sym, &elf_sym_size) == 0) { - sz = elf_sym_size; - ok = 1; - } - } } - if (!ok) str_exception(ERR_INV_DWARF, "Object has no size attribute"); + if (!ok) { + set_errno(ERR_INV_DWARF, "Object has no size attribute"); + return -1; + } *size = (ContextAddress)sz; - clear_trap(&trap); } else if (sym->tbl != NULL) { ELF_SymbolInfo info; @@ -1892,6 +1921,31 @@ int get_symbol_index_type(const Symbol * sym, Symbol ** index_type) { return -1; } +int get_symbol_containing_type(const Symbol * sym, Symbol ** containing_type) { + ObjectInfo * obj = sym->obj; + if (obj != NULL) { + if (unpack(sym) < 0) return -1; + if (obj->mTag == TAG_ptr_to_member_type) { + U8_T id = 0; + if (get_num_prop(obj, AT_constaining_type, &id)) { + ObjectInfo * type = find_object(get_dwarf_cache(obj->mCompUnit->mFile), (ContextAddress)id); + if (type != NULL) { + object2symbol(type, containing_type); + return 0; + } + } + set_errno(ERR_INV_DWARF, "Invalid AT_constaining_type attribute"); + return -1; + } + if (obj->mTag == TAG_member && obj->mParent != NULL) { + object2symbol(obj->mParent, containing_type); + return 0; + } + } + errno = ERR_UNSUPPORTED; + return -1; +} + int get_symbol_length(const Symbol * sym, ContextAddress * length) { ObjectInfo * obj = sym->obj; assert(sym->magic == SYMBOL_MAGIC); @@ -2060,6 +2114,7 @@ int get_symbol_offset(const Symbol * sym, ContextAddress * offset) { if (unpack(sym) < 0) return -1; if (obj != NULL && (obj->mTag == TAG_member || obj->mTag == TAG_inheritance)) { U8_T v; + dwarf_expression_obj_addr = 0; if (get_num_prop(obj, AT_data_member_location, &v)) { *offset = (ContextAddress)v; return 0; @@ -2100,26 +2155,8 @@ int get_symbol_value(const Symbol * sym, void ** value, size_t * size, int * big Trap trap; PropertyValue v; if (set_trap(&trap)) { - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_const_value, &v); - if (v.mAddr != NULL) { - *size = v.mSize; - *value = v.mAddr; - } - else if (v.mRegister != NULL || v.mPieces != NULL) { - str_exception(ERR_INV_CONTEXT, "Constant DWARF attribute value expected"); - } - else { - U8_T n = v.mValue; - size_t i = 0; - U1_T * bf = (U1_T *)tmp_alloc(sizeof(v.mValue)); - for (i = 0; i < sizeof(v.mValue); i++) { - bf[v.mBigEndian ? sizeof(v.mValue) - i - 1 : i] = n & 0xffu; - n = n >> 8; - } - *size = sizeof(v.mValue); - *value = bf; - } - *big_endian = v.mBigEndian; + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, obj, AT_const_value, &v); + read_object_value(&v, value, size, big_endian); clear_trap(&trap); return 0; } @@ -2127,7 +2164,7 @@ int get_symbol_value(const Symbol * sym, void ** value, size_t * size, int * big return -1; } if (set_trap(&trap)) { - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_location, &v); + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, obj, AT_location, &v); read_object_value(&v, value, size, big_endian); clear_trap(&trap); return 0; @@ -2170,14 +2207,16 @@ static int calc_member_offset(ObjectInfo * type, ObjectInfo * member, ContextAdd PropertyValue v; ObjectInfo * obj = NULL; if (member->mParent == type) { - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, member, AT_data_member_location, &v); + dwarf_expression_obj_addr = 0; + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, member, AT_data_member_location, &v); *offs = (ContextAddress)get_numeric_property_value(&v); return 1; } obj = get_dwarf_children(type); while (obj != NULL) { if (obj->mTag == TAG_inheritance && calc_member_offset(obj->mType, member, offs)) { - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_data_member_location, &v); + dwarf_expression_obj_addr = 0; + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, obj, AT_data_member_location, &v); *offs += (ContextAddress)get_numeric_property_value(&v); return 1; } @@ -2186,19 +2225,178 @@ static int calc_member_offset(ObjectInfo * type, ObjectInfo * member, ContextAdd return 0; } -int get_symbol_address(const Symbol * sym, ContextAddress * address) { +static LocationInfo * location_info = NULL; +static LocationExpressionState * user_command_state = NULL; + +static void user_command_client_op(uint8_t op) { + switch (op) { +#if 0 + case OP_addr: + U8_T addr = dio_ReadAddress(§ion); + addr = elf_map_to_run_time_address(user_command_state->ctx, Unit->mFile, section, (ContextAddress)addr); + if (errno) str_exception(errno, "Cannot get object run-time address"); + user_command_state->stk[user_command_state->stk_pos++] = addr; + break; +#endif + default: + str_fmt_exception(ERR_UNSUPPORTED, "Unsupported location expression op 0x%02x", op); + break; + } +} + +static int user_command_callback(LocationExpressionState * state) { + user_command_state = state; + state->client_op = user_command_client_op; + return evaluate_vm_expression(state); +} + +static LocationExpressionCommand * add_location_command(int op) { + LocationExpressionCommand * cmd = NULL; + if (location_info->cmds_cnt >= location_info->cmds_max) { + location_info->cmds_max += 4; + location_info->cmds = (LocationExpressionCommand *)tmp_realloc(location_info->cmds, + sizeof(LocationExpressionCommand) * location_info->cmds_max); + } + cmd = location_info->cmds + location_info->cmds_cnt++; + memset(cmd, 0, sizeof(LocationExpressionCommand)); + cmd->cmd = op; + return cmd; +} + +static LocationExpressionCommand * add_user_command(PropertyValue * v) { + DWARFExpressionInfo info; + LocationExpressionCommand * cmd = add_location_command(SFT_CMD_USER); + + dwarf_find_expression(v, sym_ip, &info); + dwarf_transform_expression(sym_ctx, sym_ip, &info); + location_info->addr = info.code_addr; + location_info->size = info.code_size; + cmd->args.user.code_addr = info.expr_addr; + cmd->args.user.code_size = info.expr_size; + cmd->args.user.reg_id_scope = v->mObject->mCompUnit->mRegIdScope; + cmd->args.user.addr_size = v->mObject->mCompUnit->mDesc.mAddressSize; + cmd->args.user.big_endian = v->mBigEndian; + cmd->args.user.func = user_command_callback; + return cmd; +} + +int get_location_info(const Symbol * sym, LocationInfo ** info) { ObjectInfo * obj = sym->obj; + assert(sym->magic == SYMBOL_MAGIC); + *info = location_info = (LocationInfo *)tmp_alloc_zero(sizeof(LocationInfo)); + + if (sym->has_address) { + add_location_command(SFT_CMD_NUMBER)->args.num = sym->address; + return 0; + } + if (is_array_type_pseudo_symbol(sym) || is_cardinal_type_pseudo_symbol(sym) || is_constant_pseudo_symbol(sym)) { errno = ERR_INV_CONTEXT; return -1; } + + if (unpack(sym) < 0) return -1; + + if (obj != NULL) { + Trap trap; + PropertyValue v; + if (obj->mTag == TAG_ptr_to_member_type) { + if (set_trap(&trap)) { + read_dwarf_object_property(sym_ctx, sym_frame, obj, AT_use_location, &v); + add_location_command(SFT_CMD_ARG)->args.arg_no = 1; + add_location_command(SFT_CMD_ARG)->args.arg_no = 0; + add_user_command(&v); + clear_trap(&trap); + return 0; + } + else { + if (errno != ERR_SYM_NOT_FOUND) set_errno(errno, "Cannot evaluate member location expression"); + else set_errno(ERR_OTHER, "Member location info not avaiable"); + return -1; + } + } + if (obj->mTag == TAG_member || obj->mTag == TAG_inheritance) { + if (set_trap(&trap)) { + read_dwarf_object_property(sym_ctx, sym_frame, obj, AT_data_member_location, &v); + switch (v.mForm) { + case FORM_DATA1 : + case FORM_DATA4 : + case FORM_DATA8 : + case FORM_SDATA : + case FORM_UDATA : + add_location_command(SFT_CMD_ARG)->args.arg_no = 0; + add_location_command(SFT_CMD_NUMBER)->args.num = get_numeric_property_value(&v); + add_location_command(SFT_CMD_ADD); + break; + case FORM_BLOCK1 : + case FORM_BLOCK2 : + case FORM_BLOCK4 : + case FORM_BLOCK : + add_location_command(SFT_CMD_ARG)->args.arg_no = 0; + add_user_command(&v); + break; + } + clear_trap(&trap); + return 0; + } + else { + if (errno != ERR_SYM_NOT_FOUND) set_errno(errno, "Cannot evaluate member location expression"); + else set_errno(ERR_OTHER, "Member location info not avaiable"); + return -1; + } + } + { + U8_T addr = 0; + Symbol * s = NULL; + if (set_trap(&trap)) { + read_dwarf_object_property(sym_ctx, sym_frame, obj, AT_location, &v); + add_user_command(&v); + clear_trap(&trap); + return 0; + } + else if (errno != ERR_SYM_NOT_FOUND) { + set_errno(errno, "Cannot evaluate location expression"); + return -1; + } + if (get_num_prop(obj, AT_low_pc, &addr)) { + add_location_command(SFT_CMD_NUMBER)->args.num = addr; + return 0; + } + if (get_error_code(errno) != ERR_SYM_NOT_FOUND) return -1; + if (map_to_sym_table(obj, &s)) return get_location_info(s, info); + } + } + + if (sym->tbl != NULL) { + ELF_SymbolInfo info; + ContextAddress addr = 0; + unpack_elf_symbol_info(sym->tbl, sym->index, &info); + if (syminfo2address(sym_ctx, &info, &addr) < 0) return -1; + add_location_command(SFT_CMD_NUMBER)->args.num = addr; + return 0; + } + + set_errno(ERR_OTHER, "No object location info found in DWARF data"); + return -1; +} + +int get_symbol_address(const Symbol * sym, ContextAddress * address) { + ObjectInfo * obj = sym->obj; + + assert(sym->magic == SYMBOL_MAGIC); if (sym->has_address) { *address = sym->address; return 0; } + if (is_array_type_pseudo_symbol(sym) || + is_cardinal_type_pseudo_symbol(sym) || + is_constant_pseudo_symbol(sym)) { + errno = ERR_INV_CONTEXT; + return -1; + } if (unpack(sym) < 0) return -1; if (obj != NULL && (obj->mFlags & DOIF_external) == 0 && sym->var != NULL) { /* The symbol represents a member of a class instance */ @@ -2213,7 +2411,7 @@ int get_symbol_address(const Symbol * sym, ContextAddress * address) { return -1; } if ((type->mTag != TAG_pointer_type && type->mTag != TAG_mod_pointer) || type->mType == NULL) exception(ERR_INV_CONTEXT); - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, sym->var, AT_location, &v); + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, sym->var, AT_location, &v); base = (ContextAddress)read_cardinal_object_value(&v); type = get_original_type(type->mType); if (!calc_member_offset(type, obj, &offs)) exception(ERR_INV_CONTEXT); @@ -2250,29 +2448,28 @@ int get_symbol_address(const Symbol * sym, ContextAddress * address) { int get_symbol_register(const Symbol * sym, Context ** ctx, int * frame, RegisterDefinition ** reg) { ObjectInfo * obj = sym->obj; + assert(sym->magic == SYMBOL_MAGIC); - if (is_array_type_pseudo_symbol(sym) || - is_cardinal_type_pseudo_symbol(sym) || - is_constant_pseudo_symbol(sym) || - sym->has_address) { - errno = ERR_INV_CONTEXT; - return -1; - } - if (unpack(sym) < 0) return -1; - if (obj != NULL && obj->mTag != TAG_member && obj->mTag != TAG_inheritance) { + if (!sym->has_address && obj != NULL && obj->mTag != TAG_member && obj->mTag != TAG_inheritance) { Trap trap; + if (unpack(sym) < 0) return -1; if (set_trap(&trap)) { PropertyValue v; - read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, 0, obj, AT_location, &v); + read_and_evaluate_dwarf_object_property(sym_ctx, sym_frame, obj, AT_location, &v); *ctx = sym_ctx; *frame = sym_frame; - *reg = v.mRegister; + if (v.mPieceCnt == 1 && v.mPieces[0].reg != NULL && v.mPieces[0].bit_size == 0) { + *reg = v.mPieces[0].reg; + } + else { + *reg = NULL; + } clear_trap(&trap); return 0; } } - errno = ERR_INV_CONTEXT; + set_errno(ERR_OTHER, "Symbol is not located in a register"); return -1; } diff --git a/agent/tcf/services/symbols_proxy.c b/agent/tcf/services/symbols_proxy.c index 7b39a2fc..ef986fc1 100644 --- a/agent/tcf/services/symbols_proxy.c +++ b/agent/tcf/services/symbols_proxy.c @@ -145,8 +145,8 @@ typedef struct StackFrameCache { uint64_t address; uint64_t size; - StackTracingCommandSequence * fp; - StackTracingCommandSequence ** regs; + StackFrameRegisterLocation * fp; + StackFrameRegisterLocation ** regs; int regs_cnt; int disposed; @@ -297,6 +297,17 @@ static void free_list_sym_cache(ListSymCache * c) { } } +static void free_sft_sequence(StackFrameRegisterLocation * seq) { + if (seq != NULL) { + unsigned i = 0; + while (i < seq->cmds_cnt) { + LocationExpressionCommand * cmd = seq->cmds + i++; + if (cmd->cmd == SFT_CMD_USER) loc_free(cmd->args.user.code_addr); + } + loc_free(seq); + } +} + static void free_stack_frame_cache(StackFrameCache * c) { list_remove(&c->link_syms); c->disposed = 1; @@ -305,9 +316,9 @@ static void free_stack_frame_cache(StackFrameCache * c) { cache_dispose(&c->cache); release_error_report(c->error); context_unlock(c->ctx); - for (i = 0; i < c->regs_cnt; i++) loc_free(c->regs[i]); + for (i = 0; i < c->regs_cnt; i++) free_sft_sequence(c->regs[i]); + free_sft_sequence(c->fp); loc_free(c->regs); - loc_free(c->fp); loc_free(c); } } @@ -832,6 +843,11 @@ int get_symbol_index_type(const Symbol * sym, Symbol ** type) { return 0; } +int get_symbol_containing_type(const Symbol * sym, Symbol ** containing_type) { + errno = ERR_UNSUPPORTED; + return -1; +} + int get_symbol_size(const Symbol * sym, ContextAddress * size) { SymInfoCache * c = get_sym_info_cache(sym); if (c == NULL) return -1; @@ -1073,27 +1089,60 @@ int get_array_symbol(const Symbol * sym, ContextAddress length, Symbol ** ptr) { static int trace_cmds_cnt = 0; static int trace_cmds_max = 0; -static StackTracingCommand * trace_cmds = NULL; +static LocationExpressionCommand * trace_cmds = NULL; static int trace_regs_cnt = 0; static int trace_regs_max = 0; -static StackTracingCommandSequence ** trace_regs = NULL; +static StackFrameRegisterLocation ** trace_regs = NULL; static int trace_error = 0; +static LocationInfo * location_info = NULL; + ContextAddress is_plt_section(Context * ctx, ContextAddress addr) { /* TODO: is_plt_section() in symbols proxy */ return 0; } +static LocationExpressionCommand * add_location_command(int op) { + LocationExpressionCommand * cmd = NULL; + if (location_info->cmds_cnt >= location_info->cmds_max) { + location_info->cmds_max += 4; + location_info->cmds = (LocationExpressionCommand *)tmp_realloc(location_info->cmds, + sizeof(LocationExpressionCommand) * location_info->cmds_max); + } + cmd = location_info->cmds + location_info->cmds_cnt++; + memset(cmd, 0, sizeof(LocationExpressionCommand)); + cmd->cmd = op; + return cmd; +} + +int get_location_info(const Symbol * sym, LocationInfo ** loc) { + SymInfoCache * c = get_sym_info_cache(sym); + if (c == NULL) return -1; + *loc = location_info = (LocationInfo *)tmp_alloc_zero(sizeof(LocationInfo)); + if (c->has_address) { + add_location_command(SFT_CMD_NUMBER)->args.num = c->address; + return 0; + } + if (c->has_offset) { + add_location_command(SFT_CMD_ARG)->args.arg_no = 0; + add_location_command(SFT_CMD_NUMBER)->args.num = c->offset; + add_location_command(SFT_CMD_ADD); + return 0; + } + set_errno(ERR_OTHER, "No object location info found"); + return -1; +} + static void read_stack_trace_command(InputStream * inp, void * args) { char id[256]; Context * ctx = NULL; int frame = STACK_NO_FRAME; - StackTracingCommand * cmd = NULL; + LocationExpressionCommand * cmd = NULL; if (trace_cmds_cnt >= trace_cmds_max) { trace_cmds_max += 16; - trace_cmds = (StackTracingCommand *)loc_realloc(trace_cmds, trace_cmds_max * sizeof(StackTracingCommand)); + trace_cmds = (LocationExpressionCommand *)loc_realloc(trace_cmds, trace_cmds_max * sizeof(LocationExpressionCommand)); } cmd = trace_cmds + trace_cmds_cnt++; memset(cmd, 0, sizeof(*cmd)); @@ -1101,18 +1150,22 @@ static void read_stack_trace_command(InputStream * inp, void * args) { switch (cmd->cmd) { case SFT_CMD_NUMBER: if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX); - cmd->num = json_read_int64(inp); + cmd->args.num = json_read_int64(inp); break; case SFT_CMD_REGISTER: if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX); json_read_string(inp, id, sizeof(id)); - if (id2register(id, &ctx, &frame, &cmd->reg) < 0) trace_error = errno; + if (id2register(id, &ctx, &frame, &cmd->args.reg) < 0) trace_error = errno; break; case SFT_CMD_DEREF: if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX); - cmd->size = json_read_ulong(inp); + cmd->args.deref.size = json_read_ulong(inp); if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX); - cmd->big_endian = json_read_boolean(inp); + cmd->args.deref.big_endian = json_read_boolean(inp); + break; + case SFT_CMD_USER: + if (read_stream(inp) != ',') exception(ERR_JSON_SYNTAX); + cmd->args.user.code_addr = (uint8_t *)json_read_alloc_binary(inp, &cmd->args.user.code_size); break; } } @@ -1120,14 +1173,14 @@ static void read_stack_trace_command(InputStream * inp, void * args) { static void read_stack_trace_register(InputStream * inp, const char * id, void * args) { if (trace_regs_cnt >= trace_regs_max) { trace_regs_max += 16; - trace_regs = (StackTracingCommandSequence **)loc_realloc(trace_regs, trace_regs_max * sizeof(StackTracingCommandSequence *)); + trace_regs = (StackFrameRegisterLocation **)loc_realloc(trace_regs, trace_regs_max * sizeof(StackFrameRegisterLocation *)); } trace_cmds_cnt = 0; if (json_read_array(inp, read_stack_trace_command, NULL)) { Context * ctx = NULL; int frame = STACK_NO_FRAME; - StackTracingCommandSequence * reg = (StackTracingCommandSequence *)loc_alloc( - sizeof(StackTracingCommandSequence) + (trace_cmds_cnt - 1) * sizeof(StackTracingCommand)); + StackFrameRegisterLocation * reg = (StackFrameRegisterLocation *)loc_alloc( + sizeof(StackFrameRegisterLocation) + (trace_cmds_cnt - 1) * sizeof(LocationExpressionCommand)); if (id2register(id, &ctx, &frame, ®->reg) < 0) { trace_error = errno; loc_free(reg); @@ -1135,7 +1188,7 @@ static void read_stack_trace_register(InputStream * inp, const char * id, void * else { reg->cmds_cnt = trace_cmds_cnt; reg->cmds_max = trace_cmds_cnt; - memcpy(reg->cmds, trace_cmds, trace_cmds_cnt * sizeof(StackTracingCommand)); + memcpy(reg->cmds, trace_cmds, trace_cmds_cnt * sizeof(LocationExpressionCommand)); trace_regs[trace_regs_cnt++] = reg; } } @@ -1168,18 +1221,18 @@ static void validate_frame(Channel * c, void * args, int error) { } trace_cmds_cnt = 0; if (json_read_array(&c->inp, read_stack_trace_command, NULL)) { - f->fp = (StackTracingCommandSequence *)loc_alloc(sizeof(StackTracingCommandSequence) + (trace_cmds_cnt - 1) * sizeof(StackTracingCommand)); + f->fp = (StackFrameRegisterLocation *)loc_alloc(sizeof(StackFrameRegisterLocation) + (trace_cmds_cnt - 1) * sizeof(LocationExpressionCommand)); f->fp->reg = NULL; f->fp->cmds_cnt = trace_cmds_cnt; f->fp->cmds_max = trace_cmds_cnt; - memcpy(f->fp->cmds, trace_cmds, trace_cmds_cnt * sizeof(StackTracingCommand)); + memcpy(f->fp->cmds, trace_cmds, trace_cmds_cnt * sizeof(LocationExpressionCommand)); } if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); trace_regs_cnt = 0; if (json_read_struct(&c->inp, read_stack_trace_register, NULL)) { f->regs_cnt = trace_regs_cnt; - f->regs = (StackTracingCommandSequence **)loc_alloc(trace_regs_cnt * sizeof(StackTracingCommandSequence *)); - memcpy(f->regs, trace_regs, trace_regs_cnt * sizeof(StackTracingCommandSequence *)); + f->regs = (StackFrameRegisterLocation **)loc_alloc(trace_regs_cnt * sizeof(StackFrameRegisterLocation *)); + memcpy(f->regs, trace_regs, trace_regs_cnt * sizeof(StackFrameRegisterLocation *)); } if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); @@ -1256,10 +1309,25 @@ int get_next_stack_frame(StackFrame * frame, StackFrame * down) { Trap trap; if (set_trap(&trap)) { int i; - frame->fp = (ContextAddress)evaluate_stack_trace_commands(ctx, frame, f->fp); + LocationExpressionState * state; + state = evaluate_location_expression(ctx, frame, f->fp->cmds, f->fp->cmds_cnt, NULL, 0); + if (state->stk_pos != 1) str_exception(ERR_OTHER, "Invalid stack trace expression"); + frame->fp = (ContextAddress)state->stk[0]; + frame->is_walked = 1; for (i = 0; i < f->regs_cnt; i++) { - uint64_t v = evaluate_stack_trace_commands(ctx, frame, f->regs[i]); - if (write_reg_value(down, f->regs[i]->reg, v) < 0) exception(errno); + int ok = 0; + uint64_t v = 0; + Trap trap_reg; + if (set_trap(&trap_reg)) { + /* If a saved register value cannot be evaluated - ignore it */ + state = evaluate_location_expression(ctx, frame, f->regs[i]->cmds, f->regs[i]->cmds_cnt, NULL, 0); + if (state->stk_pos == 1) { + v = state->stk[0]; + ok = 1; + } + clear_trap(&trap_reg); + } + if (ok && write_reg_value(down, f->regs[i]->reg, v) < 0) exception(errno); } clear_trap(&trap); } diff --git a/agent/tcf/services/symbols_win32.c b/agent/tcf/services/symbols_win32.c index 3b2c8d7a..0e5a4791 100644 --- a/agent/tcf/services/symbols_win32.c +++ b/agent/tcf/services/symbols_win32.c @@ -121,6 +121,7 @@ static size_t context_extension_offset = 0; static char * tmp_buf = NULL; static int tmp_buf_size = 0; +static LocationInfo * location_info = NULL; #define SYMBOL_MAGIC 0x34875234 @@ -590,6 +591,11 @@ int get_symbol_index_type(const Symbol * sym, Symbol ** type) { return 0; } +int get_symbol_containing_type(const Symbol * sym, Symbol ** containing_type) { + errno = ERR_UNSUPPORTED; + return -1; +} + int get_symbol_length(const Symbol * sym, ContextAddress * length) { DWORD res = 0; Symbol type = *sym; @@ -1136,6 +1142,61 @@ ContextAddress is_plt_section(Context * ctx, ContextAddress addr) { return 0; } +static LocationExpressionCommand * add_location_command(int op) { + LocationExpressionCommand * cmd = NULL; + if (location_info->cmds_cnt >= location_info->cmds_max) { + location_info->cmds_max += 4; + location_info->cmds = (LocationExpressionCommand *)tmp_realloc(location_info->cmds, + sizeof(LocationExpressionCommand) * location_info->cmds_max); + } + cmd = location_info->cmds + location_info->cmds_cnt++; + memset(cmd, 0, sizeof(LocationExpressionCommand)); + cmd->cmd = op; + return cmd; +} + +int get_location_info(const Symbol * sym, LocationInfo ** loc) { + DWORD dword = 0; + SYMBOL_INFO * info = NULL; + + assert(sym->magic == SYMBOL_MAGIC); + *loc = location_info = (LocationInfo *)tmp_alloc_zero(sizeof(LocationInfo)); + + if (sym->address != 0) { + add_location_command(SFT_CMD_NUMBER)->args.num = sym->address; + return 0; + } + + if (sym->base || sym->info) { + errno = ERR_INV_CONTEXT; + return -1; + } + + if (get_type_info(sym, TI_GET_OFFSET, &dword) == 0) { + add_location_command(SFT_CMD_ARG)->args.arg_no = 0; + add_location_command(SFT_CMD_NUMBER)->args.num = dword; + add_location_command(SFT_CMD_ADD); + return 0; + } + + if (get_sym_info(sym, sym->index, &info) < 0) return -1; + + if (is_register(info)) { + set_errno(ERR_INV_CONTEXT, "Register variable"); + return -1; + } + + if (is_frame_relative(info)) { + add_location_command(SFT_CMD_FP); + add_location_command(SFT_CMD_NUMBER)->args.num = info->Address - sizeof(ContextAddress) * 2; + add_location_command(SFT_CMD_ADD); + return 0; + } + + add_location_command(SFT_CMD_NUMBER)->args.num = info->Address; + return 0; +} + int get_stack_tracing_info(Context * ctx, ContextAddress addr, StackTracingInfo ** info) { *info = NULL; return 0; diff --git a/agent/tcf/services/vm.c b/agent/tcf/services/vm.c index 4bf94809..347cbfb6 100644 --- a/agent/tcf/services/vm.c +++ b/agent/tcf/services/vm.c @@ -25,9 +25,12 @@ #include <tcf/services/dwarf.h> #include <tcf/services/vm.h> -#define check_e_stack(n) { if (state->stk_pos < n) inv_dwarf("Invalid DWARF expression stack"); } +#define check_e_stack(n) { if (state->stk_pos < n) inv_dwarf("Invalid location expression stack"); } -static VMState * state = NULL; +static LocationExpressionState * state = NULL; +static RegisterDefinition * reg_def = NULL; +static void * value_addr = NULL; +static size_t value_size = 0; static uint8_t * code = NULL; static size_t code_pos = 0; static size_t code_len = 0; @@ -36,13 +39,6 @@ static void inv_dwarf(const char * msg) { str_exception(ERR_INV_DWARF, msg); } -static StackFrame * get_stack_frame(void) { - StackFrame * info = NULL; - if (state->stack_frame == STACK_NO_FRAME) return NULL; - if (get_frame_info(state->ctx, state->stack_frame, &info) < 0) exception(errno); - return info; -} - static uint64_t read_memory(uint64_t addr, size_t size) { size_t i; uint64_t n = 0; @@ -83,7 +79,7 @@ static uint32_t read_u4leb128(void) { int i = 0; for (;; i += 7) { uint8_t n = read_u1(); - res |= (n & 0x7Fu) << i; + res |= (uint32_t)(n & 0x7Fu) << i; if ((n & 0x80) == 0) break; } return res; @@ -94,7 +90,7 @@ static uint64_t read_u8leb128(void) { int i = 0; for (;; i += 7) { uint8_t n = read_u1(); - res |= (n & 0x7Fu) << i; + res |= (uint64_t)(n & 0x7Fu) << i; if ((n & 0x80) == 0) break; } return res; @@ -105,9 +101,9 @@ static int64_t read_i8leb128(void) { int i = 0; for (;; i += 7) { uint8_t n = read_u1(); - res |= (n & 0x7Fu) << i; + res |= (uint64_t)(n & 0x7Fu) << i; if ((n & 0x80) == 0) { - res |= -(n & 0x40) << i; + res |= -(int64_t)(n & 0x40) << i; break; } } @@ -136,19 +132,48 @@ static uint64_t read_ua(void) { return 0; } -static void set_state(VMState * s) { +static LocationPiece * add_piece(void) { + LocationPiece * piece = NULL; + if (state->pieces_cnt >= state->pieces_max) { + state->pieces_max += 4; + state->pieces = (LocationPiece *)tmp_realloc(state->pieces, state->pieces_max * sizeof(LocationPiece)); + } + piece = state->pieces + state->pieces_cnt++; + memset(piece, 0, sizeof(LocationPiece)); + if (reg_def != NULL) { + piece->reg = reg_def; + piece->size = reg_def->size; + piece->big_endian = reg_def->big_endian; + } + else if (value_addr != NULL) { + piece->value = value_addr; + piece->size = value_size; + piece->big_endian = state->big_endian; + } + else if (state->stk_pos == 0) { + /* An empty location description represents a piece or all of an object that is + * present in the source but not in the object code (perhaps due to optimization). */ + } + else { + state->stk_pos--; + piece->addr = (ContextAddress)state->stk[state->stk_pos]; + piece->big_endian = state->big_endian; + } + reg_def = NULL; + value_addr = NULL; + return piece; +} + +static void set_state(LocationExpressionState * s) { state = s; code = state->code; code_pos = state->code_pos; code_len = state->code_len; - state->reg = NULL; - state->value_addr = NULL; - state->value_size = 0; - state->piece_offs = 0; - state->piece_bits = 0; + reg_def = NULL; } -static void get_state(VMState * s) { +static void get_state(LocationExpressionState * s) { + if (reg_def != NULL || value_addr != NULL) add_piece(); s->code_pos = code_pos; state = NULL; code = NULL; @@ -166,9 +191,10 @@ static int is_end_of_loc_expr(void) { static void evaluate_expression(void) { uint64_t data = 0; - if (code_len == 0) inv_dwarf("DWARF expression size = 0"); + if (code_len == 0) inv_dwarf("location expression size = 0"); - while (code_pos < code_len && state->piece_bits == 0) { + while (code_pos < code_len) { + LocationPiece * piece = NULL; uint8_t op = code[code_pos++]; if (state->stk_pos + 4 > state->stk_max) { @@ -281,7 +307,7 @@ static void evaluate_expression(void) { case OP_div: check_e_stack(2); state->stk_pos--; - if (state->stk[state->stk_pos] == 0) inv_dwarf("Division by zero in DWARF expression"); + if (state->stk[state->stk_pos] == 0) inv_dwarf("Division by zero in location expression"); state->stk[state->stk_pos - 1] /= state->stk[state->stk_pos]; break; case OP_minus: @@ -292,7 +318,7 @@ static void evaluate_expression(void) { case OP_mod: check_e_stack(2); state->stk_pos--; - if (state->stk[state->stk_pos] == 0) inv_dwarf("Division by zero in DWARF expression"); + if (state->stk[state->stk_pos] == 0) inv_dwarf("Division by zero in location expression"); state->stk[state->stk_pos - 1] %= state->stk[state->stk_pos]; break; case OP_mul: @@ -472,25 +498,25 @@ static void evaluate_expression(void) { case OP_reg31: { unsigned n = op - OP_reg0; - if (!is_end_of_loc_expr()) inv_dwarf("OP_reg must be last instruction"); - state->reg = get_reg_by_id(state->ctx, n, &state->reg_id_scope); - if (state->reg == NULL) exception(errno); + if (!is_end_of_loc_expr()) inv_dwarf("OP_reg* must be last instruction"); + reg_def = get_reg_by_id(state->ctx, n, &state->reg_id_scope); + if (reg_def == NULL) exception(errno); } break; case OP_regx: { unsigned n = (unsigned)read_u4leb128(); if (!is_end_of_loc_expr()) inv_dwarf("OP_regx must be last instruction"); - state->reg = get_reg_by_id(state->ctx, n, &state->reg_id_scope); - if (state->reg == NULL) exception(errno); + reg_def = get_reg_by_id(state->ctx, n, &state->reg_id_scope); + if (reg_def == NULL) exception(errno); } break; case OP_reg: { unsigned n = (unsigned)read_ua(); if (!is_end_of_loc_expr()) inv_dwarf("OP_reg must be last instruction"); - state->reg = get_reg_by_id(state->ctx, n, &state->reg_id_scope); - if (state->reg == NULL) exception(errno); + reg_def = get_reg_by_id(state->ctx, n, &state->reg_id_scope); + if (reg_def == NULL) exception(errno); } break; case OP_breg0: @@ -528,7 +554,7 @@ static void evaluate_expression(void) { { RegisterDefinition * def = get_reg_by_id(state->ctx, op - OP_breg0, &state->reg_id_scope); if (def == NULL) exception(errno); - if (read_reg_value(get_stack_frame(), def, state->stk + state->stk_pos) < 0) exception(errno); + if (read_reg_value(state->stack_frame, def, state->stk + state->stk_pos) < 0) exception(errno); state->stk[state->stk_pos++] += read_i8leb128(); } break; @@ -536,7 +562,7 @@ static void evaluate_expression(void) { { RegisterDefinition * def = get_reg_by_id(state->ctx, (unsigned)read_u4leb128(), &state->reg_id_scope); if (def == NULL) exception(errno); - if (read_reg_value(get_stack_frame(), def, state->stk + state->stk_pos) < 0) exception(errno); + if (read_reg_value(state->stack_frame, def, state->stk + state->stk_pos) < 0) exception(errno); state->stk[state->stk_pos++] += read_i8leb128(); } break; @@ -544,13 +570,13 @@ static void evaluate_expression(void) { { RegisterDefinition * def = get_reg_by_id(state->ctx, (unsigned)read_ua(), &state->reg_id_scope); if (def == NULL) exception(errno); - if (read_reg_value(get_stack_frame(), def, state->stk + state->stk_pos) < 0) exception(errno); + if (read_reg_value(state->stack_frame, def, state->stk + state->stk_pos) < 0) exception(errno); state->stk_pos++; } break; case OP_call_frame_cfa: { - StackFrame * frame = get_stack_frame(); + StackFrame * frame = state->stack_frame; if (frame == NULL) str_exception(ERR_INV_ADDRESS, "Stack frame address not available"); state->stk[state->stk_pos++] = frame->fp; } @@ -558,46 +584,37 @@ static void evaluate_expression(void) { case OP_nop: break; case OP_push_object_address: - state->stk[state->stk_pos++] = state->object_address; + if (state->args_cnt == 0) str_exception(ERR_INV_ADDRESS, "Invalid address of containing object"); + state->stk[state->stk_pos++] = state->args[0]; break; case OP_piece: - state->piece_bits = read_u4leb128() * 8; - state->piece_offs = 0; - if (code_pos < code_len && state->piece_bits == 0) { - if (state->reg) state->reg = NULL; - else if (state->value_addr) state->value_addr = NULL; - else state->stk_pos--; - } + piece = add_piece(); + piece->size = read_u4leb128(); break; case OP_bit_piece: - state->piece_bits = read_u4leb128(); - state->piece_offs = read_u4leb128(); - if (code_pos < code_len && state->piece_bits == 0) { - if (state->reg) state->reg = NULL; - else if (state->value_addr) state->value_addr = NULL; - else state->stk_pos--; - state->piece_offs = 0; - } + piece = add_piece(); + piece->bit_size = read_u4leb128(); + piece->bit_offs = read_u4leb128(); break; case OP_implicit_value: - state->value_size = read_u4leb128(); - if (code_pos + state->value_size > code_len) inv_dwarf("Invalid command"); - state->value_addr = tmp_alloc(state->value_size); - memcpy(state->value_addr, code + code_pos, state->value_size); - code_pos += state->value_size; + value_size = read_u4leb128(); + if (code_pos + value_size > code_len) inv_dwarf("Invalid command"); + value_addr = tmp_alloc(value_size); + memcpy(value_addr, code + code_pos, value_size); + code_pos += value_size; if (!is_end_of_loc_expr()) inv_dwarf("OP_implicit_value must be last instruction"); break; case OP_stack_value: check_e_stack(1); state->stk_pos--; - state->value_size = sizeof(uint64_t); - state->value_addr = tmp_alloc(state->value_size); - memcpy(state->value_addr, state->stk + state->stk_pos, state->value_size); + value_size = sizeof(uint64_t); + value_addr = tmp_alloc(value_size); + memcpy(value_addr, state->stk + state->stk_pos, value_size); if (!is_end_of_loc_expr()) inv_dwarf("OP_stack_value must be last instruction"); if (big_endian_host() != state->big_endian) { - size_t i, j, n = state->value_size >> 1; - char * p = (char *)state->value_addr; - for (i = 0, j = state->value_size - 1; i < n; i++, j--) { + size_t i, j, n = value_size >> 1; + char * p = (char *)value_addr; + for (i = 0, j = value_size - 1; i < n; i++, j--) { char x = p[i]; p[i] = p[j]; p[j] = x; @@ -609,7 +626,7 @@ static void evaluate_expression(void) { case OP_call_ref: default: { - VMState * s = state; + LocationExpressionState * s = state; get_state(s); s->client_op(op); set_state(s); @@ -618,7 +635,7 @@ static void evaluate_expression(void) { } } -int evaluate_vm_expression(VMState * vm_state) { +int evaluate_vm_expression(LocationExpressionState * vm_state) { int error = 0; Trap trap; diff --git a/agent/tcf/services/vm.h b/agent/tcf/services/vm.h index b541c511..f174b03b 100644 --- a/agent/tcf/services/vm.h +++ b/agent/tcf/services/vm.h @@ -23,37 +23,7 @@ #include <tcf/framework/context.h> -typedef struct VMState { - /* Evaluation context */ - Context * ctx; - int stack_frame; - int big_endian; - size_t addr_size; - uint64_t object_address; - RegisterIdScope reg_id_scope; - - /* Code to execute */ - uint8_t * code; - size_t code_pos; - size_t code_len; - - /* VM callback */ - void (*client_op)(uint8_t op); - - /* Result */ - RegisterDefinition * reg; - void * value_addr; - size_t value_size; - uint32_t piece_offs; - uint32_t piece_bits; - - /* Stack */ - unsigned stk_pos; - unsigned stk_max; - uint64_t * stk; -} VMState; - -extern int evaluate_vm_expression(VMState * state); +extern int evaluate_vm_expression(LocationExpressionState * state); #endif /* ENABLE_DebugContext */ |