mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1757 lines
39 KiB
1757 lines
39 KiB
#include "givit.h"
|
|
|
|
|
|
extern HANDLE PipeRead; // see DbgKdpKbdPollThread
|
|
extern HANDLE PipeWrite;
|
|
extern ULONG NumberProcessors;
|
|
static SHORT LastProcessorToPrint = -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 = FALSE;
|
|
|
|
BOOLEAN KdDebug = FALSE;
|
|
|
|
BOOLEAN KdResync = FALSE;
|
|
UCHAR PrintBuf[PACKET_MAX_SIZE];
|
|
|
|
#define CONTROL_B 2
|
|
#define CONTROL_D 4
|
|
#define CONTROL_R 18
|
|
#define CONTROL_V 22
|
|
|
|
ULONG DbgKdpPacketExpected; // ID for expected incoming packet
|
|
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); \
|
|
}
|
|
|
|
DWORD
|
|
DbgKdConnectAndInitialize(
|
|
)
|
|
{
|
|
|
|
DWORD BytesWritten;
|
|
BOOL rc;
|
|
USHORT Length;
|
|
|
|
//
|
|
// Initialize comport, packet queue and start the packet receiving
|
|
// thread.
|
|
//
|
|
|
|
DbgKdpInitComPort(0L);
|
|
DbgKdpPacketExpected = INITIAL_PACKET_ID;
|
|
DbgKdpNextPacketToSend = INITIAL_PACKET_ID;
|
|
|
|
DbgKdpStartThreads();
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
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 = -1;
|
|
if ( j < (USHORT)IoMessage->u.GetString.LengthOfStringRead ) {
|
|
IoMessage->u.GetString.LengthOfStringRead = j;
|
|
}
|
|
|
|
//
|
|
// 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 SHORT LastProcessor = -1;
|
|
|
|
assert(StringLength < PACKET_MAX_SIZE - 2);
|
|
|
|
d = PrintBuf;
|
|
if (NumberProcessors > 1 && Processor != LastProcessorToPrint) {
|
|
assert(Processor < 8);
|
|
LastProcessorToPrint = Processor;
|
|
*d++ = (UCHAR)((UCHAR)Processor + '0');
|
|
*d++ = ':';
|
|
j = 2;
|
|
} else {
|
|
j = 0;
|
|
}
|
|
for(i=0;i<StringLength;i++) {
|
|
c = *(String+i);
|
|
if ( c == '\n' ) {
|
|
LastProcessorToPrint = -1;
|
|
*d++ = '\n';
|
|
*d++ = '\r';
|
|
j += 2;
|
|
} else {
|
|
if ( c ) {
|
|
*d++ = c;
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// print the string. someday this should probably
|
|
// be a callout.
|
|
|
|
WriteFile(ConsoleOutputHandle,PrintBuf,j,&i,NULL);
|
|
}
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - A state change occured. Valid state change information
|
|
was returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PDBGKD_WAIT_STATE_CHANGE LocalStateChange;
|
|
DWORD st;
|
|
UCHAR *pt;
|
|
|
|
st = ERROR_INVALID_FUNCTION;
|
|
while ( st != ERROR_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 = ERROR_SUCCESS;
|
|
assert(StateChange);
|
|
*StateChange = *LocalStateChange;
|
|
|
|
switch ( (USHORT) StateChange->NewState ) {
|
|
case DbgKdExceptionStateChange:
|
|
break;
|
|
case DbgKdLoadSymbolsStateChange:
|
|
if ( BufferLength < LocalStateChange->u.LoadSymbols.PathNameLength ) {
|
|
st = ERROR_MORE_DATA;
|
|
} 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;
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
DbgKdContinue (
|
|
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 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:
|
|
|
|
ERROR_SUCCESS - Successful call to DbgUiContinue
|
|
|
|
ERROR_INVALID_PARAMETER - An invalid continue status or was
|
|
specified.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_CONTINUE a = &m.u.Continue;
|
|
DWORD st;
|
|
|
|
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 = ERROR_SUCCESS;
|
|
}
|
|
else {
|
|
st = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
DWORD
|
|
DbgKdContinue2 (
|
|
IN DWORD 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:
|
|
|
|
ERROR_SUCCESS - Successful call to DbgUiContinue
|
|
|
|
ERROR_INVALID_PARAMETER - An invalid continue status or was
|
|
specified.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
DWORD st;
|
|
|
|
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 = ERROR_SUCCESS;
|
|
|
|
} else {
|
|
st = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return st;
|
|
}
|
|
|
|
DWORD
|
|
DbgKdReadVirtualMemory(
|
|
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:
|
|
|
|
ERROR_SUCCESS - The specified read occured.
|
|
|
|
ERROR_MORE_DATA - A read that is to large was specified.
|
|
|
|
ERROR_NO_ACCESS - The TargetBaseAddress/TransferCount
|
|
parameters refers to invalid virtual memory.
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_READ_MEMORY a = &m.u.ReadMemory;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
if ( TransferCount + sizeof(m) > PACKET_MAX_SIZE ) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdReadVirtualMemoryApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
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 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 <= TransferCount);
|
|
|
|
//
|
|
// Return actual bytes read, and then transfer the bytes
|
|
//
|
|
|
|
if (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);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - The specified read occured.
|
|
|
|
ERROR_MORE_DATA - A read that is to large was specified.
|
|
|
|
ERROR_NO_ACCESS - The TargetBaseAddress/TransferCount
|
|
parameters refers to invalid virtual memory.
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_WRITE_MEMORY a = &m.u.WriteMemory;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
if ( TransferCount + sizeof(m) > PACKET_MAX_SIZE ) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdWriteVirtualMemoryApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
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 WriteMemory response than protocol is screwed up.
|
|
// assert that protocol is ok.
|
|
//
|
|
|
|
st = Reply->ReturnStatus;
|
|
assert(Reply->ApiNumber == DbgKdWriteVirtualMemoryApi);
|
|
|
|
//
|
|
// Reset message address to reply.
|
|
//
|
|
|
|
a = &Reply->u.WriteMemory;
|
|
assert(a->ActualBytesWritten <= TransferCount);
|
|
|
|
//
|
|
// Return actual bytes written
|
|
//
|
|
|
|
if (ActualBytesWritten) {
|
|
*ActualBytesWritten = a->ActualBytesWritten;
|
|
}
|
|
st = Reply->ReturnStatus;
|
|
|
|
return st;
|
|
}
|
|
|
|
DWORD
|
|
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.
|
|
|
|
|
|
On x86, control space is a per-processor area which contains:
|
|
|
|
Current Context (CONTEXT)
|
|
Special Registers (KSPECIAL_REGISTERS)
|
|
|
|
This means that to read the special registers:
|
|
|
|
DbgKdReadControlSpace(
|
|
NtsdCurrentProcessor,
|
|
(PVOID)sizeof(CONTEXT),
|
|
(PVOID)&SpecialRegContext,
|
|
sizeof(KSPECIAL_REGISTERS),
|
|
&cBytesRead
|
|
);
|
|
|
|
The above will read the special registers of the current processor
|
|
since the control space address is sizeof(CONTEXT)
|
|
|
|
On MIPS, control space addresses are used to address the translation
|
|
buffer.
|
|
|
|
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:
|
|
|
|
ERROR_SUCCESS - The specified read occured.
|
|
|
|
ERROR_MORE_DATA - A read that is to large was specified.
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_READ_MEMORY a = &m.u.ReadMemory;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
if ( TransferCount + sizeof(m) > PACKET_MAX_SIZE ) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// 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 (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);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - The specified read occured.
|
|
|
|
ERROR_MORE_DATA - A read that is to large was specified.
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_WRITE_MEMORY a = &m.u.WriteMemory;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
if ( TransferCount + sizeof(m) > PACKET_MAX_SIZE ) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - The specified get context occured.
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_GET_CONTEXT a = &m.u.GetContext;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
//
|
|
// 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));
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - The specified set context occured.
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_SET_CONTEXT a = &m.u.SetContext;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
//
|
|
// 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;
|
|
|
|
return st;
|
|
}
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - The specified breakpoint write occured.
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_WRITE_BREAKPOINT a = &m.u.WriteBreakPoint;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
//
|
|
// 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;
|
|
|
|
return st;
|
|
}
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - The specified breakpoint restore occured.
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_RESTORE_BREAKPOINT a = &m.u.RestoreBreakPoint;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - Data was successfully read from the I/O
|
|
address.
|
|
|
|
ERROR_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was
|
|
specified.
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_READ_WRITE_IO a = &m.u.ReadWriteIo;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
switch ( DataSize ) {
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
break;
|
|
default:
|
|
return ERROR_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;
|
|
}
|
|
|
|
return st;
|
|
}
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - Data was successfully written to the I/O
|
|
address.
|
|
|
|
ERROR_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was
|
|
specified.
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_READ_WRITE_IO a = &m.u.ReadWriteIo;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
switch ( DataSize ) {
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
break;
|
|
default:
|
|
return ERROR_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
|
|
//
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
if (c == CONTROL_B) {
|
|
exit(0);
|
|
} else if (c == CONTROL_D) {
|
|
chLastCommand[0] = '\0';
|
|
if (KdDebug) {
|
|
KdDebug = FALSE;
|
|
} else {
|
|
KdDebug = TRUE;
|
|
}
|
|
continue;
|
|
} else if (c == CONTROL_R) {
|
|
KdResync = TRUE;
|
|
chLastCommand[0] = '\0';
|
|
continue;
|
|
}
|
|
rc = WriteFile(PipeWrite, &c, 1, &i, NULL);
|
|
if ((rc != TRUE) || (i != 1)) {
|
|
continue;
|
|
}
|
|
// FlushFileBuffers(PipeWrite);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
DbgKdReboot(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reboots being debugged.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
|
|
//
|
|
// 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);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - The specified read occured.
|
|
|
|
ERROR_MORE_DATA - A read that is too large was specified.
|
|
|
|
ERROR_NO_ACCESS - TBD // Can you even HAVE an access
|
|
// violation with a physical
|
|
// memory access??
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_READ_MEMORY a = &m.u.ReadMemory;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
if ( TransferCount + sizeof(m) > PACKET_MAX_SIZE ) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdReadPhysicalMemoryApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
//
|
|
// BUGBUG TargetBaseAddress should be >32 bits
|
|
//
|
|
a->TargetBaseAddress = (PVOID)TargetBaseAddress.LowPart;
|
|
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 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 <= TransferCount);
|
|
|
|
//
|
|
// Return actual bytes read, and then transfer the bytes
|
|
//
|
|
|
|
if (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);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
DWORD
|
|
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:
|
|
|
|
ERROR_SUCCESS - The specified read occured.
|
|
|
|
ERROR_MORE_DATA - A read that is to large was specified.
|
|
|
|
ERROR_NO_ACCESS - TBD // Can you even HAVE an access
|
|
// violation with a physical
|
|
// memory access??
|
|
|
|
!ERROR_SUCCESS - TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE m;
|
|
PDBGKD_MANIPULATE_STATE Reply;
|
|
PDBGKD_WRITE_MEMORY a = &m.u.WriteMemory;
|
|
DWORD st;
|
|
BOOLEAN rc;
|
|
|
|
if ( TransferCount + sizeof(m) > PACKET_MAX_SIZE ) {
|
|
return ERROR_MORE_DATA;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdWritePhysicalMemoryApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
//
|
|
// BUGBUG TargetBaseAddress should be >32 bits
|
|
//
|
|
a->TargetBaseAddress = (PVOID)TargetBaseAddress.LowPart;
|
|
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 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 <= TransferCount);
|
|
|
|
//
|
|
// Return actual bytes written
|
|
//
|
|
|
|
if (ActualBytesWritten) {
|
|
*ActualBytesWritten = a->ActualBytesWritten;
|
|
}
|
|
st = Reply->ReturnStatus;
|
|
|
|
return st;
|
|
}
|