| /******************************************************************************* |
| * Copyright (c) 2008, 2010 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 |
| *******************************************************************************/ |
| |
| /* |
| * This module implements DWARF expressions evaluation. |
| */ |
| |
| #include <config.h> |
| |
| #if ENABLE_ELF && ENABLE_DebugContext |
| |
| #include <assert.h> |
| #include <stdio.h> |
| #include <framework/events.h> |
| #include <framework/myalloc.h> |
| #include <framework/exceptions.h> |
| #include <framework/errors.h> |
| #include <framework/trace.h> |
| #include <services/dwarf.h> |
| #include <services/dwarfio.h> |
| #include <services/dwarfexpr.h> |
| #include <services/stacktrace.h> |
| #include <services/vm.h> |
| |
| typedef struct ValuePieces { |
| U4_T mCnt; |
| U4_T mMax; |
| PropertyValuePiece * mArray; |
| struct ValuePieces * mNext; |
| } ValuePieces; |
| |
| static VMState sState; |
| static ELF_Section * sSection = NULL; |
| static U8_T sSectionOffs = 0; |
| static PropertyValue * sValue = NULL; |
| static ValuePieces * sValuePieces = NULL; |
| |
| static ValuePieces * sFreeValuePieces = NULL; |
| static ValuePieces * sBusyValuePieces = NULL; |
| static unsigned sValuePiecesCnt = 0; |
| static int sValuePiecesPosted = 0; |
| |
| static void free_value_pieces(void * args) { |
| while (sBusyValuePieces != NULL) { |
| ValuePieces * Pieces = sBusyValuePieces; |
| sBusyValuePieces = Pieces->mNext; |
| Pieces->mNext = sFreeValuePieces; |
| sFreeValuePieces = Pieces; |
| } |
| while (sFreeValuePieces != NULL && sValuePiecesCnt > 16) { |
| ValuePieces * Pieces = sFreeValuePieces; |
| sFreeValuePieces = sFreeValuePieces->mNext; |
| sValuePiecesCnt--; |
| loc_free(Pieces->mArray); |
| loc_free(Pieces); |
| } |
| } |
| |
| static ValuePieces * alloc_value_pieces(void) { |
| ValuePieces * Pieces = sFreeValuePieces; |
| if (Pieces == NULL) { |
| Pieces = (ValuePieces *)loc_alloc_zero(sizeof(ValuePieces)); |
| sValuePiecesCnt++; |
| } |
| else { |
| sFreeValuePieces = sFreeValuePieces->mNext; |
| } |
| Pieces->mNext = sBusyValuePieces; |
| sBusyValuePieces = Pieces; |
| if (!sValuePiecesPosted && sValuePiecesCnt > 8) { |
| post_event(free_value_pieces, NULL); |
| sValuePiecesPosted = 1; |
| } |
| Pieces->mCnt = 0; |
| return Pieces; |
| } |
| |
| static StackFrame * get_stack_frame(PropertyValue * sValue) { |
| StackFrame * Info = NULL; |
| if (sValue->mFrame == STACK_NO_FRAME) return NULL; |
| if (get_frame_info(sValue->mContext, sValue->mFrame, &Info) < 0) exception(errno); |
| return Info; |
| } |
| |
| static ObjectInfo * get_parent_function(ObjectInfo * Info) { |
| while (Info != NULL) { |
| switch (Info->mTag) { |
| case TAG_global_subroutine: |
| case TAG_subroutine: |
| case TAG_subprogram: |
| case TAG_entry_point: |
| return Info; |
| } |
| Info = Info->mParent; |
| } |
| return NULL; |
| } |
| |
| static U8_T read_address(void) { |
| U8_T addr = 0; |
| ELF_Section * section = NULL; |
| CompUnit * Unit = sValue->mObject->mCompUnit; |
| |
| addr = dio_ReadAddress(§ion); |
| addr = elf_map_to_run_time_address(sState.ctx, Unit->mFile, section, (ContextAddress)addr); |
| if (addr == 0) str_exception(ERR_INV_ADDRESS, "Object has no RT address"); |
| return addr; |
| } |
| |
| static U8_T get_fbreg(void) { |
| PropertyValue FP; |
| CompUnit * Unit = sValue->mObject->mCompUnit; |
| ObjectInfo * Parent = get_parent_function(sValue->mObject); |
| U8_T addr = 0; |
| |
| if (Parent == NULL) str_exception(ERR_INV_DWARF, "OP_fbreg: no parent function"); |
| memset(&FP, 0, sizeof(FP)); |
| |
| { |
| PropertyValue * OrgValue = sValue; |
| ValuePieces * OrgValuePieces = sValuePieces; |
| ELF_Section * OrgSection = sSection; |
| U8_T OrgSectionOffs = sSectionOffs; |
| VMState OrgState = sState; |
| |
| read_and_evaluate_dwarf_object_property(sState.ctx, sState.stack_frame, 0, Parent, AT_frame_base, &FP); |
| |
| assert(sState.ctx == OrgState.ctx); |
| assert(sState.addr_size == OrgState.addr_size); |
| assert(sState.big_endian == OrgState.big_endian); |
| |
| sState.code = OrgState.code; |
| sState.code_pos = OrgState.code_pos; |
| sState.code_len = OrgState.code_len; |
| sState.object_address = OrgState.object_address; |
| sSectionOffs = OrgSectionOffs; |
| sSection = OrgSection; |
| sValuePieces = OrgValuePieces; |
| sValue = OrgValue; |
| } |
| |
| if (FP.mRegister != NULL) { |
| if (read_reg_value(get_stack_frame(&FP), FP.mRegister, &addr) < 0) exception(errno); |
| } |
| else { |
| addr = get_numeric_property_value(&FP); |
| } |
| dio_EnterSection(&Unit->mDesc, sSection, sSectionOffs + sState.code_pos); |
| return addr + dio_ReadS8LEB128(); |
| } |
| |
| static void client_op(uint8_t op) { |
| dio_SetPos(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"); |
| sState.stk[sState.stk_pos++] = get_fbreg(); |
| break; |
| default: |
| trace(LOG_ALWAYS, "Unsupported DWARF expression op 0x%02x", op); |
| str_exception(ERR_UNSUPPORTED, "Unsupported DWARF expression op"); |
| } |
| sState.code_pos = (size_t)(dio_GetPos() - sSectionOffs); |
| } |
| |
| static void evaluate_expression(ELF_Section * Section, U1_T * Buf, size_t Size) { |
| int error = 0; |
| CompUnit * Unit = sValue->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) { |
| sValuePieces = alloc_value_pieces(); |
| while (!error) { |
| PropertyValuePiece * Piece; |
| if (sValuePieces->mCnt >= sValuePieces->mMax) { |
| sValuePieces->mMax += 8; |
| sValuePieces->mArray = (PropertyValuePiece *)loc_realloc(sValuePieces->mArray, |
| sizeof(PropertyValuePiece) * sValuePieces->mMax); |
| } |
| Piece = sValuePieces->mArray + sValuePieces->mCnt++; |
| memset(Piece, 0, sizeof(PropertyValuePiece)); |
| if (sState.reg) { |
| Piece->mRegister = sState.reg; |
| Piece->mBigEndian = sState.reg->big_endian; |
| } |
| else { |
| Piece->mAddress = sState.stk[--sState.stk_pos]; |
| Piece->mBigEndian = sState.big_endian; |
| } |
| Piece->mBitOffset = sState.piece_offs; |
| Piece->mBitSize = sState.piece_bits; |
| if (sState.code_pos >= sState.code_len) break; |
| if (evaluate_vm_expression(&sState) < 0) error = errno; |
| } |
| } |
| 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); |
| } |
| } |
| 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) { |
| unsigned stk_pos = 0; |
| CompUnit * Unit = v->mObject->mCompUnit; |
| |
| sValue = v; |
| sValuePieces = NULL; |
| sState.ctx = sValue->mContext; |
| 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.client_op = client_op;; |
| |
| if (sValue->mAttr != AT_frame_base) sState.stk_pos = 0; |
| stk_pos = sState.stk_pos; |
| |
| if (sValue->mAttr == AT_data_member_location) { |
| if (sState.stk_pos >= sState.stk_max) { |
| sState.stk_max += 8; |
| sState.stk = (U8_T *)loc_alloc(sizeof(U8_T) * sState.stk_max); |
| } |
| sState.stk[sState.stk_pos++] = BaseAddress; |
| } |
| if (sValue->mRegister != 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); |
| } |
| |
| 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->mArray; |
| sValue->mPieceCnt = sValuePieces->mCnt; |
| } |
| else if (sState.reg) { |
| sValue->mSize = sState.reg->size; |
| sValue->mBigEndian = sState.reg->big_endian; |
| sValue->mRegister = sState.reg; |
| } |
| else { |
| sValue->mValue = sState.stk[--sState.stk_pos]; |
| } |
| |
| if (sState.stk_pos != stk_pos) { |
| str_exception(ERR_INV_DWARF, "Invalid DWARF expression stack"); |
| } |
| } |
| |
| #endif /* ENABLE_ELF && ENABLE_DebugContext */ |