Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1072 lines
25 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
kdcpuapi.c
Abstract:
This module implements CPU specific remote debug APIs.
Author:
Mark Lucovsky (markl) 04-Sep-1990
Revision History:
24-sep-90 bryanwi
Port to the x86.
--*/
#include <stdio.h>
#include "kdp.h"
#define END_OF_CONTROL_SPACE (sizeof(KPROCESSOR_STATE))
extern ULONG KdpCurrentSymbolStart, KdpCurrentSymbolEnd;
extern ULONG KdSpecialCalls[];
extern ULONG KdNumberOfSpecialCalls;
extern BOOLEAN KdpSendContext;
LONG
KdpLevelChange (
ULONG Pc,
PCONTEXT ContextRecord
);
LONG
regValue(
UCHAR reg,
PCONTEXT ContextRecord
);
BOOLEAN
KdpIsSpecialCall (
ULONG Pc,
PCONTEXT ContextRecord
);
ULONG
KdpGetReturnAddress (
PCONTEXT ContextRecord
);
ULONG
KdpGetCallNextOffset (
ULONG Pc
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGEKD, KdpLevelChange)
#pragma alloc_text(PAGEKD, regValue)
#pragma alloc_text(PAGEKD, KdpIsSpecialCall)
#pragma alloc_text(PAGEKD, KdpGetReturnAddress)
#pragma alloc_text(PAGEKD, KdpSetLoadState)
#pragma alloc_text(PAGEKD, KdpSetStateChange)
#pragma alloc_text(PAGEKD, KdpGetStateChange)
#pragma alloc_text(PAGEKD, KdpReadControlSpace)
#pragma alloc_text(PAGEKD, KdpWriteControlSpace)
#pragma alloc_text(PAGEKD, KdpReadIoSpace)
#pragma alloc_text(PAGEKD, KdpWriteIoSpace)
#pragma alloc_text(PAGEKD, KdpReadMachineSpecificRegister)
#pragma alloc_text(PAGEKD, KdpWriteMachineSpecificRegister)
#pragma alloc_text(PAGEKD, KdpGetCallNextOffset)
#endif
/**** KdpLevelChange - say how the instruction affects the call level
*
* Input:
* pc - program counter of instruction to check
*
* Output:
* returns -1 for a level pop, 1 for a push and 0 if it is
* unchanged.
* NOTE: This function belongs in some other file. I should move it.
***************************************************************************/
LONG
KdpLevelChange (
ULONG Pc,
PCONTEXT ContextRecord
)
{
UCHAR membuf[2];
UCHAR opcode;
KdpMoveMemory( (PCHAR)membuf, (PCHAR)Pc, 2 );
opcode = membuf[0];
if ( (opcode == 0x9a) ||
(opcode == 0xe8) ||
((opcode == 0xff) && ((membuf[1] & 0x30) == 0x10)) ) {
return 1;
}
//
// The complier generates code for a try-finally that involves having
// a ret instruction that does not match with a call instruction.
// This ret never returns a value (ie, it's a c3 return and not a
// c2). It always returns into the current symbol scope. It is never
// preceeded by a leave, which (hopefully) should differentiate it
// from recursive returns. Check for this, and if we find it count
// it as *0* level change.
//
if ( opcode == 0xc3 ) {
//
// figure out the return address. It's the first 4 bytes on
// the stack.
//
ULONG retaddr;
KdpMoveMemory( (PCHAR)&retaddr, (PCHAR)ContextRecord->Esp, 4 );
if ( (KdpCurrentSymbolStart < retaddr) && (retaddr < KdpCurrentSymbolEnd) ) {
//
// returning to the current function. Either a finally
// or a recursive return. Check for a leave.
//
KdpMoveMemory( (PCHAR)&opcode,(PCHAR)Pc-1, 1 );
if ( opcode != 0xc9 ) {
// not a leave. Assume a try-finally.
return 0;
}
}
return -1; // not into current sym, or recursive return.
}
if ( (opcode == 0xc2) || // ret with arg opcode
(opcode == 0xca) || (opcode == 0xcb) ) { // retf opcodes
return -1;
}
return 0;
} // KdpLevelChange
LONG
regValue(
UCHAR reg,
PCONTEXT ContextRecord
)
{
switch (reg) {
case 0x0:
return(ContextRecord->Eax);
break;
case 0x1:
return(ContextRecord->Ecx);
break;
case 0x2:
return(ContextRecord->Edx);
break;
case 0x3:
return(ContextRecord->Ebx);
break;
case 0x4:
return(ContextRecord->Esp);
break;
case 0x5:
return(ContextRecord->Ebp);
break;
case 0x6:
return(ContextRecord->Esi);
break;
case 0x7:
return(ContextRecord->Edi);
break;
}
}
BOOLEAN
KdpIsSpecialCall (
ULONG Pc,
PCONTEXT ContextRecord
)
/*++
Routine Description:
Check to see if the instruction at pc is a call to one of the
SpecialCall routines.
Argument:
Pc - program counter of instruction in question.
--*/
{
UCHAR opcode;
UCHAR modRM;
UCHAR sib;
USHORT twoBytes;
ULONG callAddr;
ULONG addrAddr;
LONG offset;
ULONG i;
char d8;
KdpMoveMemory(( PCHAR)&opcode, (PCHAR)Pc, 1 );
if ( opcode == 0xe8 ) {
//
// Signed offset from pc
//
KdpMoveMemory( (PCHAR)&offset, (PCHAR)Pc+1, 4 );
callAddr = Pc + offset + 5; // +5 for instr len.
} else if ( opcode == 0xff ) {
KdpMoveMemory( (PCHAR)&modRM, (PCHAR)Pc+1, 1 );
if ( ((modRM & 0x30) == 0x00) || ((modRM & 0x30) == 0x30) ) {
// not call or jump
return FALSE;
}
if ( (modRM & 0x08) == 0x08 ) {
// m16:16 or m16:32 -- we don't handle this
return FALSE;
}
if ( (modRM & 0xc0) == 0xc0 ) {
/* Direct register addressing */
callAddr = regValue( (UCHAR)(modRM&0x7), ContextRecord );
} else if ( (modRM & 0xc7) == 0x05 ) {
//
// ff15 or ff25 -- call or jump with disp32
//
KdpMoveMemory( (PCHAR)&addrAddr, (PCHAR)Pc+2, 4 );
KdpMoveMemory( (PCHAR)&callAddr, (PCHAR)addrAddr, 4 );
} else if ( (modRM & 0x7) == 0x4 ) {
LONG indexValue;
/* sib byte present */
KdpMoveMemory( (PCHAR)&sib, (PCHAR)Pc+2, 1 );
indexValue = regValue( (UCHAR)((sib & 0x31) >> 3), ContextRecord );
switch ( sib&0xc0 ) {
case 0x0: /* x1 */
break;
case 0x40:
indexValue *= 2;
break;
case 0x80:
indexValue *= 4;
break;
case 0xc0:
indexValue *= 8;
break;
} /* switch */
switch ( modRM & 0xc0 ) {
case 0x0: /* no displacement */
if ( (sib & 0x7) == 0x5 ) {
DPRINT(("funny call #1 at %x\n", Pc));
return FALSE;
}
callAddr = indexValue + regValue((UCHAR)(sib&0x7), ContextRecord );
break;
case 0x40:
if ( (sib & 0x6) == 0x4 ) {
DPRINT(("Funny call #2\n")); /* calling into the stack */
return FALSE;
}
KdpMoveMemory( &d8, (PCHAR)Pc+3,1 );
callAddr = indexValue + d8 +
regValue((UCHAR)(sib&0x7), ContextRecord );
break;
case 0x80:
if ( (sib & 0x6) == 0x4 ) {
DPRINT(("Funny call #3\n")); /* calling into the stack */
return FALSE;
}
KdpMoveMemory( (PCHAR)&offset, (PCHAR)Pc+3, 4 );
callAddr = indexValue + offset +
regValue((UCHAR)(sib&0x7), ContextRecord );
break;
case 0xc0:
ASSERT( FALSE );
break;
}
} else {
//KdPrint(( "undecoded call at %x\n",
// CONTEXT_TO_PROGRAM_COUNTER(ContextRecord) ));
return FALSE;
}
} else if ( opcode == 0x9a ) {
/* Absolute address call (best I can tell, cc doesn't generate this) */
KdpMoveMemory( (PCHAR)&callAddr, (PCHAR)Pc+1, 4 );
} else {
return FALSE;
}
//
// Calls across dll boundaries involve a call into a jump table,
// wherein the jump address is set to the real called routine at DLL
// load time. Check to see if we're calling such an instruction,
// and if so, compute its target address and set callAddr there.
//
#if 0
KdpMoveMemory( (PCHAR)&twoBytes, (PCHAR)callAddr, 2 );
if ( twoBytes == 0x25ff ) { /* i386 is little-Endian; really 0xff25 */
//
// This is a 'jmp dword ptr [mem]' instruction, which is the sort of
// jump used for a dll-boundary crossing call. Fixup callAddr.
//
KdpMoveMemory( (PCHAR)&addrAddr, (PCHAR)callAddr+2, 4 );
KdpMoveMemory( (PCHAR)&callAddr, (PCHAR)addrAddr, 4 );
}
#endif
for ( i = 0; i < KdNumberOfSpecialCalls; i++ ) {
if ( KdSpecialCalls[i] == callAddr ) {
return TRUE;
}
}
return FALSE;
}
/*
* Find the return address of the current function. Only works when
* locals haven't yet been pushed (ie, on the first instruction of the
* function).
*/
ULONG
KdpGetReturnAddress (
PCONTEXT ContextRecord
)
{
ULONG retaddr;
KdpMoveMemory((PCHAR)(&retaddr), (PCHAR)(ContextRecord->Esp), 4 );
return retaddr;
} // KdpGetReturnAddress
VOID
KdpSetLoadState(
IN PDBGKD_WAIT_STATE_CHANGE WaitStateChange,
IN PCONTEXT ContextRecord
)
/*++
Routine Description:
Fill in the Wait_State_Change message record for the load symbol case.
Arguments:
WaitStateChange - Supplies pointer to record to fill in
ContextRecord - Supplies a pointer to a context record.
Return Value:
None.
--*/
{
WaitStateChange->ControlReport.Dr6 =
KeGetCurrentPrcb()->ProcessorState.SpecialRegisters.KernelDr6;
WaitStateChange->ControlReport.Dr7 =
KeGetCurrentPrcb()->ProcessorState.SpecialRegisters.KernelDr7;
WaitStateChange->ControlReport.ReportFlags = 0;
}
VOID
KdpSetStateChange(
IN PDBGKD_WAIT_STATE_CHANGE WaitStateChange,
IN PEXCEPTION_RECORD ExceptionRecord,
IN PCONTEXT ContextRecord,
IN BOOLEAN SecondChance
)
/*++
Routine Description:
Fill in the Wait_State_Change message record.
Arguments:
WaitStateChange - Supplies pointer to record to fill in
ExceptionRecord - Supplies a pointer to an exception record.
ContextRecord - Supplies a pointer to a context record.
SecondChance - Supplies a boolean value that determines whether this is
the first or second chance for the exception.
Return Value:
None.
--*/
{
PKPRCB Prcb;
BOOLEAN status;
//
// Set up description of event, including exception record
//
WaitStateChange->NewState = DbgKdExceptionStateChange;
WaitStateChange->ProcessorLevel = KeProcessorLevel;
WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number;
WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;
WaitStateChange->Thread = (PVOID)KeGetCurrentThread();
WaitStateChange->ProgramCounter = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(ContextRecord);
KdpQuickMoveMemory(
(PCHAR)&WaitStateChange->u.Exception.ExceptionRecord,
(PCHAR)ExceptionRecord,
sizeof(EXCEPTION_RECORD)
);
WaitStateChange->u.Exception.FirstChance = !SecondChance;
//
// Copy instruction stream immediately following location of event
//
WaitStateChange->ControlReport.InstructionCount =
(USHORT)KdpMoveMemory(
(PCHAR)(&(WaitStateChange->ControlReport.InstructionStream[0])),
(PCHAR)(WaitStateChange->ProgramCounter),
DBGKD_MAXSTREAM
);
//
// Copy context record immediately following instruction stream
//
if (KdpSendContext) {
KdpMoveMemory(
(PCHAR)(&WaitStateChange->Context),
(PCHAR)ContextRecord,
sizeof(*ContextRecord)
);
}
//
// Clear breakpoints in copied area
//
status = KdpDeleteBreakpointRange(
WaitStateChange->ProgramCounter,
(PVOID)((PUCHAR)WaitStateChange->ProgramCounter +
WaitStateChange->ControlReport.InstructionCount - 1)
);
//
// If there were any breakpoints cleared, recopy the area without them
//
if (status == TRUE) {
KdpMoveMemory(
&(WaitStateChange->ControlReport.InstructionStream[0]),
WaitStateChange->ProgramCounter,
WaitStateChange->ControlReport.InstructionCount
);
}
//
// Special registers for the x86
//
Prcb = KeGetCurrentPrcb();
WaitStateChange->ControlReport.Dr6 =
Prcb->ProcessorState.SpecialRegisters.KernelDr6;
WaitStateChange->ControlReport.Dr7 =
Prcb->ProcessorState.SpecialRegisters.KernelDr7;
WaitStateChange->ControlReport.SegCs = (USHORT)(ContextRecord->SegCs);
WaitStateChange->ControlReport.SegDs = (USHORT)(ContextRecord->SegDs);
WaitStateChange->ControlReport.SegEs = (USHORT)(ContextRecord->SegEs);
WaitStateChange->ControlReport.SegFs = (USHORT)(ContextRecord->SegFs);
WaitStateChange->ControlReport.EFlags = ContextRecord->EFlags;
WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_SEGS;
}
VOID
KdpGetStateChange(
IN PDBGKD_MANIPULATE_STATE ManipulateState,
IN PCONTEXT ContextRecord
)
/*++
Routine Description:
Extract continuation control data from Manipulate_State message
Arguments:
ManipulateState - supplies pointer to Manipulate_State packet
ContextRecord - Supplies a pointer to a context record.
Return Value:
None.
--*/
{
PKPRCB Prcb;
ULONG Processor;
if (NT_SUCCESS(ManipulateState->u.Continue2.ContinueStatus) == TRUE) {
//
// If NT_SUCCESS returns TRUE, then the debugger is doing a
// continue, and it makes sense to apply control changes.
// Otherwise the debugger is saying that it doesn't know what
// to do with this exception, so control values are ignored.
//
if (ManipulateState->u.Continue2.ControlSet.TraceFlag == TRUE) {
ContextRecord->EFlags |= 0x100L;
} else {
ContextRecord->EFlags &= ~0x100L;
}
for (Processor = 0; Processor < (ULONG)KeNumberProcessors; Processor++) {
Prcb = KiProcessorBlock[Processor];
Prcb->ProcessorState.SpecialRegisters.KernelDr7 =
ManipulateState->u.Continue2.ControlSet.Dr7;
Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0L;
}
if (ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart != 1) {
KdpCurrentSymbolStart = ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart;
KdpCurrentSymbolEnd = ManipulateState->u.Continue2.ControlSet.CurrentSymbolEnd;
}
}
}
VOID
KdpReadControlSpace(
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a read control space state
manipulation message. Its function is to read implementation
specific system data.
IMPLEMENTATION NOTE:
On the X86, control space is defined as follows:
0: Base of KPROCESSOR_STATE structure. (KPRCB.ProcessorState)
This includes CONTEXT record,
followed by a SPECIAL_REGISTERs record
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_MEMORY a = &m->u.ReadMemory;
STRING MessageHeader;
ULONG Length, t;
PVOID StartAddr;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
if (a->TransferCount > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE))) {
Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE);
} else {
Length = a->TransferCount;
}
if ((a->TargetBaseAddress < (PVOID)END_OF_CONTROL_SPACE) &&
(m->Processor < (USHORT)KeNumberProcessors)) {
t = (ULONG)END_OF_CONTROL_SPACE - (ULONG)(a->TargetBaseAddress);
if (t < Length) {
Length = t;
}
StartAddr = (PVOID)((ULONG)a->TargetBaseAddress +
(ULONG)&(KiProcessorBlock[m->Processor]->ProcessorState));
AdditionalData->Length = (USHORT)KdpMoveMemory(
AdditionalData->Buffer,
StartAddr,
Length
);
if (Length == AdditionalData->Length) {
m->ReturnStatus = STATUS_SUCCESS;
} else {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
a->ActualBytesRead = AdditionalData->Length;
} else {
AdditionalData->Length = 0;
m->ReturnStatus = STATUS_UNSUCCESSFUL;
a->ActualBytesRead = 0;
}
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData
);
UNREFERENCED_PARAMETER(Context);
}
VOID
KdpWriteControlSpace(
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a write control space state
manipulation message. Its function is to write implementation
specific system data.
Control space for x86 is as defined above.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_WRITE_MEMORY a = &m->u.WriteMemory;
ULONG Length;
STRING MessageHeader;
PVOID StartAddr;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
if ((((PUCHAR)a->TargetBaseAddress + a->TransferCount) <=
(PUCHAR)END_OF_CONTROL_SPACE) && (m->Processor < (USHORT)KeNumberProcessors)) {
StartAddr = (PVOID)((ULONG)a->TargetBaseAddress +
(ULONG)&(KiProcessorBlock[m->Processor]->ProcessorState));
Length = KdpMoveMemory(
StartAddr,
AdditionalData->Buffer,
AdditionalData->Length
);
if (Length == AdditionalData->Length) {
m->ReturnStatus = STATUS_SUCCESS;
} else {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
a->ActualBytesWritten = Length;
} else {
AdditionalData->Length = 0;
m->ReturnStatus = STATUS_UNSUCCESSFUL;
a->ActualBytesWritten = 0;
}
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData
);
UNREFERENCED_PARAMETER(Context);
}
VOID
KdpReadIoSpace(
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a read io space state
manipulation message. Its function is to read system io
locations.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_WRITE_IO a = &m->u.ReadWriteIo;
STRING MessageHeader;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
m->ReturnStatus = STATUS_SUCCESS;
//
// Check Size and Alignment
//
switch ( a->DataSize ) {
case 1:
a->DataValue = (ULONG)READ_PORT_UCHAR(a->IoAddress);
break;
case 2:
if ((ULONG)a->IoAddress & 1 ) {
m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT;
} else {
a->DataValue = (ULONG)READ_PORT_USHORT(a->IoAddress);
}
break;
case 4:
if ((ULONG)a->IoAddress & 3 ) {
m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT;
} else {
a->DataValue = READ_PORT_ULONG(a->IoAddress);
}
break;
default:
m->ReturnStatus = STATUS_INVALID_PARAMETER;
}
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL
);
UNREFERENCED_PARAMETER(Context);
}
VOID
KdpWriteIoSpace(
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a write io space state
manipulation message. Its function is to write to system io
locations.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_WRITE_IO a = &m->u.ReadWriteIo;
STRING MessageHeader;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
m->ReturnStatus = STATUS_SUCCESS;
//
// Check Size and Alignment
//
switch ( a->DataSize ) {
case 1:
WRITE_PORT_UCHAR(a->IoAddress, (UCHAR)a->DataValue);
break;
case 2:
if ((ULONG)a->IoAddress & 1 ) {
m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT;
} else {
WRITE_PORT_USHORT(a->IoAddress, (USHORT)a->DataValue);
}
break;
case 4:
if ((ULONG)a->IoAddress & 3 ) {
m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT;
} else {
WRITE_PORT_ULONG(a->IoAddress, a->DataValue);
}
break;
default:
m->ReturnStatus = STATUS_INVALID_PARAMETER;
}
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL
);
UNREFERENCED_PARAMETER(Context);
}
VOID
KdpReadMachineSpecificRegister(
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a read MSR
manipulation message. Its function is to read the MSR.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_WRITE_MSR a = &m->u.ReadWriteMsr;
STRING MessageHeader;
LARGE_INTEGER l;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
m->ReturnStatus = STATUS_SUCCESS;
try {
l.QuadPart = RDMSR(a->Msr);
} except (EXCEPTION_EXECUTE_HANDLER) {
l.QuadPart = 0;
m->ReturnStatus = STATUS_NO_SUCH_DEVICE;
}
a->DataValueLow = l.LowPart;
a->DataValueHigh = l.HighPart;
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL
);
UNREFERENCED_PARAMETER(Context);
}
VOID
KdpWriteMachineSpecificRegister(
IN PDBGKD_MANIPULATE_STATE m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a write of a MSR
manipulation message. Its function is to write to the MSR
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_WRITE_MSR a = &m->u.ReadWriteMsr;
STRING MessageHeader;
LARGE_INTEGER l;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
ASSERT(AdditionalData->Length == 0);
m->ReturnStatus = STATUS_SUCCESS;
l.HighPart = a->DataValueHigh;
l.LowPart = a->DataValueLow;
try {
WRMSR (a->Msr, l.QuadPart);
} except (EXCEPTION_EXECUTE_HANDLER) {
m->ReturnStatus = STATUS_NO_SUCH_DEVICE;
}
KdpSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL
);
UNREFERENCED_PARAMETER(Context);
}
/*** KdpGetCallNextOffset - compute length of a call instruction
*
* Purpose:
* Compute how many bytes are in a call-type instruction
* so that a breakpoint can be set upon this instruction's
* return.
*
* Returns:
* length of instruction, or -1 if it wasn't a call instruction.
*
*************************************************************************/
ULONG
KdpGetCallNextOffset (
ULONG Pc
)
{
UCHAR membuf[2];
UCHAR opcode;
ULONG sib;
ULONG disp;
KdpMoveMemory( membuf, (PVOID)Pc, 2 );
opcode = membuf[0];
if ( opcode == 0xe8 ) {
return Pc+5;
} else if ( opcode == 0x9a ) {
return Pc+7;
} else if ( opcode == 0xff ) {
sib = ((membuf[1] & 0x07) == 0x04) ? 1 : 0;
disp = (membuf[1] & 0xc0) >> 6;
switch (disp) {
case 0:
if ( (membuf[1] & 0x07) == 0x05 ) {
disp = 4; // disp32 alone
} else {
// disp = 0; // no displacement with reg or sib
}
break;
case 1:
// disp = 1; // disp8 with reg or sib
break;
case 2:
disp = 4; // disp32 with reg or sib
break;
case 3:
disp = 0; // direct register addressing (e.g., call esi)
break;
}
return Pc + 2 + sib + disp;
}
return 0;
} // KdpGetCallNextOffset