3234 lines
71 KiB
C
3234 lines
71 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
dbgkdapi.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the DbgKd APIs
|
||
|
||
Author:
|
||
|
||
Mark Lucovsky (markl) 25-Jul-1990
|
||
|
||
Revision History:
|
||
|
||
Shie-Lin Tzong (shielint) Updated for packet control protocol.
|
||
|
||
--*/
|
||
|
||
#include "ntsdp.h"
|
||
#include "dbgpnt.h"
|
||
#include <xxsetjmp.h>
|
||
|
||
extern PSTR CrashFileName;
|
||
extern PCONTEXT CrashContext;
|
||
|
||
extern HANDLE ConsoleInputHandle;
|
||
extern HANDLE ConsoleOutputHandle;
|
||
|
||
extern UCHAR DbgKdpPacket[];
|
||
extern KD_PACKET PacketHeader;
|
||
extern UCHAR chLastCommand[]; // last command executed
|
||
|
||
extern BOOLEAN restart;
|
||
extern BOOLEAN SendInitialConnect;
|
||
|
||
extern HANDLE PipeRead; // see DbgKdpKbdPollThread
|
||
extern HANDLE PipeWrite;
|
||
extern ULONG NumberProcessors;
|
||
extern BOOLEAN KdVerbose;
|
||
extern BOOLEAN KdModemControl;
|
||
extern int loghandle;
|
||
static USHORT LastProcessorToPrint = (USHORT) -1;
|
||
|
||
UCHAR DbgKdpPacketLeader[4] = {
|
||
PACKET_LEADER_BYTE,
|
||
PACKET_LEADER_BYTE,
|
||
PACKET_LEADER_BYTE,
|
||
PACKET_LEADER_BYTE
|
||
};
|
||
|
||
//
|
||
// DbgKdpCmdCanceled indicates the fact that the current kd command has
|
||
// been canceled by user (using ctrl-C.) With the Packet Id controlling
|
||
// the packet exchange, the Ctrl-C has to be handled in controlled manner.
|
||
// At each end of DbgKdpXXXX routine, we will check for this flag. If the
|
||
// command has been canceled, a longjmp will be performed to transfer control
|
||
// back to kd prompt.
|
||
//
|
||
|
||
BOOLEAN DbgKdpCmdCanceled;
|
||
extern jmp_buf cmd_return;
|
||
|
||
#ifdef DBG
|
||
BOOLEAN KdDebug;
|
||
#endif
|
||
|
||
BOOLEAN KdResync;
|
||
ULONG KdPollThreadMode;
|
||
#define OUT_NORMAL 0
|
||
#define OUT_TERMINAL 1
|
||
|
||
UCHAR PrintBuf[PACKET_MAX_SIZE];
|
||
|
||
#define CONTROL_B 2
|
||
#define CONTROL_D 4
|
||
#define CONTROL_R 18
|
||
#define CONTROL_V 22
|
||
#define CONTROL_X 24
|
||
#ifdef _PPC_
|
||
#define CONTROL_T 20
|
||
#endif
|
||
|
||
extern ULONG DbgKdpPacketExpected; // ID for expected incoming packet
|
||
extern ULONG DbgKdpNextPacketToSend; // ID for Next packet to send
|
||
extern VOID DbgKdpSynchronizeTarget ( VOID );
|
||
|
||
//++
|
||
//
|
||
// VOID
|
||
// DbgKdpWaitPacketForever (
|
||
// IN ULONG PacketType,
|
||
// IN PVOID Buffer
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This macro is invoked to wait for specifi type of message without
|
||
// timeout.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// PacketType - Type of the message we are expecting.
|
||
//
|
||
// Buffer - Buffer to store the message.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
#define DbgKdpWaitPacketForever( PacketType, Buffer) { \
|
||
BOOLEAN rc; \
|
||
do { \
|
||
rc = DbgKdpWaitForPacket( \
|
||
PacketType, \
|
||
Buffer \
|
||
); \
|
||
} while ( rc == FALSE); \
|
||
}
|
||
|
||
NTSTATUS
|
||
DbgKdConnectAndInitialize(
|
||
IN ULONG CommunicationPortNumber OPTIONAL,
|
||
IN PSTRING BootCommand OPTIONAL,
|
||
IN PUSHORT LogHandle
|
||
)
|
||
{
|
||
|
||
DWORD BytesWritten;
|
||
BOOL rc;
|
||
//
|
||
// Initialize comport, packet queue and start the packet receiving
|
||
// thread.
|
||
//
|
||
|
||
if (!restart) DbgKdpInitComPort(0L);
|
||
DbgKdpPacketExpected = INITIAL_PACKET_ID;
|
||
DbgKdpNextPacketToSend = INITIAL_PACKET_ID;
|
||
|
||
if (!restart) DbgKdpStartThreads();
|
||
|
||
if ( ARGUMENT_PRESENT(BootCommand) ) {
|
||
|
||
rc = DbgKdpWriteComPort(
|
||
BootCommand->Buffer,
|
||
BootCommand->Length,
|
||
&BytesWritten
|
||
);
|
||
|
||
if ( rc != TRUE || BytesWritten != BootCommand->Length ){
|
||
|
||
//
|
||
// an error occured writing the pathname so fail the Boot
|
||
//
|
||
|
||
fprintf(
|
||
stderr,
|
||
"KD: Boot pathname Error rc %d BytesWritten %d\n",
|
||
rc,
|
||
BytesWritten
|
||
);
|
||
}
|
||
|
||
}
|
||
|
||
KdResync = SendInitialConnect;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
BOOLEAN
|
||
DbgKdpWriteComPort(
|
||
IN PUCHAR Buffer,
|
||
IN ULONG SizeOfBuffer,
|
||
IN PULONG BytesWritten
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes the supplied bytes to the COM port. Handles overlapped
|
||
IO requirements and other common com port maintanance.
|
||
|
||
--*/
|
||
{
|
||
BOOLEAN rc;
|
||
DWORD TrashErr;
|
||
COMSTAT TrashStat;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "attempted to write to the com port while debugging a crash dump\n" );
|
||
DebugBreak();
|
||
}
|
||
|
||
if (DbgKdpComEvent) {
|
||
DbgKdpCheckComStatus ();
|
||
}
|
||
|
||
rc = WriteFile(
|
||
DbgKdpComPort,
|
||
Buffer,
|
||
SizeOfBuffer,
|
||
BytesWritten,
|
||
&WriteOverlapped
|
||
);
|
||
|
||
if (!rc) {
|
||
|
||
if (GetLastError() == ERROR_IO_PENDING) {
|
||
|
||
rc = GetOverlappedResult(
|
||
DbgKdpComPort,
|
||
&WriteOverlapped,
|
||
BytesWritten,
|
||
TRUE
|
||
);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Device could be locked up. Clear it just in case.
|
||
//
|
||
|
||
ClearCommError(
|
||
DbgKdpComPort,
|
||
&TrashErr,
|
||
&TrashStat
|
||
);
|
||
}
|
||
}
|
||
|
||
return rc;
|
||
}
|
||
|
||
BOOLEAN
|
||
DbgKdpReadComPort(
|
||
IN PUCHAR Buffer,
|
||
IN ULONG SizeOfBuffer,
|
||
IN PULONG BytesRead
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads bytes from the COM port. Handles overlapped
|
||
IO requirements and other common com port maintanance.
|
||
|
||
--*/
|
||
{
|
||
BOOLEAN rc;
|
||
DWORD TrashErr;
|
||
COMSTAT TrashStat;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "attempted to read from the com port while debugging a crash dump\n" );
|
||
DebugBreak();
|
||
}
|
||
|
||
if (DbgKdpComEvent) {
|
||
DbgKdpCheckComStatus ();
|
||
}
|
||
|
||
rc = ReadFile(
|
||
DbgKdpComPort,
|
||
Buffer,
|
||
SizeOfBuffer,
|
||
BytesRead,
|
||
&ReadOverlapped
|
||
);
|
||
|
||
if (!rc) {
|
||
|
||
if (GetLastError() == ERROR_IO_PENDING) {
|
||
|
||
rc = GetOverlappedResult(
|
||
DbgKdpComPort,
|
||
&ReadOverlapped,
|
||
BytesRead,
|
||
TRUE
|
||
);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Device could be locked up. Clear it just in case.
|
||
//
|
||
|
||
ClearCommError(
|
||
DbgKdpComPort,
|
||
&TrashErr,
|
||
&TrashStat
|
||
);
|
||
}
|
||
}
|
||
|
||
return rc;
|
||
}
|
||
|
||
VOID
|
||
DbgKdpCheckComStatus (VOID)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Called when the com port status trigger signals a change.
|
||
This function handles the change in status.
|
||
|
||
Note: status is only monitored when being used over the modem.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
BOOLEAN rc;
|
||
ULONG br, bw;
|
||
UCHAR buf[20];
|
||
DWORD CommErr;
|
||
COMSTAT CommStat;
|
||
|
||
if (!DbgKdpComEvent) {
|
||
//
|
||
// Not triggered, just return
|
||
//
|
||
|
||
return ;
|
||
}
|
||
DbgKdpComEvent = 0;
|
||
|
||
GetCommModemStatus (DbgKdpComPort, &status);
|
||
if (!(status & 0x80)) {
|
||
dprintf ("KD: No carrier detect - in terminal mode\n");
|
||
|
||
//
|
||
// Send any keystrokes to the ComPort
|
||
//
|
||
|
||
KdPollThreadMode = OUT_TERMINAL;
|
||
|
||
//
|
||
// Loop and read any com input
|
||
//
|
||
|
||
while (!(status & 0x80)) {
|
||
GetCommModemStatus (DbgKdpComPort, &status);
|
||
rc = DbgKdpReadComPort(buf, sizeof buf, &br);
|
||
if (rc != TRUE || br == 0)
|
||
continue;
|
||
|
||
//
|
||
// print the string. someday this should probably
|
||
// be a callout.
|
||
//
|
||
|
||
WriteFile(ConsoleOutputHandle,buf,br,&bw,NULL);
|
||
|
||
//
|
||
// if logging is on, log the output
|
||
//
|
||
|
||
if (loghandle != -1) {
|
||
_write(loghandle,buf,br);
|
||
}
|
||
}
|
||
|
||
KdPollThreadMode = OUT_NORMAL;
|
||
dprintf ("KD: Carrier detect - returning to debugger\n");
|
||
|
||
ClearCommError (
|
||
DbgKdpComPort,
|
||
&CommErr,
|
||
&CommStat
|
||
);
|
||
|
||
} else {
|
||
|
||
CommErr = 0;
|
||
ClearCommError (
|
||
DbgKdpComPort,
|
||
&CommErr,
|
||
&CommStat
|
||
);
|
||
|
||
if (CommErr & 0x02) { // BUGBUG: where are these equs??
|
||
dprintf (" [FRAME ERR] ");
|
||
}
|
||
|
||
if (CommErr & 0x04) {
|
||
dprintf (" [OVERRUN ERR] ");
|
||
}
|
||
|
||
if (CommErr & 0x10) {
|
||
dprintf (" [PARITY ERR] ");
|
||
}
|
||
}
|
||
|
||
//
|
||
// Reset trigger
|
||
//
|
||
|
||
WaitCommEvent (DbgKdpComPort, &DbgKdpComEvent, &EventOverlapped);
|
||
}
|
||
|
||
VOID
|
||
DbgKdpHandlePromptString(
|
||
IN PDBGKD_DEBUG_IO IoMessage
|
||
)
|
||
{
|
||
PUCHAR IoData;
|
||
DWORD i;
|
||
DWORD j;
|
||
BOOL rc;
|
||
UCHAR c;
|
||
PUCHAR d;
|
||
|
||
IoData = (PUCHAR)(IoMessage+1);
|
||
|
||
DbgKdpPrint(IoMessage->Processor,
|
||
IoData,
|
||
(USHORT)IoMessage->u.GetString.LengthOfPromptString
|
||
);
|
||
|
||
//
|
||
// read the prompt data
|
||
//
|
||
|
||
j = 0;
|
||
d = IoData;
|
||
rc = DbgKdpGetConsoleByte(&c, 1, &i);
|
||
|
||
while ( rc == TRUE &&
|
||
i == 1 &&
|
||
j < (USHORT)IoMessage->u.GetString.LengthOfStringRead) {
|
||
|
||
if ( c == '\r' ) {
|
||
*d++ = '\0';
|
||
j++;
|
||
} else if ( c == '\n' ) {
|
||
*d++ = '\0';
|
||
j++;
|
||
break;
|
||
} else {
|
||
*d++ = c;
|
||
j++;
|
||
}
|
||
rc = DbgKdpGetConsoleByte(&c, 1, &i);
|
||
}
|
||
|
||
LastProcessorToPrint = (USHORT)-1;
|
||
if ( j < (USHORT)IoMessage->u.GetString.LengthOfStringRead ) {
|
||
IoMessage->u.GetString.LengthOfStringRead = j;
|
||
}
|
||
|
||
//
|
||
// Log the user's input
|
||
//
|
||
|
||
if (loghandle != -1) {
|
||
_write(loghandle,IoData,j);
|
||
dprintf("\n");
|
||
}
|
||
|
||
//
|
||
// Send data to the debugger-target
|
||
//
|
||
|
||
DbgKdpWritePacket(
|
||
IoMessage,
|
||
sizeof(*IoMessage),
|
||
PACKET_TYPE_KD_DEBUG_IO,
|
||
IoData,
|
||
(USHORT)IoMessage->u.GetString.LengthOfStringRead
|
||
);
|
||
}
|
||
|
||
VOID
|
||
DbgKdpPrint(
|
||
IN USHORT Processor,
|
||
IN PUCHAR String,
|
||
IN USHORT StringLength
|
||
)
|
||
{
|
||
DWORD i;
|
||
DWORD j;
|
||
UCHAR c;
|
||
PUCHAR d;
|
||
static USHORT LastProcessor = (USHORT)-1;
|
||
|
||
assert(StringLength < PACKET_MAX_SIZE - 2);
|
||
|
||
d = PrintBuf;
|
||
if (NumberProcessors > 1 && Processor != LastProcessorToPrint) {
|
||
LastProcessorToPrint = Processor;
|
||
_itoa(Processor, d, 10);
|
||
while (*d != 0) {
|
||
d++;
|
||
}
|
||
*d++ = ':';
|
||
}
|
||
|
||
for(i=0;i<StringLength;i++) {
|
||
c = *(String+i);
|
||
if ( c == '\n' ) {
|
||
LastProcessorToPrint = (USHORT)-1;
|
||
*d++ = '\n';
|
||
*d++ = '\r';
|
||
} else {
|
||
if ( c ) {
|
||
*d++ = c;
|
||
}
|
||
}
|
||
}
|
||
|
||
j = d - PrintBuf;
|
||
|
||
//
|
||
// print the string. someday this should probably
|
||
// be a callout.
|
||
|
||
WriteFile(ConsoleOutputHandle,PrintBuf,j,&i,NULL);
|
||
|
||
//
|
||
// if logging is on, log the output
|
||
//
|
||
|
||
if (loghandle != -1) {
|
||
_write(loghandle,PrintBuf,j);
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
DbgKdWaitStateChange(
|
||
OUT PDBGKD_WAIT_STATE_CHANGE StateChange,
|
||
OUT PVOID Buffer,
|
||
IN ULONG BufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function causes the calling user interface to wait for a state
|
||
change to occur in the system being debugged. Once a state change
|
||
occurs, the user interface can either continue the system using
|
||
DbgKdContinue, or it can manipulate system state using anyone of the
|
||
DbgKd state manipulation APIs.
|
||
|
||
Arguments:
|
||
|
||
StateChange - Supplies the address of state change record that
|
||
will contain the state change information.
|
||
|
||
Buffer - Supplies the address of a buffer that returns additional
|
||
information.
|
||
|
||
BufferLength - Supplies the length of Buffer.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - A state change occured. Valid state change information
|
||
was returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PDBGKD_WAIT_STATE_CHANGE LocalStateChange;
|
||
NTSTATUS st;
|
||
UCHAR *pt;
|
||
|
||
st = STATUS_UNSUCCESSFUL;
|
||
while ( st != STATUS_SUCCESS ) {
|
||
|
||
//
|
||
// Waiting for a state change message. Copy the message to the callers
|
||
// buffer, and then free the packet entry.
|
||
//
|
||
|
||
DbgKdpWaitPacketForever(
|
||
PACKET_TYPE_KD_STATE_CHANGE,
|
||
&LocalStateChange
|
||
);
|
||
LocalStateChange = (PDBGKD_WAIT_STATE_CHANGE)DbgKdpPacket;
|
||
st = STATUS_SUCCESS;
|
||
assert(StateChange);
|
||
*StateChange = *LocalStateChange;
|
||
|
||
switch ( (USHORT) StateChange->NewState ) {
|
||
case DbgKdExceptionStateChange:
|
||
//
|
||
// do signed compare here for packets shorter than
|
||
// WAIT_STATE_CHANGE struct
|
||
//
|
||
if ((LONG)BufferLength < (LONG)(PacketHeader.ByteCount - sizeof(DBGKD_WAIT_STATE_CHANGE))) {
|
||
st = STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
pt = (UCHAR *)LocalStateChange +
|
||
sizeof(DBGKD_WAIT_STATE_CHANGE);
|
||
memcpy(Buffer, pt,
|
||
PacketHeader.ByteCount - sizeof(DBGKD_WAIT_STATE_CHANGE));
|
||
}
|
||
break;
|
||
case DbgKdLoadSymbolsStateChange:
|
||
if ( BufferLength < LocalStateChange->u.LoadSymbols.PathNameLength ) {
|
||
st = STATUS_BUFFER_OVERFLOW;
|
||
} else {
|
||
pt = ((UCHAR *) LocalStateChange) + PacketHeader.ByteCount -
|
||
(int)LocalStateChange->u.LoadSymbols.PathNameLength;
|
||
memcpy(Buffer, pt,
|
||
(int)LocalStateChange->u.LoadSymbols.PathNameLength);
|
||
}
|
||
break;
|
||
default:
|
||
assert(FALSE);
|
||
}
|
||
return st;
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
DbgKdContinue (
|
||
IN NTSTATUS 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 DbgKd 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_STATE m;
|
||
PDBGKD_CONTINUE a = &m.u.Continue;
|
||
NTSTATUS st;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot continue a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
if ( ContinueStatus == DBG_EXCEPTION_HANDLED ||
|
||
ContinueStatus == DBG_EXCEPTION_NOT_HANDLED ||
|
||
ContinueStatus == DBG_CONTINUE ) {
|
||
|
||
m.ApiNumber = DbgKdContinueApi;
|
||
m.ReturnStatus = ContinueStatus;
|
||
|
||
a->ContinueStatus = ContinueStatus;
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
st = STATUS_SUCCESS;
|
||
KdpPurgeCachedVirtualMemory ();
|
||
}
|
||
else {
|
||
st = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdContinue2 (
|
||
IN NTSTATUS ContinueStatus,
|
||
IN DBGKD_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 DbgKd 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_STATE m;
|
||
NTSTATUS st;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot continue a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
if ( ContinueStatus == DBG_EXCEPTION_HANDLED ||
|
||
ContinueStatus == DBG_EXCEPTION_NOT_HANDLED ||
|
||
ContinueStatus == DBG_CONTINUE) {
|
||
|
||
m.ApiNumber = DbgKdContinueApi2;
|
||
m.ReturnStatus = ContinueStatus;
|
||
|
||
m.u.Continue2.ContinueStatus = ContinueStatus;
|
||
m.u.Continue2.ControlSet = ControlSet;
|
||
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
st = STATUS_SUCCESS;
|
||
KdpPurgeCachedVirtualMemory ();
|
||
|
||
} else {
|
||
st = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
return st;
|
||
}
|
||
|
||
NTSTATUS
|
||
DbgKdSetSpecialCalls (
|
||
IN ULONG NumSpecialCalls,
|
||
IN PULONG 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_STATE m;
|
||
ULONG i;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot continue a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
ClearTraceDataSyms();
|
||
|
||
m.ApiNumber = DbgKdClearSpecialCallsApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
KdpPurgeCachedVirtualMemory ();
|
||
|
||
for (i = 0; i < NumSpecialCalls; i++) {
|
||
|
||
m.ApiNumber = DbgKdSetSpecialCallApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
m.u.SetSpecialCall.SpecialCall = Calls[i];
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
NTSTATUS
|
||
DbgKdSetInternalBp (
|
||
ULONG 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_STATE m;
|
||
NTSTATUS st;
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot bp a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
m.ApiNumber = DbgKdSetInternalBreakPointApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
|
||
m.u.SetInternalBreakpoint.BreakpointAddress = addr;
|
||
m.u.SetInternalBreakpoint.Flags = flags;
|
||
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
st = STATUS_SUCCESS;
|
||
|
||
return st;
|
||
}
|
||
|
||
NTSTATUS
|
||
DbgKdGetInternalBp (
|
||
ULONG 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
NTSTATUS st;
|
||
ULONG rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot bp a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
m.ApiNumber = DbgKdGetInternalBreakPointApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
|
||
m.u.GetInternalBreakpoint.BreakpointAddress = addr;
|
||
|
||
do {
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
rc = DbgKdpWaitForPacket(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;
|
||
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdReadVirtualMemory(
|
||
IN PVOID 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
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS st;
|
||
ULONG BytesRead;
|
||
|
||
st = KdpReadCachedVirtualMemory (
|
||
(ULONG) TargetBaseAddress,
|
||
(ULONG) TransferCount,
|
||
(PUCHAR) UserInterfaceBuffer,
|
||
(PULONG) ActualBytesRead ? ActualBytesRead : &BytesRead
|
||
);
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdReadVirtualMemoryNow(
|
||
IN PVOID 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_READ_MEMORY a = &m.u.ReadMemory;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
ULONG cb, cb2;
|
||
|
||
if (CrashFileName) {
|
||
cb = DmpReadMemory( TargetBaseAddress, UserInterfaceBuffer, TransferCount );
|
||
if (ActualBytesRead) {
|
||
*ActualBytesRead = cb;
|
||
}
|
||
if (cb == 0) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
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
|
||
//
|
||
|
||
m.ApiNumber = DbgKdReadVirtualMemoryApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
a->TargetBaseAddress = (PVOID) ((DWORD)TargetBaseAddress+cb2);
|
||
a->TransferCount = cb;
|
||
a->ActualBytesRead = 0L;
|
||
|
||
//
|
||
// Send the message and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
|
||
rc = DbgKdpWaitForPacket(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)((DWORD)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;
|
||
}
|
||
}
|
||
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdWriteVirtualMemory(
|
||
IN PVOID 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_WRITE_MEMORY a = &m.u.WriteMemory;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
ULONG cb, cb2;
|
||
|
||
KdpWriteCachedVirtualMemory (
|
||
(ULONG) TargetBaseAddress,
|
||
(ULONG) TransferCount,
|
||
(PUCHAR) UserInterfaceBuffer
|
||
);
|
||
|
||
if (CrashFileName) {
|
||
cb = DmpWriteMemory( TargetBaseAddress, UserInterfaceBuffer, TransferCount );
|
||
if (ActualBytesWritten) {
|
||
*ActualBytesWritten = cb;
|
||
}
|
||
if (cb == 0) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
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
|
||
//
|
||
|
||
m.ApiNumber = DbgKdWriteVirtualMemoryApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
a->TargetBaseAddress = (PVOID)((DWORD)TargetBaseAddress + cb2);
|
||
a->TransferCount = cb;
|
||
a->ActualBytesWritten = 0L;
|
||
|
||
//
|
||
// Send the message and data to write and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
(PVOID)((DWORD)UserInterfaceBuffer + cb2),
|
||
(USHORT)cb
|
||
);
|
||
rc = DbgKdpWaitForPacket(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;
|
||
}
|
||
}
|
||
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdReadControlSpace(
|
||
IN USHORT Processor,
|
||
IN PVOID 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_READ_MEMORY a = &m.u.ReadMemory;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
if (!DmpReadControlSpace(
|
||
Processor,
|
||
TargetBaseAddress,
|
||
UserInterfaceBuffer,
|
||
TransferCount,
|
||
ActualBytesRead
|
||
)) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
} else {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
if ( TransferCount + sizeof(m) > PACKET_MAX_SIZE ) {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdReadControlSpaceApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
m.Processor = Processor;
|
||
a->TargetBaseAddress = TargetBaseAddress;
|
||
a->TransferCount = TransferCount;
|
||
a->ActualBytesRead = 0L;
|
||
|
||
//
|
||
// Send the message and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
|
||
rc = DbgKdpWaitForPacket(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?
|
||
//
|
||
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
return st;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdWriteControlSpace(
|
||
IN USHORT Processor,
|
||
IN PVOID 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_WRITE_MEMORY a = &m.u.WriteMemory;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
if ( TransferCount + sizeof(m) > PACKET_MAX_SIZE ) {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot write control space on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdWriteControlSpaceApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
m.Processor = Processor;
|
||
a->TargetBaseAddress = TargetBaseAddress;
|
||
a->TransferCount = TransferCount;
|
||
a->ActualBytesWritten = 0L;
|
||
|
||
//
|
||
// Send the message and data to write and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
UserInterfaceBuffer,
|
||
(USHORT)TransferCount
|
||
);
|
||
|
||
rc = DbgKdpWaitForPacket(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;
|
||
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdGetContext(
|
||
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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_GET_CONTEXT a = &m.u.GetContext;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
DmpGetContext( (ULONG)Processor, Context );
|
||
return 0;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdGetContextApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
m.Processor = Processor;
|
||
a->ContextFlags = Context->ContextFlags;
|
||
|
||
//
|
||
// Send the message and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
rc = DbgKdpWaitForPacket(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));
|
||
|
||
//
|
||
// Check if current command has been canceled. If yes, go back to
|
||
// kd prompt. BUGBUG Do we really need to check for this call?
|
||
//
|
||
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
return st;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdSetContext(
|
||
IN USHORT Processor,
|
||
IN PCONTEXT 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_SET_CONTEXT a = &m.u.SetContext;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot set context on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdSetContextApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
m.Processor = Processor;
|
||
a->ContextFlags = Context->ContextFlags;
|
||
|
||
//
|
||
// Send the message and context and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
Context,
|
||
sizeof(*Context)
|
||
);
|
||
rc = DbgKdpWaitForPacket(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.
|
||
//
|
||
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdWriteBreakPoint(
|
||
IN PVOID 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 DbgKdRestoreBreakPoint.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - The specified breakpoint write occured.
|
||
|
||
!NT_SUCCESS() - TBD
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DBGKD_MANIPULATE_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_WRITE_BREAKPOINT a = &m.u.WriteBreakPoint;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot set bps on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdWriteBreakPointApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
a->BreakPointAddress = BreakPointAddress;
|
||
|
||
//
|
||
// Send the message and context and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
rc = DbgKdpWaitForPacket(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.
|
||
//
|
||
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdRestoreBreakPoint(
|
||
IN ULONG BreakPointHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is used to restore a breakpoint to its original
|
||
value.
|
||
|
||
Arguments:
|
||
|
||
BreakPointHandle - Supplies a handle returned by
|
||
DbgKdWriteBreakPoint. 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_RESTORE_BREAKPOINT a = &m.u.RestoreBreakPoint;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot set bps on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdRestoreBreakPointApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
a->BreakPointHandle = BreakPointHandle;
|
||
|
||
//
|
||
// Send the message and context and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
rc = DbgKdpWaitForPacket(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
|
||
//
|
||
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdReadIoSpace(
|
||
IN PVOID 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_READ_WRITE_IO a = &m.u.ReadWriteIo;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot read io space on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
switch ( DataSize ) {
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
break;
|
||
default:
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdReadIoSpaceApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
|
||
a->DataSize = DataSize;
|
||
a->IoAddress = IoAddress;
|
||
|
||
//
|
||
// Send the message and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
rc = DbgKdpWaitForPacket(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?
|
||
//
|
||
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdWriteIoSpace(
|
||
IN PVOID 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_READ_WRITE_IO a = &m.u.ReadWriteIo;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot write io space on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
switch ( DataSize ) {
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
break;
|
||
default:
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdWriteIoSpaceApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
|
||
a->DataSize = DataSize;
|
||
a->IoAddress = IoAddress;
|
||
a->DataValue = DataValue;
|
||
|
||
//
|
||
// Send the message and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
rc = DbgKdpWaitForPacket(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.
|
||
//
|
||
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdReadMsr(
|
||
IN ULONG MsrReg,
|
||
OUT PULONGLONG MsrValue
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is used read a MSR at the specified location
|
||
|
||
Arguments:
|
||
|
||
MsrReg - Which model specific register to read
|
||
MsrValue - It's value
|
||
|
||
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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_READ_WRITE_MSR a = &m.u.ReadWriteMsr;
|
||
LARGE_INTEGER li;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot read MSR space on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdReadMachineSpecificRegister;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
|
||
a->Msr = MsrReg;
|
||
|
||
//
|
||
// Send the message and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
rc = DbgKdpWaitForPacket(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 == DbgKdReadMachineSpecificRegister);
|
||
|
||
//
|
||
// Reset message address to reply.
|
||
//
|
||
|
||
a = &Reply->u.ReadWriteMsr;
|
||
st = Reply->ReturnStatus;
|
||
|
||
li.LowPart = a->DataValueLow;
|
||
li.HighPart = a->DataValueHigh;
|
||
*MsrValue = li.QuadPart;
|
||
|
||
//
|
||
// Check if current command has been canceled. If yes, go back to
|
||
// kd prompt. BUGBUG Do we really need to check for this call?
|
||
//
|
||
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdWriteMsr(
|
||
IN ULONG MsrReg,
|
||
IN ULONGLONG MsrValue
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is used write a MSR to the specified location
|
||
|
||
Arguments:
|
||
|
||
MsrReg - Which model specific register to read
|
||
MsrValue - It's value
|
||
|
||
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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_READ_WRITE_MSR a = &m.u.ReadWriteMsr;
|
||
LARGE_INTEGER li;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot write MSR space on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
li.QuadPart = MsrValue;
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdWriteMachineSpecificRegister;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
|
||
a->Msr = MsrReg;
|
||
a->DataValueLow = li.LowPart;
|
||
a->DataValueHigh = li.HighPart;
|
||
|
||
//
|
||
// Send the message and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
rc = DbgKdpWaitForPacket(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 == DbgKdWriteMachineSpecificRegister);
|
||
|
||
//
|
||
// Reset message address to reply.
|
||
//
|
||
|
||
a = &Reply->u.ReadWriteMsr;
|
||
st = Reply->ReturnStatus;
|
||
|
||
//
|
||
// free the packet
|
||
//
|
||
|
||
//
|
||
// Check should we return to caller or to kd prompt.
|
||
//
|
||
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
return st;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdReadIoSpaceExtended(
|
||
IN PVOID IoAddress,
|
||
OUT PVOID ReturnedData,
|
||
IN ULONG DataSize,
|
||
IN INTERFACE_TYPE 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.
|
||
|
||
InterfaceType - The type of interface for the bus.
|
||
|
||
BusNumber - The bus number of the bus to be used. Normally this would
|
||
be zero.
|
||
|
||
AddressSpace - This contains a zero if we are using I/O memory space,
|
||
else it contains a one if we are using I/O port space.
|
||
|
||
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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_READ_WRITE_IO_EXTENDED a = &m.u.ReadWriteIoExtended;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot read io space on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
switch ( DataSize ) {
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
break;
|
||
default:
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
if ( !(AddressSpace == 0 || AddressSpace == 1) ) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdReadIoSpaceExtendedApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
|
||
a->DataSize = DataSize;
|
||
a->IoAddress = IoAddress;
|
||
a->InterfaceType = InterfaceType;
|
||
a->BusNumber = BusNumber;
|
||
a->AddressSpace = AddressSpace;
|
||
|
||
//
|
||
// Send the message and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
rc = DbgKdpWaitForPacket(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?
|
||
//
|
||
/*
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
*/
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdWriteIoSpaceExtended(
|
||
IN PVOID IoAddress,
|
||
IN ULONG DataValue,
|
||
IN ULONG DataSize,
|
||
IN INTERFACE_TYPE 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_READ_WRITE_IO_EXTENDED a = &m.u.ReadWriteIoExtended;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot write io space on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
switch ( DataSize ) {
|
||
case 1:
|
||
case 2:
|
||
case 4:
|
||
break;
|
||
default:
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
if ( !(AddressSpace == 0 || AddressSpace == 1) ) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdWriteIoSpaceExtendedApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
|
||
a->DataSize = DataSize;
|
||
a->IoAddress = IoAddress;
|
||
a->DataValue = DataValue;
|
||
a->InterfaceType = InterfaceType;
|
||
a->BusNumber = BusNumber;
|
||
a->AddressSpace = AddressSpace;
|
||
|
||
//
|
||
// Send the message and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
rc = DbgKdpWaitForPacket(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.
|
||
//
|
||
/*
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
*/
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdGetVersion (
|
||
PDBGKD_GET_VERSION GetVersion
|
||
)
|
||
{
|
||
DBGKD_MANIPULATE_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_GET_VERSION a = &m.u.GetVersion;
|
||
DWORD st;
|
||
NTSTATUS rc;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot get version packet on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
m.ApiNumber = DbgKdGetVersionApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
a->ProtocolVersion = 1; // request context records on state changes
|
||
|
||
do {
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
rc = DbgKdpWaitForPacket( PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
&Reply
|
||
);
|
||
} while (rc == FALSE);
|
||
|
||
*GetVersion = Reply->u.GetVersion;
|
||
|
||
st = Reply->ReturnStatus;
|
||
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdPageIn(
|
||
ULONG Address
|
||
)
|
||
{
|
||
DBGKD_MANIPULATE_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
NTSTATUS rc;
|
||
|
||
|
||
ZeroMemory( &m, sizeof(m) );
|
||
m.ApiNumber = DbgKdPageInApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
m.u.PageIn.Address = Address;
|
||
m.u.PageIn.ContinueStatus = DBG_CONTINUE;
|
||
|
||
do {
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
rc = DbgKdpWaitForPacket( PACKET_TYPE_KD_STATE_MANIPULATE, &Reply );
|
||
} while (rc == FALSE);
|
||
|
||
return Reply->ReturnStatus;
|
||
}
|
||
|
||
|
||
VOID far
|
||
DbgKdpKbdPollThread(VOID)
|
||
{
|
||
HANDLE StandardInputHandle;
|
||
DWORD i;
|
||
BOOLEAN rc;
|
||
UCHAR c;
|
||
|
||
//
|
||
// Capture all typed input immediately so that control-c,
|
||
// control-break, etc, get processed in a timely fashion.
|
||
// Stuff the characters into an anonymous pipe, from which
|
||
// DbgKdpGetConsole byte will read them.
|
||
//
|
||
// (WHAT??? A PIPE??? Very very simple way to get data flow
|
||
// between two threads correctly synchronized, folks.)
|
||
//
|
||
|
||
StandardInputHandle = GetStdHandle(STD_INPUT_HANDLE);
|
||
|
||
while (TRUE) {
|
||
rc = ReadFile(StandardInputHandle,&c,1,&i,NULL);
|
||
if ((rc != TRUE) || (i != 1)) {
|
||
continue;
|
||
}
|
||
|
||
switch (c) {
|
||
case CONTROL_B:
|
||
exit(0);
|
||
|
||
case CONTROL_D:
|
||
chLastCommand[0] = '\0';
|
||
KdDebug = !KdDebug;
|
||
continue;
|
||
|
||
#ifdef _PPC_
|
||
//
|
||
// Toggle register names to MIPS or PPC naming conventions
|
||
//
|
||
case CONTROL_T:
|
||
|
||
chLastCommand[0] = '\0';
|
||
ToggleRegisterNames();
|
||
continue;
|
||
#endif
|
||
|
||
case CONTROL_R:
|
||
chLastCommand[0] = '\0';
|
||
KdResync = TRUE;
|
||
continue;
|
||
|
||
case CONTROL_V:
|
||
chLastCommand[0] = '\0';
|
||
KdVerbose = !KdVerbose;
|
||
continue;
|
||
|
||
case CONTROL_X:
|
||
if (KdModemControl) {
|
||
//
|
||
// Hang up the phone..
|
||
// (for now just exit)
|
||
//
|
||
|
||
exit(0);
|
||
}
|
||
|
||
continue;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
switch (KdPollThreadMode) {
|
||
case OUT_NORMAL:
|
||
rc = WriteFile(PipeWrite, &c, 1, &i, NULL);
|
||
break;
|
||
case OUT_TERMINAL:
|
||
rc = DbgKdpWriteComPort(&c, 1, &i);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
BOOL
|
||
DbgKdpGetConsoleByte(
|
||
PVOID pBuf,
|
||
DWORD cbBuf,
|
||
LPDWORD pcbBytesRead
|
||
)
|
||
{
|
||
return ReadFile(PipeRead,pBuf,cbBuf,pcbBytesRead,NULL);
|
||
}
|
||
|
||
|
||
PUCHAR
|
||
DbgKdGets(
|
||
PUCHAR Buffer,
|
||
USHORT Length
|
||
)
|
||
{
|
||
DWORD i;
|
||
BOOLEAN rc;
|
||
USHORT j;
|
||
UCHAR c;
|
||
|
||
for (j = 0; (j+1) < Length; j++) {
|
||
|
||
rc = DbgKdpGetConsoleByte(&c, 1, &i);
|
||
|
||
if ((rc != TRUE) || (i != 1)) {
|
||
}
|
||
|
||
if (c == '\n') {
|
||
Buffer[j] = '\n';
|
||
Buffer[j+1] = '\0';
|
||
return Buffer;
|
||
}
|
||
|
||
Buffer[j] = c;
|
||
|
||
}
|
||
Buffer[j-1] = '\0';
|
||
return Buffer;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdReboot(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function reboots being debugged.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DBGKD_MANIPULATE_STATE m;
|
||
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot reboot a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdRebootApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
|
||
//
|
||
// Send the message.
|
||
//
|
||
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
KdpPurgeCachedVirtualMemory ();
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdCrash(
|
||
DWORD BugCheckCode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function reboots being debugged.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DBGKD_MANIPULATE_STATE m;
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot crash a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Format state manipulate message
|
||
//
|
||
|
||
m.ApiNumber = DbgKdCauseBugCheckApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
*(PULONG)&m.u = BugCheckCode;
|
||
|
||
//
|
||
// Send the message.
|
||
//
|
||
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
KdpPurgeCachedVirtualMemory ();
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdReadPhysicalMemory(
|
||
IN PHYSICAL_ADDRESS 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_READ_MEMORY a = &m.u.ReadMemory;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
ULONG cb, cb2;
|
||
|
||
if (CrashFileName) {
|
||
cb = DmpReadPhysicalMemory( (PVOID)TargetBaseAddress.LowPart, UserInterfaceBuffer, TransferCount );
|
||
if (ActualBytesRead) {
|
||
*ActualBytesRead = cb;
|
||
}
|
||
if (cb == 0) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
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
|
||
//
|
||
|
||
m.ApiNumber = DbgKdReadPhysicalMemoryApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
//
|
||
// BUGBUG TargetBaseAddress should be >32 bits
|
||
//
|
||
a->TargetBaseAddress = (PVOID)(TargetBaseAddress.LowPart+cb2);
|
||
a->TransferCount = cb;
|
||
a->ActualBytesRead = 0L;
|
||
|
||
//
|
||
// Send the message and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
|
||
rc = DbgKdpWaitForPacket(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)((DWORD) UserInterfaceBuffer+cb2), Reply+1, (int)a->ActualBytesRead);
|
||
|
||
//
|
||
// Check if current command has been canceled. If yes, go back to
|
||
// kd prompt.
|
||
//
|
||
|
||
if (DbgKdpCmdCanceled) {
|
||
longjmp(cmd_return, 1);
|
||
}
|
||
|
||
if (st != STATUS_SUCCESS) {
|
||
TransferCount = 0;
|
||
} else {
|
||
TransferCount -= cb;
|
||
cb2 += cb;
|
||
cb = PACKET_MAX_SIZE;
|
||
}
|
||
}
|
||
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdWritePhysicalMemory(
|
||
IN PHYSICAL_ADDRESS 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_STATE m;
|
||
PDBGKD_MANIPULATE_STATE Reply;
|
||
PDBGKD_WRITE_MEMORY a = &m.u.WriteMemory;
|
||
NTSTATUS st;
|
||
BOOLEAN rc;
|
||
ULONG cb, cb2;
|
||
|
||
KdpPurgeCachedVirtualMemory ();
|
||
|
||
if (CrashFileName) {
|
||
cb = DmpWritePhysicalMemory( (PVOID)TargetBaseAddress.LowPart, UserInterfaceBuffer, TransferCount );
|
||
if (ActualBytesWritten) {
|
||
*ActualBytesWritten = cb;
|
||
}
|
||
if (cb == 0) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
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
|
||
//
|
||
|
||
m.ApiNumber = DbgKdWritePhysicalMemoryApi;
|
||
m.ReturnStatus = STATUS_PENDING;
|
||
//
|
||
// BUGBUG TargetBaseAddress should be >32 bits
|
||
//
|
||
a->TargetBaseAddress = (PVOID)(TargetBaseAddress.LowPart+cb2);
|
||
a->TransferCount = cb;
|
||
a->ActualBytesWritten = 0L;
|
||
|
||
//
|
||
// Send the message and data to write and then wait for reply
|
||
//
|
||
|
||
do {
|
||
DbgKdpWritePacket(
|
||
&m,
|
||
sizeof(m),
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
(PVOID)((DWORD)UserInterfaceBuffer+cb2),
|
||
(USHORT)cb
|
||
);
|
||
|
||
rc = DbgKdpWaitForPacket(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;
|
||
}
|
||
}
|
||
|
||
return st;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DbgKdSwitchActiveProcessor (
|
||
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_STATE m;
|
||
|
||
if (CrashFileName) {
|
||
dprintf( "cannot change active processors on a crash dump" );
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
m.ApiNumber = (USHORT)DbgKdSwitchProcessor;
|
||
m.Processor = (USHORT)ProcessorNumber;
|
||
|
||
DbgKdpWritePacket(&m,sizeof(m),PACKET_TYPE_KD_STATE_MANIPULATE,NULL,0);
|
||
KdpPurgeCachedVirtualMemory ();
|
||
return STATUS_SUCCESS;
|
||
}
|