Windows2000/private/windbg64/debugger/dm/support.c
2020-09-30 17:12:32 +02:00

2829 lines
68 KiB
C

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
api.c
Abstract:
This module implements the all apis that simulate their WIN32 counterparts.
Author:
Wesley Witt (wesw) 8-Mar-1992
Environment:
NT 3.1
--*/
#include "precomp.h"
#pragma hdrstop
extern CRITICAL_SECTION csPacket;
extern USHORT ContextSize;
//#define dp(s) OutputDebugString(s)
#define dp(s)
DWORD
DmKdReadPhysicalMemory(
IN ULONG64 TargetBaseAddress,
OUT PVOID UserInterfaceBuffer,
IN ULONG TransferCount,
OUT PULONG ActualBytesRead OPTIONAL
)
/*++
Routine Description:
This function reads the specified data from the physical memory of
the system being debugged.
Arguments:
TargetBaseAddress - Supplies the physical address of the memory to read
from the system being debugged.
UserInterfaceBuffer - Supplies the address of the buffer in the user
interface that data read is to be placed.
TransferCount - Specifies the number of bytes to read.
ActualBytesRead - An optional parameter that if supplied, returns
the number of bytes actually read.
Return Value:
STATUS_SUCCESS - The specified read occured.
STATUS_BUFFER_OVERFLOW - A read that is too large was specified.
STATUS_ACCESS_VIOLATION - TBD // Can you even HAVE an access
// violation with a physical
// memory access??
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_READ_MEMORY64 a = &m64.u.ReadMemory;
PDBGKD_READ_MEMORY32 a32 = &m32.u.ReadMemory;
PDBGKD_MANIPULATE_STATE64 Reply;
DWORD st, cb, cb2;
BOOL rc;
assert( Is64PtrSE(TargetBaseAddress) );
dp("DmKdReadPhysicalMemory\n");
EnterCriticalSection(&csPacket);
if (TransferCount > PACKET_MAX_SIZE) {
// Read the partial the first time.
cb = TransferCount % PACKET_MAX_SIZE;
} else {
cb = TransferCount;
}
cb2 = 0;
if (ARGUMENT_PRESENT(ActualBytesRead)) {
*ActualBytesRead = 0;
}
while (TransferCount != 0) {
// Format state manipulate message
// 64 bit
m64.ApiNumber = DbgKdReadPhysicalMemoryApi;
m64.ReturnStatus = STATUS_PENDING;
a->TargetBaseAddress = TargetBaseAddress+cb2;
a->TransferCount = cb;
a->ActualBytesRead = 0L;
// 32 bit
m32.ApiNumber = DbgKdReadPhysicalMemoryApi;
m32.ReturnStatus = STATUS_PENDING;
a32->TargetBaseAddress = (ULONG) TargetBaseAddress+cb2;
a32->TransferCount = cb;
a32->ActualBytesRead = 0L;
// Send the message and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&Reply
);
} while (rc == FALSE);
// If this is not a ReadMemory response then protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdReadPhysicalMemoryApi);
// Reset message address to reply.
a = &Reply->u.ReadMemory;
assert(a->ActualBytesRead <= cb);
// Return actual bytes read, and then transfer the bytes
if (ARGUMENT_PRESENT(ActualBytesRead)) {
*ActualBytesRead += a->ActualBytesRead;
}
st = Reply->ReturnStatus;
// Since read response data follows message, Reply+1 should point
// at the data
memcpy((PCHAR)((UINT_PTR) UserInterfaceBuffer+cb2), Reply+1, (int)a->ActualBytesRead);
if (st != STATUS_SUCCESS) {
TransferCount = 0;
} else {
TransferCount -= cb;
cb2 += cb;
cb = PACKET_MAX_SIZE;
}
}
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdWritePhysicalMemory(
IN ULONG64 TargetBaseAddress,
OUT PVOID UserInterfaceBuffer,
IN ULONG TransferCount,
OUT PULONG ActualBytesWritten OPTIONAL
)
/*++
Routine Description:
This function writes the specified data to the physical memory of the
system being debugged.
Arguments:
TargetBaseAddress - Supplies the physical address of the memory to write
to the system being debugged.
UserInterfaceBuffer - Supplies the address of the buffer in the user
interface that contains the data to be written.
TransferCount - Specifies the number of bytes to write.
ActualBytesWritten - An optional parameter that if supplied, returns
the number of bytes actually written.
Return Value:
STATUS_SUCCESS - The specified read occured.
STATUS_BUFFER_OVERFLOW - A read that is to large was specified.
STATUS_ACCESS_VIOLATION - TBD // Can you even HAVE an access
// violation with a physical
// memory access??
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_WRITE_MEMORY64 a = &m64.u.WriteMemory;
PDBGKD_WRITE_MEMORY32 a32 = &m32.u.WriteMemory;
DWORD st;
BOOL rc;
ULONG cb, cb2;
dp("DmKdWritePhysicalMemory\n");
assert( Is64PtrSE(TargetBaseAddress) );
EnterCriticalSection(&csPacket);
if (TransferCount > PACKET_MAX_SIZE) {
// Read the partial the first time.
cb = TransferCount % PACKET_MAX_SIZE;
} else {
cb = TransferCount;
}
cb2 = 0;
if (ARGUMENT_PRESENT(ActualBytesWritten)) {
*ActualBytesWritten = 0;
}
while (TransferCount != 0) {
// Format state manipulate message
// 64 bit
m64.ApiNumber = DbgKdWritePhysicalMemoryApi;
m64.ReturnStatus = STATUS_PENDING;
a->TargetBaseAddress = TargetBaseAddress+cb2;
a->TransferCount = cb;
a->ActualBytesWritten = 0L;
// 32 bit
m32.ApiNumber = DbgKdWritePhysicalMemoryApi;
m32.ReturnStatus = STATUS_PENDING;
a32->TargetBaseAddress = (ULONG) TargetBaseAddress+cb2;
a32->TransferCount = cb;
a32->ActualBytesWritten = 0L;
// Send the message and data to write and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
(PVOID)((UINT_PTR)UserInterfaceBuffer+cb2),
(USHORT)cb
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a WriteMemory response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdWritePhysicalMemoryApi);
// Reset message address to reply.
a = &Reply->u.WriteMemory;
assert(a->ActualBytesWritten <= cb);
// Return actual bytes written
if (ARGUMENT_PRESENT(ActualBytesWritten)) {
*ActualBytesWritten += a->ActualBytesWritten;
}
st = Reply->ReturnStatus;
if (st != STATUS_SUCCESS) {
TransferCount = 0;
} else {
TransferCount -= cb;
cb2 += cb;
cb = PACKET_MAX_SIZE;
}
}
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdReboot( VOID )
/*++
Routine Description:
This function reboots being debugged.
Arguments:
None.
Return Value:
None.
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
// Format state manipulate message
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdRebootApi;
m64.ReturnStatus = STATUS_PENDING;
// 32 bit
m32.ApiNumber = DbgKdRebootApi;
m32.ReturnStatus = STATUS_PENDING;
// Send the message.
if (!DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
)) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
LeaveCriticalSection(&csPacket);
return STATUS_SUCCESS;
}
DWORD
DmKdGetContext(
IN USHORT Processor,
IN OUT PCONTEXT Context
)
/*++
Routine Description:
This function reads the context from the system being debugged.
The ContextFlags field determines how much context is read.
Arguments:
Processor - Supplies a processor number to get context from.
Context - On input, the ContextFlags field controls what portions of
the context record the caller as interested in reading. On
output, the context record returns the current context for the
processor that reported the last state change.
Return Value:
STATUS_SUCCESS - The specified get context occured.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_GET_CONTEXT a = &m64.u.GetContext;
DWORD st;
BOOL rc;
dp("DmKdGetContext\n");
// Format state manipulate message
EnterCriticalSection(&csPacket);
m64.ApiNumber = DbgKdGetContextApi;
m64.ReturnStatus = STATUS_PENDING;
m64.Processor = Processor;
DbgkdManipulateState64To32(&m64, &m32);
// Send the message and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a GetContext response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdGetContextApi);
// Reset message address to reply.
a = &Reply->u.GetContext;
st = Reply->ReturnStatus;
// Since get context response data follows message, Reply+1 should point
// at the data
memcpy(Context, Reply+1, sizeof(*Context));
#if defined(TARGET_i386)
if (vs.MinorVersion < CONTEXT_SIZE_NT5_VERSION) {
ZeroMemory(Context->ExtendedRegisters, sizeof(Context->ExtendedRegisters));
}
#endif
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdSetContext(
IN USHORT Processor,
IN CONST CONTEXT *Context
)
/*++
Routine Description:
This function writes the specified context to the system being debugged.
Arguments:
Processor - Supplies a processor number to set the context to.
Context - Supplies a context record used to set the context for the
processor that reported the last state change. Only the
portions of the context indicated by the ContextFlags field are
actually written.
Return Value:
STATUS_SUCCESS - The specified set context occured.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_SET_CONTEXT a = &m64.u.SetContext;
PDBGKD_SET_CONTEXT a32 = &m32.u.SetContext;
DWORD st;
BOOL rc;
USHORT ContextSize;
dp("DmKdSetContext\n");
// Format state manipulate message
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdSetContextApi;
m64.ReturnStatus = STATUS_PENDING;
m64.Processor = Processor;
a->ContextFlags = Context->ContextFlags;
// 32 bit
m32.ApiNumber = DbgKdSetContextApi;
m32.ReturnStatus = STATUS_PENDING;
m32.Processor = Processor;
a32->ContextFlags = Context->ContextFlags;
#if defined(TARGET_i386)
if (vs.MinorVersion < CONTEXT_SIZE_NT5_VERSION) {
ContextSize = CONTEXT_SIZE_PRE_NT5;
} else {
ContextSize = sizeof(*Context);
}
#else
ContextSize = sizeof(*Context);
#endif
// Send the message and context and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
(PVOID)Context,
ContextSize
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a SetContext response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdSetContextApi);
// Reset message address to reply.
a = &Reply->u.SetContext;
st = Reply->ReturnStatus;
// Check if the current command has been canceled.
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdWriteBreakPoint(
IN ULONG64 BreakPointAddress,
OUT PULONG BreakPointHandle
)
/*++
Routine Description:
This function is used to write a breakpoint at the address specified.
Arguments:
BreakPointAddress - Supplies the address that a breakpoint
instruction is to be written. This address is interpreted using
the current mapping on the processor reporting the previous
state change. If the address refers to a page that is not
valid, the the breakpoint is remembered by the system. As each
page is made valid, the system will check for pending
breakpoints and install breakpoints as necessary.
BreakPointHandle - Returns a handle to a breakpoint. This handle
may be used in a subsequent call to DmKdRestoreBreakPoint.
Return Value:
STATUS_SUCCESS - The specified breakpoint write occured.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_WRITE_BREAKPOINT64 a = &m64.u.WriteBreakPoint;
PDBGKD_WRITE_BREAKPOINT32 a32 = &m32.u.WriteBreakPoint;
DWORD st;
BOOL rc;
assert( Is64PtrSE(BreakPointAddress) );
dp("DmKdWriteBreakPoint\n");
// Format state manipulate message
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdWriteBreakPointApi;
m64.ReturnStatus = STATUS_PENDING;
a->BreakPointAddress = BreakPointAddress;
// 32 bit
m32.ApiNumber = DbgKdWriteBreakPointApi;
m32.ReturnStatus = STATUS_PENDING;
a32->BreakPointAddress = (ULONG) BreakPointAddress;
// Send the message and context and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a WriteBreakPoint response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdWriteBreakPointApi);
// Reset message address to reply.
a = &Reply->u.WriteBreakPoint;
st = Reply->ReturnStatus;
*BreakPointHandle = a->BreakPointHandle;
// Check should we return to caller or to kd prompt.
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdRestoreBreakPoint(
IN ULONG BreakPointHandle
)
/*++
Routine Description:
This function is used to restore a breakpoint to its original
value.
Arguments:
BreakPointHandle - Supplies a handle returned by
DmKdWriteBreakPoint. This handle must refer to a valid
address. The contents of the address must also be a breakpoint
instruction. If both of these are true, then the original value
at the breakpoint address is restored.
Return Value:
STATUS_SUCCESS - The specified breakpoint restore occured.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_RESTORE_BREAKPOINT a = &m64.u.RestoreBreakPoint;
PDBGKD_RESTORE_BREAKPOINT a32 = &m32.u.RestoreBreakPoint;
DWORD st;
BOOL rc;
dp("DmKdRestoreBreakPoint\n");
// Format state manipulate message
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdRestoreBreakPointApi;
m64.ReturnStatus = STATUS_PENDING;
a->BreakPointHandle = BreakPointHandle;
// 32 bit
m32.ApiNumber = DbgKdRestoreBreakPointApi;
m32.ReturnStatus = STATUS_PENDING;
a32->BreakPointHandle = BreakPointHandle;
// Send the message and context and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a RestoreBreakPoint response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdRestoreBreakPointApi);
// Reset message address to reply.
a = &Reply->u.RestoreBreakPoint;
st = Reply->ReturnStatus;
// free the packet
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdReadIoSpace(
IN ULONG64 IoAddress,
OUT PVOID ReturnedData,
IN ULONG DataSize
)
/*++
Routine Description:
This function is used read a byte, short, or long (1,2,4 bytes) from
the specified I/O address.
Arguments:
IoAddress - Supplies the Io address to read from.
ReturnedData - Supplies the value read from the I/O address.
DataSize - Supplies the size in bytes to read. Values of 1, 2, or
4 are accepted.
Return Value:
STATUS_SUCCESS - Data was successfully read from the I/O
address.
STATUS_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was
specified.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_READ_WRITE_IO64 a = &m64.u.ReadWriteIo;
PDBGKD_READ_WRITE_IO32 a32 = &m32.u.ReadWriteIo;
DWORD st;
BOOL rc;
dp("DmKdReadIoSpace\n");
assert( Is64PtrSE(IoAddress) );
EnterCriticalSection(&csPacket);
switch ( DataSize ) {
case 1:
case 2:
case 4:
break;
default:
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_INVALID_PARAMETER;
}
// Format state manipulate message
// 64 bit
m64.ApiNumber = DbgKdReadIoSpaceApi;
m64.ReturnStatus = STATUS_PENDING;
a->DataSize = DataSize;
a->IoAddress = IoAddress;
// 32 bit
m32.ApiNumber = DbgKdReadIoSpaceApi;
m32.ReturnStatus = STATUS_PENDING;
a32->DataSize = DataSize;
a32->IoAddress = (ULONG) IoAddress;
// Send the message and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a ReadIo response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdReadIoSpaceApi);
// Reset message address to reply.
a = &Reply->u.ReadWriteIo;
st = Reply->ReturnStatus;
switch ( DataSize ) {
case 1:
*(PUCHAR)ReturnedData = (UCHAR)a->DataValue;
break;
case 2:
*(PUSHORT)ReturnedData = (USHORT)a->DataValue;
break;
case 4:
*(PULONG)ReturnedData = a->DataValue;
break;
}
// Check if current command has been canceled. If yes, go back to
// kd prompt. BUGBUG Do we really need to check for this call?
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdWriteIoSpace(
IN ULONG64 IoAddress,
IN ULONG DataValue,
IN ULONG DataSize
)
/*++
Routine Description:
This function is used write a byte, short, or long (1,2,4 bytes) to
the specified I/O address.
Arguments:
IoAddress - Supplies the Io address to write to.
DataValue - Supplies the value to write to the I/O address.
DataSize - Supplies the size in bytes to write. Values of 1, 2, or
4 are accepted.
Return Value:
STATUS_SUCCESS - Data was successfully written to the I/O
address.
STATUS_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was
specified.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_READ_WRITE_IO64 a = &m64.u.ReadWriteIo;
PDBGKD_READ_WRITE_IO32 a32 = &m32.u.ReadWriteIo;
DWORD st;
BOOL rc;
dp("DmKdWriteIoSpace\n");
assert( Is64PtrSE(IoAddress) );
EnterCriticalSection(&csPacket);
switch ( DataSize ) {
case 1:
case 2:
case 4:
break;
default:
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_INVALID_PARAMETER;
}
// Format state manipulate message
// 64 bit
m64.ApiNumber = DbgKdWriteIoSpaceApi;
m64.ReturnStatus = STATUS_PENDING;
a->DataSize = DataSize;
a->IoAddress = IoAddress;
a->DataValue = DataValue;
// 32 bit
m32.ApiNumber = DbgKdWriteIoSpaceApi;
m32.ReturnStatus = STATUS_PENDING;
a32->DataSize = DataSize;
a32->IoAddress = (ULONG) IoAddress;
a32->DataValue = DataValue;
// Send the message and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a WriteIo response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdWriteIoSpaceApi);
// Reset message address to reply.
a = &Reply->u.ReadWriteIo;
st = Reply->ReturnStatus;
// free the packet
// Check should we return to caller or to kd prompt.
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdReadIoSpaceEx(
IN ULONG64 IoAddress,
OUT PVOID ReturnedData,
IN ULONG DataSize,
IN ULONG InterfaceType,
IN ULONG BusNumber,
IN ULONG AddressSpace
)
/*++
Routine Description:
This function is used read a byte, short, or long (1,2,4 bytes) from
the specified I/O address.
Arguments:
IoAddress - Supplies the Io address to read from.
ReturnedData - Supplies the value read from the I/O address.
DataSize - Supplies the size in bytes to read. Values of 1, 2, or
4 are accepted.
Return Value:
STATUS_SUCCESS - Data was successfully read from the I/O
address.
STATUS_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was
specified.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_READ_WRITE_IO_EXTENDED64 a = &m64.u.ReadWriteIoExtended;
PDBGKD_READ_WRITE_IO_EXTENDED32 a32 = &m32.u.ReadWriteIoExtended;
DWORD st;
BOOL rc;
dp("DmKdReadIoSpaceEx\n");
assert( Is64PtrSE(IoAddress) );
EnterCriticalSection(&csPacket);
switch ( DataSize ) {
case 1:
case 2:
case 4:
break;
default:
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_INVALID_PARAMETER;
}
// Format state manipulate message
// 64 bit
m64.ApiNumber = DbgKdReadIoSpaceExtendedApi;
m64.ReturnStatus = STATUS_PENDING;
a->DataSize = DataSize;
a->IoAddress = IoAddress;
a->InterfaceType = InterfaceType;
a->BusNumber = BusNumber;
a->AddressSpace = AddressSpace;
// 32 bit
m32.ApiNumber = DbgKdReadIoSpaceExtendedApi;
m32.ReturnStatus = STATUS_PENDING;
a32->DataSize = DataSize;
a32->IoAddress = (ULONG) IoAddress;
a32->InterfaceType = InterfaceType;
a32->BusNumber = BusNumber;
a32->AddressSpace = AddressSpace;
// Send the message and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a ReadIo response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdReadIoSpaceExtendedApi);
// Reset message address to reply.
a = &Reply->u.ReadWriteIoExtended;
st = Reply->ReturnStatus;
switch ( DataSize ) {
case 1:
*(PUCHAR)ReturnedData = (UCHAR)a->DataValue;
break;
case 2:
*(PUSHORT)ReturnedData = (USHORT)a->DataValue;
break;
case 4:
*(PULONG)ReturnedData = a->DataValue;
break;
}
// Check if current command has been canceled. If yes, go back to
// kd prompt. BUGBUG Do we really need to check for this call?
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdWriteIoSpaceEx(
IN ULONG64 IoAddress,
IN ULONG DataValue,
IN ULONG DataSize,
IN ULONG InterfaceType,
IN ULONG BusNumber,
IN ULONG AddressSpace
)
/*++
Routine Description:
This function is used write a byte, short, or long (1,2,4 bytes) to
the specified I/O address.
Arguments:
IoAddress - Supplies the Io address to write to.
DataValue - Supplies the value to write to the I/O address.
DataSize - Supplies the size in bytes to write. Values of 1, 2, or
4 are accepted.
Return Value:
STATUS_SUCCESS - Data was successfully written to the I/O
address.
STATUS_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was
specified.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_READ_WRITE_IO_EXTENDED64 a = &m64.u.ReadWriteIoExtended;
PDBGKD_READ_WRITE_IO_EXTENDED32 a32 = &m32.u.ReadWriteIoExtended;
DWORD st;
BOOL rc;
dp("DmKdWriteIoSpaceEx\n");
assert( Is64PtrSE(IoAddress) );
EnterCriticalSection(&csPacket);
switch ( DataSize ) {
case 1:
case 2:
case 4:
break;
default:
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_INVALID_PARAMETER;
}
// Format state manipulate message
// 64 bit
m64.ApiNumber = DbgKdWriteIoSpaceExtendedApi;
m64.ReturnStatus = STATUS_PENDING;
a->DataSize = DataSize;
a->IoAddress = IoAddress;
a->DataValue = DataValue;
a->InterfaceType = InterfaceType;
a->BusNumber = BusNumber;
a->AddressSpace = AddressSpace;
// 32 bit
m32.ApiNumber = DbgKdWriteIoSpaceExtendedApi;
m32.ReturnStatus= STATUS_PENDING;
a32->DataSize = DataSize;
a32->IoAddress = (ULONG) IoAddress;
a32->DataValue = DataValue;
a32->InterfaceType = InterfaceType;
a32->BusNumber = BusNumber;
a32->AddressSpace = AddressSpace;
// Send the message and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a WriteIo response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdWriteIoSpaceExtendedApi);
// Reset message address to reply.
a = &Reply->u.ReadWriteIoExtended;
st = Reply->ReturnStatus;
// free the packet
// Check should we return to caller or to kd prompt.
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdReadMemoryWrapper(
IN ULONG64 TargetBaseAddress,
OUT PVOID UserInterfaceBuffer,
IN ULONG TransferCount,
OUT PULONG ActualBytesRead OPTIONAL
)
/*++
Routine Description:
Wrapper around DmpReadMemory and DmKdReadVirtualMemory.
Arguments:
See the documentation for DmpReadMemory and DmKdReadVirtualMemory.
Return Value:
See the documentation for DmKdReadVirtualMemory.
--*/
{
extern BOOL fCrashDump;
ULONG Result;
DWORD Status;
if ( !fCrashDump ) {
Status = DmKdReadVirtualMemory(TargetBaseAddress,
UserInterfaceBuffer,
TransferCount,
&Result);
} else {
Result = DmpReadMemory(TargetBaseAddress,
UserInterfaceBuffer,
TransferCount
);
if (Result == TransferCount) {
Status = STATUS_SUCCESS;
} else {
// Return something for an error code
Status = STATUS_ACCESS_VIOLATION;
}
}
if ( ActualBytesRead ) {
*ActualBytesRead = Result;
}
return Status;
}
DWORD
DmKdReadVirtualMemory(
IN ULONG64 TargetBaseAddress,
OUT PVOID UserInterfaceBuffer,
IN ULONG TransferCount,
OUT PULONG ActualBytesRead OPTIONAL
)
/*++
Routine Description:
Interface to read VirtualMemory from target machine.
Goes through cached memory addresses, then through serial port.
Arguments:
TargetBaseAddress - Supplies the base address of the memory to read
from the system being debugged. The virtual address is in terms
of the current mapping for the processor that reported the last
state change. Until we figure out how to do this differently,
the virtual address must refer to a valid page (although it does
not necesserily have to be in the TB).
UserInterfaceBuffer - Supplies the address of the buffer in the user
interface that data read is to be placed.
TransferCount - Specifies the number of bytes to read.
ActualBytesRead - An optional parameter that if supplied, returns
the number of bytes actually read.
Return Value:
STATUS_SUCCESS - The specified read occured.
STATUS_BUFFER_OVERFLOW - A read that is to large was specified.
STATUS_ACCESS_VIOLATION - The TargetBaseAddress/TransferCount
parameters refers to invalid virtual memory.
!NT_SUCCESS() - TBD
--*/
{
ULONG BytesRead=0;
ULONG BytesRequested=TransferCount;
DWORD rc=0;
dp("DmKdReadVirtualMemory\n");
assert( Is64PtrSE(TargetBaseAddress) );
EnterCriticalSection(&csPacket);
rc = DmKdReadCachedVirtualMemory(TargetBaseAddress,
(ULONG) BytesRequested,
(PUCHAR) UserInterfaceBuffer,
&BytesRead,
FALSE );
if (BytesRead > TransferCount) {
BytesRead = TransferCount;
}
if (ActualBytesRead) {
*ActualBytesRead = BytesRead;
}
LeaveCriticalSection(&csPacket);
return rc;
}
DWORD
DmKdReadVirtualMemoryNow(
IN ULONG64 TargetBaseAddress,
OUT PVOID UserInterfaceBuffer,
IN ULONG TransferCount,
OUT PULONG ActualBytesRead OPTIONAL
)
/*++
Routine Description:
This function reads the specified data from the system being debugged
using the current mapping of the processor.
Arguments:
TargetBaseAddress - Supplies the base address of the memory to read
from the system being debugged. The virtual address is in terms
of the current mapping for the processor that reported the last
state change. Until we figure out how to do this differently,
the virtual address must refer to a valid page (although it does
not necesserily have to be in the TB).
UserInterfaceBuffer - Supplies the address of the buffer in the user
interface that data read is to be placed.
TransferCount - Specifies the number of bytes to read.
ActualBytesRead - An optional parameter that if supplied, returns
the number of bytes actually read.
Return Value:
STATUS_SUCCESS - The specified read occured.
STATUS_BUFFER_OVERFLOW - A read that is to large was specified.
STATUS_ACCESS_VIOLATION - The TargetBaseAddress/TransferCount
parameters refers to invalid virtual memory.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_READ_MEMORY64 a = &m64.u.ReadMemory;
PDBGKD_READ_MEMORY32 a32 = &m32.u.ReadMemory;
DWORD st;
BOOL rc;
DWORD cb, cb2;
dp("DmKdReadVirtualMemoryNow\n");
assert( Is64PtrSE(TargetBaseAddress) );
EnterCriticalSection(&csPacket);
if (TransferCount > PACKET_MAX_SIZE) {
// Read the partial the first time.
cb = TransferCount % PACKET_MAX_SIZE;
} else {
cb = TransferCount;
}
cb2 = 0;
if (ARGUMENT_PRESENT(ActualBytesRead)) {
*ActualBytesRead = 0;
}
while (TransferCount != 0) {
// Format state manipulate message
// 64 bit
m64.ApiNumber = DbgKdReadVirtualMemoryApi;
m64.ReturnStatus = STATUS_PENDING;
a->TargetBaseAddress = TargetBaseAddress+cb2;
a->TransferCount = cb;
a->ActualBytesRead = 0L;
// 32 bit
m32.ApiNumber = DbgKdReadVirtualMemoryApi;
m32.ReturnStatus = STATUS_PENDING;
a32->TargetBaseAddress = (ULONG) (TargetBaseAddress+cb2);
a32->TransferCount = cb;
a32->ActualBytesRead = 0L;
// Send the message and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&Reply
);
} while (rc == FALSE);
// If this is not a ReadMemory response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdReadVirtualMemoryApi);
// Reset message address to reply.
a = &Reply->u.ReadMemory;
assert(a->ActualBytesRead <= cb);
// Return actual bytes read, and then transfer the bytes
if (ARGUMENT_PRESENT(ActualBytesRead)) {
*ActualBytesRead += a->ActualBytesRead;
}
// Since read response data follows message, Reply+1 should point
// at the data
memcpy((PVOID)((UINT_PTR)UserInterfaceBuffer+cb2), Reply+1, (int)a->ActualBytesRead);
st = Reply->ReturnStatus;
if (st != STATUS_SUCCESS) {
TransferCount = 0;
} else {
TransferCount -= cb;
cb2 += cb;
cb = PACKET_MAX_SIZE;
}
}
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdWriteVirtualMemory(
IN ULONG64 TargetBaseAddress,
OUT PVOID UserInterfaceBuffer,
IN ULONG TransferCount,
OUT PULONG ActualBytesWritten OPTIONAL
)
/*++
Routine Description:
This function writes the specified data to the system being debugged
using the current mapping of the processor.
Arguments:
TargetBaseAddress - Supplies the base address of the memory to be written
into the system being debugged. The virtual address is in terms
of the current mapping for the processor that reported the last
state change. Until we figure out how to do this differently,
the virtual address must refer to a valid page (although it does
not necesserily have to be in the TB).
UserInterfaceBuffer - Supplies the address of the buffer in the user
interface that contains the data to be written.
TransferCount - Specifies the number of bytes to write.
ActualBytesWritten - An optional parameter that if supplied, returns
the number of bytes actually written.
Return Value:
STATUS_SUCCESS - The specified read occured.
STATUS_BUFFER_OVERFLOW - A read that is to large was specified.
STATUS_ACCESS_VIOLATION - The TargetBaseAddress/TransferCount
parameters refers to invalid virtual memory.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_WRITE_MEMORY64 a = &m64.u.WriteMemory;
PDBGKD_WRITE_MEMORY32 a32 = &m32.u.WriteMemory;
DWORD st, cb, cb2;
BOOL rc;
dp("DmKdWriteVirtualMemory\n");
assert( Is64PtrSE(TargetBaseAddress) );
EnterCriticalSection(&csPacket);
DmKdWriteCachedVirtualMemory (
TargetBaseAddress,
TransferCount,
UserInterfaceBuffer
);
if (TransferCount > PACKET_MAX_SIZE) {
// Read the partial the first time.
cb = TransferCount % PACKET_MAX_SIZE;
} else {
cb = TransferCount;
}
cb2 = 0;
if (ARGUMENT_PRESENT(ActualBytesWritten)) {
*ActualBytesWritten = 0;
}
while (TransferCount != 0) {
// Format state manipulate message
// 64 bit
m64.ApiNumber = DbgKdWriteVirtualMemoryApi;
m64.ReturnStatus = STATUS_PENDING;
a->TargetBaseAddress = TargetBaseAddress + cb2;
a->TransferCount = cb;
a->ActualBytesWritten = 0L;
// 32 bit
m32.ApiNumber = DbgKdWriteVirtualMemoryApi;
m32.ReturnStatus = STATUS_PENDING;
a32->TargetBaseAddress = (ULONG) (TargetBaseAddress + cb2);
a32->TransferCount = cb;
a32->ActualBytesWritten = 0L;
// Send the message and data to write and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
(PVOID)((UINT_PTR)UserInterfaceBuffer + cb2),
(USHORT)cb
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&Reply
);
} while (rc == FALSE);
// If this is not a WriteMemory response than protocol is screwed up.
// assert that protocol is ok.
assert(Reply->ApiNumber == DbgKdWriteVirtualMemoryApi);
// Reset message address to reply.
a = &Reply->u.WriteMemory;
assert(a->ActualBytesWritten <= cb);
// Return actual bytes written
if (ARGUMENT_PRESENT(ActualBytesWritten)) {
*ActualBytesWritten += a->ActualBytesWritten;
}
st = Reply->ReturnStatus;
if (st != STATUS_SUCCESS) {
TransferCount = 0;
} else {
TransferCount -= cb;
cb2 += cb;
cb = PACKET_MAX_SIZE;
}
}
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdReadControlSpace(
IN USHORT Processor,
IN ULONG64 TargetBaseAddress,
OUT PVOID UserInterfaceBuffer,
IN ULONG TransferCount,
OUT PULONG ActualBytesRead OPTIONAL
)
/*++
Routine Description:
This function reads the specified data from the control space of
the system being debugged.
Control space is processor dependent. TargetBaseAddress is mapped
to control space in a processor/implementation defined manner.
Arguments:
Processor - Supplies the processor whoes control space is desired.
TargetBaseAddress - Supplies the base address in control space to
read. This address is interpreted in an implementation defined
manner.
UserInterfaceBuffer - Supplies the address of the buffer in the user
interface that data read is to be placed.
TransferCount - Specifies the number of bytes to read.
ActualBytesRead - An optional parameter that if supplied, returns
the number of bytes actually read.
Return Value:
STATUS_SUCCESS - The specified read occured.
STATUS_BUFFER_OVERFLOW - A read that is to large was specified.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_READ_MEMORY64 a = &m64.u.ReadMemory;
PDBGKD_READ_MEMORY32 a32 = &m32.u.ReadMemory;
DWORD st;
BOOL rc;
dp("DmKdReadControlSpace\n");
assert( Is64PtrSE(TargetBaseAddress) );
// Use the largest struct to calc the size
if ( TransferCount + sizeof(m64) > PACKET_MAX_SIZE ) {
return (DWORD)STATUS_BUFFER_OVERFLOW;
}
// Format state manipulate message
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdReadControlSpaceApi;
m64.ReturnStatus = STATUS_PENDING;
m64.Processor = Processor;
a->TargetBaseAddress = TargetBaseAddress;
a->TransferCount = TransferCount;
a->ActualBytesRead = 0L;
// 32 bit
m32.ApiNumber = DbgKdReadControlSpaceApi;
m32.ReturnStatus = STATUS_PENDING;
m32.Processor = Processor;
a32->TargetBaseAddress = (ULONG) TargetBaseAddress;
a32->TransferCount = TransferCount;
a32->ActualBytesRead = 0L;
// Send the message and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket( PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a ReadControl response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdReadControlSpaceApi);
// Reset message address to reply.
a = &Reply->u.ReadMemory;
assert(a->ActualBytesRead <= TransferCount);
// Return actual bytes read, and then transfer the bytes
if (ARGUMENT_PRESENT(ActualBytesRead)) {
*ActualBytesRead = a->ActualBytesRead;
}
st = Reply->ReturnStatus;
// Since read response data follows message, Reply+1 should point
// at the data
memcpy(UserInterfaceBuffer, Reply+1, (int)a->ActualBytesRead);
// Check if current command has been canceled. If yes, go back to
// kd prompt. BUGBUG Do we really need to check for this call?
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdWriteControlSpace(
IN USHORT Processor,
IN ULONG64 TargetBaseAddress,
OUT PVOID UserInterfaceBuffer,
IN ULONG TransferCount,
OUT PULONG ActualBytesWritten OPTIONAL
)
/*++
Routine Description:
This function writes the specified data to control space on the system
being debugged.
Control space is processor dependent. TargetBaseAddress is mapped
to control space in a processor/implementation defined manner.
Arguments:
Processor - Supplies the processor whoes control space is desired.
TargetBaseAddress - Supplies the base address in control space to be
written.
UserInterfaceBuffer - Supplies the address of the buffer in the user
interface that contains the data to be written.
TransferCount - Specifies the number of bytes to write.
ActualBytesWritten - An optional parameter that if supplied, returns
the number of bytes actually written.
Return Value:
STATUS_SUCCESS - The specified read occured.
STATUS_BUFFER_OVERFLOW - A read that is to large was specified.
!NT_SUCCESS() - TBD
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_WRITE_MEMORY64 a = &m64.u.WriteMemory;
PDBGKD_WRITE_MEMORY32 a32 = &m32.u.WriteMemory;
DWORD st;
BOOL rc;
dp("DmKdWriteControlSpace\n");
assert( Is64PtrSE(TargetBaseAddress) );
if ( TransferCount + sizeof(m64) > PACKET_MAX_SIZE ) {
return (DWORD)STATUS_BUFFER_OVERFLOW;
}
// Format state manipulate message
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdWriteControlSpaceApi;
m64.ReturnStatus = STATUS_PENDING;
m64.Processor = Processor;
a->TargetBaseAddress = TargetBaseAddress;
a->TransferCount = TransferCount;
a->ActualBytesWritten = 0L;
// 32 bit
m32.ApiNumber = DbgKdWriteControlSpaceApi;
m32.ReturnStatus = STATUS_PENDING;
m32.Processor = Processor;
a32->TargetBaseAddress = (ULONG) TargetBaseAddress;
a32->TransferCount = TransferCount;
a32->ActualBytesWritten = 0L;
// Send the message and data to write and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
UserInterfaceBuffer,
(USHORT)TransferCount
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket( PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a WriteControl response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdWriteControlSpaceApi);
// Reset message address to reply.
a = &Reply->u.WriteMemory;
assert(a->ActualBytesWritten <= TransferCount);
// Return actual bytes written
*ActualBytesWritten = a->ActualBytesWritten;
st = Reply->ReturnStatus;
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdContinue (
IN DWORD ContinueStatus
)
/*++
Routine Description:
Continuing a system that previously reported a state change causes
the system to continue executiontion using the context in effect at
the time the state change was reported (of course this context could
have been modified using the DmKd state manipulation APIs).
Arguments:
ContinueStatus - Supplies the continuation status to the thread
being continued. Valid values for this are
DBG_EXCEPTION_HANDLED, DBG_EXCEPTION_NOT_HANDLED
or DBG_CONTINUE.
Return Value:
STATUS_SUCCESS - Successful call to DbgUiContinue
STATUS_INVALID_PARAMETER - An invalid continue status or was
specified.
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_CONTINUE a = &m64.u.Continue;
PDBGKD_CONTINUE a32 = &m32.u.Continue;
DWORD st;
dp("DmKdContinue\n");
EnterCriticalSection(&csPacket);
if ( ContinueStatus == DBG_EXCEPTION_HANDLED ||
ContinueStatus == DBG_EXCEPTION_NOT_HANDLED ||
ContinueStatus == DBG_CONTINUE ) {
// 64 bit
m64.ApiNumber = DbgKdContinueApi;
m64.ReturnStatus = ContinueStatus;
a->ContinueStatus = ContinueStatus;
// 32 bit
m32.ApiNumber = DbgKdContinueApi;
m32.ReturnStatus = ContinueStatus;
a32->ContinueStatus = ContinueStatus;
if (!DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
)) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
st = STATUS_SUCCESS;
DmKdPurgeCachedVirtualMemory( FALSE );
} else {
st = (DWORD)STATUS_INVALID_PARAMETER;
}
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdContinue2 (
IN DWORD ContinueStatus,
IN PDBGKD_CONTROL_SET ControlSet
)
/*++
Routine Description:
Continuing a system that previously reported a state change causes
the system to continue executiontion using the context in effect at
the time the state change was reported, modified by the values set
in the ControlSet structure. (And, of course, the context could have
been modified by used the DmKd state manipulation APIs.)
Arguments:
ContinueStatus - Supplies the continuation status to the thread
being continued. Valid values for this are
DBG_EXCEPTION_HANDLED, DBG_EXCEPTION_NOT_HANDLED
or DBG_CONTINUE.
ControlSet - Supplies a pointer to a structure containing the machine
specific control data to set. For the x86 this is the TraceFlag
and Dr7.
Return Value:
STATUS_SUCCESS - Successful call to DbgUiContinue
STATUS_INVALID_PARAMETER - An invalid continue status or was
specified.
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
DWORD st;
dp("DmKdContinue2\n");
EnterCriticalSection(&csPacket);
if ( ContinueStatus == DBG_EXCEPTION_HANDLED ||
ContinueStatus == DBG_EXCEPTION_NOT_HANDLED ||
ContinueStatus == DBG_CONTINUE ) {
// 64 bit
m64.ApiNumber = DbgKdContinueApi2;
m64.ReturnStatus = ContinueStatus;
m64.u.Continue2.ContinueStatus = ContinueStatus;
m64.u.Continue2.ControlSet = *ControlSet;
// 32 bit
m32.ApiNumber = DbgKdContinueApi2;
m32.ReturnStatus = ContinueStatus;
m32.u.Continue2.ContinueStatus = ContinueStatus;
m32.u.Continue2.ControlSet = *ControlSet;
if (!DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
)) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
st = STATUS_SUCCESS;
DmKdPurgeCachedVirtualMemory( FALSE );
}
else {
st = (DWORD)STATUS_INVALID_PARAMETER;
}
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdSetSpecialCalls (
IN ULONG NumSpecialCalls,
IN PULONG64 Calls
)
/*++
Routine Description:
Inform the debugged kernel that calls to these addresses
are "special" calls, and they should result in callbacks
to the kernel debugger rather than continued local stepping.
The new values *replace* any old ones that may have previously
set (not that you're likely to want to change this).
Arguments:
NumSpecialCalls - how many special calls there are
Calls - pointer to an array of calls.
Return Value:
STATUS_SUCCESS - Successful call to DbgUiContinue
STATUS_INVALID_PARAMETER - The number of special calls
wasn't between 0 and MAX_SPECIAL_CALLS.
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
ULONG i;
dp("DmKdSetSpecialCalls\n");
EnterCriticalSection(&csPacket);
#if 0
ClearTraceDataSyms();
#endif
// 64 bit
m64.ApiNumber = DbgKdClearSpecialCallsApi;
m64.ReturnStatus = STATUS_PENDING;
// 32 bit
m32.ApiNumber = DbgKdClearSpecialCallsApi;
m32.ReturnStatus = STATUS_PENDING;
if (!DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
)) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
DmKdPurgeCachedVirtualMemory( FALSE );
for (i = 0; i < NumSpecialCalls; i++) {
// 64 bit
m64.ApiNumber = DbgKdSetSpecialCallApi;
m64.ReturnStatus = STATUS_PENDING;
m64.u.SetSpecialCall.SpecialCall = Calls[i];
// 32 bit
m32.ApiNumber = DbgKdSetSpecialCallApi;
m32.ReturnStatus = STATUS_PENDING;
m32.u.SetSpecialCall.SpecialCall = (ULONG) Calls[i];
if (!DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
)) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
}
LeaveCriticalSection(&csPacket);
return STATUS_SUCCESS;
}
DWORD
DmKdSetInternalBp (
ULONG64 addr,
ULONG flags
)
/*++
Routine Description:
Inform the debugged kernel that a breakpoint at this address
is to be internally counted, and not result in a callback to the
remote debugger (us). This function DOES NOT cause the kernel to
set the breakpoint; the debugger must do that independently.
Arguments:
Addr - address of the breakpoint
Flags - the breakpoint flags to set (note: if the invalid bit
is set, this CLEARS a breakpoint).
Return Value:
STATUS_SUCCESS - Successful call to DbgUiContinue
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
DWORD st;
dp("DmKdSetInternalBp\n");
assert( Is64PtrSE(addr) );
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdSetInternalBreakPointApi;
m64.ReturnStatus = STATUS_PENDING;
m64.u.SetInternalBreakpoint.BreakpointAddress = addr;
m64.u.SetInternalBreakpoint.Flags = flags;
// 64 bit
m32.ApiNumber = DbgKdSetInternalBreakPointApi;
m32.ReturnStatus = STATUS_PENDING;
m32.u.SetInternalBreakpoint.BreakpointAddress = (ULONG) addr;
m32.u.SetInternalBreakpoint.Flags = flags;
if (!DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
)) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
st = STATUS_SUCCESS;
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdGetInternalBp (
ULONG64 addr,
PULONG flags,
PULONG calls,
PULONG minInstr,
PULONG maxInstr,
PULONG totInstr,
PULONG maxCPS
)
/*++
Routine Description:
Query the status of an internal breakpoint from the debugged
kernel and return the data to the caller.
Arguments:
Addr - address of the breakpoint
flags, calls, minInstr, maxInstr, totInstr - values returned
describing the particular breakpoint. flags will contain
the invalid bit if the breakpoint is bogus.
Return Value:
STATUS_SUCCESS - Successful call to DbgUiContinue
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
DWORD st;
ULONG rc;
dp("DmKdGetInternalBp\n");
assert( Is64PtrSE(addr) );
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdGetInternalBreakPointApi;
m64.ReturnStatus = STATUS_PENDING;
m64.u.GetInternalBreakpoint.BreakpointAddress = addr;
// 32 bit
m32.ApiNumber = DbgKdGetInternalBreakPointApi;
m32.ReturnStatus = STATUS_PENDING;
m32.u.GetInternalBreakpoint.BreakpointAddress = (ULONG) addr;
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket( PACKET_TYPE_KD_STATE_MANIPULATE,
&Reply
);
} while (rc == FALSE);
*flags = Reply->u.GetInternalBreakpoint.Flags;
*calls = Reply->u.GetInternalBreakpoint.Calls;
*maxCPS = Reply->u.GetInternalBreakpoint.MaxCallsPerPeriod;
*maxInstr = Reply->u.GetInternalBreakpoint.MaxInstructions;
*minInstr = Reply->u.GetInternalBreakpoint.MinInstructions;
*totInstr = Reply->u.GetInternalBreakpoint.TotalInstructions;
st = STATUS_SUCCESS;
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdGetVersion (
PDBGKD_GET_VERSION64 GetVersion
)
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_GET_VERSION64 a = &m64.u.GetVersion64;
PDBGKD_GET_VERSION32 a32 = &m32.u.GetVersion32;
DWORD st;
ULONG rc;
extern BOOL KdCacheDecodePTEs;
dp("DmKdGetVersion\n");
// 64 bit
m64.ApiNumber = DbgKdGetVersionApi;
m64.ReturnStatus = STATUS_PENDING;
a->ProtocolVersion = 1; // request context records on state changes
// 32 bit
m32.ApiNumber = DbgKdGetVersionApi;
m32.ReturnStatus = STATUS_PENDING;
a32->ProtocolVersion = 1; // request context records on state changes
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket( PACKET_TYPE_KD_STATE_MANIPULATE,
&Reply
);
} while (rc == FALSE);
*GetVersion = Reply->u.GetVersion64;
DmKdPtr64 = ((GetVersion->Flags & DBGKD_VERS_FLAG_PTR64) == DBGKD_VERS_FLAG_PTR64);
if (GetVersion->Flags & DBGKD_VERS_FLAG_NOMM) {
KdCacheDecodePTEs = FALSE;
}
st = Reply->ReturnStatus;
#if defined(TARGET_i386)
if (vs.MinorVersion < CONTEXT_SIZE_NT5_VERSION) {
ContextSize = CONTEXT_SIZE_PRE_NT5;
} else {
ContextSize = sizeof(CONTEXT);
}
#else
ContextSize = sizeof(CONTEXT);
#endif
return st;
}
DWORD
DmKdCrash(
DWORD BugCheckCode
)
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
dp("DmKdCrash\n");
// Format state manipulate message
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdCauseBugCheckApi;
m64.ReturnStatus = STATUS_PENDING;
*(PULONG)&m64.u = BugCheckCode;
// 32 bit
m32.ApiNumber = DbgKdCauseBugCheckApi;
m32.ReturnStatus = STATUS_PENDING;
*(PULONG)&m32.u = BugCheckCode;
// Send the message.
DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
LeaveCriticalSection(&csPacket);
return STATUS_SUCCESS;
}
DWORD
DmKdWriteBreakPointEx(
IN ULONG BreakPointCount,
IN OUT PDBGKD_WRITE_BREAKPOINT64 BreakPoints,
IN DWORD ContinueStatus
)
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
PDBGKD_MANIPULATE_STATE64 Reply;
PDBGKD_BREAKPOINTEX a = &m64.u.BreakPointEx;
PDBGKD_BREAKPOINTEX a32 = &m32.u.BreakPointEx;
DWORD st;
BOOL rc;
dp("DmKdWriteBreakPointEx\n");
// Format state manipulate message
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdWriteBreakPointExApi;
m64.ReturnStatus = STATUS_PENDING;
a->BreakPointCount = BreakPointCount;
a->ContinueStatus = (NTSTATUS)ContinueStatus;
// 32 bit
m32.ApiNumber = DbgKdWriteBreakPointExApi;
m32.ReturnStatus = STATUS_PENDING;
a32->BreakPointCount = BreakPointCount;
a32->ContinueStatus = (NTSTATUS)ContinueStatus;
// Send the message and context and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
(PVOID)BreakPoints,
(USHORT)(sizeof(*BreakPoints) * BreakPointCount)
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
} while (rc == FALSE);
// If this is not a SetContext response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdWriteBreakPointExApi);
// Reset message address to reply.
a = &Reply->u.BreakPointEx;
st = Reply->ReturnStatus;
memcpy(BreakPoints, Reply+1, sizeof(*BreakPoints) * BreakPointCount );
BreakPointCount = a->BreakPointCount;
// Check if the current command has been canceled.
LeaveCriticalSection(&csPacket);
return st;
}
DWORD
DmKdRestoreBreakPointEx(
IN ULONG BreakPointCount,
IN PDBGKD_RESTORE_BREAKPOINT BreakPointHandles
)
{
DBGKD_MANIPULATE_STATE64 m64 = {0};
DBGKD_MANIPULATE_STATE32 m32 = {0};
PDBGKD_MANIPULATE_STATE64 Reply;
DWORD st;
BOOL rc;
dp("DmKdRestoreBreakPointEx\n");
// Format state manipulate message
EnterCriticalSection(&csPacket);
// 64 bit
m64.ApiNumber = DbgKdRestoreBreakPointExApi;
m64.ReturnStatus = STATUS_PENDING;
m64.u.BreakPointEx.BreakPointCount = BreakPointCount;
// 32 bit
m32.ApiNumber = DbgKdRestoreBreakPointExApi;
m32.ReturnStatus = STATUS_PENDING;
m32.u.BreakPointEx.BreakPointCount = BreakPointCount;
// Send the message and context and then wait for reply
do {
rc = DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
(PVOID)BreakPointHandles,
(USHORT)(sizeof(*BreakPointHandles) * BreakPointCount)
);
if (!rc) {
LeaveCriticalSection(&csPacket);
return (DWORD)STATUS_DATA_ERROR;
}
rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&Reply
);
} while (rc == FALSE);
// If this is not a SetContext response than protocol is screwed up.
// assert that protocol is ok.
st = Reply->ReturnStatus;
assert(Reply->ApiNumber == DbgKdRestoreBreakPointExApi);
// Reset message address to reply.
st = Reply->ReturnStatus;
memcpy(BreakPointHandles, Reply+1, sizeof(*BreakPointHandles) * BreakPointCount );
// Check if the current command has been canceled.
LeaveCriticalSection(&csPacket);
return st;
}
NTSTATUS
DmKdSwitchActiveProcessor (
IN ULONG ProcessorNumber
)
/*++
Routine Description:
Arguments:
ProcessorNumber -
Return Value:
STATUS_SUCCESS - Successful call to DbgUiContinue
STATUS_INVALID_PARAMETER - An invalid continue status or was
specified.
--*/
{
DBGKD_MANIPULATE_STATE64 m64;
DBGKD_MANIPULATE_STATE32 m32;
extern BOOL fCrashDump;
if (fCrashDump) {
DMPrintShellMsg( "DMKD: Cannot change active processors on a crash dump" );
return STATUS_UNSUCCESSFUL;
}
// 64 bit
m64.ApiNumber = (USHORT)DbgKdSwitchProcessor;
m64.Processor = (USHORT)ProcessorNumber;
// 32 bit
m32.ApiNumber = (USHORT)DbgKdSwitchProcessor;
m32.Processor = (USHORT)ProcessorNumber;
DmKdWritePacket(
DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32,
DmKdApi64 ? sizeof(m64) : sizeof(m32),
PACKET_TYPE_KD_STATE_MANIPULATE,
NULL,
0
);
DmKdPurgeCachedVirtualMemory (TRUE);
return STATUS_SUCCESS;
}