libraries/memoryaccess/TrkNextInstructionAfterPC.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Sat, 31 Jul 2010 19:07:57 +0100
changeset 23 092bcc217d9d
parent 0 7f656887cf89
permissions -rw-r--r--
Tidied iocli exports, build macro tweaks. Removed 4 overloads of CCommandBase::RunCommand[L] that are no longer used at all, and changed one more to not be exported as it's only used internally to iocli.dll. fixed builds on platforms that don't support btrace or any form of tracing.

// TrkNextInstructionAfterPC.cpp
// 
// Copyright (c) 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//
#include "fdebuggerkernel.h"

//BEGIN TOMSCI
#include <kernel/arm/arm.h>

#define LOG_MSG(x)
#define LOG_MSG2(x,y)
#define LOG_MSG3(x,y,z)
#define iChannel this // Saves rewriting a whole load
#define ReturnIfError(x) { TInt y = (x); if (KErrNone != y) return y; }

#ifdef ASSERT
#undef ASSERT
#endif
#ifdef __WINS__
#define ASSERT(x) __ASSERT_ALWAYS((x), Kern::Fault("TRKNIAPC Assertion failed: " #x, __LINE__))
#else
#define ASSERT(x) if (!(x)) { Kern::Printf("TRKNIAPC Assertion failed @ %d: " #x, __LINE__); NKern::Sleep(NKern::TimerTicks(5000)); }
#endif

TInt DDebuggerEventHandler::ReadKernelRegisterValue(DThread* aThread, TInt aRegister, TUint32& aResult)
	{
	TUint32 regs[32];
	TUint32 valid = 0;
	NKern::ThreadGetUserContext(&aThread->iNThread, &regs[0], valid);
	if (valid & (1<<aRegister))
		{
		aResult = regs[aRegister];
		return KErrNone;
		}
	else
		{
		return KErrNotSupported;
		}
	}

TInt DDebuggerEventHandler::DoReadMemory(DThread* aThread, TLinAddr aAddress, TInt aLength, TDes8& aResult)
	{
	// First check if this address is something we've overwritten with a software breakpoint - if so, return the stored value instead
	ASSERT(aLength == 4 || aLength == 2);
	if (aResult.MaxLength() < aLength) return KErrArgument;
	
	// Check for a breakpoint covering this region
	SBreakpoint* b = FindBreakpointByAddress(aAddress & ~1);
	if (b && b->iOrigInstruction.Length() > 0)
		{
		ASSERT(b->iOrigInstruction.Length() == aLength); // Otherwise we've trying to read an ARM instruction from somewhere we have a thumb breakpoint (or vice versa)
		aResult.Copy(b->iOrigInstruction);
		return KErrNone;
		}
	
	TInt err = Kern::ThreadRawRead(aThread, (void*)aAddress, (void*)aResult.Ptr(), aLength);
	if (err == KErrNone) aResult.SetLength(aLength);
	return err;
	}

namespace Debug {
	enum TArchitectureMode
	{
	/** Represents the ARM CPU architecture. */
	EArmMode = 1,
	/** Represents the Thumb CPU architecture. */
	EThumbMode = 2,
	/**
	  Represents the Thumb2 CPU architecture.
	  @prototype
	  */
	EThumb2EEMode = 3
	};
}
using namespace Debug;
typedef TUint32 T4ByteRegisterValue;

//END TOMSCI


// Register definitions
#define SP_REGISTER			13
#define LINK_REGISTER		14
#define PC_REGISTER			15
#define STATUS_REGISTER		16

/*
// ARM instruction bitmasks
#define ARM_OPCODE(x)		(((TUint32)(x) & 0x0E000000) >> 25)

// Generic instruction defines
#define ARM_RM(x)				((TUint32)(x) & 0x0000000F)			// bit 0- 4
#define ARM_RS(x)				(((TUint32)(x) & 0x00000F00) >> 8)	// bit 8-11
#define ARM_RD(x)				(((TUint32)(x) & 0x0000F000) >> 12)	// bit 12-15
#define ARM_RN(x)				(((TUint32)(x) & 0x000F0000) >> 16)	// bit 16-19
#define ARM_LOAD(x)				(((TUint32)(x) & 0x00100000) >> 20)	// bit 20

// Data processing instruction defines
#define ARM_DATA_SHIFT(x)		(((TUint32)(x) & 0x00000060) >> 5) 	// bit 5- 6
#define ARM_DATA_C(x)			(((TUint32)(x) & 0x00000F80) >> 7) 	// bit 7-11
#define ARM_DATA_IMM(x)			((TUint32)(x) & 0x000000FF)			// bit 0-7
#define ARM_DATA_ROT(x)			(((TUint32)(x) & 0x00000F00) >> 8) 	// bit 8-11

// Single date transfer instruction defines
#define ARM_SINGLE_IMM(x)		((TUint32)(x) & 0x00000FFF)			// bit 0-11
#define ARM_SINGLE_BYTE(x)		(((TUint32)(x) & 0x00400000) >> 22)	// bit 22
#define ARM_SINGLE_U(x)			(((TUint32)(x) & 0x00800000) >> 23)	// bit 23
#define ARM_SINGLE_PRE(x)		(((TUint32)(x) & 0x01000000) >> 24)	// bit 24

// Block data transfer instruction defines
#define ARM_BLOCK_REGLIST(x)	((TUint32)(x) & 0x0000FFFF)		// bit 0-15
#define ARM_BLOCK_U(x)			(((TUint32)(x) & 0x00800000) >> 23)	// bit 23
#define ARM_BLOCK_PRE(x)		(((TUint32)(x) & 0x01000000) >> 24)	// bit 24

// Branch instruction defines
#define ARM_B_ADDR(x)			((x & 0x00800000) ? ((TUint32)(x) & 0x00FFFFFF | 0xFF000000) : (TUint32)(x) & 0x00FFFFFF)
#define ARM_INSTR_B_DEST(x,a)	(ARM_B_ADDR(x) << 2) + ((TUint32)(a) + 8)

#define ARM_CARRY_BIT			0x20000000	// bit 30


// Thumb instruction bitmasks
#define THUMB_OPCODE(x)		(((TUint16)(x) & 0xF800) >> 11)
#define THUMB_INST_7_15(x)	(((TUint16)(x) & 0xFF80) >> 7)
#define THUMB_INST_8_15(x)	(((TUint16)(x) & 0xFF00) >> 8)
*/

TUint32 IsBitSet(const TUint32 aBitset, const TUint8 aNum)
	{
	return (aBitset & (1 << aNum) );
	}

// 
// BitCount
//
// Count number of bits in aVal
TUint32 BitCount(const TUint32 aVal)
	{
	TUint32 num = 0;

	for(TInt i = 0; i < 32; i++)
		{
		if ((1 << i) & aVal)
			{
			num++;
			}
		}
	return num;
	}

//
// Thumb2 opcode decoding
//
// Special data instructions and branch and exchange.
//
// Returns Opcode as defined in ARM ARM DDI0406A, section A6.2.3
TUint16 t2opcode16special(const TUint16 aInst)
	{
	TUint8 aVal = (aInst & 0x03C0) >> 5;

	return aVal;
	}


// Thumb2 opcode decoding instructions
// 
// Returns Opcode as defined in ARM ARM DDI0406A, section A6.2
// 16-bit Thumb instruction encoding
TUint16 t2opcode16(const TUint16 aInst)
{
	TUint16 aVal = (aInst & 0xFC00) >> 9;

	return aVal;
}

// ARM opcode decoding functions
TUint32 arm_opcode(const TUint32 aInst)
{
// #define ARM_OPCODE(x)		(((TUint32)(x) & 0x0E000000) >> 25)

	TUint32 aVal = ((aInst) & 0x0E000000) >> 25;

	return aVal;
}

TUint32  arm_rm(const TUint32 aInst)
{
//#define ARM_RM(x)				((TUint32)(x) & 0x0000000F)			// bit 0- 4

	TUint32 aVal = (aInst) & 0x0000000F;

	return aVal;
}

TUint32  arm_rs(const TUint32 aInst)
{
//#define ARM_RS(x)				(((TUint32)(x) & 0x00000F00) >> 8)	// bit 8-11

	TUint32 aVal = ((aInst) & 0x00000F00) >> 8;

	return aVal;
}

