crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianETMLib/Common/State/Implementations/ETMDecodeStatePHeader.cs
changeset 0 818e61de6cd1
--- /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
+    }
+}