mirror of
https://github.com/reactos/reactos.git
synced 2024-11-18 21:13:52 +00:00
446 lines
13 KiB
C
446 lines
13 KiB
C
/*
|
|
* COPYRIGHT: GPL, see COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: drivers/base/kddll/kdpacket.c
|
|
* PURPOSE: Base functions for the kernel debugger.
|
|
*/
|
|
|
|
#include "kdgdb.h"
|
|
|
|
/* LOCALS *********************************************************************/
|
|
static
|
|
BOOLEAN
|
|
FirstSendHandler(
|
|
_In_ ULONG PacketType,
|
|
_In_ PSTRING MessageHeader,
|
|
_In_ PSTRING MessageData);
|
|
static BOOLEAN InException = FALSE;
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
DBGKD_GET_VERSION64 KdVersion;
|
|
KDDEBUGGER_DATA64* KdDebuggerDataBlock;
|
|
LIST_ENTRY* ProcessListHead;
|
|
LIST_ENTRY* ModuleListHead;
|
|
/* Callbacks used to communicate with KD aside from GDB */
|
|
KDP_SEND_HANDLER KdpSendPacketHandler = FirstSendHandler;
|
|
KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
|
|
/* Data describing the current exception */
|
|
DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
|
|
CONTEXT CurrentContext;
|
|
PEPROCESS TheIdleProcess;
|
|
PETHREAD TheIdleThread;
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
static
|
|
BOOLEAN
|
|
GetContextSendHandler(
|
|
_In_ ULONG PacketType,
|
|
_In_ PSTRING MessageHeader,
|
|
_In_ PSTRING MessageData
|
|
)
|
|
{
|
|
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
|
const CONTEXT* Context = (const CONTEXT*)MessageData->Buffer;
|
|
|
|
if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
|
|| (State->ApiNumber != DbgKdGetContextApi)
|
|
|| (MessageData->Length < sizeof(*Context)))
|
|
{
|
|
KDDBGPRINT("ERROR: Received wrong packet from KD.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/* Just copy it */
|
|
RtlCopyMemory(&CurrentContext, Context, sizeof(*Context));
|
|
KdpSendPacketHandler = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
static
|
|
KDSTATUS
|
|
GetContextManipulateHandler(
|
|
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
|
_Out_ PSTRING MessageData,
|
|
_Out_ PULONG MessageLength,
|
|
_Inout_ PKD_CONTEXT KdContext
|
|
)
|
|
{
|
|
State->ApiNumber = DbgKdGetContextApi;
|
|
State->Processor = CurrentStateChange.Processor;
|
|
State->ReturnStatus = STATUS_SUCCESS;
|
|
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
|
MessageData->Length = 0;
|
|
|
|
/* Update the send <-> receive loop handler */
|
|
KdpSendPacketHandler = GetContextSendHandler;
|
|
KdpManipulateStateHandler = NULL;
|
|
|
|
return KdPacketReceived;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
SetContextSendHandler(
|
|
_In_ ULONG PacketType,
|
|
_In_ PSTRING MessageHeader,
|
|
_In_ PSTRING MessageData
|
|
)
|
|
{
|
|
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
|
|
|
/* We just confirm that all went well */
|
|
if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
|
|| (State->ApiNumber != DbgKdSetContextApi)
|
|
|| (State->ReturnStatus != STATUS_SUCCESS))
|
|
{
|
|
/* Should we bugcheck ? */
|
|
KDDBGPRINT("BAD BAD BAD not manipulating state for sending context.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
KdpSendPacketHandler = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
KDSTATUS
|
|
SetContextManipulateHandler(
|
|
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
|
_Out_ PSTRING MessageData,
|
|
_Out_ PULONG MessageLength,
|
|
_Inout_ PKD_CONTEXT KdContext
|
|
)
|
|
{
|
|
State->ApiNumber = DbgKdSetContextApi;
|
|
State->Processor = CurrentStateChange.Processor;
|
|
State->ReturnStatus = STATUS_SUCCESS;
|
|
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
|
MessageData->Length = sizeof(CurrentContext);
|
|
|
|
if (MessageData->MaximumLength < sizeof(CurrentContext))
|
|
{
|
|
KDDBGPRINT("Wrong message length %u.\n", MessageData->MaximumLength);
|
|
while (1);
|
|
}
|
|
|
|
RtlCopyMemory(MessageData->Buffer, &CurrentContext, sizeof(CurrentContext));
|
|
|
|
/* Update the send <-> receive loop handlers */
|
|
KdpSendPacketHandler = SetContextSendHandler;
|
|
KdpManipulateStateHandler = NULL;
|
|
|
|
return KdPacketReceived;
|
|
}
|
|
|
|
static
|
|
void
|
|
send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
|
|
{
|
|
InException = TRUE;
|
|
|
|
switch (StateChange->NewState)
|
|
{
|
|
case DbgKdLoadSymbolsStateChange:
|
|
case DbgKdExceptionStateChange:
|
|
{
|
|
PETHREAD Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
|
|
/* Save current state for later GDB queries */
|
|
CurrentStateChange = *StateChange;
|
|
KDDBGPRINT("Exception 0x%08x in thread p%p.%p.\n",
|
|
StateChange->u.Exception.ExceptionRecord.ExceptionCode,
|
|
PsGetThreadProcessId(Thread),
|
|
PsGetThreadId(Thread));
|
|
/* Set the current debugged process/thread accordingly */
|
|
gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread));
|
|
#if MONOPROCESS
|
|
gdb_dbg_pid = 0;
|
|
#else
|
|
gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread));
|
|
#endif
|
|
gdb_send_exception();
|
|
/* Next receive call will ask for the context */
|
|
KdpManipulateStateHandler = GetContextManipulateHandler;
|
|
break;
|
|
}
|
|
default:
|
|
KDDBGPRINT("Unknown StateChange %u.\n", StateChange->NewState);
|
|
while (1);
|
|
}
|
|
}
|
|
|
|
static
|
|
void
|
|
send_kd_debug_io(
|
|
_In_ DBGKD_DEBUG_IO* DebugIO,
|
|
_In_ PSTRING String)
|
|
{
|
|
if (InException)
|
|
return;
|
|
|
|
switch (DebugIO->ApiNumber)
|
|
{
|
|
case DbgKdPrintStringApi:
|
|
case DbgKdGetStringApi:
|
|
gdb_send_debug_io(String, TRUE);
|
|
break;
|
|
default:
|
|
KDDBGPRINT("Unknown ApiNumber %u.\n", DebugIO->ApiNumber);
|
|
while (1);
|
|
}
|
|
}
|
|
|
|
static
|
|
void
|
|
send_kd_state_manipulate(
|
|
_In_ DBGKD_MANIPULATE_STATE64* State,
|
|
_In_ PSTRING MessageData)
|
|
{
|
|
switch (State->ApiNumber)
|
|
{
|
|
#if 0
|
|
case DbgKdGetContextApi:
|
|
/* This is an answer to a 'g' GDB request */
|
|
gdb_send_registers((CONTEXT*)MessageData->Buffer);
|
|
return;
|
|
#endif
|
|
default:
|
|
KDDBGPRINT("Unknown ApiNumber %u.\n", State->ApiNumber);
|
|
while (1);
|
|
}
|
|
}
|
|
|
|
KDSTATUS
|
|
ContinueManipulateStateHandler(
|
|
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
|
_Out_ PSTRING MessageData,
|
|
_Out_ PULONG MessageLength,
|
|
_Inout_ PKD_CONTEXT KdContext
|
|
)
|
|
{
|
|
/* Let's go on */
|
|
State->ApiNumber = DbgKdContinueApi;
|
|
State->ReturnStatus = STATUS_SUCCESS; /* ? */
|
|
State->Processor = CurrentStateChange.Processor;
|
|
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
|
if (MessageData)
|
|
MessageData->Length = 0;
|
|
*MessageLength = 0;
|
|
State->u.Continue.ContinueStatus = STATUS_SUCCESS;
|
|
|
|
/* We definitely are at the end of the send <-> receive loop, if any */
|
|
KdpSendPacketHandler = NULL;
|
|
KdpManipulateStateHandler = NULL;
|
|
/* We're not handling an exception anymore */
|
|
InException = FALSE;
|
|
|
|
return KdPacketReceived;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
GetVersionSendHandler(
|
|
_In_ ULONG PacketType,
|
|
_In_ PSTRING MessageHeader,
|
|
_In_ PSTRING MessageData)
|
|
{
|
|
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
|
LIST_ENTRY* DebuggerDataList;
|
|
|
|
/* Confirm that all went well */
|
|
if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
|
|| (State->ApiNumber != DbgKdGetVersionApi)
|
|
|| !NT_SUCCESS(State->ReturnStatus))
|
|
{
|
|
KDDBGPRINT("Wrong packet received after asking for data.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/* Copy the relevant data */
|
|
RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
|
|
DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
|
|
KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
|
|
ProcessListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsActiveProcessHead.Pointer;
|
|
ModuleListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsLoadedModuleList.Pointer;
|
|
|
|
/* Now we can get the context for the current state */
|
|
KdpSendPacketHandler = NULL;
|
|
KdpManipulateStateHandler = GetContextManipulateHandler;
|
|
return TRUE;
|
|
}
|
|
|
|
static
|
|
KDSTATUS
|
|
GetVersionManipulateStateHandler(
|
|
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
|
_Out_ PSTRING MessageData,
|
|
_Out_ PULONG MessageLength,
|
|
_Inout_ PKD_CONTEXT KdContext)
|
|
{
|
|
/* Ask for the version data */
|
|
State->ApiNumber = DbgKdGetVersionApi;
|
|
State->Processor = CurrentStateChange.Processor;
|
|
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
|
|
|
/* The next send call will serve this query */
|
|
KdpSendPacketHandler = GetVersionSendHandler;
|
|
KdpManipulateStateHandler = NULL;
|
|
|
|
return KdPacketReceived;
|
|
}
|
|
|
|
static
|
|
BOOLEAN
|
|
FirstSendHandler(
|
|
_In_ ULONG PacketType,
|
|
_In_ PSTRING MessageHeader,
|
|
_In_ PSTRING MessageData)
|
|
{
|
|
DBGKD_ANY_WAIT_STATE_CHANGE* StateChange = (DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer;
|
|
PETHREAD Thread;
|
|
|
|
if (PacketType != PACKET_TYPE_KD_STATE_CHANGE64)
|
|
{
|
|
KDDBGPRINT("First KD packet is not a state change!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
KDDBGPRINT("KDGDB: START!\n");
|
|
|
|
Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
|
|
|
|
/* Set up the current state */
|
|
CurrentStateChange = *StateChange;
|
|
gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread));
|
|
#if MONOPROCESS
|
|
gdb_dbg_pid = 0;
|
|
#else
|
|
gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread));
|
|
#endif
|
|
/* This is the idle process. Save it! */
|
|
TheIdleThread = Thread;
|
|
TheIdleProcess = (PEPROCESS)Thread->Tcb.ApcState.Process;
|
|
|
|
KDDBGPRINT("Pid Tid of the first message: %" PRIxPTR", %" PRIxPTR ".\n", gdb_dbg_pid, gdb_dbg_tid);
|
|
|
|
/* The next receive call will be asking for the version data */
|
|
KdpSendPacketHandler = NULL;
|
|
KdpManipulateStateHandler = GetVersionManipulateStateHandler;
|
|
return TRUE;
|
|
}
|
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
|
|
/******************************************************************************
|
|
* \name KdReceivePacket
|
|
* \brief Receive a packet from the KD port.
|
|
* \param [in] PacketType Describes the type of the packet to receive.
|
|
* This can be one of the PACKET_TYPE_ constants.
|
|
* \param [out] MessageHeader Pointer to a STRING structure for the header.
|
|
* \param [out] MessageData Pointer to a STRING structure for the data.
|
|
* \return KdPacketReceived if successful, KdPacketTimedOut if the receive
|
|
* timed out, KdPacketNeedsResend to signal that the last packet needs
|
|
* to be sent again.
|
|
* \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
|
|
* wait for any data, but returns KdPacketTimedOut instantly if no breakin
|
|
* packet byte is received.
|
|
* \sa http://www.nynaeve.net/?p=169
|
|
*/
|
|
KDSTATUS
|
|
NTAPI
|
|
KdReceivePacket(
|
|
_In_ ULONG PacketType,
|
|
_Out_ PSTRING MessageHeader,
|
|
_Out_ PSTRING MessageData,
|
|
_Out_ PULONG DataLength,
|
|
_Inout_ PKD_CONTEXT KdContext)
|
|
{
|
|
KDDBGPRINT("KdReceivePacket --> ");
|
|
|
|
if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
|
|
{
|
|
static BOOLEAN firstTime = TRUE;
|
|
KDDBGPRINT("Polling break in.\n");
|
|
if (firstTime)
|
|
{
|
|
/* Force debug break on init */
|
|
firstTime = FALSE;
|
|
return KdPacketReceived;
|
|
}
|
|
|
|
return KdpPollBreakIn();
|
|
}
|
|
|
|
if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
|
|
{
|
|
static BOOLEAN ignore = 0;
|
|
KDDBGPRINT("Debug prompt.\n");
|
|
/* HACK ! Debug prompt asks for break or ignore. First break, then ignore. */
|
|
MessageData->Length = 1;
|
|
MessageData->Buffer[0] = ignore ? 'i' : 'b';
|
|
ignore = !ignore;
|
|
return KdPacketReceived;
|
|
}
|
|
|
|
if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
|
|
{
|
|
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
|
|
|
KDDBGPRINT("State manipulation: ");
|
|
|
|
/* Maybe we are in a send<->receive loop that GDB doesn't need to know about */
|
|
if (KdpManipulateStateHandler != NULL)
|
|
{
|
|
KDDBGPRINT("We have a manipulate state handler.\n");
|
|
return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
|
|
}
|
|
|
|
/* Receive data from GDB and interpret it */
|
|
KDDBGPRINT("Receiving data from GDB.\n");
|
|
return gdb_receive_and_interpret_packet(State, MessageData, DataLength, KdContext);
|
|
}
|
|
|
|
/* What should we do ? */
|
|
while (1);
|
|
return KdPacketNeedsResend;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdSendPacket(
|
|
IN ULONG PacketType,
|
|
IN PSTRING MessageHeader,
|
|
IN PSTRING MessageData,
|
|
IN OUT PKD_CONTEXT KdContext)
|
|
{
|
|
/* Override if we have some debug print from KD. */
|
|
if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
|
|
{
|
|
send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
|
|
return;
|
|
}
|
|
|
|
/* Maybe we are in a send <-> receive loop that GDB doesn't need to know about */
|
|
if (KdpSendPacketHandler
|
|
&& KdpSendPacketHandler(PacketType, MessageHeader, MessageData))
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (PacketType)
|
|
{
|
|
case PACKET_TYPE_KD_STATE_CHANGE64:
|
|
send_kd_state_change((DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer);
|
|
return;
|
|
case PACKET_TYPE_KD_DEBUG_IO:
|
|
send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
|
|
break;
|
|
case PACKET_TYPE_KD_STATE_MANIPULATE:
|
|
send_kd_state_manipulate((DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer, MessageData);
|
|
break;
|
|
default:
|
|
KDDBGPRINT("Unknown packet type %u.\n", PacketType);
|
|
while (1);
|
|
}
|
|
}
|
|
|
|
/* EOF */
|