TUint32  arm_rd(const TUint32 aInst)
{
//#define ARM_RD(x)				(((TUint32)(x) & 0x0000F000) >> 12)	// bit 12-15

	TUint32 aVal = ((aInst) & 0x0000F000) >> 12;

	return aVal;
}

TUint32  arm_rn(const TUint32 aInst)
{
//#define ARM_RN(x)				(((TUint32)(x) & 0x000F0000) >> 16)	// bit 16-19

	TUint32 aVal = ((aInst) & 0x000F0000) >> 16;

	return aVal;
}

TUint32 arm_load(const TUint32 aInst)
{
//#define ARM_LOAD(x)				(((TUint32)(x) & 0x00100000) >> 20)	// bit 20

	TUint32 aVal = ((aInst) & 0x00100000) >> 20;

	return aVal;
}

// Data processing instruction defines
TUint32 arm_data_shift(const TUint32 aInst)
{
//#define ARM_DATA_SHIFT(x)		(((TUint32)(x) & 0x00000060) >> 5) 	// bit 5- 6
	
	TUint32 aVal = ((aInst) & 0x00000060) >> 5;

	return aVal;
}

TUint32 arm_data_c(const TUint32 aInst)
{
//#define ARM_DATA_C(x)			(((TUint32)(x) & 0x00000F80) >> 7) 	// bit 7-11

	TUint32 aVal = ((aInst) & 0x00000F80) >> 7;

	return aVal;
}

TUint32 arm_data_imm(const TUint32 aInst)
{
//#define ARM_DATA_IMM(x)			((TUint32)(x) & 0x000000FF)			// bit 0-7

	TUint32 aVal = (aInst) & 0x000000FF;

	return aVal;
}

TUint32 arm_data_rot(const TUint32 aInst)
{
//#define ARM_DATA_ROT(x)			(((TUint32)(x) & 0x00000F00) >> 8) 	// bit 8-11

	TUint32 aVal = ((aInst) & 0x00000F00) >> 8;

	return aVal;
}

// Single date transfer instruction defines
TUint32 arm_single_imm(const TUint32 aInst)
{
//#define ARM_SINGLE_IMM(x)		((TUint32)(x) & 0x00000FFF)			// bit 0-11

	TUint32 aVal = (aInst) & 0x00000FFF;

	return aVal;
}

TUint32 arm_single_byte(const TUint32 aInst)
{
//#define ARM_SINGLE_BYTE(x)		(((TUint32)(x) & 0x00400000) >> 22)	// bit 22

	TUint32 aVal = ((aInst) & 0x00400000) >> 22;

	return aVal;
}

TUint32 arm_single_u(const TUint32 aInst)
{
//#define ARM_SINGLE_U(x)			(((TUint32)(x) & 0x00800000) >> 23)	// bit 23

	TUint32 aVal = ((aInst) & 0x00800000) >> 23;

	return aVal;
}

TUint32 arm_single_pre(const TUint32 aInst)
{
//#define ARM_SINGLE_PRE(x)		(((TUint32)(x) & 0x01000000) >> 24)	// bit 24

	TUint32 aVal = ((aInst) & 0x01000000) >> 24;

	return aVal;
}

// Block data transfer instruction defines
TUint32 arm_block_reglist(const TUint32 aInst)
{
//#define ARM_BLOCK_REGLIST(x)	((TUint32)(x) & 0x0000FFFF)		// bit 0-15

	TUint32 aVal = (aInst) & 0x0000FFFF;

	return aVal;
}

TUint32 arm_block_u(const TUint32 aInst)
{
//#define ARM_BLOCK_U(x)			(((TUint32)(x) & 0x00800000) >> 23)	// bit 23

	TUint32 aVal = ((aInst) & 0x00800000) >> 23;

	return aVal;
}

TUint32 arm_block_pre(const TUint32 aInst)
{
//#define ARM_BLOCK_PRE(x)		(((TUint32)(x) & 0x01000000) >> 24)	// bit 24

	TUint32 aVal = ((aInst) & 0x01000000) >> 24;

	return aVal;
}

// Branch instruction defines
TUint32 arm_b_addr(const TUint32 aInst)
{
//#define ARM_B_ADDR(x)			((x & 0x00800000) ? ((TUint32)(x) & 0x00FFFFFF | 0xFF000000) : (TUint32)(x) & 0x00FFFFFF)

	TUint32 aVal = ((aInst & 0x00800000) ? ((TUint32)(aInst) & 0x00FFFFFF | 0xFF000000) : (TUint32)(aInst) & 0x00FFFFFF);

	return aVal;
}

TUint32 arm_instr_b_dest(const TUint32 aInst, TUint32& aAddress)
{
//#define ARM_INSTR_B_DEST(x,a)	(ARM_B_ADDR(x) << 2) + ((TUint32)(a) + 8)

	TUint32 aVal = (arm_b_addr(aInst) << 2) + ((TUint32)(aAddress) + 8);

	return aVal;
}

TUint32 thumb_b_addr(const TUint32 aInst)
{
//#define THUMB_B_ADDR(x) ((x & 0x0400) ? ((((TUint32)(x) & 0x07FF)<<11) | (((TUint32)(x) & 0x07FF0000)>>16) | 0xFFC00000) :\
                                            ((TUint32)(x) & 0x07FF)<<11) | (((TUint32)(x) & 0x07FF0000)>>16)

	TUint32 aVal = ((((TUint32)(aInst) & 0x07FF)<<11) | ((TUint32)(aInst) & 0x07FF0000)>>16);

	return ((aInst & 0x0400) ? (aVal | 0xFFC00000) : aVal);
}

TUint32 thumb_instr_b_dest(const TUint32 aInst, TUint32& aAddress)
{
//#define THUMB_INSTR_B_DEST(x,a)	(THUMB_B_ADDR(x) << 1) + ((TUint32)(a) + 4)

	TUint32 aVal = (thumb_b_addr(aInst) << 1) + ((TUint32)(aAddress) + 4);

	return aVal;
}

TUint32 arm_carry_bit(void)
{
//#define ARM_CARRY_BIT			0x20000000	// bit 30

	TUint32 aVal = 0x20000000;

	return aVal;
}

// Thumb instruction bitmasks
TUint16 thumb_opcode(const TUint16 aInst)
{
//	#define THUMB_OPCODE(x)		(((TUint16)(x) & 0xF800) >> 11)

	TUint16 aVal = ((aInst) & 0xF800) >> 11;

	return aVal;
}

TUint16 thumb_inst_7_15(const TUint16 aInst)
{
//	#define THUMB_INST_7_15(x)	(((TUint16)(x) & 0xFF80) >> 7)

	TUint16 aVal = ((aInst) & 0xFF80) >> 7;

	return aVal;
}

TUint16 thumb_inst_8_15(const TUint16 aInst)
{
//	#define THUMB_INST_8_15(x)	(((TUint16)(x) & 0xFF00) >> 8)

	TUint16 aVal = ((aInst) & 0xFF00) >> 8;

	return aVal;
}



TBool IsExecuted(TUint8 aCondition ,TUint32 aStatusRegister)
{
	LOG_MSG("DRMDStepping::IsExecuted()");

	TBool N = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000008;
	TBool Z = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000004;
	TBool C = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000002;
	TBool V = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000001;

	switch(aCondition)
	{
		case 0:
			return Z;
		case 1:
			return !Z;
		case 2:
			return C;
		case 3:
			return !C;
		case 4:
			return N;
		case 5:
			return !N;
		case 6:
			return V;
		case 7:
			return !V;
		case 8:
			return (C && !Z);
		case 9:
			return (!C || Z);
		case 10:
			return (N == V);
		case 11:
			return (N != V);
		case 12:
			return ((N == V) && !Z);
		case 13:
			return (Z || (N != V));
		case 14:
		case 15:
			return ETrue;
	}
	
	return EFalse;
}

