windows-nt/Source/XPSP1/NT/sdktools/debuggers/ntsd64/dbgkdapi.cpp

2825 lines
66 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}