Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

958 lines
22 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
api.c
Abstract:
This module implements the boot bebugger platform independent remote APIs.
Author:
Mark Lucovsky (markl) 31-Aug-1990
Revision History:
--*/
#include "bd.h"
VOID
BdGetVersion(
IN PDBGKD_MANIPULATE_STATE64 m
)
/*++
Routine Description:
This function returns to the caller a general information packet
that contains useful information to a debugger. This packet is also
used for a debugger to determine if the writebreakpointex and
readbreakpointex apis are available.
Arguments:
m - Supplies the state manipulation message.
Return Value:
None.
--*/
{
STRING messageHeader;
messageHeader.Length = sizeof(*m);
messageHeader.Buffer = (PCHAR)m;
RtlZeroMemory(&m->u.GetVersion64, sizeof(m->u.GetVersion64));
//
// the current build number
//
// - 4 - tells the debugger this is a "special" OS - the boot loader.
// The boot loader has a lot of special cases associated with it, like
// the lack of the DebuggerDataBlock, lack of ntoskrnl, etc ...
//
m->u.GetVersion64.MinorVersion = (short)NtBuildNumber;
m->u.GetVersion64.MajorVersion = 0x400 |
(short)((NtBuildNumber >> 28) & 0xFFFFFFF);
//
// Kd protocol version number.
//
m->u.GetVersion64.ProtocolVersion = DBGKD_64BIT_PROTOCOL_VERSION2;
m->u.GetVersion64.Flags = DBGKD_VERS_FLAG_DATA;
#if defined(_M_IX86)
m->u.GetVersion64.MachineType = IMAGE_FILE_MACHINE_I386;
#elif defined(_M_MRX000)
m->u.GetVersion64.MachineType = IMAGE_FILE_MACHINE_R4000;
#elif defined(_M_ALPHA)
m->u.GetVersion64.MachineType = IMAGE_FILE_MACHINE_ALPHA;
#elif defined(_M_PPC)
m->u.GetVersion64.MachineType = IMAGE_FILE_MACHINE_POWERPC;
#elif defined(_IA64_)
m->u.GetVersion64.MachineType = IMAGE_FILE_MACHINE_IA64;
m->u.GetVersion64.Flags |= DBGKD_VERS_FLAG_PTR64;
#else
#error( "unknown target machine" );
#endif
m->u.GetVersion64.MaxPacketType = (UCHAR)(PACKET_TYPE_KD_FILE_IO + 1);;
m->u.GetVersion64.MaxStateChange = (UCHAR)(DbgKdLoadSymbolsStateChange + 1);;
m->u.GetVersion64.MaxManipulate = (UCHAR)(DbgKdSetBusDataApi + 1);
//
// address of the loader table
//
m->u.GetVersion64.PsLoadedModuleList = 0;
m->u.GetVersion64.KernBase = 0;
//m->u.GetVersion64.ThCallbackStack = 0;
//m->u.GetVersion64.KiCallUserMode = 0;
//m->u.GetVersion64.KeUserCallbackDispatcher = 0;
//m->u.GetVersion64.NextCallback = 0;
#if defined(_X86_)
//m->u.GetVersion64.FramePointer = 0;
#endif
//m->u.GetVersion64.BreakpointWithStatus = 0;
m->u.GetVersion64.DebuggerDataList = 0;
//
// the usual stuff
//
m->ReturnStatus = STATUS_SUCCESS;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&messageHeader,
NULL);
return;
}
VOID
BdGetContext(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a get context state
manipulation message. Its function is to return the current
context.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_GET_CONTEXT a = &m->u.GetContext;
STRING MessageHeader;
m->ReturnStatus = STATUS_SUCCESS;
AdditionalData->Length = sizeof(CONTEXT);
BdCopyMemory(AdditionalData->Buffer, (PCHAR)Context, sizeof(CONTEXT));
//
// Send reply packet.
//
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData);
return;
}
VOID
BdSetContext(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a set context state
manipulation message. Its function is set the current
context.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_SET_CONTEXT a = &m->u.SetContext;
STRING MessageHeader;
m->ReturnStatus = STATUS_SUCCESS;
BdCopyMemory((PCHAR)Context, AdditionalData->Buffer, sizeof(CONTEXT));
//
// Send reply packet.
//
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL);
}
VOID
BdReadVirtualMemory(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response to a read virtual memory 32-bit
state manipulation message. Its function is to read virtual memory
and return.
Arguments:
m - Supplies a pointer to the state manipulation message.
AdditionalData - Supplies a pointer to a descriptor for the data to read.
Context - Supplies a pointer to the current context.
Return Value:
None.
--*/
{
ULONG Length;
STRING MessageHeader;
//
// Trim the transfer count to fit in a single message.
//
Length = min(m->u.ReadMemory.TransferCount,
PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64));
//
// Move the data to the destination buffer.
//
AdditionalData->Length = (USHORT)BdMoveMemory((PCHAR)AdditionalData->Buffer,
(PCHAR)m->u.ReadMemory.TargetBaseAddress,
Length);
//
// If all the data is read, then return a success status. Otherwise,
// return an unsuccessful status.
//
m->ReturnStatus = STATUS_SUCCESS;
if (Length != AdditionalData->Length) {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
//
// Set the actual number of bytes read, initialize the message header,
// and send the reply packet to the host debugger.
//
m->u.ReadMemory.ActualBytesRead = AdditionalData->Length;
MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64);
MessageHeader.Buffer = (PCHAR)m;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData);
return;
}
VOID
BdWriteVirtualMemory(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a write virtual memory 32-bit
state manipulation message. Its function is to write virtual memory
and return.
Arguments:
m - Supplies a pointer to the state manipulation message.
AdditionalData - Supplies a pointer to a descriptor for the data to write.
Context - Supplies a pointer to the current context.
Return Value:
None.
--*/
{
ULONG Length;
STRING MessageHeader;
//
// Move the data to the destination buffer.
//
Length = BdMoveMemory((PCHAR)m->u.WriteMemory.TargetBaseAddress,
(PCHAR)AdditionalData->Buffer,
AdditionalData->Length);
//
// If all the data is written, then return a success status. Otherwise,
// return an unsuccessful status.
//
m->ReturnStatus = STATUS_SUCCESS;
if (Length != AdditionalData->Length) {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
//
// Set the actual number of bytes written, initialize the message header,
// and send the reply packet to the host debugger.
//
m->u.WriteMemory.ActualBytesWritten = Length;
MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64);
MessageHeader.Buffer = (PCHAR)m;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL);
return;
}
VOID
BdWriteBreakpoint(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a write breakpoint state
manipulation message. Its function is to write a breakpoint
and return a handle to the breakpoint.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_WRITE_BREAKPOINT64 a = &m->u.WriteBreakPoint;
STRING MessageHeader;
a->BreakPointHandle = BdAddBreakpoint(a->BreakPointAddress);
if (a->BreakPointHandle != 0) {
m->ReturnStatus = STATUS_SUCCESS;
} else {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
//
// Send reply packet.
//
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL);
return;
}
VOID
BdRestoreBreakpoint(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a restore breakpoint state
manipulation message. Its function is to restore a breakpoint
using the specified handle.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_RESTORE_BREAKPOINT a = &m->u.RestoreBreakPoint;
STRING MessageHeader;
if (BdDeleteBreakpoint(a->BreakPointHandle)) {
m->ReturnStatus = STATUS_SUCCESS;
} else {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
//
// Send reply packet.
//
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL);
}
VOID
BdReadPhysicalMemory(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response to a read physical memory
state manipulation message. Its function is to read physical memory
and return.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_READ_MEMORY64 a = &m->u.ReadMemory;
ULONG Length;
STRING MessageHeader;
PVOID VirtualAddress;
PHYSICAL_ADDRESS Source;
PUCHAR Destination;
USHORT NumberBytes;
USHORT BytesLeft;
//
// Trim transfer count to fit in a single message.
//
Length = min(a->TransferCount,
PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64));
//
// Since the BdTranslatePhysicalAddress only maps in one physical
// page at a time, we need to break the memory move up into smaller
// moves which don't cross page boundaries. There are two cases we
// need to deal with. The area to be moved may start and end on the
// same page, or it may start and end on different pages (with an
// arbitrary number of pages in between)
//
Source.QuadPart = (ULONG_PTR)a->TargetBaseAddress;
Destination = AdditionalData->Buffer;
BytesLeft = (USHORT)Length;
if(PAGE_ALIGN((PUCHAR)a->TargetBaseAddress) ==
PAGE_ALIGN((PUCHAR)(a->TargetBaseAddress)+Length)) {
//
// Memory move starts and ends on the same page.
//
VirtualAddress=BdTranslatePhysicalAddress(Source);
if (VirtualAddress == NULL) {
AdditionalData->Length = 0;
} else {
AdditionalData->Length = (USHORT)BdMoveMemory(Destination,
VirtualAddress,
BytesLeft);
BytesLeft -= AdditionalData->Length;
}
} else {
//
// Memory move spans page boundaries
//
VirtualAddress=BdTranslatePhysicalAddress(Source);
if (VirtualAddress == NULL) {
AdditionalData->Length = 0;
} else {
NumberBytes = (USHORT)(PAGE_SIZE - BYTE_OFFSET(VirtualAddress));
AdditionalData->Length = (USHORT)BdMoveMemory(Destination,
VirtualAddress,
NumberBytes);
Source.LowPart += NumberBytes;
Destination += NumberBytes;
BytesLeft -= NumberBytes;
while(BytesLeft > 0) {
//
// Transfer a full page or the last bit,
// whichever is smaller.
//
VirtualAddress = BdTranslatePhysicalAddress(Source);
if (VirtualAddress == NULL) {
break;
} else {
NumberBytes = (USHORT) ((PAGE_SIZE < BytesLeft) ? PAGE_SIZE : BytesLeft);
AdditionalData->Length += (USHORT)BdMoveMemory(
Destination,
VirtualAddress,
NumberBytes);
Source.LowPart += NumberBytes;
Destination += NumberBytes;
BytesLeft -= NumberBytes;
}
}
}
}
if (Length == AdditionalData->Length) {
m->ReturnStatus = STATUS_SUCCESS;
} else {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
a->ActualBytesRead = AdditionalData->Length;
//
// Send reply packet.
//
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData);
return;
}
VOID
BdWritePhysicalMemory(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response to a write physical memory
state manipulation message. Its function is to write physical memory
and return.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_WRITE_MEMORY64 a = &m->u.WriteMemory;
ULONG Length;
STRING MessageHeader;
PVOID VirtualAddress;
PHYSICAL_ADDRESS Destination;
PUCHAR Source;
USHORT NumberBytes;
USHORT BytesLeft;
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
//
// Since the BdTranslatePhysicalAddress only maps in one physical
// page at a time, we need to break the memory move up into smaller
// moves which don't cross page boundaries. There are two cases we
// need to deal with. The area to be moved may start and end on the
// same page, or it may start and end on different pages (with an
// arbitrary number of pages in between)
//
Destination.QuadPart = (ULONG_PTR)a->TargetBaseAddress;
Source = AdditionalData->Buffer;
BytesLeft = (USHORT) a->TransferCount;
if(PAGE_ALIGN(Destination.QuadPart) ==
PAGE_ALIGN(Destination.QuadPart+BytesLeft)) {
//
// Memory move starts and ends on the same page.
//
VirtualAddress=BdTranslatePhysicalAddress(Destination);
Length = (USHORT)BdMoveMemory(VirtualAddress,
Source,
BytesLeft);
BytesLeft -= (USHORT) Length;
} else {
//
// Memory move spans page boundaries
//
VirtualAddress=BdTranslatePhysicalAddress(Destination);
NumberBytes = (USHORT) (PAGE_SIZE - BYTE_OFFSET(VirtualAddress));
Length = (USHORT)BdMoveMemory(VirtualAddress,
Source,
NumberBytes);
Source += NumberBytes;
Destination.LowPart += NumberBytes;
BytesLeft -= NumberBytes;
while(BytesLeft > 0) {
//
// Transfer a full page or the last bit, whichever is smaller.
//
VirtualAddress = BdTranslatePhysicalAddress(Destination);
NumberBytes = (USHORT) ((PAGE_SIZE < BytesLeft) ? PAGE_SIZE : BytesLeft);
Length += (USHORT)BdMoveMemory(VirtualAddress,
Source,
NumberBytes);
Source += NumberBytes;
Destination.LowPart += NumberBytes;
BytesLeft -= NumberBytes;
}
}
if (Length == AdditionalData->Length) {
m->ReturnStatus = STATUS_SUCCESS;
} else {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
a->ActualBytesWritten = Length;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
NULL);
return;
}
NTSTATUS
BdWriteBreakPointEx(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a write breakpoint state 'ex'
manipulation message. Its function is to clear breakpoints, write
new breakpoints, and continue the target system. The clearing of
breakpoints is conditional based on the presence of breakpoint handles.
The setting of breakpoints is conditional based on the presence of
valid, non-zero, addresses. The continueing of the target system
is conditional based on a non-zero continuestatus.
This api allows a debugger to clear breakpoints, add new breakpoint,
and continue the target system all in one api packet. This reduces the
amount of traffic across the wire and greatly improves source stepping.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_BREAKPOINTEX a = &m->u.BreakPointEx;
PDBGKD_WRITE_BREAKPOINT64 b;
STRING MessageHeader;
ULONG i;
DBGKD_WRITE_BREAKPOINT64 BpBuf[BREAKPOINT_TABLE_SIZE];
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
//
// verify that the packet size is correct
//
if (AdditionalData->Length !=
a->BreakPointCount*sizeof(DBGKD_WRITE_BREAKPOINT64)) {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
BdSendPacket(
PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData
);
return m->ReturnStatus;
}
BdMoveMemory((PUCHAR)BpBuf,
AdditionalData->Buffer,
a->BreakPointCount*sizeof(DBGKD_WRITE_BREAKPOINT64));
//
// assume success
//
m->ReturnStatus = STATUS_SUCCESS;
//
// loop thru the breakpoint handles passed in from the debugger and
// clear any breakpoint that has a non-zero handle
//
b = BpBuf;
for (i=0; i<a->BreakPointCount; i++,b++) {
if (b->BreakPointHandle) {
if (!BdDeleteBreakpoint(b->BreakPointHandle)) {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
b->BreakPointHandle = 0;
}
}
//
// loop thru the breakpoint addesses passed in from the debugger and
// add any new breakpoints that have a non-zero address
//
b = BpBuf;
for (i=0; i<a->BreakPointCount; i++,b++) {
if (b->BreakPointAddress) {
b->BreakPointHandle = BdAddBreakpoint( b->BreakPointAddress );
if (!b->BreakPointHandle) {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
}
}
//
// send back our response
//
BdMoveMemory(AdditionalData->Buffer,
(PUCHAR)BpBuf,
a->BreakPointCount*sizeof(DBGKD_WRITE_BREAKPOINT64));
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData);
//
// return the caller's continue status value. if this is a non-zero
// value the system is continued using this value as the continuestatus.
//
return a->ContinueStatus;
}
VOID
BdRestoreBreakPointEx(
IN PDBGKD_MANIPULATE_STATE64 m,
IN PSTRING AdditionalData,
IN PCONTEXT Context
)
/*++
Routine Description:
This function is called in response of a restore breakpoint state 'ex'
manipulation message. Its function is to clear a list of breakpoints.
Arguments:
m - Supplies the state manipulation message.
AdditionalData - Supplies any additional data for the message.
Context - Supplies the current context.
Return Value:
None.
--*/
{
PDBGKD_BREAKPOINTEX a = &m->u.BreakPointEx;
PDBGKD_RESTORE_BREAKPOINT b;
STRING MessageHeader;
ULONG i;
DBGKD_RESTORE_BREAKPOINT BpBuf[BREAKPOINT_TABLE_SIZE];
MessageHeader.Length = sizeof(*m);
MessageHeader.Buffer = (PCHAR)m;
//
// verify that the packet size is correct
//
if (AdditionalData->Length !=
a->BreakPointCount*sizeof(DBGKD_RESTORE_BREAKPOINT)) {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData);
return;
}
BdMoveMemory((PUCHAR)BpBuf,
AdditionalData->Buffer,
a->BreakPointCount*sizeof(DBGKD_RESTORE_BREAKPOINT));
//
// assume success
//
m->ReturnStatus = STATUS_SUCCESS;
//
// loop thru the breakpoint handles passed in from the debugger and
// clear any breakpoint that has a non-zero handle
//
b = BpBuf;
for (i=0; i<a->BreakPointCount; i++,b++) {
if (!BdDeleteBreakpoint(b->BreakPointHandle)) {
m->ReturnStatus = STATUS_UNSUCCESSFUL;
}
}
//
// send back our response
//
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
AdditionalData);
return;
}