TBool DDebuggerEventHandler::IsPreviousInstructionMovePCToLR(DThread *aThread)
{
	TInt err = KErrNone;
	
	// there are several types of instructions that modify the PC that aren't
	// designated as linked or non linked branches.  the way gcc generates the
	// code can tell us whether or not these instructions are to be treated as
	// linked branches.  the main cases are bx and any type of mov or load or
	// arithmatic operation that changes the PC.  if these are really just
	// function calls that will return, gcc will generate a mov	lr, pc
	// instruction as the previous instruction.  note that this is just for arm
	// and armi
	
	// get the address of the previous instruction
	TUint32 address = 0;
	//err = iChannel->ReadKernelRegisterValue(aThread, PC_REGISTER, address);
	err = ReadKernelRegisterValue(aThread, PC_REGISTER, address);
	if(err != KErrNone)
	{
		LOG_MSG2("Non-zero error code discarded: %d", err);
	}
	address -= 4;

	TBuf8<4> previousInstruction;
	err = DoReadMemory(aThread, address, 4, previousInstruction);
	if (KErrNone != err)
	{
		LOG_MSG2("Error %d reading memory at address %x", address);
		return EFalse;
	}

	const TUint32 movePCToLRIgnoringCondition = 0x01A0E00F;

	TUint32 inst = *(TUint32 *)previousInstruction.Ptr();
	
	if ((inst & 0x0FFFFFFF) == movePCToLRIgnoringCondition)
	{
		return ETrue;
	}
		
	return EFalse;
}

void DecodeDataProcessingInstruction(TUint8 aOpcode, TUint32 aOp1, TUint32 aOp2, TUint32 aStatusRegister, TUint32 &aBreakAddress)
{
	LOG_MSG("DRMDStepping::DecodeDataProcessingInstruction()");

	switch(aOpcode)
	{
		case 0:
		{
			// AND
			aBreakAddress = aOp1 & aOp2;
			break;
		}
		case 1:
		{
			// EOR
			aBreakAddress = aOp1 ^ aOp2;
			break;
		}
		case 2:
		{
			// SUB
			aBreakAddress = aOp1 - aOp2;
			break;
		}
		case 3:
		{
			// RSB
			aBreakAddress = aOp2 - aOp1;
			break;
		}
		case 4:
		{
			// ADD
			aBreakAddress = aOp1 + aOp2;
			break;
		}
		case 5:
		{
			// ADC
			aBreakAddress = aOp1 + aOp2 + (aStatusRegister & arm_carry_bit()) ? 1 : 0;
			break;
		}
		case 6:
		{
			// SBC
			aBreakAddress = aOp1 - aOp2 - (aStatusRegister & arm_carry_bit()) ? 0 : 1;
			break;
		}
		case 7:
		{
			// RSC
			aBreakAddress = aOp2 - aOp1 - (aStatusRegister & arm_carry_bit()) ? 0 : 1;
			break;
		}
		case 12:
		{
			// ORR
			aBreakAddress = aOp1 | aOp2;
			break;
		}
		case 13:
		{
			// MOV
			aBreakAddress = aOp2;
			break;
		}
		case 14:
		{
			// BIC
			aBreakAddress = aOp1 & ~aOp2;
			break;
		}
		case 15:
		{
			// MVN
			aBreakAddress = ~aOp2;
			break;
		}
	}
}


// Returns the current instruction bitpattern (either 32-bits or 16-bits) if possible
//BEGIN TOMSCI who was smoking crack while writing this?

TInt DDebuggerEventHandler::CurrentInstructionArm(DThread* aThread, TUint32& aInstruction)
	{
	TUint32 pc;	
	ReturnIfError(CurrentPC(aThread,pc));
	TBuf8<4> buf;
	ReturnIfError(DoReadMemory(aThread, pc, 4, buf));
	aInstruction = *(TUint32*)buf.Ptr();
	return KErrNone;
	}

TInt DDebuggerEventHandler::CurrentInstructionThumb(DThread* aThread, TUint32& aInstruction)
	{
	TUint32 pc;	
	ReturnIfError(CurrentPC(aThread,pc));
	TBuf8<2> buf;
	ReturnIfError(DoReadMemory(aThread, pc, 2, buf));
	aInstruction = *(TUint16*)buf.Ptr();
	return KErrNone;
	}

/*
TInt DDebuggerEventHandler::CurrentInstruction(DThread* aThread, TUint32& aInstruction)
	{
	LOG_MSG("DRMDStepping::CurrentInstruction");

	// What is the current PC?
	TUint32 pc;	
	ReturnIfError(CurrentPC(aThread,pc));

	
	// Read it one byte at a time to ensure alignment doesn't matter
	TUint32 inst = 0;
	for(TInt i=3;i>=0;i--)
		{

		TBuf8<1> instruction;
		TInt err = iChannel->DoReadMemory(aThread, (pc+i), 1, instruction); 
		if (KErrNone != err)
			{
			LOG_MSG2("DRMDStepping::CurrentInstruction : Failed to read memory at current PC: return 0x%08x",pc);
			return err;
			}

		inst = (inst << 8) | (*(TUint8 *)instruction.Ptr());
		}

	aInstruction = inst;

	LOG_MSG2("DRMDStepping::CurrentInstruction 0x%08x", aInstruction);

	return KErrNone;
	}
END TOMSCI*/

// Determines architecture mode from the supplied cpsr
TInt CurrentArchMode(const TUint32 aCpsr, Debug::TArchitectureMode& aMode)
	{
// Thumb2 work will depend on having a suitable cpu architecture to compile for...
#ifdef ECpuJf
	// State table as per ARM ARM DDI0406A, section A.2.5.1
	if(aCpsr & ECpuJf)
		{
		if (aCpsr & ECpuThumb)
			{
			// ThumbEE (Thumb2)
			aMode = Debug::EThumb2EEMode;
			}
		else
			{
			// Jazelle mode - not supported
			return KErrNotSupported;
			}
		}
	else
#endif
		{
		if (aCpsr & ECpuThumb)
			{
			// Thumb mode
			aMode = Debug::EThumbMode;
			}
		else
			{
			// ARM mode
			aMode = Debug::EArmMode;
			}
		}

	return KErrNone;
	}

