[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 ****************************************************************/
typedef enum _KD_CONTINUE_TYPE
{
kdContinue = 0,
kdDoNotHandleException,
kdHandleException
} KD_CONTINUE_TYPE;
/* KD Internal Debug Services */
typedef enum _KDP_DEBUG_SERVICE
{

View file

@ -88,13 +88,15 @@
#define NOEXTAPI
#include <windbgkd.h>
#include <wdbgexts.h>
#ifdef KDBG
#define KdDebuggerInitialize0 KdpDebuggerInitialize0
#define KdDebuggerInitialize1 KdpDebuggerInitialize1
#define KdSendPacket KdpSendPacket
#define KdReceivePacket KdpReceivePacket
#endif
#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__
#include <reactos/rossym.h>
#endif

View file

@ -20,6 +20,9 @@
#define NDEBUG
#include <debug.h>
#undef KdSendPacket
#undef KdReceivePacket
/* GLOBALS *******************************************************************/
#define KdpBufferSize (1024 * 512)
@ -54,12 +57,6 @@ PKDP_INIT_ROUTINE InitRoutines[KdMax] =
#endif
};
static ULONG KdbgNextApiNumber = DbgKdContinueApi;
static CONTEXT KdbgContext;
static EXCEPTION_RECORD64 KdbgExceptionRecord;
static BOOLEAN KdbgFirstChanceException;
static NTSTATUS KdbgContinueStatus = STATUS_SUCCESS;
/* LOCKING FUNCTIONS *********************************************************/
KIRQL
@ -607,93 +604,36 @@ KdSendPacket(
_In_opt_ PSTRING MessageData,
_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;
/* 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);
KdIoPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType);
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
/* 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);
}
DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
Result = KdbEnterDebuggerException(&KdbgExceptionRecord,
KdbgContext.SegCs & 1,
&KdbgContext,
KdbgFirstChanceException);
#else
/* We'll 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;
}
/* Validate API call */
if (MessageHeader->Length != sizeof(DBGKD_DEBUG_IO))
return;
if ((DebugIo->ApiNumber != DbgKdPrintStringApi) &&
(DebugIo->ApiNumber != DbgKdGetStringApi))
{
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
@ -705,48 +645,16 @@ KdReceivePacket(
_Out_ PULONG DataLength,
_Inout_ PKD_CONTEXT Context)
{
#ifdef KDBG
STRING ResponseString;
PDBGKD_DEBUG_IO DebugIo;
STRING ResponseString;
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)
{
KdIoPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType);
return KdPacketTimedOut;
}
#ifdef KDBG
DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
/* Validate API call */
@ -795,7 +703,6 @@ KdReceivePacket(
/* Only now we can copy back the data into MessageData->Buffer */
RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, *DataLength);
#endif
return KdPacketReceived;
}

View file

@ -51,6 +51,25 @@ typedef enum _KDB_ENTER_CONDITION
KdbEnterFromUmode
} 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 *****************************************************************/
@ -74,8 +93,6 @@ KdbpStackSwitchAndCall(
/* from kdb_cli.c */
extern PCHAR KdbInitFileBuffer;
NTSTATUS
NTAPI
KdbInitialize(
@ -175,13 +192,6 @@ KdbSymInit(
/* from kdb.c */
extern PEPROCESS KdbCurrentProcess;
extern PETHREAD KdbCurrentThread;
extern LONG KdbLastBreakPointNr;
extern ULONG KdbNumSingleSteps;
extern BOOLEAN KdbSingleStepOver;
extern PKDB_KTRAP_FRAME KdbCurrentTrapFrame;
LONG
KdbpGetNextBreakPointNr(
IN ULONG Start OPTIONAL);

View file

@ -13,6 +13,14 @@
/* FUNCTIONS *****************************************************************/
static KD_CONTEXT KdbgKdContext;
#undef KdSendPacket
#define pKdSendPacket KdSendPacket
#undef KdReceivePacket
#define pKdReceivePacket KdReceivePacket
static VOID
KdbPrintStringWorker(
_In_ const CSTRING* Output,
@ -48,7 +56,8 @@ KdbPrintStringWorker(
Data->Buffer = (PCHAR)Output->Buffer;
/* 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
@ -88,11 +97,12 @@ KdbPromptStringWorker(
do
{
/* Get our reply */
Status = KdReceivePacket(PACKET_TYPE_KD_DEBUG_IO,
&Header,
&Data,
&Length,
&KdpContext);
/* IO packet: call KdTerm */
Status = pKdReceivePacket(PACKET_TYPE_KD_DEBUG_IO,
&Header,
&Data,
&Length,
&KdbgKdContext);
/* Return TRUE if we need to resend */
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)
list(APPEND SOURCE
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdbg.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_cli.c
${REACTOS_SOURCE_DIR}/ntoskrnl/kdbg/kdb_cmdhist.c