diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianETMLib/Common/State/Implementations/ETMDecodeStatePHeader.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianETMLib/Common/State/Implementations/ETMDecodeStatePHeader.cs Thu Feb 11 15:50:58 2010 +0200 @@ -0,0 +1,496 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using SymbianUtils.BasicTypes; +using SymbianStructuresLib.Arm; +using SymbianStructuresLib.Arm.Exceptions; +using SymbianETMLib.Common.Types; +using SymbianETMLib.Common.Packets; +using SymbianETMLib.Common.Utilities; +using SymbianETMLib.Common.Exception; + +namespace SymbianETMLib.Common.State +{ + public class ETMDecodeStatePHeader : ETMDecodeState + { + #region Constructors + public ETMDecodeStatePHeader( ETMStateData aManager ) + : base( aManager ) + { + } + + static ETMDecodeStatePHeader() + { + // ARM branch instructions + iBranchMask_ARM_BOrBL = new SymMask( "#### 101 # ######## ######## ########" ); + iBranchMask_ARM_BLX_BranchToThumb = new SymMask( "1111 101 # ######## ######## ########" ); + + // THUMB branch instructions + iBranchMask_THUMB_B1 = new SymMask( "1101 #### ########" ); + iBranchMask_THUMB_B2 = new SymMask( "11100 ###########" ); + iBranchMask_THUMB_BLX_Part1 = new SymMask( "11110 ###########" ); // Multi-instruction branch + iBranchMask_THUMB_BLX_Part2 = new SymMask( "111#1 ###########" ); // Multi-instruction branch + } + #endregion + + #region API + public override ETMDecodeState HandleByte( SymByte aByte ) + { + ETMDecodeState nextState = new ETMDecodeStateSynchronized( base.StateData ); + // + ETMPcktBase packet = Packets.Factory.ETMPacketFactory.Create( aByte ); + if ( packet is ETMPcktPHeaderFormat1 ) + { + ETMPcktPHeaderFormat1 pHeader1 = (ETMPcktPHeaderFormat1) packet; + ProcessFormat1Conditions( pHeader1 ); + } + else if ( packet is ETMPcktPHeaderFormat2 ) + { + ETMPcktPHeaderFormat2 pHeader2 = (ETMPcktPHeaderFormat2) packet; + ProcessFormat2Conditions( pHeader2 ); + } + else + { + throw new ETMException( "ERROR: P-HEADER is not supported" ); + } + // + return nextState; + } + #endregion + + #region Properties + #endregion + + #region Internal enumerations + private enum TMultiPartThumbBranch + { + ETHUMBBL = 0x3, + ETHUMBBLX = 0x1, + } + #endregion + + #region Internal methods + private void ProcessFormat1Conditions( ETMPcktPHeaderFormat1 aHeader ) + { + string pass = aHeader.ConditionCountPassed > 0 ? string.Format( "{0} x PASS", aHeader.ConditionCountPassed ) : string.Empty; + string fail = aHeader.ConditionCountFailed > 0 ? string.Format( ", {0} x FAIL", aHeader.ConditionCountFailed ) : string.Empty; + base.Trace( "{0} - {1} {2}", base.MakeTracePacketPrefix( "P-HEADER(1)" ), pass, fail ); + + // Get the total number of instructions processed + int totalExecutedInstructionCount = aHeader.ConditionCountPassed + aHeader.ConditionCountFailed; + + // Trace passed instructions + for ( int i = 0; i < aHeader.ConditionCountPassed; i++ ) + { + uint address = base.StateData.CurrentAddress; + ETMInstruction instruction = base.StateData.FetchInstruction( address ); + // + TraceAtom( ETMPcktPHeaderBase.TAtomType.EAtomE_Passed, instruction ); + + // We will now check the current instruction to see if it's a branch. + // If it is, then we don't need to increment the instruction address, because + // the explicit branch will set a new PC location. + // + // Note that in the case of a thumb BLX, i.e. two 16-bit instructions which + // interpreted together form a +/-4mb branch address, we also need + // to ensure that the + bool branched = CheckForBranch( instruction ); + if ( !branched ) + { + base.StateData.IncrementPC(); + } + } + + // Trace and failed instructions + if ( aHeader.ConditionCountFailed > 0 ) + { + uint address = base.StateData.CurrentAddress; + ETMInstruction instruction = base.StateData.FetchInstruction( address ); + // + TraceAtom( ETMPcktPHeaderBase.TAtomType.EAtomN_Failed, instruction ); + base.StateData.IncrementPC(); + } + + // Spacer - to make the verbose output easier to read... + base.Trace( string.Empty ); + } + + private void ProcessFormat2Conditions( ETMPcktPHeaderFormat2 aHeader ) + { + string atom1TypeName = TraceAtomTypeName( aHeader.Atom1Type ); + string atom2TypeName = TraceAtomTypeName( aHeader.Atom2Type ); + base.Trace( "{0} - 1 x {1}, 1 x {2}", base.MakeTracePacketPrefix( "P-HEADER(2)" ), atom1TypeName, atom2TypeName ); + + // First instruction + { + uint address1 = base.StateData.CurrentAddress; + ETMInstruction inst1 = base.StateData.FetchInstruction( address1 ); + TraceAtom( aHeader.Atom1Type, inst1 ); + if ( aHeader.Atom1Type == ETMPcktPHeaderBase.TAtomType.EAtomE_Passed ) + { + bool branched = CheckForBranch( inst1 ); + if ( !branched ) + { + base.StateData.IncrementPC(); + } + } + else + { + base.StateData.IncrementPC(); + } + } + + // Second instruction + { + uint address2 = base.StateData.CurrentAddress; + ETMInstruction inst2 = base.StateData.FetchInstruction( address2 ); + TraceAtom( aHeader.Atom2Type, inst2 ); + if ( aHeader.Atom2Type == ETMPcktPHeaderBase.TAtomType.EAtomE_Passed ) + { + bool branched = CheckForBranch( inst2 ); + if ( !branched ) + { + base.StateData.IncrementPC(); + } + } + else + { + base.StateData.IncrementPC(); + } + } + + // Spacer - to make the verbose output easier to read... + base.Trace( string.Empty ); + } + + private bool HandleTHUMBMultiInstructionBranch( uint aInstruction1, uint aInstruction2 ) + { + bool branched = false; + + // THUMB multi branch with link exchange instruction - consumes 32 bits + // of the instruction pipeline, i.e. instructions @ aIndex and aIndex+1 both + // consumed. + // + // Check the signature is correct: + // + // NB: + // The first Thumb instruction has H == 10 and supplies the high part of the + // branch offset. This instruction sets up for the subroutine call and is + // shared between the BL and BLX forms. + // + // The second Thumb instruction has H == 11 (for BL) or H == 01 (for BLX). It + // supplies the low part of the branch offset and causes the subroutine call + // to take place. + // + // 15 14 13 12 11 10 0 + // ---------------------------------------------------- + // 1 1 1 H <--- offset_11 --> + // + // mask1 = 11 00000000000 + // value1 = 10 00000000000 + // 111 11 10111010101 + // mask2 = 1 00000000000 + // value2 = 1 00000000000 + // 111 10 11111111111 + bool inst1Valid = ( ( aInstruction1 & 0x1800 ) == 0x1000 ); + bool inst2Valid = ( ( aInstruction2 & 0x0800 ) == 0x0800 ); + + if ( inst1Valid && inst2Valid ) + { + TArmInstructionSet newInstructionSet = TArmInstructionSet.ETHUMB; + TMultiPartThumbBranch branchType = TMultiPartThumbBranch.ETHUMBBL; + if ( ( aInstruction2 & 0x1800 ) == 0x0800 ) + { + branchType = TMultiPartThumbBranch.ETHUMBBLX; + newInstructionSet = TArmInstructionSet.EARM; + } + + // We subtract two, because we're already handling the second instruction + // and the address is relative to the first. + uint address = base.StateData.CurrentAddress - 2; + + // 111 10 00000000100 + // 100000000000000 + // + int instImmediate1 = SignExtend11BitTo32BitTHUMB( aInstruction1 & 0x7FF, 12 ); + address = (uint) ( address + instImmediate1 ); + address += 4; + + // 111 01 11101011010 + // 11111111111 (0x7FF) + // 11101011010 = 0x75A * 2 = EB4 + // + // 111 01 11011100010 + // 11011100010 = 0X6E2 * 2 = DC4 + // + // + + // Second instruction + uint instImmediate2 = ( aInstruction2 & 0x7FF ) * 2; + address += instImmediate2; + + // For BLX, the resulting address is forced to be word-aligned by + // clearing bit[1]. + if ( branchType == TMultiPartThumbBranch.ETHUMBBLX ) + { + address = address & 0xFFFFFFFD; + } + + base.StateData.SetPC( address, newInstructionSet ); + branched = true; + } + else + { + // Oops. We ran out of instructions. This shouldn't ever happen + // assuming that the P-HEADER's are synched properly. + throw new ETMException( "ERROR - synchronisation lost with P-HEADERS - 2nd THUMB BLX instruction missing" ); + } + + return branched; + } + + private bool CheckForBranch( ETMInstruction aInstruction ) + { + bool branched = false; + TArmInstructionSet originalInstructionSet = base.StateData.CurrentInstructionSet; + SymAddress originalAddress = new SymAddress( base.StateData.CurrentAddress.Address ); + // + if ( base.StateData.LastBranch.IsKnown ) + { + uint address = base.StateData.CurrentAddress; + TArmInstructionSet instructionSet = base.StateData.CurrentInstructionSet; + // + if ( instructionSet == TArmInstructionSet.EARM ) + { + if ( iBranchMask_ARM_BOrBL.IsMatch( aInstruction ) ) + { + // 1110 101 0 111111111111111111111101 + int offset = SignExtend24BitTo32BitARM( aInstruction & 0x00FFFFFF ); + base.StateData.SetPC( (uint) ( address + offset ) ); + branched = true; + } + else if ( iBranchMask_ARM_BLX_BranchToThumb.IsMatch( aInstruction ) ) + { + // TODO: verify this - no data to test at the moment + int offset = SignExtend24BitTo32BitARM( aInstruction & 0x00FFFFFF ); + base.StateData.SetPC( (uint) ( address + offset ), TArmInstructionSet.ETHUMB ); + branched = true; + } + } + else if ( instructionSet == TArmInstructionSet.ETHUMB ) + { + if ( iBranchMask_THUMB_B1.IsMatch( aInstruction ) ) + { + // 15 14 13 12 11 -> 8 7 -> 0 + // ----------------------------------------- + // 1 1 0 1 cond signed_immed_8 + int offset = SignExtend8BitTo32BitTHUMB( aInstruction & 0xFF ); + base.StateData.SetPC( (uint) ( address + offset ) ); + branched = true; + } + else if ( iBranchMask_THUMB_B2.IsMatch( aInstruction ) ) + { + // 15 14 13 12 11 10 -> 0 + // ----------------------------------------- + // 1 1 0 1 1 signed_immed_11 + int offset = SignExtend11BitTo32BitTHUMB( aInstruction & 0x7FF ); + base.StateData.SetPC( (uint) ( address + offset ) ); + branched = true; + } + else + { + ETMInstruction inst1 = base.StateData.LastInstruction; + bool inst1Match = iBranchMask_THUMB_BLX_Part1.IsMatch( inst1.AIRawValue ); + ETMInstruction inst2 = aInstruction; + bool inst2Match = iBranchMask_THUMB_BLX_Part2.IsMatch( inst2.AIRawValue ); + // + if ( inst1Match && inst2Match ) + { + branched = HandleTHUMBMultiInstructionBranch( inst1.AIRawValue, inst2.AIRawValue ); + System.Diagnostics.Debug.Assert( branched == true ); + } + } + } + else + { + throw new NotSupportedException(); + } + } + if ( branched ) + { + base.StateData.IncrementProcessedInstructionCounter(); + TraceDirectBranch( originalAddress, originalInstructionSet, base.StateData.CurrentAddress, base.StateData.CurrentInstructionSet ); + } + + // Always cache the last processed instruction + base.StateData.LastInstruction = aInstruction; + return branched; + } + + private void TraceDirectBranch( SymAddress aOriginalAddress, TArmInstructionSet aOriginalISet, SymAddress aNewAddress, TArmInstructionSet aNewISet ) + { + StringBuilder lines = new StringBuilder(); + lines.AppendLine( " BRANCH-D" ); + // + if ( base.StateData.LastBranch.IsKnown ) + { + lines.AppendLine( string.Format( " from: {0} 0x{1:x8} {2}", ETMDecodeState.MakeInstructionSetPrefix( aOriginalISet ), aOriginalAddress, StateData.Engine.LookUpSymbol( aOriginalAddress ) ) ); + lines.AppendLine( string.Format( " to: {0} 0x{1:x8} {2}", ETMDecodeState.MakeInstructionSetPrefix( aNewISet ), aNewAddress, StateData.Engine.LookUpSymbol( aNewAddress ) ) ); + } + else + { + } + // + base.Trace( lines.ToString() ); + } + + #region Utilities + private static string TraceAtomTypeName( ETMPcktPHeaderBase.TAtomType aType ) + { + switch ( aType ) + { + default: + case ETMPcktPHeaderBase.TAtomType.EAtomNotApplicable: + return " "; + case ETMPcktPHeaderBase.TAtomType.EAtomE_Passed: + return " PASS "; + case ETMPcktPHeaderBase.TAtomType.EAtomN_Failed: + return "* FAIL *"; + case ETMPcktPHeaderBase.TAtomType.EAtomW_CycleBoundary: + return " CYBNDR "; + } + } + + private void TraceAtom( ETMPcktPHeaderBase.TAtomType aType, ETMInstruction aInstruction ) + { + string atomTypeName = TraceAtomTypeName( aType ); + // + StringBuilder text = new StringBuilder(); + text.AppendFormat( "{0} 0x{1}: {2} {3}", + base.StateData.NumberOfProcessedInstructions.ToString().PadLeft( 6, ' ' ), + base.StateData.CurrentAddress.AddressHex, + base.StateData.CurrentAddress.AddressBinary, + atomTypeName + ); + // + if ( base.StateData.LastBranch.IsKnown ) + { + string disasm = aInstruction.ToString(); + text.Append( " " + disasm ); + } + // + base.Trace( text.ToString() ); + } + + private static int SignExtend24BitTo32BitARM( uint aImmediate ) + { + int offset; + // + unchecked + { + if ( ( aImmediate & 0x00800000 ) == 0x00800000 ) + { + offset = (int) ( 0xff000000 | aImmediate ); + } + else + { + offset = (int) aImmediate; + } + } + // + offset <<= 2; + offset += 8; // pipeline + return offset; + } + + private static int SignExtend11BitTo32BitTHUMB( uint aImmediate ) + { + int offset = SignExtend11BitTo32BitTHUMB( aImmediate, 1 ); + offset += 4; // pipeline + return offset; + } + + private static int SignExtend11BitTo32BitTHUMB( uint aImmediate, int aLeftShiftCount ) + { + int offset; + // + unchecked + { + // 10 9 8 7 6 5 4 3 2 1 0 + // ---------------------------------- + // 1 0 0 0 0 0 0 0 0 0 0 + if ( ( aImmediate & 0x00000400 ) == 0x00000400 ) + { + // 11111111111111111111100000000000 + // 10000000000 + offset = (int) ( 0xFFFFF800 | aImmediate ); + } + else + { + offset = (int) aImmediate; + } + } + // + offset <<= aLeftShiftCount; + return offset; + } + + private static int SignExtend8BitTo32BitTHUMB( uint aImmediate ) + { + int offset; + // + unchecked + { + // 7 6 5 4 3 2 1 0 + // ------------------------ + // 1 0 0 0 0 0 0 0 + if ( ( aImmediate & 0x00000080 ) == 0x00000080 ) + { + // 11111111111111111111111100000000 + // 10000000 + offset = (int) ( 0xFFFFFF00 | aImmediate ); + } + else + { + offset = (int) aImmediate; + } + } + // + offset <<= 1; + offset += 4; // pipeline + return offset; + } + #endregion + + #endregion + + #region From System.Object + #endregion + + #region Data members + private static readonly SymMask iBranchMask_ARM_BOrBL; + private static readonly SymMask iBranchMask_ARM_BLX_BranchToThumb; + private static readonly SymMask iBranchMask_THUMB_B1; + private static readonly SymMask iBranchMask_THUMB_B2; + private static readonly SymMask iBranchMask_THUMB_BLX_Part1; + private static readonly SymMask iBranchMask_THUMB_BLX_Part2; + #endregion + } +}