//
// DRMDStepping::PCAfterInstructionExecutes
//
// Note, this function pretty much ignores all the arguments except for aThread.
// The arguments continue to exist so that the function has the same prototype as
// the original from Nokia. In the long term this function will be re-factored
// to remove obsolete parameters.
//
TUint32 DDebuggerEventHandler::PCAfterInstructionExecutes(DThread *aThread, TUint32 aCurrentPC, TUint32 aStatusRegister, TInt aInstSize, /*TBool aStepInto,*/ TUint32 &aNewRangeEnd, TBool &aChangingModes)
{
	LOG_MSG("DRMDStepping::PCAfterInstructionExecutes()");

	// by default we will set the breakpoint at the next instruction
	TUint32 breakAddress = aCurrentPC + aInstSize;

	TInt err = KErrNone;

	// determine the architecture
    TUint32 cpuid;
   	asm("mrc p15, 0, cpuid, c0, c0, 0 ");
	LOG_MSG2("DRMDStepping::PCAfterInstructionExecutes() - cpuid = 0x%08x\n",cpuid);

    cpuid >>= 8;
    cpuid &= 0xFF;

	// determine the architecture mode for the current instruction
	TArchitectureMode mode = EArmMode;	// Default assumption is ARM 

	// Now we must examine the CPSR to read the T and J bits. See ARM ARM DDI0406A, section B1.3.3
	TUint32 cpsr;

	ReturnIfError(CurrentCPSR(aThread,cpsr));
	LOG_MSG2("DRMDStepping::PCAfterInstructionExecutes() - cpsr = 0x%08x\n",cpsr);

	aStatusRegister = cpsr; // The passed-in value of aStatusRegister is ignored, but I can't be bothered to change all the code below. -Tomsci
	
	// Determine the mode
	ReturnIfError(CurrentArchMode(cpsr,mode));

	// Decode instruction based on current CPU mode
	switch(mode)
	{
		case Debug::EArmMode:
		{
			// Obtain the current instruction bit pattern
			TUint32 inst;
			ReturnIfError(CurrentInstructionArm(aThread,inst));
			
			LOG_MSG2("Current instruction: %x", inst);

			// check the conditions to see if this will actually get executed
			if (IsExecuted(((inst>>28) & 0x0000000F), aStatusRegister)) 
			{
				switch(arm_opcode(inst)) // bits 27-25
				{
					case 0:
					{
						switch((inst & 0x00000010) >> 4) // bit 4
						{
							case 0:
							{
								switch((inst & 0x01800000) >> 23) // bits 24-23
								{
									case 2:
									{
										// move to/from status register.  pc updates not allowed
										// or TST, TEQ, CMP, CMN which don't modify the PC
										break;
									}
									default:
									{
										// Data processing immediate shift
										if (arm_rd(inst) == PC_REGISTER)
										{
											TUint32 rn = aCurrentPC + 8;
											if (arm_rn(inst) != PC_REGISTER) // bits 19-16
											{
												err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), rn);
												if(err != KErrNone)
												{
													LOG_MSG2("Non-zero error code discarded: %d", err);
												}
											}

											TUint32 shifter = ShiftedRegValue(aThread, inst, aCurrentPC, aStatusRegister);

											DecodeDataProcessingInstruction(((inst & 0x01E00000) >> 21), rn, shifter, aStatusRegister, breakAddress);
										}
										break;
									}
								}
								break;
							}					
							case 1:
							{
								switch((inst & 0x00000080) >> 7) // bit 7
								{
									case 0:
									{
										switch((inst & 0x01900000) >> 20) // bits 24-23 and bit 20
										{
											case 0x10:
											{
												// from figure 3-3
												switch((inst & 0x000000F0) >> 4) // bits 7-4
												{
													case 1:
													{
														if (((inst & 0x00400000) >> 22) == 0) // bit 22
														{
															// BX
															// this is a strange case.  normally this is used in the epilogue to branch the the link
															// register.  sometimes it is used to call a function, and the LR is stored in the previous
															// instruction.  since what we want to do is different for the two cases when stepping over,
															// we need to read the previous instruction to see what we should do
															err = iChannel->ReadKernelRegisterValue(aThread, (inst & 0x0000000F), breakAddress);
															if(err != KErrNone)
															{
																LOG_MSG2("Non-zero error code discarded: %d", err);
															}

															if ((breakAddress & 0x00000001) == 1)
															{
																aChangingModes = ETrue;
															}

															breakAddress &= 0xFFFFFFFE;
														}
														break;
													}
													case 3:
													{
														// BLX
														{
															err = iChannel->ReadKernelRegisterValue(aThread, (inst & 0x0000000F), breakAddress);
															if(err != KErrNone)
															{
																LOG_MSG2("Non-zero error code discarded: %d", err);
															}

															if ((breakAddress & 0x00000001) == 1)
															{
																aChangingModes = ETrue;
															}
															
															breakAddress &= 0xFFFFFFFE;
														}
														break;
													}
													default:
													{
														// either doesn't modify the PC or it is illegal to
														break;
													}
												}
												break;
											}
											default:
											{
												// Data processing register shift
												if (((inst & 0x01800000) >> 23) == 2) // bits 24-23
												{
													// TST, TEQ, CMP, CMN don't modify the PC
												}
												else if (arm_rd(inst) == PC_REGISTER)
												{
													// destination register is the PC
													TUint32 rn = aCurrentPC + 8;
													if (arm_rn(inst) != PC_REGISTER) // bits 19-16
													{
														err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), rn);
														if(err != KErrNone)
														{
															LOG_MSG2("Non-zero error code discarded: %d", err);
														}
													}
													
													TUint32 shifter = ShiftedRegValue(aThread, inst, aCurrentPC, aStatusRegister);
													
													DecodeDataProcessingInstruction(((inst & 0x01E00000) >> 21), rn, shifter, aStatusRegister, breakAddress);
												}
												break;
											}
										}
										break;
									}
									default:
									{
										// from figure 3-2, updates to the PC illegal
										break;
									}
								}
								break;
							}
						}
						break;
					}
					case 1:
					{
						if (((inst & 0x01800000) >> 23) == 2) // bits 24-23
						{
							// cannot modify the PC
							break;
						}
						else if (arm_rd(inst) == PC_REGISTER)
						{
							// destination register is the PC
							TUint32 rn;
							err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), rn); // bits 19-16
							if(err != KErrNone)
							{
								LOG_MSG2("Non-zero error code discarded: %d", err);
							}
							TUint32 shifter = ((arm_data_imm(inst) >> arm_data_rot(inst)) | (arm_data_imm(inst) << (32 - arm_data_rot(inst)))) & 0xffffffff;

							DecodeDataProcessingInstruction(((inst & 0x01E00000) >> 21), rn, shifter, aStatusRegister, breakAddress);
						}
						break;
					}
					case 2:
					{
						// load/store immediate offset
						if (arm_load(inst)) // bit 20
						{
							// loading a register from memory
							if (arm_rd(inst) == PC_REGISTER)
							{
								// loading the PC register
								TUint32 base;
								err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), base);
								if(err != KErrNone)
								{
									LOG_MSG2("Non-zero error code discarded: %d", err);
								}

								/* Note: At runtime the PC would be 8 further on
								 */
								if (arm_rn(inst) == PC_REGISTER)
								{
									base = aCurrentPC + 8;
								}

								TUint32 offset = 0;
					    		
					    		if (arm_single_pre(inst))
					    		{
					    			// Pre-indexing
					    			offset = arm_single_imm(inst);
									
									if (arm_single_u(inst))
									{
							    		base += offset;
									}
									else
									{
							    		base -= offset;
									}
								}

								TBuf8<4> destination;
								err = iChannel->DoReadMemory(aThread, base, 4, destination);
								
								if (KErrNone == err)
								{
									breakAddress = *(TUint32 *)destination.Ptr();
								
									if ((breakAddress & 0x00000001) == 1)
									{
										aChangingModes = ETrue;
									}								
									breakAddress &= 0xFFFFFFFE;
								}
								else
								{
									LOG_MSG("Error reading memory in decoding step instruction");
								}
							}
						}	
						break;
					}
					case 3:
					{
						if (((inst & 0xF0000000) != 0xF0000000) && ((inst & 0x00000010) == 0))
						{
							// load/store register offset
							if (arm_load(inst)) // bit 20
							{
								// loading a register from memory
								if (arm_rd(inst) == PC_REGISTER)
								{
									// loading the PC register
									TUint32 base = 0;
									if(arm_rn(inst) == PC_REGISTER)
									{
										base = aCurrentPC + 8;
									}
									else
									{
										err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), base);
										if(err != KErrNone)
										{
											LOG_MSG2("Non-zero error code discarded: %d", err);
										}
									}

									TUint32 offset = 0;

									if (arm_single_pre(inst))
									{
										offset = ShiftedRegValue(aThread, inst, aCurrentPC, aStatusRegister);

										if (arm_single_u(inst))
										{
											base += offset;
										}
										else
										{
											base -= offset;
										}
									}

									TBuf8<4> destination;
									err = iChannel->DoReadMemory(aThread, base, 4, destination);

									if (KErrNone == err)
									{
										breakAddress = *(TUint32 *)destination.Ptr();

										if ((breakAddress & 0x00000001) == 1)
										{
											aChangingModes = ETrue;
										}								
										breakAddress &= 0xFFFFFFFE;
									}
									else
									{
										LOG_MSG("Error reading memory in decoding step instruction");
									}
								}
							}	
						}
						break;
					}
					case 4:
					{
						if ((inst & 0xF0000000) != 0xF0000000)
						{
							// load/store multiple
							if (arm_load(inst)) // bit 20
							{
								// loading a register from memory
								if (((inst & 0x00008000) >> 15))
								{
									// loading the PC register
									TInt offset = 0;	
									if (arm_block_u(inst))
									{
										TUint32 reglist = arm_block_reglist(inst);
										offset = BitCount(reglist) * 4 - 4;
										if (arm_block_pre(inst))
											offset += 4;
									}
									else if (arm_block_pre(inst))
									{
										offset = -4;
									}
										
									TUint32 temp = 0;
									err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), temp);
									if(err != KErrNone)
									{
										LOG_MSG2("Non-zero error code discarded: %d", err);
									}
									
									temp += offset;

									TBuf8<4> destination;
									err = iChannel->DoReadMemory(aThread, temp, 4, destination);
									
									if (KErrNone == err)
									{
										breakAddress = *(TUint32 *)destination.Ptr();
										if ((breakAddress & 0x00000001) == 1)
										{
											aChangingModes = ETrue;
										}
										breakAddress &= 0xFFFFFFFE;
									}
									else
									{
										LOG_MSG("Error reading memory in decoding step instruction");
									}
								}
							}					
						}
						break;
					}
					case 5:
					{
						if ((inst & 0xF0000000) == 0xF0000000)
						{
							// BLX
							{
								breakAddress = (TUint32)arm_instr_b_dest(inst, aCurrentPC);

								// Unconditionally change into Thumb mode
								aChangingModes = ETrue;
								
								breakAddress &= 0xFFFFFFFE;
							}
						}
						else
						{
							if ((inst & 0x01000000)) // bit 24
							{
								// BL
								{
									breakAddress = (TUint32)arm_instr_b_dest(inst, aCurrentPC);
								}
							}
							else
							{
								// B
								breakAddress = (TUint32)arm_instr_b_dest(inst, aCurrentPC);
							}
						}
						break;
					}
				}	
			}
		}
		break;

		case Debug::EThumbMode:
		{
			// Thumb Mode
			//
			// Notes: This now includes the extra code
			// required to decode V6T2 instructions
			
			LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Thumb Instruction");

			TUint16 inst;

			// Obtain the current instruction bit pattern
			TUint32 inst32;
			ReturnIfError(CurrentInstructionThumb(aThread,inst32));

			inst = static_cast<TUint16>(inst32 & 0xFFFF);

			LOG_MSG2("Current Thumb instruction: 0x%x", inst);

			// v6T2 instructions

// Note: v6T2 decoding is only enabled for DEBUG builds or if using an
// an ARM_V6T2 supporting build system. At the time of writing, no
// ARM_V6T2 supporting build system exists, so the stepping code cannot
// be said to be known to work. Hence it is not run for release builds

			TBool use_v6t2_decodings = EFalse;

#if defined(DEBUG) || defined(__ARMV6T2__)
			use_v6t2_decodings = ETrue;

#endif
			// coverity[dead_error_line]
			if (use_v6t2_decodings)
			{
				// 16-bit encodings
	 
				// A6.2.5 Misc 16-bit instructions
				// DONE Compare and branch on zero (page A8-66)
				// If then hints

				// ARM ARM DDI0406A - section A8.6.27 CBNZ, CBZ
				//
				// Compare and branch on Nonzero and Compare and Branch on Zero.
				if ((inst & 0xF500) == 0xB100)
				{
					LOG_MSG("ARM ARM DDI0406A - section A8.6.27 CBNZ, CBZ");

					// Decoding as per ARM ARM description
					TUint32 op = (inst & 0x0800) >> 11;
					TUint32 i = (inst & 0x0200) >> 9;
					TUint32 imm5 = (inst & 0x00F8) >> 3;
					TUint32 Rn = inst & 0x0007;

					TUint32 imm32 = (i << 6) | (imm5 << 1);

					// Obtain value for register Rn
					TUint32 RnVal = 0;
					ReturnIfError(RegisterValue(aThread,Rn,RnVal));

					if (op)
						{
						// nonzero
						if (RnVal != 0x0)
							{
							// Branch
							breakAddress = aCurrentPC + imm32;
							}
						}
					else
						{
						// zero
						if (RnVal == 0x0)
							{
							// Branch
							breakAddress = aCurrentPC + imm32;
							}
						}
				}

				// ARM ARM DDI0406A - section A8.6.50 IT
				//
				// If Then instruction
				if ((inst & 0xFF00) == 0xBF00)
				{
					LOG_MSG("ARM ARM DDI0406A - section A8.6.50 IT");

					// Decoding as per ARM ARM description
					TUint32 firstcond = inst & 0x00F0 >> 4;
					TUint32 mask = inst & 0x000F;

					if (firstcond == 0xF)
					{
						// unpredictable
						LOG_MSG("ARM ARM DDI0406A - section A8.6.50 IT - Unpredictable");
						break;
					}

					if ((firstcond == 0xE) && (BitCount(mask) != 1))
					{
						// unpredictable
						LOG_MSG("ARM ARM DDI0406A - section A8.6.50 IT - Unpredictable");
						break;
					}

					// should check if 'in-it-block'
					LOG_MSG("Cannot step IT instructions.");

					// all the conds are as per Table A8-1 (i.e. the usual 16 cases)
					// no idea how to decode the it block 'after-the-fact'
					// so probably need to treat instructions in the it block
					// as 'may' be executed. So breakpoints at both possible locations
					// depending on whether the instruction is executed or not.

					// also, how do we know if we have hit a breakpoint whilst 'in' an it block?
					// can we check the status registers to find out?
					//
					// see arm arm page 390.
					//
					// seems to depend on the itstate field. this also says what the condition code
					// actually is, and how many instructions are left in the itblock.
					// perhaps we can just totally ignore this state, and always do the two-instruction
					// breakpoint thing? Not if there is any possibility that the address target
					// would be invalid for the non-taken branch address...
				}


				// 32-bit encodings.
				//

				// Load word A6-23
				// Data processing instructions a6-28
				// 

				// ARM ARM DDI0406A - section A8.6.26
				if (inst32 & 0xFFF0FFFF == 0xE3C08F00)
				{
					LOG_MSG("ARM ARM DDI0406A - section A8.6.26 - BXJ is not supported");

					// Decoding as per ARM ARM description
					// TUint32 Rm = inst32 & 0x000F0000;	// not needed yet
				}

				// return from exception... SUBS PC,LR. page b6-25
				//
				// ARM ARM DDi046A - section B6.1.13 - SUBS PC,LR
				//
				// Encoding T1
				if (inst32 & 0xFFFFFF00 == 0xF3DE8F00)
				{
					LOG_MSG("ARM ARM DDI0406A - section B6.1.13 - SUBS PC,LR Encoding T1");

					// Decoding as per ARM ARM description
					TUint32 imm8 = inst32 & 0x000000FF;
					TUint32 imm32 = imm8;

					// TUint32 register_form = EFalse;	// not needed for this decoding
					// TUint32 opcode = 0x2;	// SUB	// not needed for this decoding
					TUint32 n = 14;

					// Obtain LR
					TUint32 lrVal;
					ReturnIfError(RegisterValue(aThread,n,lrVal));

					TUint32 operand2 = imm32;	// always for Encoding T1
					
					TUint32 result = lrVal - operand2;
					
					breakAddress = result;
				}
				
				// ARM ARM DDI0406A - section A8.6.16 - B
				//
				// Branch Encoding T3
				if (inst32 & 0xF800D000 == 0xF0008000)
				{
					LOG_MSG("ARM ARM DDI0406A - section A8.6.16 - B Encoding T3");

					// Decoding as per ARM ARM description
					TUint32 S = inst32 & 0x04000000 >> 26;
					// TUint32 cond = inst32 & 0x03C00000 >> 22;	// not needed for this decoding
					TUint32 imm6 = inst32 & 0x003F0000 >> 16;
					TUint32 J1 = inst32 & 0x00002000 >> 13;
					TUint32 J2 = inst32 & 0x00000800 >> 11;
					TUint32 imm11 = inst32 & 0x000007FF;

					TUint32 imm32 = S ? 0xFFFFFFFF : 0 ;
					imm32 = (imm32 << 1) | J2;
					imm32 = (imm32 << 1) | J1;
					imm32 = (imm32 << 6) | imm6;
					imm32 = (imm32 << 11) | imm11;
					imm32 = (imm32 << 1) | 0;

					breakAddress = aCurrentPC + imm32;
				}

				// ARM ARM DDI0406A - section A8.6.16 - B
				//
				// Branch Encoding T4
				if (inst32 & 0xF800D000 == 0xF0009000)
				{
					LOG_MSG("ARM ARM DDI0406A - section A8.6.16 - B");

					// Decoding as per ARM ARM description
					TUint32 S = inst32 & 0x04000000 >> 26;
					TUint32 imm10 = inst32 & 0x03FF0000 >> 16;
					TUint32 J1 = inst32 & 0x00002000 >> 12;
					TUint32 J2 = inst32 & 0x00000800 >> 11;
					TUint32 imm11 = inst32 & 0x000003FF;

					TUint32 I1 = !(J1 ^ S);
					TUint32 I2 = !(J2 ^ S);

					TUint32 imm32 = S ? 0xFFFFFFFF : 0;
					imm32 = (imm32 << 1) | S;
					imm32 = (imm32 << 1) | I1;
					imm32 = (imm32 << 1) | I2;
					imm32 = (imm32 << 10) | imm10;
					imm32 = (imm32 << 11) | imm11;
					imm32 = (imm32 << 1) | 0;

					breakAddress = aCurrentPC + imm32;
				}


				// ARM ARM DDI0406A - section A8.6.225 - TBB, TBH
				//
				// Table Branch Byte, Table Branch Halfword
				if (inst32 & 0xFFF0FFE0 == 0xE8D0F000)
				{
					LOG_MSG("ARM ARM DDI0406A - section A8.6.225 TBB,TBH Encoding T1");

					// Decoding as per ARM ARM description
					TUint32 Rn = inst32 & 0x000F0000 >> 16;
					TUint32 H = inst32 & 0x00000010 >> 4;
					TUint32 Rm = inst32 & 0x0000000F;

					// Unpredictable?
					if (Rm == 13 || Rm == 15)
					{
						LOG_MSG("ARM ARM DDI0406A - section A8.6.225 TBB,TBH Encoding T1 - Unpredictable");
						break;
					}

					TUint32 halfwords;
					TUint32 address;
					ReturnIfError(RegisterValue(aThread,Rn,address));

					TUint32 offset;
					ReturnIfError(RegisterValue(aThread,Rm,offset));

					if (H)
					{

						address += offset << 1;
					}
					else
					{
						address += offset;
					}

					ReturnIfError(ReadMem32(aThread,address,halfwords));

					breakAddress = aCurrentPC + 2*halfwords;
					break;
				}

				// ARM ARM DDI0406A - section A8.6.55 - LDMDB, LDMEA
				//
				// LDMDB Encoding T1
				if (inst32 & 0xFFD02000 == 0xE9100000)
				{
					LOG_MSG("ARM ARM DDI0406 - section A8.6.55 LDMDB Encoding T1");

					// Decoding as per ARM ARM description
					// TUint32 W = inst32 & 0x00200000 >> 21;	// Not needed for this encoding
					TUint32 Rn = inst32 & 0x000F0000 >> 16;
					TUint32 P = inst32 & 0x00008000 >> 15;
					TUint32 M = inst32 & 0x00004000 >> 14;
					TUint32 registers = inst32 & 0x00001FFF;

					//TBool wback = (W == 1);	// not needed for this encoding

					// Unpredictable?
					if (Rn == 15 || BitCount(registers) < 2 || ((P == 1) && (M==1)))
					{
						LOG_MSG("ARM ARM DDI0406 - section A8.6.55 LDMDB Encoding T1 - Unpredictable");
						break;
					}

					TUint32 address;
					ReturnIfError(RegisterValue(aThread,Rn,address));

					address -= 4*BitCount(registers);

					for(TInt i=0; i<15; i++)
					{
						if (IsBitSet(registers,i))
						{
							address +=4;
						}
					}

					if (IsBitSet(registers,15))
					{
						TUint32 RnVal = 0;
						ReturnIfError(ReadMem32(aThread,address,RnVal));

						breakAddress = RnVal;
					}
					break;
				}

				// ARM ARM DDI0406A - section A8.6.121 POP
				//
				// POP.W Encoding T2
				if (inst32 & 0xFFFF2000 == 0xE8BD0000)
				{
					LOG_MSG("ARM ARM DDI0406A - section A8.6.121 POP Encoding T2");

					// Decoding as per ARM ARM description
					TUint32 registers = inst32 & 0x00001FFF;
					TUint32 P = inst32 & 0x00008000;
					TUint32 M = inst32 & 0x00004000;

					// Unpredictable?
					if ( (BitCount(registers)<2) || ((P == 1)&&(M == 1)) )
					{
						LOG_MSG("ARM ARM DDI0406A - section A8.6.121 POP Encoding T2 - Unpredictable");
						break;
					}

					TUint32 address;
					ReturnIfError(RegisterValue(aThread,13,address));
					
					for(TInt i=0; i< 15; i++)
					{
						if (IsBitSet(registers,i))
						{
							address += 4;
						}
					}

					// Is the PC written?
					if (IsBitSet(registers,15))
					{
						// Yes
						ReturnIfError(ReadMem32(aThread,address,breakAddress));
					}
				}

				// POP Encoding T3
				if (inst32 & 0xFFFF0FFFF == 0xF85D0B04)
				{
					LOG_MSG("ARM ARM DDI0406A - section A8.6.121 POP Encoding T3");

					// Decoding as per ARM ARM description
					TUint32 Rt = inst32 & 0x0000F000 >> 12;
					TUint32 registers = 1 << Rt;

					// Unpredictable?
					if (Rt == 13 || Rt == 15)
					{
						LOG_MSG("ARM ARM DDI0406A - section A8.6.121 POP Encoding T3 - Unpredictable");
						break;
					}
					
					TUint32 address;
					ReturnIfError(RegisterValue(aThread,13,address));
					
					for(TInt i=0; i< 15; i++)
					{
						if (IsBitSet(registers,i))
						{
							address += 4;
						}
					}

					// Is the PC written?
					if (IsBitSet(registers,15))
					{
						// Yes
						ReturnIfError(ReadMem32(aThread,address,breakAddress));
					}

					break;
				}

				// ARM ARM DDI0406A - section A8.6.53 LDM
				//
				// Load Multiple Encoding T2 
				if ((inst32 & 0xFFD02000) == 0xE8900000)
				{
					LOG_MSG("ARM ARM DDI0406A - section A8.6.53 LDM Encoding T2");

					// Decoding as per ARM ARM description
					TUint32 W = inst32 & 0x0020000 >> 21;
					TUint32 Rn = inst32 & 0x000F0000 >> 16;
					TUint32 P = inst32 & 0x00008000 >> 15;
					TUint32 M = inst32 & 0x00004000 >> 14;
					TUint32 registers = inst32 & 0x0000FFFF;
					TUint32 register_list = inst32 & 0x00001FFF;
				
					// POP?
					if ( (W == 1) && (Rn == 13) )
					{
						// POP instruction
						LOG_MSG("ARM ARM DDI0406A - section A8.6.53 LDM Encoding T2 - POP");
					}

					// Unpredictable?
					if (Rn == 15 || BitCount(register_list) < 2 || ((P == 1) && (M == 1)) )
					{
						LOG_MSG("ARM ARM DDI0406A - section A8.6.53 LDM Encoding T2 - Unpredictable");
						break;
					}
					
					TUint32 RnVal;
					ReturnIfError(RegisterValue(aThread,Rn,RnVal));

					TUint32 address = RnVal;

					// Calculate offset of address
					for(TInt i = 0; i < 15; i++)
					{
						if (IsBitSet(registers,i))
						{
							address += 4;
						}
					}

					// Does it load the PC?
					if (IsBitSet(registers,15))
					{
						// Obtain the value loaded into the PC
						ReturnIfError(ReadMem32(aThread,address,breakAddress));
					}
					break;

				}

				// ARM ARM DDI0406A - section B6.1.8 RFE
				//
				// Return From Exception Encoding T1 RFEDB
				if ((inst32 & 0xFFD0FFFF) == 0xE810C000)
				{
					LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding T1");

					// Decoding as per ARM ARM description
					// TUint32 W = (inst32 & 0x00200000) >> 21;	// not needed for this encoding
					TUint32 Rn = (inst32 & 0x000F0000) >> 16;
					
					// TBool wback = (W == 1);	// not needed for this encoding
					TBool increment = EFalse;
					TBool wordhigher = EFalse;

					// Do calculation
					if (Rn == 15)
					{
						// Unpredictable 
						LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding T1 - Unpredictable");
						break;
					}

					TUint32 RnVal = 0;
					ReturnIfError(RegisterValue(aThread,Rn,RnVal));

					TUint32 address = 0;
					ReturnIfError(ReadMem32(aThread,RnVal,address));

					if (increment)
					{
						address -= 8;
					}

					if (wordhigher)
					{
						address += 4;
					}				

					breakAddress = address;
					break;
				}

				// Return From Exception Encoding T2 RFEIA
				if ((inst32 & 0xFFD0FFFF) == 0xE990C000)
				{
					LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding T2");

					// Decoding as per ARM ARM description
					// TUint32 W = (inst32 & 0x00200000) >> 21;	// not needed for this encoding
					TUint32 Rn = (inst32 & 0x000F0000) >> 16;
					
					// TBool wback = (W == 1);	// not needed for this encoding
					TBool increment = ETrue;
					TBool wordhigher = EFalse;

					// Do calculation
					if (Rn == 15)
					{
						// Unpredictable 
						LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding T2 - Unpredictable");
						break;
					}

					TUint32 RnVal = 0;
					ReturnIfError(RegisterValue(aThread,Rn,RnVal));

					TUint32 address = 0;
					ReturnIfError(ReadMem32(aThread,RnVal,address));

					if (increment)
					{
						address -= 8;
					}

					if (wordhigher)
					{
						address += 4;
					}				

					breakAddress = RnVal;
					break;
				}

				// Return From Exception Encoding A1 RFE<amode>
				if ((inst32 & 0xFE50FFFF) == 0xF8100A00)
				{
					LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding A1");

					// Decoding as per ARM ARM description
					TUint32 P = (inst32 & 0x01000000) >> 24;
					TUint32 U = (inst32 & 0x00800000) >> 23;
					// TUint32 W = (inst32 & 0x00200000) >> 21; // not needed for this encoding
					TUint32 Rn = (inst32 & 0x000F0000) >> 16;	
					
					// TBool wback = (W == 1);	// not needed for this encoding
					TBool increment = (U == 1);
					TBool wordhigher = (P == U);

					// Do calculation
					if (Rn == 15)
					{
						// Unpredictable 
						LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding A1 - Unpredictable");
						break;
					}

					TUint32 RnVal = 0;
					ReturnIfError(RegisterValue(aThread,Rn,RnVal));

					TUint32 address = 0;
					ReturnIfError(ReadMem32(aThread,RnVal,address));

					if (increment)
					{
						address -= 8;
					}

					if (wordhigher)
					{
						address += 4;
					}				

					breakAddress = address;
					break;
				}
			}

			// v4T/v5T/v6T instructions
			switch(thumb_opcode(inst))
			{		
				case 0x08:
				{
					// Data-processing. See ARM ARM DDI0406A, section A6-8, A6.2.2.

					if ((thumb_inst_7_15(inst) == 0x08F))
					{
						// BLX(2)
						err = iChannel->ReadKernelRegisterValue(aThread, ((inst & 0x0078) >> 3), breakAddress);
						if(err != KErrNone)
						{
							LOG_MSG2("Non-zero error code discarded: %d", err);
						}

						if ((breakAddress & 0x00000001) == 0)
						{
							aChangingModes = ETrue;
						}
						
						breakAddress &= 0xFFFFFFFE;

						// Report how we decoded this instruction
						LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as BLX (2)");
					}
					else if (thumb_inst_7_15(inst) == 0x08E)
					{
						// BX
						err = iChannel->ReadKernelRegisterValue(aThread, ((inst & 0x0078) >> 3), breakAddress);
						if(err != KErrNone)
						{
							LOG_MSG2("Non-zero error code discarded: %d", err);
						}

						if ((breakAddress & 0x00000001) == 0)
						{
							aChangingModes = ETrue;
						}
						
						breakAddress &= 0xFFFFFFFE;

						// Report how we decoded this instruction
						LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as BX");
					}
					else if ((thumb_inst_8_15(inst) == 0x46) && ((inst & 0x87) == 0x87))
					{
						// MOV with PC as the destination
						err = iChannel->ReadKernelRegisterValue(aThread, ((inst & 0x0078) >> 3), breakAddress);
						if(err != KErrNone)
						{
							LOG_MSG2("Non-zero error code discarded: %d", err);
						}

						// Report how we decoded this instruction
						LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as MOV with PC as the destination");
					}
					else if ((thumb_inst_8_15(inst) == 0x44) && ((inst & 0x87) == 0x87))
					{
						// ADD with PC as the destination
						err = iChannel->ReadKernelRegisterValue(aThread, ((inst & 0x0078) >> 3), breakAddress);
						if(err != KErrNone)
						{
							LOG_MSG2("Non-zero error code discarded: %d", err);
						}
						breakAddress += aCurrentPC + 4; // +4 because we need to use the PC+4 according to ARM ARM DDI0406A, section A6.1.2.

						// Report how we decoded this instruction
						LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as ADD with PC as the destination");
					}
					break;
				}
				case 0x13:
				{
					// Load/Store single data item. See ARM ARM DDI0406A, section A6-10

					//This instruction doesn't modify the PC.

					//if (thumb_inst_8_15(inst) == 0x9F)
					//{
						// LDR(4) with the PC as the destination
					//	breakAddress = ReadRegister(aThread, SP_REGISTER) + (4 * (inst & 0x00FF));
					//}

					// Report how we decoded this instruction
					LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as This instruction doesn't modify the PC.");
					break;
				}
				case 0x17:
				{	
					// Misc 16-bit instruction. See ARM ARM DDI0406A, section A6-11

					if (thumb_inst_8_15(inst) == 0xBD)
					{
						// POP with the PC in the list
						TUint32 regList = (inst & 0x00FF);
						TInt offset = 0;
						err = iChannel->ReadKernelRegisterValue(aThread,  SP_REGISTER, (T4ByteRegisterValue&)offset);
						if(err != KErrNone)
						{
							LOG_MSG2("Non-zero error code discarded: %d", err);
						}
						offset += (BitCount(regList) * 4);

						TBuf8<4> destination;
						err = iChannel->DoReadMemory(aThread, offset, 4, destination);
						
						if (KErrNone == err)
						{
							breakAddress = *(TUint32 *)destination.Ptr();

							if ((breakAddress & 0x00000001) == 0)
							{
								aChangingModes = ETrue;
							}

							breakAddress &= 0xFFFFFFFE;
						}
						else
						{
							LOG_MSG("Error reading memory in decoding step instruction");
						}

						// Report how we decoded this instruction
						LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as POP with the PC in the list");
					}
					break;
				}
				case 0x1A:
				case 0x1B:
				{	
					// Conditional branch, and supervisor call. See ARM ARM DDI0406A, section A6-13

					if (thumb_inst_8_15(inst) < 0xDE)
					{
						// B(1) conditional branch
						if (IsExecuted(((inst & 0x0F00) >> 8), aStatusRegister))
						{
							TUint32 offset = ((inst & 0x000000FF) << 1);
							if (offset & 0x00000100)
							{
								offset |= 0xFFFFFF00;
							}
							
							breakAddress = aCurrentPC + 4 + offset;

							// Report how we decoded this instruction
							LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as B(1) conditional branch");
						}
					}
					break;
				}
				case 0x1C:
				{
					// Unconditional branch, See ARM ARM DDI0406A, section A8-44.

					// B(2) unconditional branch
					TUint32 offset = (inst & 0x000007FF) << 1;
					if (offset & 0x00000800)
					{
						offset |= 0xFFFFF800;
					}
					
					breakAddress = aCurrentPC + 4 + offset;

					// Report how we decoded this instruction
					LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as B(2) unconditional branch");

					break;
				}
				case 0x1D:
				{
					if (!(inst & 0x0001))
					{
						// BLX(1)
						err = iChannel->ReadKernelRegisterValue(aThread, LINK_REGISTER, breakAddress);
						if(err != KErrNone)
						{
							LOG_MSG2("Non-zero error code discarded: %d", err);
						}
						breakAddress +=  ((inst & 0x07FF) << 1);
						if ((breakAddress & 0x00000001) == 0)
						{
							aChangingModes = ETrue;
						}

						breakAddress &= 0xFFFFFFFC;

						// Report how we decoded this instruction
						LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as BLX(1)");

					}
					break;
				}
				case 0x1E:
				{
                    // Check for ARMv7 CPU
                    if(cpuid == 0xC0)
                    {
    					// BL/BLX 32-bit instruction
	    				aNewRangeEnd += 4;

						breakAddress = (TUint32)thumb_instr_b_dest(inst32, aCurrentPC);

            			if((inst32 >> 27) == 0x1D)
            			{
            			    // BLX(1)
    						if ((breakAddress & 0x00000001) == 0)
	    					{
		    					aChangingModes = ETrue;
			    			}
    
	    					breakAddress &= 0xFFFFFFFC;

    						// Report how we decoded this instruction
	    					LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as 32-bit BLX(1)");
                        }
                        else
                        {                            
    					    // Report how we decoded this instruction
	        				LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: 32-bit BL instruction");
                        }
        				LOG_MSG2(" 32-bit BL/BLX instruction: breakAddress = 0x%X", breakAddress);
                    }            
                    else
                    {
					    // BL/BLX prefix - destination is encoded in this and the next instruction
					    aNewRangeEnd += 2;

					    // Report how we decoded this instruction
					    LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: BL/BLX prefix - destination is encoded in this and the next instruction");
                    }


					break;
				}
				case 0x1F:
				{
					{
						// BL
						err = iChannel->ReadKernelRegisterValue(aThread, LINK_REGISTER, breakAddress);
						if(err != KErrNone)
						{
							LOG_MSG2("Non-zero error code discarded: %d", err);
						}
						breakAddress += ((inst & 0x07FF) << 1);

						// Report how we decoded this instruction
						LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as BL");
					}
					break;
				}
				default:
					{
						// Don't know any better at this point!
						LOG_MSG("DRMDStepping::PCAfterInstructionExecutes:- default to next instruction");
					}
					break;
			}
		}
		break;
		
		case Debug::EThumb2EEMode:
		{
			// Not yet supported
			LOG_MSG("DRMDStepping::PCAfterInstructionExecutes - Debug::EThumb2Mode is not supported");

		}
		break;

		default:
			LOG_MSG("DRMDStepping::PCAfterInstructionExecutes - Cannot determine CPU mode architecture");
	}	

	LOG_MSG2("DRMDStepping::PCAfterInstructionExecutes : return 0x%08x",breakAddress);
	return breakAddress;
}

