mirror of https://github.com/tongzx/nt5src
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.
2824 lines
66 KiB
2824 lines
66 KiB
/*++
|
|
|
|
Copyright (c) 1990-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dbgkdapi.cpp
|
|
|
|
Abstract:
|
|
|
|
This module implements the DbgKd APIs
|
|
|
|
--*/
|
|
|
|
#include "ntsdp.hpp"
|
|
|
|
BOOL DbgKdApi64;
|
|
|
|
ULONG g_KdMaxPacketType;
|
|
ULONG g_KdMaxStateChange;
|
|
ULONG g_KdMaxManipulate;
|
|
|
|
//++
|
|
//
|
|
// 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 ) { \
|
|
ULONG WaitStatus; \
|
|
do { \
|
|
WaitStatus = g_DbgKdTransport->WaitForPacket( \
|
|
PacketType, \
|
|
Buffer \
|
|
); \
|
|
} while (WaitStatus != DBGKD_WAIT_PACKET); \
|
|
}
|
|
|
|
#define COPYSE(p64, p32, f) p64->f = (ULONG64)(LONG64)(LONG)p32->f
|
|
|
|
void
|
|
WaitStateChange32ToAny(
|
|
IN PDBGKD_WAIT_STATE_CHANGE32 Ws32,
|
|
IN ULONG ControlReportSize,
|
|
OUT PDBGKD_ANY_WAIT_STATE_CHANGE WsAny
|
|
)
|
|
{
|
|
WsAny->NewState = Ws32->NewState;
|
|
WsAny->ProcessorLevel = Ws32->ProcessorLevel;
|
|
WsAny->Processor = Ws32->Processor;
|
|
WsAny->NumberProcessors = Ws32->NumberProcessors;
|
|
COPYSE(WsAny, Ws32, Thread);
|
|
COPYSE(WsAny, Ws32, ProgramCounter);
|
|
memcpy(&WsAny->ControlReport, Ws32 + 1, ControlReportSize);
|
|
if (Ws32->NewState == DbgKdLoadSymbolsStateChange)
|
|
{
|
|
DbgkdLoadSymbols32To64(&Ws32->u.LoadSymbols, &WsAny->u.LoadSymbols);
|
|
}
|
|
else
|
|
{
|
|
DbgkmException32To64(&Ws32->u.Exception, &WsAny->u.Exception);
|
|
}
|
|
}
|
|
|
|
#undef COPYSE
|
|
|
|
NTSTATUS
|
|
DbgKdWaitStateChange(
|
|
OUT PDBGKD_ANY_WAIT_STATE_CHANGE StateChange,
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferLength,
|
|
IN BOOL SuspendEngine
|
|
)
|
|
|
|
/*++
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PVOID LocalStateChange;
|
|
NTSTATUS Status;
|
|
PUCHAR Data;
|
|
ULONG SizeofStateChange;
|
|
|
|
//
|
|
// Waiting for a state change message. Copy the message to the callers
|
|
// buffer.
|
|
//
|
|
|
|
DBG_ASSERT(g_DbgKdTransport->m_WaitingThread == 0);
|
|
g_DbgKdTransport->m_WaitingThread = GetCurrentThreadId();
|
|
if (SuspendEngine)
|
|
{
|
|
SUSPEND_ENGINE();
|
|
}
|
|
|
|
DbgKdpWaitPacketForever(
|
|
PACKET_TYPE_KD_STATE_CHANGE64,
|
|
&LocalStateChange
|
|
);
|
|
|
|
if (SuspendEngine)
|
|
{
|
|
RESUME_ENGINE();
|
|
}
|
|
g_DbgKdTransport->m_WaitingThread = 0;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
// If this is the very first wait we don't know what machine
|
|
// type we've connected to. Update the version information
|
|
// right away.
|
|
if (g_TargetMachineType == IMAGE_FILE_MACHINE_UNKNOWN)
|
|
{
|
|
g_DbgKdTransport->SaveReadPacket();
|
|
|
|
g_Target->GetKdVersion();
|
|
|
|
g_DbgKdTransport->RestoreReadPacket();
|
|
|
|
if (g_TargetMachineType == IMAGE_FILE_MACHINE_UNKNOWN)
|
|
{
|
|
//
|
|
// We were unable to determine what kind of machine
|
|
// has connected so we cannot properly communicate with it.
|
|
//
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
if (DbgKdApi64)
|
|
{
|
|
if (g_KdVersion.ProtocolVersion < DBGKD_64BIT_PROTOCOL_VERSION2)
|
|
{
|
|
PDBGKD_WAIT_STATE_CHANGE64 Ws64 =
|
|
(PDBGKD_WAIT_STATE_CHANGE64)LocalStateChange;
|
|
ULONG Offset, Align, Pad;
|
|
|
|
//
|
|
// The 64-bit structures contain 64-bit quantities and
|
|
// therefore the compiler rounds the total size up to
|
|
// an even multiple of 64 bits (or even more, the IA64
|
|
// structures are 16-byte aligned). Internal structures
|
|
// are also aligned, so make sure that we account for any
|
|
// padding. Knowledge of which structures need which
|
|
// padding pretty much has to be hard-coded in.
|
|
//
|
|
|
|
C_ASSERT((sizeof(DBGKD_WAIT_STATE_CHANGE64) & 15) == 0);
|
|
|
|
SizeofStateChange =
|
|
sizeof(DBGKD_WAIT_STATE_CHANGE64) +
|
|
g_TargetMachine->m_SizeControlReport +
|
|
g_TargetMachine->m_SizeTargetContext;
|
|
|
|
// We shouldn't need to align the base of the control report
|
|
// so copy the base data and control report.
|
|
Offset = sizeof(DBGKD_WAIT_STATE_CHANGE64) +
|
|
g_TargetMachine->m_SizeControlReport;
|
|
memcpy(StateChange, Ws64, Offset);
|
|
|
|
//
|
|
// Add alignment padding before the context.
|
|
//
|
|
|
|
switch(g_TargetMachineType)
|
|
{
|
|
case IMAGE_FILE_MACHINE_IA64:
|
|
Align = 15;
|
|
break;
|
|
default:
|
|
Align = 7;
|
|
break;
|
|
}
|
|
|
|
Pad = ((Offset + Align) & ~Align) - Offset;
|
|
Offset += Pad;
|
|
SizeofStateChange += Pad;
|
|
|
|
//
|
|
// Add alignment padding after the context.
|
|
//
|
|
|
|
Offset += g_TargetMachine->m_SizeTargetContext;
|
|
Pad = ((Offset + Align) & ~Align) - Offset;
|
|
SizeofStateChange += Pad;
|
|
}
|
|
else
|
|
{
|
|
PDBGKD_ANY_WAIT_STATE_CHANGE WsAny =
|
|
(PDBGKD_ANY_WAIT_STATE_CHANGE)LocalStateChange;
|
|
SizeofStateChange = sizeof(*WsAny);
|
|
*StateChange = *WsAny;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SizeofStateChange =
|
|
sizeof(DBGKD_WAIT_STATE_CHANGE32) +
|
|
g_TargetMachine->m_SizeControlReport +
|
|
g_TargetMachine->m_SizeTargetContext;
|
|
WaitStateChange32ToAny((PDBGKD_WAIT_STATE_CHANGE32)LocalStateChange,
|
|
g_TargetMachine->m_SizeControlReport,
|
|
StateChange);
|
|
}
|
|
|
|
switch(StateChange->NewState)
|
|
{
|
|
case DbgKdExceptionStateChange:
|
|
case DbgKdCommandStringStateChange:
|
|
if (BufferLength <
|
|
(g_DbgKdTransport->s_PacketHeader.ByteCount - SizeofStateChange))
|
|
{
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
Data = (UCHAR *)LocalStateChange + SizeofStateChange;
|
|
memcpy(Buffer, Data,
|
|
g_DbgKdTransport->s_PacketHeader.ByteCount -
|
|
SizeofStateChange);
|
|
}
|
|
break;
|
|
case DbgKdLoadSymbolsStateChange:
|
|
if ( BufferLength < StateChange->u.LoadSymbols.PathNameLength )
|
|
{
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
Data = ((UCHAR *) LocalStateChange) +
|
|
g_DbgKdTransport->s_PacketHeader.ByteCount -
|
|
(int)StateChange->u.LoadSymbols.PathNameLength;
|
|
memcpy(Buffer, Data,
|
|
(int)StateChange->u.LoadSymbols.PathNameLength);
|
|
}
|
|
break;
|
|
default:
|
|
ErrOut("Unknown state change type %X\n", StateChange->NewState);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
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_STATE64 m;
|
|
PDBGKD_CONTINUE a = &m.u.Continue;
|
|
NTSTATUS st;
|
|
|
|
if ( ContinueStatus == DBG_EXCEPTION_HANDLED ||
|
|
ContinueStatus == DBG_EXCEPTION_NOT_HANDLED ||
|
|
ContinueStatus == DBG_CONTINUE )
|
|
{
|
|
m.ApiNumber = DbgKdContinueApi;
|
|
m.ReturnStatus = ContinueStatus;
|
|
|
|
a->ContinueStatus = ContinueStatus;
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
st = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
st = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
KdOut("DbgKdContinue returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdContinue2 (
|
|
IN NTSTATUS ContinueStatus,
|
|
IN DBGKD_ANY_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_STATE64 m;
|
|
NTSTATUS 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.AnyControlSet = ControlSet;
|
|
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
st = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
st = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
KdOut("DbgKdContinue2 returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdSetSpecialCalls (
|
|
IN ULONG NumSpecialCalls,
|
|
IN PULONG64 Calls
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inform the debugged kernel that calls to these addresses
|
|
are "special" calls, and they should result in callbacks
|
|
to the kernel debugger rather than continued local stepping.
|
|
The new values *replace* any old ones that may have previously
|
|
set (not that you're likely to want to change this).
|
|
|
|
Arguments:
|
|
|
|
NumSpecialCalls - how many special calls there are
|
|
|
|
Calls - pointer to an array of calls.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Successful call to DbgUiContinue
|
|
|
|
STATUS_INVALID_PARAMETER - The number of special calls
|
|
wasn't between 0 and MAX_SPECIAL_CALLS.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
ULONG i;
|
|
|
|
m.ApiNumber = DbgKdClearSpecialCallsApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
InvalidateMemoryCaches();
|
|
|
|
for (i = 0; i < NumSpecialCalls; i++)
|
|
{
|
|
m.ApiNumber = DbgKdSetSpecialCallApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
m.u.SetSpecialCall.SpecialCall = Calls[i];
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
}
|
|
|
|
KdOut("DbgKdSetSpecialCalls returns 0x00000000\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdSetInternalBp (
|
|
ULONG64 addr,
|
|
ULONG flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inform the debugged kernel that a breakpoint at this address
|
|
is to be internally counted, and not result in a callback to the
|
|
remote debugger (us). This function DOES NOT cause the kernel to
|
|
set the breakpoint; the debugger must do that independently.
|
|
|
|
Arguments:
|
|
|
|
Addr - address of the breakpoint
|
|
|
|
Flags - the breakpoint flags to set (note: if the invalid bit
|
|
is set, this CLEARS a breakpoint).
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Successful call to DbgUiContinue
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
NTSTATUS st;
|
|
|
|
m.ApiNumber = DbgKdSetInternalBreakPointApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
#ifdef IBP_WORKAROUND
|
|
// The kernel code keeps a ULONG64 for an internal breakpoint
|
|
// address but older kernels did not sign-extend the current IP
|
|
// when comparing against them. In order to work with both
|
|
// broken and fixed kernels send down zero-extended addresses.
|
|
// Don't actually enable this workaround right now as other
|
|
// internal breakpoint bugs can cause the machine to bugcheck.
|
|
addr = g_TargetMachine->m_Ptr64 ? addr : (ULONG)addr;
|
|
#endif
|
|
|
|
m.u.SetInternalBreakpoint.BreakpointAddress = addr;
|
|
m.u.SetInternalBreakpoint.Flags = flags;
|
|
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
|
|
KdOut("DbgKdSetInternalBp returns 0x00000000\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdGetInternalBp (
|
|
ULONG64 addr,
|
|
PULONG flags,
|
|
PULONG calls,
|
|
PULONG minInstr,
|
|
PULONG maxInstr,
|
|
PULONG totInstr,
|
|
PULONG maxCPS
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Query the status of an internal breakpoint from the debugged
|
|
kernel and return the data to the caller.
|
|
|
|
Arguments:
|
|
|
|
Addr - address of the breakpoint
|
|
|
|
flags, calls, minInstr, maxInstr, totInstr - values returned
|
|
describing the particular breakpoint. flags will contain
|
|
the invalid bit if the breakpoint is bogus.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Successful call to DbgUiContinue
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
m.ApiNumber = DbgKdGetInternalBreakPointApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
#ifdef IBP_WORKAROUND
|
|
// The kernel code keeps a ULONG64 for an internal breakpoint
|
|
// address but older kernels did not sign-extend the current IP
|
|
// when comparing against them. In order to work with both
|
|
// broken and fixed kernels send down zero-extended addresses.
|
|
// Don't actually enable this workaround right now as other
|
|
// internal breakpoint bugs can cause the machine to bugcheck.
|
|
addr = g_TargetMachine->m_Ptr64 ? addr : (ULONG)addr;
|
|
#endif
|
|
|
|
m.u.GetInternalBreakpoint.BreakpointAddress = addr;
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
}
|
|
while (rc != DBGKD_WAIT_PACKET);
|
|
|
|
*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;
|
|
|
|
KdOut("DbgKdGetInternalBp returns 0x00000000\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdClearAllInternalBreakpoints(
|
|
void
|
|
)
|
|
{
|
|
if (g_KdMaxManipulate <= DbgKdClearAllInternalBreakpointsApi)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
DBGKD_MANIPULATE_STATE64 Request;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
Request.ApiNumber = DbgKdClearAllInternalBreakpointsApi;
|
|
Request.ReturnStatus = STATUS_PENDING;
|
|
|
|
g_DbgKdTransport->WritePacket(&Request, sizeof(Request),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
|
|
KdOut("DbgKdClearAllInternalBreakpoints returns 0x%08X\n", Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdReadVirtualMemoryNow(
|
|
IN ULONG64 TargetBaseAddress,
|
|
OUT PVOID UserInterfaceBuffer,
|
|
IN ULONG TransferCount,
|
|
OUT PULONG ActualBytesRead
|
|
)
|
|
|
|
/*++
|
|
|
|
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 - Supplies a pointer to the variable that receives the
|
|
the number of bytes actually read.
|
|
|
|
Return Value:
|
|
|
|
If the read operation is successful, then a success status is returned.
|
|
Otherwise, and unsuccessful status is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG cb;
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
ULONG rc;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if (g_VirtualCache.m_ForceDecodePTEs)
|
|
{
|
|
return DbgKdReadVirtualTranslatedMemory(TargetBaseAddress,
|
|
UserInterfaceBuffer,
|
|
TransferCount,
|
|
ActualBytesRead);
|
|
}
|
|
|
|
cb = 0;
|
|
while (TransferCount != 0)
|
|
{
|
|
//
|
|
// Exit on user interrupt
|
|
//
|
|
if (g_EngStatus & ENG_STATUS_USER_INTERRUPT)
|
|
{
|
|
// dprintf("User interrupt during memory read - exiting.\n");
|
|
ActualBytesRead = 0;
|
|
return STATUS_CONTROL_C_EXIT;
|
|
}
|
|
|
|
//
|
|
// Initialize state manipulate message to read virtual memory.
|
|
//
|
|
|
|
m.ApiNumber = DbgKdReadVirtualMemoryApi;
|
|
m.u.ReadMemory.TargetBaseAddress = TargetBaseAddress + cb;
|
|
m.u.ReadMemory.TransferCount = min(TransferCount, PACKET_MAX_SIZE);
|
|
|
|
//
|
|
// Send the read virtual message to the target system and wait for
|
|
// a reply.
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
}
|
|
while ((rc != DBGKD_WAIT_PACKET) ||
|
|
(Reply->ApiNumber != DbgKdReadVirtualMemoryApi));
|
|
|
|
//
|
|
// If the read virtual is successful, then copy the next segment
|
|
// of data to the target buffer. Otherwise, terminate the read and
|
|
// return the number of bytes read.
|
|
//
|
|
|
|
Status = Reply->ReturnStatus;
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
else if (Reply->u.ReadMemory.ActualBytesRead == 0)
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ULONG Copy;
|
|
|
|
if (Reply->u.ReadMemory.ActualBytesRead > TransferCount)
|
|
{
|
|
ErrOut("DbgKdReadVirtualMemoryNow: Asked for %d, got %d\n",
|
|
TransferCount, Reply->u.ReadMemory.ActualBytesRead);
|
|
Copy = TransferCount;
|
|
}
|
|
else
|
|
{
|
|
Copy = Reply->u.ReadMemory.ActualBytesRead;
|
|
}
|
|
|
|
memcpy((PUCHAR)UserInterfaceBuffer + cb,
|
|
Reply + 1,
|
|
Copy);
|
|
|
|
TransferCount -= Copy;
|
|
cb += Copy;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the number of bytes actually read and return the status of the
|
|
// read operation.
|
|
//
|
|
|
|
*ActualBytesRead = cb;
|
|
|
|
KdOut("DbgKdReadVirtualMemoryNow(%s) returns %08lx, %X read\n",
|
|
FormatAddr64(TargetBaseAddress), Status, cb);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdWriteVirtualMemoryNow(
|
|
IN ULONG64 TargetBaseAddress,
|
|
OUT PVOID UserInterfaceBuffer,
|
|
IN ULONG TransferCount,
|
|
OUT PULONG ActualBytesWritten
|
|
)
|
|
|
|
/*++
|
|
|
|
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 necessarily 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 - Supplies a pointer to a variable that receives the
|
|
actual number of bytes written.
|
|
|
|
Return Value:
|
|
|
|
If the write operation is successful, then a success status is returned.
|
|
Otherwise, and unsuccessful status is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG cb;
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
ULONG rc;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DBG_ASSERT(g_TargetMachine->m_Ptr64 ||
|
|
EXTEND64((ULONG)TargetBaseAddress) == TargetBaseAddress);
|
|
|
|
if (g_VirtualCache.m_ForceDecodePTEs)
|
|
{
|
|
return DbgKdWriteVirtualTranslatedMemory(TargetBaseAddress,
|
|
UserInterfaceBuffer,
|
|
TransferCount,
|
|
ActualBytesWritten);
|
|
}
|
|
|
|
cb = 0;
|
|
while (TransferCount != 0)
|
|
{
|
|
//
|
|
// Initialize state manipulate message to write virtual memory.
|
|
//
|
|
|
|
m.ApiNumber = DbgKdWriteVirtualMemoryApi;
|
|
m.u.WriteMemory.TargetBaseAddress = TargetBaseAddress + cb;
|
|
m.u.WriteMemory.TransferCount = min(TransferCount, PACKET_MAX_SIZE);
|
|
|
|
//
|
|
// Send the write message and data to the target system and wait
|
|
// for a reply.
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
(PUCHAR)UserInterfaceBuffer + cb,
|
|
(USHORT)m.u.WriteMemory.
|
|
TransferCount);
|
|
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
}
|
|
while ((rc != DBGKD_WAIT_PACKET) ||
|
|
(Reply->ApiNumber != DbgKdWriteVirtualMemoryApi));
|
|
|
|
//
|
|
// If the write virtual is successful, then update the byte count
|
|
// and write the next data segment. Otherwise, terminate the write
|
|
// and return the number of bytes written.
|
|
//
|
|
|
|
Status = Reply->ReturnStatus;
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
TransferCount -= Reply->u.ReadMemory.ActualBytesRead;
|
|
cb += Reply->u.ReadMemory.ActualBytesRead;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the number of bytes actually written and return the status of the
|
|
// write operation.
|
|
//
|
|
|
|
*ActualBytesWritten = cb;
|
|
|
|
KdOut("DbgKdWriteVirtualMemory returns %08lx\n", Status);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdReadVirtualTranslatedMemory(
|
|
IN ULONG64 TargetBaseAddress,
|
|
OUT PVOID UserInterfaceBuffer,
|
|
IN ULONG TransferCount,
|
|
OUT PULONG ActualBytesRead
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG64 TargetPhysicalAddress;
|
|
|
|
if (TransferCount == 0)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG Levels;
|
|
ULONG PfIndex;
|
|
|
|
if (g_TargetMachine->
|
|
GetVirtualTranslationPhysicalOffsets(TargetBaseAddress, NULL, 0,
|
|
&Levels, &PfIndex,
|
|
&TargetPhysicalAddress) == S_OK)
|
|
{
|
|
Status = DbgKdReadPhysicalMemory(TargetPhysicalAddress,
|
|
UserInterfaceBuffer,
|
|
TransferCount,
|
|
ActualBytesRead);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdWriteVirtualTranslatedMemory(
|
|
IN ULONG64 TargetBaseAddress,
|
|
OUT PVOID UserInterfaceBuffer,
|
|
IN ULONG TransferCount,
|
|
OUT PULONG ActualBytesWritten OPTIONAL
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG64 TargetPhysicalAddress;
|
|
|
|
ULONG Levels;
|
|
ULONG PfIndex;
|
|
|
|
if (g_TargetMachine->
|
|
GetVirtualTranslationPhysicalOffsets(TargetBaseAddress, NULL, 0,
|
|
&Levels, &PfIndex,
|
|
&TargetPhysicalAddress) == S_OK)
|
|
{
|
|
Status = DbgKdWritePhysicalMemory(TargetPhysicalAddress,
|
|
UserInterfaceBuffer,
|
|
TransferCount,
|
|
ActualBytesWritten);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdReadControlSpace(
|
|
IN ULONG Processor,
|
|
IN ULONG OffsetAddress,
|
|
OUT PVOID UserInterfaceBuffer,
|
|
IN ULONG TransferCount,
|
|
OUT PULONG ActualBytesRead
|
|
)
|
|
|
|
/*++
|
|
|
|
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.
|
|
|
|
OffsetAddress - 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 - Specifies 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_READ_MEMORY64 a = &m.u.ReadMemory;
|
|
NTSTATUS st = STATUS_UNSUCCESSFUL;
|
|
ULONG rc;
|
|
ULONG Read;
|
|
|
|
if ( TransferCount + sizeof(m) > PACKET_MAX_SIZE )
|
|
{
|
|
st = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdReadControlSpaceApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
m.Processor = (SHORT)Processor;
|
|
a->TargetBaseAddress = OffsetAddress;
|
|
a->TransferCount = TransferCount;
|
|
a->ActualBytesRead = 0L;
|
|
|
|
//
|
|
// Send the message and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdReadControlSpaceApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
//
|
|
// Reset message address to reply.
|
|
//
|
|
|
|
a = &Reply->u.ReadMemory;
|
|
DBG_ASSERT(a->ActualBytesRead <= TransferCount);
|
|
|
|
//
|
|
// 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(UserInterfaceBuffer, Reply+1, (int)a->ActualBytesRead);
|
|
}
|
|
|
|
KdOut("DbgKdReadControlSpace returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdWriteControlSpace(
|
|
IN ULONG Processor,
|
|
IN ULONG OffsetAddress,
|
|
IN PVOID UserInterfaceBuffer,
|
|
IN ULONG TransferCount,
|
|
OUT PULONG ActualBytesWritten
|
|
)
|
|
|
|
/*++
|
|
|
|
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.
|
|
|
|
OffsetAddress - 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 - Specifies 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_WRITE_MEMORY64 a = &m.u.WriteMemory;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
if ( TransferCount + sizeof(m) > PACKET_MAX_SIZE ) {
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdWriteControlSpaceApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
m.Processor = (USHORT) Processor;
|
|
a->TargetBaseAddress = OffsetAddress;
|
|
a->TransferCount = TransferCount;
|
|
a->ActualBytesWritten = 0L;
|
|
|
|
//
|
|
// Send the message and data to write and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
UserInterfaceBuffer,
|
|
(USHORT)TransferCount);
|
|
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdWriteControlSpaceApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
a = &Reply->u.WriteMemory;
|
|
DBG_ASSERT(a->ActualBytesWritten <= TransferCount);
|
|
|
|
//
|
|
// Return actual bytes written
|
|
//
|
|
|
|
*ActualBytesWritten = a->ActualBytesWritten;
|
|
|
|
KdOut("DbgWriteControlSpace returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdGetContext(
|
|
IN ULONG Processor,
|
|
PCROSS_PLATFORM_CONTEXT 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_GET_CONTEXT a = &m.u.GetContext;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
if (g_TargetMachine == NULL) {
|
|
return STATUS_DEVICE_NOT_READY;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdGetContextApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
m.Processor = (USHORT) Processor;
|
|
|
|
//
|
|
// Send the message and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdGetContextApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
//
|
|
// Since get context response data follows message, Reply+1 should point
|
|
// at the data
|
|
//
|
|
|
|
memcpy(Context, Reply+1, g_TargetMachine->m_SizeTargetContext);
|
|
|
|
KdOut("DbgKdGetContext returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdSetContext(
|
|
IN ULONG Processor,
|
|
PCROSS_PLATFORM_CONTEXT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function writes the specified context to the system being debugged.
|
|
|
|
Arguments:
|
|
|
|
Processor - Supplies a processor number to set the context to.
|
|
|
|
Context - Supplies a context record used to set the context for the
|
|
processor that reported the last state change. Only the
|
|
portions of the context indicated by the ContextFlags field are
|
|
actually written.
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The specified set context occured.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_SET_CONTEXT a = &m.u.SetContext;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
if (g_TargetMachine == NULL) {
|
|
return STATUS_DEVICE_NOT_READY;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdSetContextApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
m.Processor = (USHORT) Processor;
|
|
|
|
//
|
|
// Send the message and context and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
Context,
|
|
(USHORT)g_TargetMachine->
|
|
m_SizeTargetContext);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdSetContextApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
KdOut("DbgKdSetContext returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdWriteBreakPoint(
|
|
IN ULONG64 BreakPointAddress,
|
|
OUT PULONG_PTR 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_WRITE_BREAKPOINT64 a = &m.u.WriteBreakPoint;
|
|
NTSTATUS st;
|
|
ULONG 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
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdWriteBreakPointApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
*BreakPointHandle = Reply->u.WriteBreakPoint.BreakPointHandle;
|
|
|
|
KdOut("DbgKdWriteBreakPoint(%s) returns %08lx, %x\n",
|
|
FormatAddr64(BreakPointAddress), st,
|
|
(ULONG)*BreakPointHandle);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdRestoreBreakPoint(
|
|
IN ULONG_PTR 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_RESTORE_BREAKPOINT a = &m.u.RestoreBreakPoint;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdRestoreBreakPointApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
a->BreakPointHandle = (ULONG)BreakPointHandle;
|
|
|
|
//
|
|
// Send the message and context and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdRestoreBreakPointApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
KdOut("DbgKdRestoreBreakPoint(%x) returns %08lx\n",
|
|
(ULONG)BreakPointHandle, st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdReadIoSpace(
|
|
IN ULONG64 IoAddress,
|
|
OUT PVOID ReturnedData,
|
|
IN ULONG DataSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used read a byte, short, or long (1,2,4 bytes) from
|
|
the specified I/O address.
|
|
|
|
Arguments:
|
|
|
|
IoAddress - Supplies the Io address to read from.
|
|
|
|
ReturnedData - Supplies the value read from the I/O address.
|
|
|
|
DataSize - Supplies the size in bytes to read. Values of 1, 2, or
|
|
4 are accepted.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Data was successfully read from the I/O
|
|
address.
|
|
|
|
STATUS_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was
|
|
specified.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_READ_WRITE_IO64 a = &m.u.ReadWriteIo;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
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
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdReadIoSpaceApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
a = &Reply->u.ReadWriteIo;
|
|
|
|
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;
|
|
}
|
|
|
|
KdOut("DbgKdReadIoSpace returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdWriteIoSpace(
|
|
IN ULONG64 IoAddress,
|
|
IN ULONG DataValue,
|
|
IN ULONG DataSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used write a byte, short, or long (1,2,4 bytes) to
|
|
the specified I/O address.
|
|
|
|
Arguments:
|
|
|
|
IoAddress - Supplies the Io address to write to.
|
|
|
|
DataValue - Supplies the value to write to the I/O address.
|
|
|
|
DataSize - Supplies the size in bytes to write. Values of 1, 2, or
|
|
4 are accepted.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Data was successfully written to the I/O
|
|
address.
|
|
|
|
STATUS_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was
|
|
specified.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_READ_WRITE_IO64 a = &m.u.ReadWriteIo;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
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
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdWriteIoSpaceApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
KdOut("DbgKdWriteIoSpace returns %08lx\n", st);
|
|
|
|
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 - Its 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_READ_WRITE_MSR a = &m.u.ReadWriteMsr;
|
|
LARGE_INTEGER li;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdReadMachineSpecificRegister;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
a->Msr = MsrReg;
|
|
|
|
//
|
|
// Send the message and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdReadMachineSpecificRegister);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
a = &Reply->u.ReadWriteMsr;
|
|
|
|
li.LowPart = a->DataValueLow;
|
|
li.HighPart = a->DataValueHigh;
|
|
*MsrValue = li.QuadPart;
|
|
|
|
KdOut("DbgKdReadMsr returns %08lx\n", st);
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_READ_WRITE_MSR a = &m.u.ReadWriteMsr;
|
|
LARGE_INTEGER li;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
li.QuadPart = MsrValue;
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdWriteMachineSpecificRegister;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
// Quiet PREfix warnings.
|
|
m.Processor = 0;
|
|
m.ProcessorLevel = 0;
|
|
|
|
a->Msr = MsrReg;
|
|
a->DataValueLow = li.LowPart;
|
|
a->DataValueHigh = li.HighPart;
|
|
|
|
//
|
|
// Send the message and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdWriteMachineSpecificRegister);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
KdOut("DbgKdWriteMsr returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdReadIoSpaceExtended(
|
|
IN ULONG64 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_READ_WRITE_IO_EXTENDED64 a = &m.u.ReadWriteIoExtended;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
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
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdReadIoSpaceExtendedApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
a = &Reply->u.ReadWriteIoExtended;
|
|
|
|
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;
|
|
}
|
|
|
|
KdOut("DbgKdReadIoSpaceExtended returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdWriteIoSpaceExtended(
|
|
IN ULONG64 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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_READ_WRITE_IO_EXTENDED64 a = &m.u.ReadWriteIoExtended;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
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
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdWriteIoSpaceExtendedApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
KdOut("DbgKdWriteIoSpaceExtended returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdGetBusData(
|
|
IN ULONG BusDataType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG SlotNumber,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Offset,
|
|
IN OUT PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to read I/O configuration space.
|
|
|
|
Arguments:
|
|
|
|
BusDataType - BUS_DATA_TYPE
|
|
|
|
BusNumber - Bus number.
|
|
|
|
SlotNumber - Slot number.
|
|
|
|
Buffer - Buffer to receive bus data.
|
|
|
|
Offset - Offset.
|
|
|
|
Length - Length.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Data was successfully read from
|
|
configuration space.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_GET_SET_BUS_DATA a = &m.u.GetSetBusData;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
//
|
|
// Check the buffer size.
|
|
//
|
|
|
|
if (*Length > PACKET_MAX_SIZE - sizeof (DBGKD_MANIPULATE_STATE64))
|
|
{
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdGetBusDataApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
a->BusDataType = BusDataType;
|
|
a->BusNumber = BusNumber;
|
|
a->SlotNumber = SlotNumber;
|
|
a->Offset = Offset;
|
|
a->Length = *Length;
|
|
|
|
//
|
|
// Send the message and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdGetBusDataApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
a = &Reply->u.GetSetBusData;
|
|
|
|
if (NT_SUCCESS(st))
|
|
{
|
|
memcpy(Buffer, Reply + 1, a->Length);
|
|
*Length = a->Length;
|
|
}
|
|
|
|
KdOut("DbgKdGetBusData returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdSetBusData(
|
|
IN ULONG BusDataType,
|
|
IN ULONG BusNumber,
|
|
IN ULONG SlotNumber,
|
|
IN PVOID Buffer,
|
|
IN ULONG Offset,
|
|
IN OUT PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to write I/O configuration space.
|
|
|
|
Arguments:
|
|
|
|
BusDataType - BUS_DATA_TYPE
|
|
|
|
BusNumber - Bus number.
|
|
|
|
SlotNumber - Slot number.
|
|
|
|
Buffer - Buffer containing bus data.
|
|
|
|
Offset - Offset.
|
|
|
|
Length - Length.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Data was successfully written to
|
|
configuration space.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_GET_SET_BUS_DATA a = &m.u.GetSetBusData;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
|
|
//
|
|
// Check the buffer size.
|
|
//
|
|
|
|
if (*Length > PACKET_MAX_SIZE - sizeof (DBGKD_MANIPULATE_STATE64))
|
|
{
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdSetBusDataApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
a->BusDataType = BusDataType;
|
|
a->BusNumber = BusNumber;
|
|
a->SlotNumber = SlotNumber;
|
|
a->Offset = Offset;
|
|
a->Length = *Length;
|
|
|
|
//
|
|
// Send the message and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
Buffer, (USHORT)*Length);
|
|
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdSetBusDataApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
if (NT_SUCCESS(st))
|
|
{
|
|
a = &Reply->u.GetSetBusData;
|
|
*Length = a->Length;
|
|
}
|
|
|
|
KdOut("DbgKdSetBusData returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdGetVersion (
|
|
PDBGKD_GET_VERSION64 GetVersion
|
|
)
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_GET_VERSION64 a = &m.u.GetVersion64;
|
|
DWORD st;
|
|
ULONG rc;
|
|
|
|
m.ApiNumber = DbgKdGetVersionApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
a->ProtocolVersion = 1; // request context records on state changes
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
*GetVersion = Reply->u.GetVersion64;
|
|
|
|
KdOut("DbgKdGetVersion returns %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdReboot(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reboots being debugged.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdRebootApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
//
|
|
// Send the message.
|
|
//
|
|
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
InvalidateMemoryCaches();
|
|
|
|
KdOut("DbgKdReboot returns 0x00000000\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdCrash(
|
|
DWORD BugCheckCode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reboots being debugged.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdCauseBugCheckApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
*(PULONG)&m.u = BugCheckCode;
|
|
|
|
//
|
|
// Send the message.
|
|
//
|
|
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
InvalidateMemoryCaches();
|
|
|
|
KdOut("DbgKdCrash returns 0x00000000\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdReadPhysicalMemory(
|
|
IN ULONG64 TargetBaseAddress,
|
|
OUT PVOID UserInterfaceBuffer,
|
|
IN ULONG TransferCount,
|
|
OUT PULONG ActualBytesRead OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reads the specified data from the physical memory of
|
|
the system being debugged.
|
|
|
|
Arguments:
|
|
|
|
TargetBaseAddress - Supplies the physical address of the memory to read
|
|
from the system being debugged.
|
|
|
|
UserInterfaceBuffer - Supplies the address of the buffer in the user
|
|
interface that data read is to be placed.
|
|
|
|
TransferCount - Specifies the number of bytes to read.
|
|
|
|
ActualBytesRead - An optional parameter that if supplied, returns
|
|
the number of bytes actually read.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The specified read occured.
|
|
|
|
STATUS_BUFFER_OVERFLOW - A read that is too large was specified.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_READ_MEMORY64 a;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
ULONG cb, cb2;
|
|
|
|
cb2 = 0;
|
|
|
|
if (ARGUMENT_PRESENT(ActualBytesRead)) {
|
|
*ActualBytesRead = 0;
|
|
}
|
|
|
|
readmore:
|
|
|
|
cb = TransferCount;
|
|
if (cb > PACKET_MAX_SIZE) {
|
|
cb = PACKET_MAX_SIZE;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdReadPhysicalMemoryApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
a = &m.u.ReadMemory;
|
|
a->TargetBaseAddress = TargetBaseAddress+cb2;
|
|
a->TransferCount = cb;
|
|
a->ActualBytesRead = 0L;
|
|
|
|
//
|
|
// Send the message and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdReadPhysicalMemoryApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
a = &Reply->u.ReadMemory;
|
|
DBG_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
|
|
//
|
|
|
|
if (NT_SUCCESS(st))
|
|
{
|
|
memcpy((PCHAR)((ULONG_PTR) UserInterfaceBuffer+cb2), Reply+1, (int)a->ActualBytesRead);
|
|
|
|
TransferCount -= a->ActualBytesRead;
|
|
|
|
if (TransferCount)
|
|
{
|
|
cb2 += a->ActualBytesRead;
|
|
goto readmore;
|
|
}
|
|
}
|
|
|
|
KdOut("DbgKdReadPhysical memory TargetBaseAddress %s, status %08lx\n",
|
|
FormatAddr64(TargetBaseAddress), st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdWritePhysicalMemory(
|
|
IN ULONG64 TargetBaseAddress,
|
|
OUT PVOID UserInterfaceBuffer,
|
|
IN ULONG TransferCount,
|
|
OUT PULONG ActualBytesWritten OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function writes the specified data to the physical memory of the
|
|
system being debugged.
|
|
|
|
Arguments:
|
|
|
|
TargetBaseAddress - Supplies the physical address of the memory to write
|
|
to the system being debugged.
|
|
|
|
UserInterfaceBuffer - Supplies the address of the buffer in the user
|
|
interface that contains the data to be written.
|
|
|
|
TransferCount - Specifies the number of bytes to write.
|
|
|
|
ActualBytesWritten - An optional parameter that if supplied, returns
|
|
the number of bytes actually written.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The specified read occured.
|
|
|
|
STATUS_BUFFER_OVERFLOW - A read that is to large was specified.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_WRITE_MEMORY64 a;
|
|
NTSTATUS st;
|
|
ULONG rc;
|
|
ULONG cb, cb2;
|
|
|
|
g_VirtualCache.Empty ();
|
|
|
|
cb2 = 0;
|
|
|
|
if (ARGUMENT_PRESENT(ActualBytesWritten)) {
|
|
*ActualBytesWritten = 0;
|
|
}
|
|
|
|
writemore:
|
|
|
|
cb = TransferCount;
|
|
if (cb > PACKET_MAX_SIZE) {
|
|
cb = PACKET_MAX_SIZE;
|
|
}
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
m.ApiNumber = DbgKdWritePhysicalMemoryApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
a = &m.u.WriteMemory;
|
|
a->TargetBaseAddress = TargetBaseAddress+cb2;
|
|
a->TransferCount = cb;
|
|
a->ActualBytesWritten = 0L;
|
|
|
|
//
|
|
// Send the message and data to write and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
(PVOID)
|
|
((ULONG_PTR)UserInterfaceBuffer+cb2),
|
|
(USHORT)cb);
|
|
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdWritePhysicalMemoryApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
a = &Reply->u.WriteMemory;
|
|
DBG_ASSERT(a->ActualBytesWritten <= cb);
|
|
|
|
//
|
|
// Return actual bytes written
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT(ActualBytesWritten)) {
|
|
*ActualBytesWritten += a->ActualBytesWritten;
|
|
}
|
|
|
|
if (NT_SUCCESS(st))
|
|
{
|
|
TransferCount -= a->ActualBytesWritten;
|
|
|
|
if (TransferCount)
|
|
{
|
|
cb2 += a->ActualBytesWritten;
|
|
goto writemore;
|
|
}
|
|
}
|
|
|
|
KdOut("DbgKdWritePhysical memory %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DbgKdCheckLowMemory(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function forces a call on the system being debugged that will check
|
|
if physical pages lower than 4gb have a specific fill pattern.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - The specified read occured.
|
|
|
|
--*/
|
|
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
ULONG rc;
|
|
|
|
//
|
|
// Format state manipulate message
|
|
//
|
|
|
|
RtlZeroMemory (&m, sizeof(m));
|
|
m.ApiNumber = DbgKdCheckLowMemoryApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
//
|
|
// We wait for an answer from the kernel side.
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
|
|
} while (rc != DBGKD_WAIT_PACKET);
|
|
|
|
if (Reply->ReturnStatus != STATUS_SUCCESS)
|
|
{
|
|
dprintf ("Corrupted page with pfn %x \n", Reply->ReturnStatus);
|
|
}
|
|
|
|
KdOut("DbgKdCheckLowMemory 0x00000000\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
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_STATE64 m;
|
|
|
|
m.ApiNumber = (USHORT)DbgKdSwitchProcessor;
|
|
m.Processor = (USHORT)ProcessorNumber;
|
|
|
|
// Quiet PREfix warnings.
|
|
m.ProcessorLevel = 0;
|
|
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
g_VirtualCache.Empty ();
|
|
|
|
KdOut("DbgKdSwitchActiveProcessor 0x00000000\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdSearchMemory(
|
|
IN ULONG64 SearchAddress,
|
|
IN ULONG64 SearchLength,
|
|
IN PUCHAR Pattern,
|
|
IN ULONG PatternLength,
|
|
OUT PULONG64 FoundAddress
|
|
)
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 m;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
PDBGKD_SEARCH_MEMORY a = &m.u.SearchMemory;
|
|
ULONG rc;
|
|
NTSTATUS st;
|
|
|
|
KdOut("Search called %s, length %I64x\n",
|
|
FormatAddr64(SearchAddress), SearchLength);
|
|
|
|
*FoundAddress = 0;
|
|
|
|
a->SearchAddress = SearchAddress;
|
|
a->SearchLength = SearchLength;
|
|
a->PatternLength = PatternLength;
|
|
|
|
m.ApiNumber = DbgKdSearchMemoryApi;
|
|
m.ReturnStatus = STATUS_PENDING;
|
|
|
|
//
|
|
// Send the message and data to write and then wait for reply
|
|
//
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&m, sizeof(m),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
Pattern, (USHORT)PatternLength);
|
|
|
|
rc = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
} while (rc != DBGKD_WAIT_PACKET ||
|
|
Reply->ApiNumber != DbgKdSearchMemoryApi);
|
|
|
|
st = Reply->ReturnStatus;
|
|
|
|
if (NT_SUCCESS(st))
|
|
{
|
|
if (g_TargetMachine->m_Ptr64)
|
|
{
|
|
*FoundAddress = Reply->u.SearchMemory.FoundAddress;
|
|
}
|
|
else
|
|
{
|
|
*FoundAddress = EXTEND64(Reply->u.SearchMemory.FoundAddress);
|
|
}
|
|
}
|
|
|
|
KdOut("DbgKdSearchMemory %08lx\n", st);
|
|
|
|
return st;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdFillMemory(
|
|
IN ULONG Flags,
|
|
IN ULONG64 Start,
|
|
IN ULONG Size,
|
|
IN PVOID Pattern,
|
|
IN ULONG PatternSize,
|
|
OUT PULONG Filled
|
|
)
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 Manip;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DBG_ASSERT(g_KdMaxManipulate > DbgKdFillMemoryApi &&
|
|
(Flags & 0xffff0000) == 0 &&
|
|
PatternSize <= PACKET_MAX_SIZE);
|
|
|
|
// Invalidate any cached memory.
|
|
if (Flags & DBGKD_FILL_MEMORY_VIRTUAL)
|
|
{
|
|
g_VirtualCache.Remove(Start, Size);
|
|
}
|
|
else if (Flags & DBGKD_FILL_MEMORY_PHYSICAL)
|
|
{
|
|
g_PhysicalCache.Remove(Start, Size);
|
|
}
|
|
|
|
//
|
|
// Initialize state manipulate message to fill memory.
|
|
//
|
|
|
|
Manip.ApiNumber = DbgKdFillMemoryApi;
|
|
Manip.u.FillMemory.Address = Start;
|
|
Manip.u.FillMemory.Length = Size;
|
|
Manip.u.FillMemory.Flags = (USHORT)Flags;
|
|
Manip.u.FillMemory.PatternLength = (USHORT)PatternSize;
|
|
|
|
//
|
|
// Send the message and data to the target system and wait
|
|
// for a reply.
|
|
//
|
|
|
|
ULONG Recv;
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&Manip, sizeof(Manip),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
Pattern, (USHORT)PatternSize);
|
|
Recv = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
}
|
|
while ((Recv != DBGKD_WAIT_PACKET) ||
|
|
(Reply->ApiNumber != DbgKdFillMemoryApi));
|
|
|
|
Status = Reply->ReturnStatus;
|
|
*Filled = Reply->u.FillMemory.Length;
|
|
|
|
KdOut("DbgKdFillMemory returns %08lx\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
DbgKdQueryMemory(
|
|
IN ULONG64 Address,
|
|
IN ULONG InSpace,
|
|
OUT PULONG OutSpace,
|
|
OUT PULONG OutFlags
|
|
)
|
|
{
|
|
DBGKD_MANIPULATE_STATE64 Manip;
|
|
PDBGKD_MANIPULATE_STATE64 Reply;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
DBG_ASSERT(g_KdMaxManipulate > DbgKdQueryMemoryApi);
|
|
|
|
//
|
|
// Initialize state manipulate message to query memory.
|
|
//
|
|
|
|
Manip.ApiNumber = DbgKdQueryMemoryApi;
|
|
Manip.u.QueryMemory.Address = Address;
|
|
Manip.u.QueryMemory.Reserved = 0;
|
|
Manip.u.QueryMemory.AddressSpace = InSpace;
|
|
Manip.u.QueryMemory.Flags = 0;
|
|
|
|
//
|
|
// Send the message and data to the target system and wait
|
|
// for a reply.
|
|
//
|
|
|
|
ULONG Recv;
|
|
|
|
do
|
|
{
|
|
g_DbgKdTransport->WritePacket(&Manip, sizeof(Manip),
|
|
PACKET_TYPE_KD_STATE_MANIPULATE,
|
|
NULL, 0);
|
|
Recv = g_DbgKdTransport->
|
|
WaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply);
|
|
}
|
|
while ((Recv != DBGKD_WAIT_PACKET) ||
|
|
(Reply->ApiNumber != DbgKdQueryMemoryApi));
|
|
|
|
Status = Reply->ReturnStatus;
|
|
*OutSpace = Reply->u.QueryMemory.AddressSpace;
|
|
*OutFlags = Reply->u.QueryMemory.Flags;
|
|
|
|
KdOut("DbgKdQueryMemory returns %08lx\n", Status);
|
|
return Status;
|
|
}
|