[NTOS:KD:KDBG] Integration into KD framework (Part 1/3)

Split KdSendPacket and KdReceivePacket into those that manipulate the
KDBG state proper (reside in kdbg/kdbg.c), and those that deal only with
debug input/output that will reside in a KDTERM "KD Terminal Driver" DLL.

Based on some previous preparatory work by Hervé Poussineau in PR #4600.
(Equivalents of commits 5162bf106 and partly e9bcf7275.)
This commit is contained in:
Hermès Bélusca-Maïto 2023-03-21 18:42:29 +01:00
parent 823b51558d
commit 2046a17ef4
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
7 changed files with 245 additions and 152 deletions

View file

@ -30,13 +30,6 @@ KdPortPutByteEx(
/* KD GLOBALS ****************************************************************/ /* KD GLOBALS ****************************************************************/
typedef enum _KD_CONTINUE_TYPE
{
kdContinue = 0,
kdDoNotHandleException,
kdHandleException
} KD_CONTINUE_TYPE;
/* KD Internal Debug Services */ /* KD Internal Debug Services */
typedef enum _KDP_DEBUG_SERVICE typedef enum _KDP_DEBUG_SERVICE
{ {

View file

@ -88,13 +88,15 @@
#define NOEXTAPI #define NOEXTAPI
#include <windbgkd.h> #include <windbgkd.h>
#include <wdbgexts.h> #include <wdbgexts.h>
#ifdef KDBG
#define KdDebuggerInitialize0 KdpDebuggerInitialize0
#define KdDebuggerInitialize1 KdpDebuggerInitialize1
#define KdSendPacket KdpSendPacket
#define KdReceivePacket KdpReceivePacket
#endif
#include <kddll.h> #include <kddll.h>
#ifdef KDBG
/* Define new names for these exports also present in KDBG */
#define KdSendPacket KdbgSendPacket
#define KdReceivePacket KdbgReceivePacket
/* And reload the definitions with these new names */
#undef _KDDLL_
#include <kddll.h>
#endif
#ifdef __ROS_ROSSYM__ #ifdef __ROS_ROSSYM__
#include <reactos/rossym.h> #include <reactos/rossym.h>
#endif #endif

View file

@ -20,6 +20,9 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
#undef KdSendPacket
#undef KdReceivePacket
/* GLOBALS *******************************************************************/ /* GLOBALS *******************************************************************/
#define KdpBufferSize (1024 * 512) #define KdpBufferSize (1024 * 512)
@ -54,12 +57,6 @@ PKDP_INIT_ROUTINE InitRoutines[KdMax] =
#endif #endif
}; };
static ULONG KdbgNextApiNumber = DbgKdContinueApi;
static CONTEXT KdbgContext;
static EXCEPTION_RECORD64 KdbgExceptionRecord;
static BOOLEAN KdbgFirstChanceException;
static NTSTATUS KdbgContinueStatus = STATUS_SUCCESS;
/* LOCKING FUNCTIONS *********************************************************/ /* LOCKING FUNCTIONS *********************************************************/
KIRQL KIRQL
@ -607,93 +604,36 @@ KdSendPacket(
_In_opt_ PSTRING MessageData, _In_opt_ PSTRING MessageData,
_Inout_ PKD_CONTEXT Context) _Inout_ PKD_CONTEXT Context)
{ {
if (PacketType == PACKET_TYPE_KD_DEBUG_IO) PDBGKD_DEBUG_IO DebugIo;
if (PacketType != PACKET_TYPE_KD_DEBUG_IO)
{ {
ULONG ApiNumber = ((PDBGKD_DEBUG_IO)MessageHeader->Buffer)->ApiNumber; KdIoPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType);
/* Validate API call */
if (MessageHeader->Length != sizeof(DBGKD_DEBUG_IO))
return;
if ((ApiNumber != DbgKdPrintStringApi) &&
(ApiNumber != DbgKdGetStringApi))
{
return;
}
if (!MessageData)
return;
/* NOTE: MessageData->Length should be equal to
* DebugIo.u.PrintString.LengthOfString, or to
* DebugIo.u.GetString.LengthOfPromptString */
if (!KdpDebugMode.Value)
return;
/* Print the string proper */
KdIoPrintString(MessageData->Buffer, MessageData->Length);
return; return;
} }
else if (PacketType == PACKET_TYPE_KD_STATE_CHANGE64)
{
PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange = (PDBGKD_ANY_WAIT_STATE_CHANGE)MessageHeader->Buffer;
if (WaitStateChange->NewState == DbgKdLoadSymbolsStateChange)
{
#ifdef KDBG
PLDR_DATA_TABLE_ENTRY LdrEntry;
/* Load symbols. Currently implemented only for KDBG! */
if (KdbpSymFindModule((PVOID)(ULONG_PTR)WaitStateChange->u.LoadSymbols.BaseOfDll, -1, &LdrEntry))
{
KdbSymProcessSymbols(LdrEntry, !WaitStateChange->u.LoadSymbols.UnloadSymbols);
}
#endif
return;
}
else if (WaitStateChange->NewState == DbgKdExceptionStateChange)
{
KdbgNextApiNumber = DbgKdGetContextApi;
KdbgExceptionRecord = WaitStateChange->u.Exception.ExceptionRecord;
KdbgFirstChanceException = WaitStateChange->u.Exception.FirstChance;
return;
}
}
else if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
{
PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer;
if (ManipulateState->ApiNumber == DbgKdGetContextApi)
{
KD_CONTINUE_TYPE Result;
#ifdef KDBG DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
/* Check if this is an assertion failure */
if (KdbgExceptionRecord.ExceptionCode == STATUS_ASSERTION_FAILURE)
{
/* Bump EIP to the instruction following the int 2C */
KeSetContextPc(&KdbgContext, KeGetContextPc(&KdbgContext) + 2);
}
Result = KdbEnterDebuggerException(&KdbgExceptionRecord, /* Validate API call */
KdbgContext.SegCs & 1, if (MessageHeader->Length != sizeof(DBGKD_DEBUG_IO))
&KdbgContext, return;
KdbgFirstChanceException); if ((DebugIo->ApiNumber != DbgKdPrintStringApi) &&
#else (DebugIo->ApiNumber != DbgKdGetStringApi))
/* We'll manually dump the stack for the user... */ {
KeRosDumpStackFrames(NULL, 0); return;
Result = kdHandleException;
#endif
if (Result != kdHandleException)
KdbgContinueStatus = STATUS_SUCCESS;
else
KdbgContinueStatus = STATUS_UNSUCCESSFUL;
KdbgNextApiNumber = DbgKdSetContextApi;
return;
}
else if (ManipulateState->ApiNumber == DbgKdSetContextApi)
{
KdbgNextApiNumber = DbgKdContinueApi;
return;
}
} }
UNIMPLEMENTED; if (!MessageData)
return;
/* NOTE: MessageData->Length should be equal to
* DebugIo.u.PrintString.LengthOfString, or to
* DebugIo.u.GetString.LengthOfPromptString */
if (!KdpDebugMode.Value)
return;
/* Print the string proper */
KdIoPrintString(MessageData->Buffer, MessageData->Length);
} }
KDSTATUS KDSTATUS
@ -705,48 +645,16 @@ KdReceivePacket(
_Out_ PULONG DataLength, _Out_ PULONG DataLength,
_Inout_ PKD_CONTEXT Context) _Inout_ PKD_CONTEXT Context)
{ {
#ifdef KDBG
STRING ResponseString;
PDBGKD_DEBUG_IO DebugIo; PDBGKD_DEBUG_IO DebugIo;
STRING ResponseString;
CHAR MessageBuffer[512]; CHAR MessageBuffer[512];
#endif
if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
{
PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer;
RtlZeroMemory(MessageHeader->Buffer, MessageHeader->MaximumLength);
if (KdbgNextApiNumber == DbgKdGetContextApi)
{
ManipulateState->ApiNumber = DbgKdGetContextApi;
MessageData->Length = 0;
MessageData->Buffer = (PCHAR)&KdbgContext;
return KdPacketReceived;
}
else if (KdbgNextApiNumber == DbgKdSetContextApi)
{
ManipulateState->ApiNumber = DbgKdSetContextApi;
MessageData->Length = sizeof(KdbgContext);
MessageData->Buffer = (PCHAR)&KdbgContext;
return KdPacketReceived;
}
else if (KdbgNextApiNumber != DbgKdContinueApi)
{
UNIMPLEMENTED;
}
ManipulateState->ApiNumber = DbgKdContinueApi;
ManipulateState->u.Continue.ContinueStatus = KdbgContinueStatus;
/* Prepare for next time */
KdbgNextApiNumber = DbgKdContinueApi;
KdbgContinueStatus = STATUS_SUCCESS;
return KdPacketReceived;
}
if (PacketType != PACKET_TYPE_KD_DEBUG_IO) if (PacketType != PACKET_TYPE_KD_DEBUG_IO)
{
KdIoPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType);
return KdPacketTimedOut; return KdPacketTimedOut;
}
#ifdef KDBG
DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer; DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
/* Validate API call */ /* Validate API call */
@ -795,7 +703,6 @@ KdReceivePacket(
/* Only now we can copy back the data into MessageData->Buffer */ /* Only now we can copy back the data into MessageData->Buffer */
RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, *DataLength); RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, *DataLength);
#endif
return KdPacketReceived; return KdPacketReceived;
} }