// Obtain a 32-bit memory value with minimum fuss
TInt DDebuggerEventHandler::ReadMem32(DThread* aThread, const TUint32 aAddress, TUint32& aValue)
	{
	TBuf8<4> valBuf;
	TInt err = iChannel->DoReadMemory(aThread, aAddress, 4, valBuf);
	if (err != KErrNone)
		{
		LOG_MSG2("DRMDStepping::ReadMem32 failed to read memory at 0x%08x", aAddress);
		return err;
		}

	aValue = *(TUint32 *)valBuf.Ptr();

	return KErrNone;
	}

// Obtain a 16-bit memory value with minimum fuss
TInt DDebuggerEventHandler::ReadMem16(DThread* aThread, const TUint32 aAddress, TUint16& aValue)
	{
	TBuf8<2> valBuf;
	TInt err = iChannel->DoReadMemory(aThread, aAddress, 2, valBuf);
	if (err != KErrNone)
		{
		LOG_MSG2("DRMDStepping::ReadMem16 failed to read memory at 0x%08x", aAddress);
		return err;
		}

	aValue = *(TUint16 *)valBuf.Ptr();

	return KErrNone;
	}

/*TOMSCI
// Obtain a 16-bit memory value with minimum fuss
TInt DRMDStepping::ReadMem8(DThread* aThread, const TUint32 aAddress, TUint8& aValue)
	{
	TBuf8<1> valBuf;
	TInt err = iChannel->DoReadMemory(aThread, aAddress, 1, valBuf);
	if (err != KErrNone)
		{
		LOG_MSG2("DRMDStepping::ReadMem8 failed to read memory at 0x%08x", aAddress);
		return err;
		}

	aValue = *(TUint8 *)valBuf.Ptr();

	return KErrNone;
	}
END TOMSCI*/

