summaryrefslogtreecommitdiffstats
path: root/private/windbg/newdm/ppcmach.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/windbg/newdm/ppcmach.c')
-rw-r--r--private/windbg/newdm/ppcmach.c913
1 files changed, 913 insertions, 0 deletions
diff --git a/private/windbg/newdm/ppcmach.c b/private/windbg/newdm/ppcmach.c
new file mode 100644
index 000000000..d2180c2c3
--- /dev/null
+++ b/private/windbg/newdm/ppcmach.c
@@ -0,0 +1,913 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ mach.c
+
+Abstract:
+
+ This file contains the PPC601 specific code for dealing with
+ the process of stepping a single instruction. This includes
+ determination of the next offset to be stopped at and if the
+ instruction is all call type instruction.
+
+Author:
+
+ Kent Forschmiedt (kentf)
+ Farooq Butt (fmbutt@engage.sps.mot.com)
+
+Environment:
+
+ Win32 - User
+
+Notes:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+ //setup a couple of macros
+
+ // The below macro is used to do subscripting operations
+ // len_item is the length of the embedded word that we are
+ // interested in subscripting
+
+#define NTH_BIT(word,n,len_item) \
+ ( ((word) >> ((len_item) - (n) - 1)) & 0x01)
+
+
+
+//
+// Stuff for debug registers
+//
+// The debug register architecture is represented to NT as
+// nearly identical to the x86.
+// As of this writing, there is one debug register, and it only
+// supports a data length of 8.
+//
+
+
+typedef struct _DR7 *PDR7;
+typedef struct _DR7 {
+ DWORD L0 : 1;
+ DWORD G0 : 1;
+ DWORD L1 : 1;
+ DWORD G1 : 1;
+ DWORD L2 : 1;
+ DWORD G2 : 1;
+ DWORD L3 : 1;
+ DWORD G3 : 1;
+ DWORD LE : 1;
+ DWORD GE : 1;
+ DWORD Pad1 : 3;
+ DWORD GD : 1;
+ DWORD Pad2 : 1;
+ DWORD Pad3 : 1;
+ DWORD Rwe0 : 2;
+ DWORD Len0 : 2;
+ DWORD Rwe1 : 2;
+ DWORD Len1 : 2;
+ DWORD Rwe2 : 2;
+ DWORD Len2 : 2;
+ DWORD Rwe3 : 2;
+ DWORD Len3 : 2;
+} DR7;
+
+
+#define RWE_EXEC 0x00
+#define RWE_WRITE 0x01
+#define RWE_RESERVED 0x02
+#define RWE_READWRITE 0x03
+
+
+DWORD LenMask[ MAX_DEBUG_REG_DATA_SIZE + 1 ] = DEBUG_REG_LENGTH_MASKS;
+
+
+extern LPDM_MSG LpDmMsg;
+
+BOOL
+IsRet(
+ HTHDX hthd,
+ LPADDR addr
+ )
+{
+ DWORD instr;
+ DWORD cBytes;
+ if (!AddrReadMemory( hthd->hprc, hthd, addr, &instr, 4, &cBytes )) {
+ return FALSE;
+ }
+ return (instr == 0x4e800020); // bclr branch always
+}
+
+
+void
+IsCall (
+ HTHDX hthd,
+ LPADDR lpaddr,
+ LPINT lpf,
+ BOOL fStepOver
+ )
+
+/*++
+
+Routine Description:
+
+ IsCall
+
+Arguments:
+
+ hthd - Supplies the handle to the thread
+
+ lpaddr - Supplies the address to be check for a call instruction
+
+ lpf - Returns class of instruction:
+ CALL
+ BREAKPOINT_INSTRUCTION
+ SOFTWARE_INTERRUPT
+ FALSE
+
+ fStepOver
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG opcode;
+ ADDR iaraddr = *lpaddr;
+ DWORD length;
+ PPC_INSTRUCTION disinstr;
+ BOOL r;
+
+
+
+ if (hthd->fIsCallDone) {
+ *lpaddr = hthd->addrIsCall;
+ *lpf = hthd->iInstrIsCall;
+ return;
+ }
+
+ /*
+ * Assume that this is not a call instruction
+ */
+
+ *lpf = FALSE;
+
+ /*
+ * Read in the dword which contains the instruction under
+ * inspection.
+ */
+
+ r = AddrReadMemory(hthd->hprc,
+ hthd,
+ &iaraddr,
+ &disinstr.Long,
+ sizeof(DWORD),
+ &length);
+ if (!r || length != sizeof(DWORD)) {
+ goto done;
+ }
+
+
+ opcode = disinstr.Primary_Op;
+
+ /* Do we have a branch or is this a breakpoint ? If it is a
+ breakpoint, is it set by the user or was it set by the
+ debugger ? If all else fails return FALSE */
+
+ switch (opcode)
+ {
+ default:
+ DPRINT(5,("IsCall opcode == DEFAULT"));
+ break; // leaving *lpf = FALSE
+
+
+ case BC_OP:
+ DPRINT(5,("IsCall opcode == BC_OP"));
+ // branch conditional NEVER a call
+ break; // leaving *lpf == FALSE
+
+ case B_OP:
+ DPRINT(5,("IsCall opcode == B_OP"));
+ // unconditional branch, could be a call
+ // THIS is the real call operation if LK == 1
+
+ if ((disinstr.Long & 1) == 1)
+ {
+ // LK is on, we have a call
+ *lpf = INSTR_IS_CALL;
+ }
+
+ break; // leaving *lpf = FALSE if not call...
+
+
+ case X19_OP:
+ DPRINT(5,("IsCall opcode == X19_OP"));
+ // branch conditional on register (various extended opcodes)
+ // This could be a function call if it is a
+ // BCCTRL
+
+ if ((disinstr.XLform_XO == BCCTR_OP) &&
+ ((disinstr.Long & 1) == 1))
+ *lpf = INSTR_IS_CALL;
+
+ if (disinstr.XLform_XO == BCLR_OP) {
+ *lpf = INSTR_IS_CALL;
+ }
+
+ break; // leaving *lpf = FALSE if not BCCTRL
+
+ case TWI_OP:
+ DPRINT(5,("IsCall opcode == TWI_OP"));
+
+ // Is this TWI instruction installed by the debugger or
+ // was it a user installed one ?
+
+ // First make sure this is a BREAK
+ if (disinstr.Dform_TO == 0x1f) // All 1's in the TO field
+ {
+ switch(disinstr.Dform_SI)
+ {
+
+ case DEBUG_PRINT_BREAKPOINT:
+ case DEBUG_PROMPT_BREAKPOINT:
+ case DEBUG_STOP_BREAKPOINT:
+ case DEBUG_LOAD_SYMBOLS_BREAKPOINT:
+ case DEBUG_UNLOAD_SYMBOLS_BREAKPOINT:
+
+ *lpf = INSTR_BREAKPOINT;
+ DPRINT(5,("IsCall opcode was an INSTR_BREAKPOINT"));
+ break;
+
+ default:
+ *lpf = INSTR_SOFT_INTERRUPT;
+ DPRINT(5,("IsCall opcode was a INSTR_SOFT_INTERRUPT"));
+ break;
+ }
+ }
+
+ }
+
+
+ DPRINT(1, ("(IsCall?) FIR=%08x Type=%s\n", iaraddr.addr.off,
+ *lpf==INSTR_IS_CALL ?"CALL":
+ (*lpf==INSTR_BREAKPOINT?"BREAKPOINT":
+ (*lpf==INSTR_SOFT_INTERRUPT ?"INTERRUPT":
+ "NORMAL"))));
+
+done:
+ if (*lpf==INSTR_IS_CALL) {
+ lpaddr->addr.off += BP_SIZE;
+ hthd->addrIsCall = *lpaddr;
+ } else if ( *lpf==INSTR_SOFT_INTERRUPT ) {
+ lpaddr->addr.off += BP_SIZE;
+ }
+ hthd->iInstrIsCall = *lpf;
+
+ return;
+} /* IsCall() */
+
+
+
+#ifndef KERNEL
+void
+ProcessGetDRegsCmd(
+ HPRCX hprc,
+ HTHDX hthd,
+ LPDBB lpdbb
+ )
+{
+ LPDWORD lpdw = (LPDWORD)LpDmMsg->rgb;
+ CONTEXT cxt;
+ int rs = 0;
+
+ DEBUG_PRINT( "ProcessGetDRegsCmd :\n");
+
+
+ if (hthd == 0) {
+ rs = 0;
+ } else {
+ cxt.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ if (!GetThreadContext(hthd->rwHand, &cxt)) {
+ LpDmMsg->xosdRet = xosdUnknown;
+ rs = 0;
+ } else {
+ lpdw[0] = hthd->context.Dr0;
+ lpdw[1] = hthd->context.Dr1;
+ lpdw[2] = hthd->context.Dr2;
+ lpdw[3] = hthd->context.Dr3;
+ lpdw[4] = hthd->context.Dr6;
+ lpdw[5] = hthd->context.Dr7;
+ LpDmMsg->xosdRet = xosdNone;
+ rs = sizeof(CONTEXT);
+ }
+ }
+
+ Reply( rs, LpDmMsg, lpdbb->hpid );
+ return;
+} /* ProcessGetDRegsCmd() */
+
+
+void
+ProcessSetDRegsCmd(
+ HPRCX hprc,
+ HTHDX hthd,
+ LPDBB lpdbb
+ )
+{
+ LPDWORD lpdw = (LPDWORD)(lpdbb->rgbVar);
+ XOSD_ xosd = xosdNone;
+
+ Unreferenced(hprc);
+
+ DPRINT(5, ("ProcessSetDRegsCmd : "));
+
+ hthd->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+
+ hthd->context.Dr0 = lpdw[0];
+ hthd->context.Dr1 = lpdw[1];
+ hthd->context.Dr2 = lpdw[2];
+ hthd->context.Dr3 = lpdw[3];
+ hthd->context.Dr6 = lpdw[4];
+ hthd->context.Dr7 = lpdw[5];
+
+
+ if (hthd->fWowEvent) {
+ WOWSetThreadContext(hthd, &hthd->context);
+ } else {
+ SetThreadContext(hthd->rwHand, &hthd->context);
+ }
+
+ Reply(0, &xosd, lpdbb->hpid);
+
+ return;
+} /* ProcessSetDRegsCmd() */
+
+VOID
+MakeThreadSuspendItselfHelper(
+ HTHDX hthd,
+ FARPROC lpSuspendThread
+ )
+{
+ //
+ // set up the args to SuspendThread
+ //
+
+ // GetCurrentThread always returns a magic cookie, safe for any thread.
+
+ hthd->context.Gpr3 = (DWORD)GetCurrentThread();
+ hthd->context.Lr = PC(hthd);
+ PC(hthd) = (DWORD)lpSuspendThread;
+ hthd->fContextDirty = TRUE;
+}
+#endif // !KERNEL
+
+
+
+ULONG
+GetNextOffset (
+ HTHDX hthd,
+ BOOL fStep
+ )
+
+/*++
+
+Routine Description:
+
+ From a limited disassembly of the instruction pointed
+ by the IAR register, compute the offset of the next
+ instruction for either a trace or step operation.
+
+Arguments:
+
+ hthd - Supplies the handle to the thread to get the next offset for
+
+ fStep - Supplies TRUE for STEP offset and FALSE for trace offset
+
+Return Value:
+
+ Offset to place breakpoint at for doing a STEP or TRACE
+
+--*/
+
+{
+ ULONG returnvalue;
+ ULONG opcode;
+ ADDR iaraddr;
+ DWORD length;
+ ULONG *regArray = &hthd->context.Gpr0;
+ PPC_INSTRUCTION disinstr;
+ ULONG absolute;
+ ULONG cr,ctr,lr,cond_ok=0,ctr_ok=0;
+ BOOL r;
+
+ AddrFromHthdx(&iaraddr, hthd);
+
+ r = AddrReadMemory(hthd->hprc,
+ hthd,
+ &iaraddr,
+ &disinstr.Long,
+ sizeof(DWORD),
+ &length);
+
+ opcode = disinstr.Primary_Op;
+
+ DPRINT(5,("Entered GetNextOffset routine, the address we start with is "
+ "0x%x\n\tThe instruction is 0x%x",iaraddr.addr.off,
+ disinstr.Long));
+
+ // setup default return value
+ returnvalue = iaraddr.addr.off + sizeof(ULONG);
+
+
+ // setup the absolute flag in case of a branch
+ absolute = (int) ((disinstr.Long >> 1) & 1);
+
+ // Before going into the switch, let us do some up front
+ // calculations
+
+ /* Let us use the algorithm described in pp 10-22 of
+ the MPC/601 users manual */
+
+ ctr = hthd->context.Ctr;
+ cr = hthd->context.Cr;
+
+ /* First find out whether the CTR has to be decremented */
+
+ if (NTH_BIT(disinstr.Bform_BO,2,5) == 0)
+ // i.e if ~B0[2] then ctr = ctr - 1
+ ctr = ctr - 1;
+
+ // next we do the following operation:
+ // ctr_ok = BO[2] OR ((ctr NEQ 0) XOR BO[3]))
+
+ ctr_ok = (NTH_BIT(disinstr.Bform_BO,2,5) ||
+ ((ctr != 0) ^ (NTH_BIT(disinstr.Bform_BO,3,5))));
+
+ // now for
+ // cond_ok= BO[0] OR ( (CR[BI] LEQIV BO[1]))
+
+ cond_ok = ((NTH_BIT(disinstr.Bform_BO,0,5)) ||
+ ((NTH_BIT(cr,(disinstr.Bform_BI),32)) ==
+ (NTH_BIT(disinstr.Bform_BO,1,5))));
+
+
+ switch (opcode)
+ {
+
+ case SC_OP:
+ DPRINT(5,("We have an SC_OP"));
+ // stepping over a syscall instruction must set the breakpoint
+ // at the inst after the syscall (default)
+ break;
+
+ case B_OP:
+ DPRINT(5,("We have an B_OP"));
+ // unconditional branch found
+ // no need to chase down branch targets unless you are
+ // tracing (i.e. NOT stepping over functions).
+ // Of course the whole test about stepping etc. only
+ // makes sense if you are stepping over a FUNCTION CALL
+ // i.e. a branch and link operation
+
+
+ if (!fStep) {
+ if (absolute) {
+ /* LI can only address words not bytes so << 2 */
+ returnvalue = disinstr.Iform_LI << 2;
+ } else {
+ returnvalue = (disinstr.Iform_LI << 2) + iaraddr.addr.off;
+ }
+ }
+
+ break;
+
+ case BC_OP:
+ DPRINT(5,("We have a BC_OP"));
+ /* We got a branch conditional, if it evaluates to true,
+ let us set return to the target. Otherwise
+ let us leave the default returnvalue in place */
+
+
+ /* << 2 bits since we address words */
+
+ if (ctr_ok && cond_ok) {
+ if (absolute) {
+ returnvalue = disinstr.Bform_BD << 2;
+ } else {
+ returnvalue = (disinstr.Bform_BD << 2)+iaraddr.addr.off;
+ }
+ }
+ break;
+
+ case X19_OP:
+ DPRINT(5,("We have an X19_OP"));
+ if (disinstr.XLform_XO == BCLR_OP) {
+ lr = hthd->context.Lr;
+
+ if (ctr_ok && cond_ok) {
+ returnvalue = lr & ~3; // remember, we address words
+ // not bytes thus ~3
+
+ }
+ } else if (disinstr.XLform_XO == BCCTR_OP) {
+ if (cond_ok) {
+ returnvalue = ctr & ~3;
+ }
+ }
+
+ break;
+
+ default:
+ DPRINT(5,("We have an unhandled DEFAULT op"));
+ break;
+
+ }
+
+ return returnvalue;
+} /* GetNextOffset() */
+
+
+
+XOSD
+SetupFunctionCall(
+ LPEXECUTE_OBJECT_DM lpeo,
+ LPEXECUTE_STRUCT lpes
+ )
+{
+ /*
+ * Can only execute functions on the current stopped thread. Therefore
+ * assert that the current thread is stopped.
+ */
+
+ assert(lpeo->hthd->tstate & ts_stopped);
+ if (!(lpeo->hthd->tstate & ts_stopped)) {
+ return xosdInvalidThread;
+ }
+
+ /*
+ * Now get the current stack offset.
+ */
+
+ lpeo->addrStack.addr.off = lpeo->hthd->context.Gpr1;
+
+ /*
+ * Now place the return address correctly
+ */
+
+ lpeo->hthd->context.Iar = lpeo->hthd->context.Lr =
+ lpeo->addrStart.addr.off;
+
+ /*
+ * Set the instruction pointer to the starting addresses
+ * and write the context back out
+ */
+
+ lpeo->hthd->context.Iar = lpeo->addrStart.addr.off;
+
+ lpeo->hthd->fContextDirty = TRUE;
+
+ return xosdNone;
+}
+
+
+
+BOOL
+CompareStacks(
+ LPEXECUTE_OBJECT_DM lpeo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to determine if the stack pointers are currect
+ for terminating function evaluation.
+
+Arguments:
+
+ lpeo - Supplies the pointer to the DM Execute Object description
+
+Return Value:
+
+ TRUE if the evaluation is to be terminated and FALSE otherwise
+
+--*/
+
+{
+
+ if (lpeo->addrStack.addr.off <= lpeo->hthd->context.Gpr1) {
+ return TRUE;
+ }
+
+ return FALSE;
+} /* CompareStacks() */
+
+BOOL
+ProcessFrameStackWalkNextCmd(
+ HPRCX hprc,
+ HTHDX hthd,
+ PCONTEXT context,
+ LPVOID pctxPtrs
+ )
+
+{
+ return FALSE;
+}
+
+
+DWORD
+BranchUnassemble(
+ void *Memory,
+ ADDR *Addr,
+ BOOL *IsBranch,
+ BOOL *TargetKnown,
+ BOOL *IsCall,
+ BOOL *IsTable,
+ ADDR *Target
+ )
+
+{
+
+ ULONG opcode, absolute=FALSE, linkbit_on=FALSE;
+ PPC_INSTRUCTION disinstr;
+ UOFF32 Offset;
+ UOFF32 TargetOffset;
+
+
+ assert( Memory );
+ assert( IsBranch );
+ assert( TargetKnown );
+ assert( IsCall );
+ assert( Target );
+
+ Offset = GetAddrOff(*Addr);
+ TargetOffset = 0;
+ *IsBranch = FALSE;
+ *IsTable = FALSE;
+ disinstr.Long = * (PULONG ) Memory;
+
+ // Is the absolute bit on ?
+ absolute = (int) ((disinstr.Long >> 1) & 1);
+
+ // Is the link bit on ?
+ linkbit_on = (int) ((disinstr.Long & 1));
+
+ opcode = disinstr.Primary_Op;
+
+ switch (opcode)
+ {
+ default:
+ break;
+
+ case BC_OP:
+ *IsCall= linkbit_on;
+ *IsBranch = TRUE;
+ *TargetKnown = TRUE;
+ if (absolute)
+ TargetOffset = disinstr.Bform_BD << 2;
+ else
+ TargetOffset = (disinstr.Bform_BD << 2)+ Offset;
+ break;
+
+ case B_OP:
+ *IsCall= linkbit_on;
+ *IsBranch = TRUE;
+ *TargetKnown = TRUE;
+ if (absolute)
+ TargetOffset = disinstr.Iform_LI << 2;
+ else
+ TargetOffset = (disinstr.Iform_LI << 2) + Offset;
+ break;
+
+
+ case X19_OP:
+ // branch conditional on register (various extended opcodes)
+ *IsCall = linkbit_on;
+ *IsBranch = TRUE;
+ *TargetKnown = FALSE;
+ TargetOffset = 0;
+ break;
+
+ }
+
+ AddrInit(Target, 0, 0, TargetOffset, TRUE, TRUE, FALSE, FALSE);
+
+ return(sizeof(DWORD));
+
+}
+
+
+BOOL
+SetupDebugRegister(
+ HTHDX hthd,
+ int Register,
+ int DataSize,
+ DWORD DataAddr,
+ DWORD BpType
+ )
+{
+ DWORD Len;
+ DWORD rwMask;
+
+#ifdef KERNEL
+ KSPECIAL_REGISTERS ksr;
+ PDWORD Dr0 = &ksr.KernelDr0;
+ PDWORD Dr1 = &ksr.KernelDr1;
+ PDWORD Dr2 = &ksr.KernelDr2;
+ PDWORD Dr3 = &ksr.KernelDr3;
+ PDR7 Dr7 = (PDR7)&(ksr.KernelDr7);
+#else
+ CONTEXT Context;
+ PDWORD Dr0 = &Context.Dr0;
+ PDWORD Dr1 = &Context.Dr1;
+ PDWORD Dr2 = &Context.Dr2;
+ PDWORD Dr3 = &Context.Dr3;
+ PDR7 Dr7 = (PDR7)&(Context.Dr7);
+#endif
+
+ // ppc currently only supports 1
+ assert(Register == 1);
+
+#ifdef KERNEL
+ if (!GetExtendedContext(hthd, &ksr))
+#else
+ Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ if (!GetThreadContext(hthd->rwHand, &Context))
+#endif
+ {
+ return FALSE;
+ }
+
+
+ Len = LenMask[ DataSize ];
+
+ switch ( BpType ) {
+ case bptpDataR:
+ rwMask = RWE_READWRITE;
+ break;
+
+ case bptpDataW:
+ case bptpDataC:
+ rwMask = RWE_WRITE;
+ break;
+
+ case bptpDataExec:
+ rwMask = RWE_EXEC;
+ //
+ // length must be 0 for exec bp
+ //
+ Len = 0;
+ break;
+
+ default:
+ assert(!"Invalid BpType!!");
+ break;
+ }
+
+
+ switch( Register ) {
+ case 0:
+ *Dr0 = DataAddr;
+ Dr7->Len0 = Len;
+ Dr7->Rwe0 = rwMask;
+ Dr7->L0 = 0x01;
+ break;
+ case 1:
+ *Dr1 = DataAddr;
+ Dr7->Len1 = Len;
+ Dr7->Rwe1 = rwMask;
+ Dr7->L1 = 0x01;
+ break;
+ case 2:
+ *Dr2 = DataAddr;
+ Dr7->Len2 = Len;
+ Dr7->Rwe2 = rwMask;
+ Dr7->L2 = 0x01;
+ break;
+ case 3:
+ *Dr3 = DataAddr;
+ Dr7->Len3 = Len;
+ Dr7->Rwe3 = rwMask;
+ Dr7->L3 = 0x01;
+ break;
+ }
+
+#ifdef KERNEL
+ ksr.KernelDr6 = 0;
+ return SetExtendedContext(hthd, &ksr);
+#else
+ return SetThreadContext(hthd->rwHand, &Context);
+#endif
+
+}
+
+VOID
+ClearDebugRegister(
+ HTHDX hthd,
+ int Register
+ )
+{
+#ifdef KERNEL
+ KSPECIAL_REGISTERS ksr;
+ PDWORD Dr0 = &ksr.KernelDr0;
+ PDWORD Dr1 = &ksr.KernelDr1;
+ PDWORD Dr2 = &ksr.KernelDr2;
+ PDWORD Dr3 = &ksr.KernelDr3;
+ PDR7 Dr7 = (PDR7)&(ksr.KernelDr7);
+#else
+ CONTEXT Context;
+ PDWORD Dr0 = &Context.Dr0;
+ PDWORD Dr1 = &Context.Dr1;
+ PDWORD Dr2 = &Context.Dr2;
+ PDWORD Dr3 = &Context.Dr3;
+ PDR7 Dr7 = (PDR7)&(Context.Dr7);
+#endif
+
+ // ppc currently only supports 1
+ assert(Register == 1);
+
+
+#ifdef KERNEL
+ if (GetExtendedContext(hthd, &ksr))
+#else
+ Context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ if (GetThreadContext(hthd->rwHand, &Context))
+#endif
+ {
+
+ switch( Register ) {
+ case 0:
+ *Dr0 = 0;
+ Dr7->Len0 = 0;
+ Dr7->Rwe0 = 0;
+ Dr7->L0 = 0;
+ break;
+ case 1:
+ *Dr1 = 0;
+ Dr7->Len1 = 0;
+ Dr7->Rwe1 = 0;
+ Dr7->L1 = 0;
+ break;
+ case 2:
+ *Dr2 = 0;
+ Dr7->Len2 = 0;
+ Dr7->Rwe2 = 0;
+ Dr7->L2 = 0;
+ break;
+ case 3:
+ *Dr3 = 0;
+ Dr7->Len3 = 0;
+ Dr7->Rwe3 = 0;
+ Dr7->L3 = 0;
+ break;
+ }
+
+#ifdef KERNEL
+ ksr.KernelDr6 = 0;
+ SetExtendedContext(hthd, &ksr);
+#else
+ SetThreadContext( hthd->rwHand, &Context );
+#endif
+ }
+}
+
+
+BOOL
+DecodeSingleStepEvent(
+ HTHDX hthd,
+ DEBUG_EVENT *de,
+ PDWORD eventCode,
+ PDWORD subClass
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ hthd - Supplies thread that has a single step exception pending
+
+ de - Supplies the DEBUG_EVENT structure for the exception
+
+ eventCode - Returns the remapped debug event id
+
+ subClass - Returns the remapped subClass id
+
+
+Return Value:
+
+ TRUE if event was a real single step or was successfully mapped
+ to a breakpoint. FALSE if a register breakpoint occurred which was
+ not expected.
+
+--*/
+{
+ return FALSE;
+}