View file

@ -51,6 +51,25 @@ typedef enum _KDB_ENTER_CONDITION
KdbEnterFromUmode KdbEnterFromUmode
} KDB_ENTER_CONDITION; } KDB_ENTER_CONDITION;
typedef enum _KD_CONTINUE_TYPE
{
kdContinue = 0,
kdDoNotHandleException,
kdHandleException
} KD_CONTINUE_TYPE;
/* GLOBALS *******************************************************************/
extern PCHAR KdbInitFileBuffer;
extern PEPROCESS KdbCurrentProcess;
extern PETHREAD KdbCurrentThread;
extern LONG KdbLastBreakPointNr;
extern ULONG KdbNumSingleSteps;
extern BOOLEAN KdbSingleStepOver;
extern PKDB_KTRAP_FRAME KdbCurrentTrapFrame;
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
@ -74,8 +93,6 @@ KdbpStackSwitchAndCall(
/* from kdb_cli.c */ /* from kdb_cli.c */
extern PCHAR KdbInitFileBuffer;
NTSTATUS NTSTATUS
NTAPI NTAPI
KdbInitialize( KdbInitialize(
@ -175,13 +192,6 @@ KdbSymInit(
/* from kdb.c */ /* from kdb.c */
extern PEPROCESS KdbCurrentProcess;
extern PETHREAD KdbCurrentThread;
extern LONG KdbLastBreakPointNr;
extern ULONG KdbNumSingleSteps;
extern BOOLEAN KdbSingleStepOver;
extern PKDB_KTRAP_FRAME KdbCurrentTrapFrame;
LONG LONG
KdbpGetNextBreakPointNr( KdbpGetNextBreakPointNr(
IN ULONG Start OPTIONAL); IN ULONG Start OPTIONAL);

View file

@ -13,6 +13,14 @@
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
static KD_CONTEXT KdbgKdContext;
#undef KdSendPacket
#define pKdSendPacket KdSendPacket
#undef KdReceivePacket
#define pKdReceivePacket KdReceivePacket
static VOID static VOID
KdbPrintStringWorker( KdbPrintStringWorker(
_In_ const CSTRING* Output, _In_ const CSTRING* Output,
@ -48,7 +56,8 @@ KdbPrintStringWorker(
Data->Buffer = (PCHAR)Output->Buffer; Data->Buffer = (PCHAR)Output->Buffer;
/* Send the packet */ /* Send the packet */
KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, Header, Data, &KdpContext); /* IO packet: call KdTerm */
pKdSendPacket(PACKET_TYPE_KD_DEBUG_IO, Header, Data, &KdbgKdContext);
} }
VOID VOID
@ -88,11 +97,12 @@ KdbPromptStringWorker(
do do
{ {
/* Get our reply */ /* Get our reply */
Status = KdReceivePacket(PACKET_TYPE_KD_DEBUG_IO, /* IO packet: call KdTerm */
&Header, Status = pKdReceivePacket(PACKET_TYPE_KD_DEBUG_IO,
&Data, &Header,
&Length, &Data,
&KdpContext); &Length,
&KdbgKdContext);
/* Return TRUE if we need to resend */ /* Return TRUE if we need to resend */
if (Status == KdPacketNeedsResend) if (Status == KdPacketNeedsResend)

170
ntoskrnl/kdbg/kdbg.c Normal file
View file

@ -0,0 +1,170 @@
/*
* PROJECT: ReactOS KDBG Kernel Debugger
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Kernel Debugger Initialization
* COPYRIGHT: Copyright 2020-2021 Hervé Poussineau <hpoussin@reactos.org>
* Copyright 2021 Jérôme Gardou <jerome.gardou@reactos.org>
* Copyright 2023 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#include "kdb.h"
/* GLOBALS *******************************************************************/
static ULONG KdbgNextApiNumber = DbgKdContinueApi;
static CONTEXT KdbgContext;
static EXCEPTION_RECORD64 KdbgExceptionRecord;
static BOOLEAN KdbgFirstChanceException;
static NTSTATUS KdbgContinueStatus = STATUS_SUCCESS;
/* FUNCTIONS *****************************************************************/
VOID
NTAPI
KdSendPacket(
_In_ ULONG PacketType,
_In_ PSTRING MessageHeader,
_In_opt_ PSTRING MessageData,
_Inout_ PKD_CONTEXT Context)
#undef KdSendPacket
#define pKdSendPacket KdSendPacket
{
if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
{
/* Call KdTerm */
pKdSendPacket(PacketType, MessageHeader, MessageData, Context);
return;
}
/* Debugger-only packets */
if (PacketType == PACKET_TYPE_KD_STATE_CHANGE64)
{
PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange = (PDBGKD_ANY_WAIT_STATE_CHANGE)MessageHeader->Buffer;
if (WaitStateChange->NewState == DbgKdLoadSymbolsStateChange)
{
/* Load or unload symbols */
PLDR_DATA_TABLE_ENTRY LdrEntry;
if (KdbpSymFindModule((PVOID)(ULONG_PTR)WaitStateChange->u.LoadSymbols.BaseOfDll, -1, &LdrEntry))
{
KdbSymProcessSymbols(LdrEntry, !WaitStateChange->u.LoadSymbols.UnloadSymbols);
}
return;
}
else if (WaitStateChange->NewState == DbgKdExceptionStateChange)
{
KdbgNextApiNumber = DbgKdGetContextApi;
KdbgExceptionRecord = WaitStateChange->u.Exception.ExceptionRecord;
KdbgFirstChanceException = WaitStateChange->u.Exception.FirstChance;
return;
}
}
else if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
{
PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer;
if (ManipulateState->ApiNumber == DbgKdGetContextApi)
{
KD_CONTINUE_TYPE Result;
/* Check if this is an assertion failure */
if (KdbgExceptionRecord.ExceptionCode == STATUS_ASSERTION_FAILURE)
{
/* Bump EIP to the instruction following the int 2C */
KeSetContextPc(&KdbgContext, KeGetContextPc(&KdbgContext) + 2);
}
Result = KdbEnterDebuggerException(&KdbgExceptionRecord,
KdbgContext.SegCs & 1,
&KdbgContext,
KdbgFirstChanceException);
#if 0
/* Manually dump the stack for the user */
KeRosDumpStackFrames(NULL, 0);
Result = kdHandleException;
#endif
if (Result != kdHandleException)
KdbgContinueStatus = STATUS_SUCCESS;
else
KdbgContinueStatus = STATUS_UNSUCCESSFUL;
KdbgNextApiNumber = DbgKdSetContextApi;
return;
}
else if (ManipulateState->ApiNumber == DbgKdSetContextApi)
{
KdbgNextApiNumber = DbgKdContinueApi;
return;
}
}
KdbPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType);
return;
}
KDSTATUS
NTAPI
KdReceivePacket(
_In_ ULONG PacketType,
_Out_ PSTRING MessageHeader,
_Out_ PSTRING MessageData,
_Out_ PULONG DataLength,
_Inout_ PKD_CONTEXT Context)
#undef KdReceivePacket
#define pKdReceivePacket KdReceivePacket
{
if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
{
// FIXME TODO: Implement break-in for the debugger
// and return KdPacketReceived when handled properly.
return KdPacketTimedOut;
}
if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
{
/* Call KdTerm */
return pKdReceivePacket(PacketType,
MessageHeader,
MessageData,
DataLength,
Context);
}
/* Debugger-only packets */
if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
{
PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer;
RtlZeroMemory(MessageHeader->Buffer, MessageHeader->MaximumLength);
if (KdbgNextApiNumber == DbgKdGetContextApi)
{
ManipulateState->ApiNumber = DbgKdGetContextApi;
MessageData->Length = 0;
MessageData->Buffer = (PCHAR)&KdbgContext;
return KdPacketReceived;
}
else if (KdbgNextApiNumber == DbgKdSetContextApi)
{
ManipulateState->ApiNumber = DbgKdSetContextApi;
MessageData->Length = sizeof(KdbgContext);
MessageData->Buffer = (PCHAR)&KdbgContext;
return KdPacketReceived;
}
else if (KdbgNextApiNumber != DbgKdContinueApi)
{
KdbPrintf("%s:%d is UNIMPLEMENTED\n", __FUNCTION__, __LINE__);
}
ManipulateState->ApiNumber = DbgKdContinueApi;
ManipulateState->u.Continue.ContinueStatus = KdbgContinueStatus;
/* Prepare for next time */
KdbgNextApiNumber = DbgKdContinueApi;
KdbgContinueStatus = STATUS_SUCCESS;
return KdPacketReceived;
}
KdbPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType);
return KdPacketTimedOut;
}
/* EOF */

View file

@ -404,6 +404,7 @@ if(NOT _WINKD_)
if(KDBG) if(KDBG)
list(APPEND SOURCE list(APPEND SOURCE
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdbg.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb.c ${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_cli.c ${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_cli.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_cmdhist.c ${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_cmdhist.c