// Obtain a core register value with minimum fuss
TInt DDebuggerEventHandler::RegisterValue(DThread *aThread, const TUint32 aKernelRegisterId, TUint32 &aValue)
	{
	TInt err = iChannel->ReadKernelRegisterValue(aThread, aKernelRegisterId, aValue);
	if(err != KErrNone)
		{
		LOG_MSG3("DRMDStepping::RegisterValue failed to read register %d err = %d", aKernelRegisterId, err);
		}
		return err;
	}


// Encodings from ARM ARM DDI0406A, section 9.2.1
enum TThumb2EEOpcode
{
	EThumb2HDP,		// Handler Branch with Parameter
	EThumb2UNDEF,	// UNDEFINED
	EThumb2HB,		// Handler Branch, Handler Branch with Link
	EThumb2HBLP,	// Handle Branch with Link and Parameter
	EThumb2LDRF,	// Load Register from a frame
	EThumb2CHKA,	// Check Array
	EThumb2LDRL,	// Load Register from a literal pool
	EThumb2LDRA,	// Load Register (array operations)
	EThumb2STR		// Store Register to a frame
};

TUint32 DDebuggerEventHandler::ShiftedRegValue(DThread *aThread, TUint32 aInstruction, TUint32 aCurrentPC, TUint32 aStatusRegister)
{
	LOG_MSG("DRM_DebugChannel::ShiftedRegValue()");

	TUint32 shift = 0;
	if (aInstruction & 0x10)	// bit 4
	{
		shift = (arm_rs(aInstruction) == PC_REGISTER ? aCurrentPC + 8 : aStatusRegister) & 0xFF;
	}
	else
	{
		shift = arm_data_c(aInstruction);
	}
	
	TInt rm = arm_rm(aInstruction);
	
	TUint32 res = 0;
	if(rm == PC_REGISTER)
	{
		res = aCurrentPC + ((aInstruction & 0x10) ? 12 : 8);
	}
	else
	{
		TInt err = iChannel->ReadKernelRegisterValue(aThread, rm, res);
		if(err != KErrNone)
		{
			LOG_MSG2("DRMDStepping::ShiftedRegValue - Non-zero error code discarded: %d", err);
		}
	}

	switch(arm_data_shift(aInstruction))
	{
		case 0:			// LSL
		{
			res = shift >= 32 ? 0 : res << shift;
			break;
		}
		case 1:			// LSR
		{
			res = shift >= 32 ? 0 : res >> shift;
			break;
		}
		case 2:			// ASR
		{
			if (shift >= 32)
			shift = 31;
			res = ((res & 0x80000000L) ? ~((~res) >> shift) : res >> shift);
			break;
		}
		case 3:			// ROR/RRX
		{
			shift &= 31;
			if (shift == 0)
			{
				res = (res >> 1) | ((aStatusRegister & arm_carry_bit()) ? 0x80000000L : 0);
			}
			else
			{
				res = (res >> shift) | (res << (32 - shift));
			}
			break;
    	}
    }

  	return res & 0xFFFFFFFF;
}

