mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
913 lines
20 KiB
913 lines
20 KiB
/*++
|
|
|
|
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 ([email protected])
|
|
|
|
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;
|
|
}
|