//
// DRMDStepping::CurrentPC
//
// 
//
TInt DDebuggerEventHandler::CurrentPC(DThread* aThread, TUint32& aPC)
	{
	LOG_MSG("DRMDStepping::CurrentPC");

	TInt err = iChannel->ReadKernelRegisterValue(aThread, PC_REGISTER, aPC);
	if(err != KErrNone)
		{
		// We don't know the current PC for this thread!
		LOG_MSG("DRMDStepping::CurrentPC - Failed to read the current PC");
		
		return KErrGeneral;
		}

	LOG_MSG2("DRMDStepping::CurrentPC 0x%08x", aPC);

	return KErrNone;
	}

TInt DDebuggerEventHandler::CurrentCPSR(DThread* aThread, TUint32& aCPSR)
	{
	LOG_MSG("DRMDStepping::CurrentCPSR");

	TInt err = iChannel->ReadKernelRegisterValue(aThread, STATUS_REGISTER, aCPSR);
	if(err != KErrNone)
		{
		// We don't know the current PC for this thread!
		LOG_MSG("DRMDStepping::CurrentPC - Failed to read the current CPSR");
		
		return KErrGeneral;
		}

	LOG_MSG2("DRMDStepping::CurrentCPSR 0x%08x", aCPSR);
	
	return KErrNone;
	}