Skip to content

Commit b15963a

Browse files
committed
[NTOS:KDBG] Reintroduce the capability of KdbpCliInit() to interpret the KDBinit file (reactos#4917)
Addendum to commit baa47fa. Similarly to what was originally done, have KdbpCliInterpretInitFile() parse the KDBinit file by breaking back into the debugger. But contrary to before, replace the deprecated call to KdbEnter() by a standard DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C) . This allows KdbEnterDebuggerException() to do the KdbpCliInterpretInitFile() call. Additional fixes and improvements: - Run KdbpCliInterpretInitFile() in full KDBG environment (interrupts disabled, modified IRQL, own stack), like the usual interactive loop. - The KDBinit data buffer must be in non-paged pool. - Demote the "Could not open KDBinit" error to a DPRINT, so that it doesn't pollute the debug log when the KDBG init function is called early (before the storage stack is initialized), or if the file doesn't exist -- since this is an optional feature.
1 parent b86c4bd commit b15963a

File tree

3 files changed

+63
-46
lines changed

3 files changed

+63
-46
lines changed

ntoskrnl/kdbg/kdb.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,20 +1141,29 @@ KdbpAttachToProcess(
11411141
return KdbpAttachToThread(Thread->Cid.UniqueThread);
11421142
}
11431143

1144-
/*!\brief Calls the main loop ...
1145-
*/
1144+
/**
1145+
* @brief Calls the main interactive debugger loop.
1146+
**/
11461147
static VOID
11471148
KdbpCallMainLoop(VOID)
11481149
{
11491150
KdbpCliMainLoop(KdbEnteredOnSingleStep);
11501151
}
11511152

1152-
/*!\brief Internal function to enter KDB.
1153+
/**
1154+
* @brief
1155+
* Internal function to enter KDBG and run the specified procedure.
11531156
*
11541157
* Disables interrupts, releases display ownership, ...
1155-
*/
1158+
*
1159+
* @param[in] Procedure
1160+
* The procedure to execute under the KDBG environment.
1161+
* Either execute the main interactive debugger loop (KdbpCallMainLoop)
1162+
* or run the KDBinit file (KdbpCliInterpretInitFile).
1163+
**/
11561164
static VOID
1157-
KdbpInternalEnter(VOID)
1165+
KdbpInternalEnter(
1166+
_In_ VOID (*Procedure)(VOID))
11581167
{
11591168
PETHREAD Thread;
11601169
PVOID SavedInitialStack, SavedStackBase, SavedKernelStack;
@@ -1166,7 +1175,7 @@ KdbpInternalEnter(VOID)
11661175
if (KdpDebugMode.Screen)
11671176
KdpScreenAcquire();
11681177

1169-
/* Call the interface's main loop on a different stack */
1178+
/* Call the specified debugger procedure on a different stack */
11701179
Thread = PsGetCurrentThread();
11711180
SavedInitialStack = Thread->Tcb.InitialStack;
11721181
SavedStackBase = Thread->Tcb.StackBase;
@@ -1179,7 +1188,7 @@ KdbpInternalEnter(VOID)
11791188
// KdbPrintf("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n",
11801189
// Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp);
11811190

1182-
KdbpStackSwitchAndCall(KdbStack + KDB_STACK_SIZE - KDB_STACK_RESERVE, KdbpCallMainLoop);
1191+
KdbpStackSwitchAndCall(KdbStack + KDB_STACK_SIZE - KDB_STACK_RESERVE, Procedure);
11831192

11841193
Thread->Tcb.InitialStack = SavedInitialStack;
11851194
Thread->Tcb.StackBase = SavedStackBase;
@@ -1276,6 +1285,7 @@ KdbEnterDebuggerException(
12761285
ULONG OldEflags;
12771286
KIRQL OldIrql;
12781287
NTSTATUS ExceptionCode;
1288+
VOID (*EntryPoint)(VOID) = KdbpCallMainLoop;
12791289

12801290
ExceptionCode = (ExceptionRecord ? ExceptionRecord->ExceptionCode : STATUS_BREAKPOINT);
12811291

@@ -1481,18 +1491,23 @@ KdbEnterDebuggerException(
14811491
}
14821492
else if (ExceptionCode == STATUS_BREAKPOINT)
14831493
{
1494+
/* Do the condition check and banner display only if we enter
1495+
* from a true code breakpoint. We skip those when running the
1496+
* KDBinit file, because it is done via an artificial breakpoint. */
14841497
if (KdbInitFileBuffer)
14851498
{
1486-
KdbpCliInterpretInitFile();
1487-
EnterConditionMet = FALSE;
1499+
EntryPoint = KdbpCliInterpretInitFile;
1500+
goto EnterKdbg;
14881501
}
1502+
14891503
if (!EnterConditionMet)
14901504
{
14911505
return kdHandleException;
14921506
}
14931507

14941508
KdbPrintf("\nEntered debugger on embedded INT3 at 0x%04x:0x%p.\n",
14951509
Context->SegCs & 0xffff, KeGetContextPc(Context));
1510+
EnterKdbg:;
14961511
}
14971512
else
14981513
{
@@ -1543,8 +1558,8 @@ KdbEnterDebuggerException(
15431558
return kdHandleException;
15441559
}
15451560

1546-
/* Call the main loop */
1547-
KdbpInternalEnter();
1561+
/* Enter KDBG proper and run either the main loop or the KDBinit file */
1562+
KdbpInternalEnter(EntryPoint);
15481563

15491564
/* Check if we should single step */
15501565
if (KdbNumSingleSteps > 0)

ntoskrnl/kdbg/kdb.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ typedef enum _KD_CONTINUE_TYPE
6161

6262
/* GLOBALS *******************************************************************/
6363

64-
extern PCHAR KdbInitFileBuffer;
64+
extern volatile PCHAR KdbInitFileBuffer;
6565

6666
extern PEPROCESS KdbCurrentProcess;
6767
extern PETHREAD KdbCurrentThread;

ntoskrnl/kdbg/kdb_cli.c

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ static ULONG KdbNumberOfColsPrinted = 0;
134134
static BOOLEAN KdbOutputAborted = FALSE;
135135
static BOOLEAN KdbRepeatLastCommand = FALSE;
136136

137-
PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */
137+
volatile PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into during initialization */
138138
BOOLEAN KdbpBugCheckRequested = FALSE;
139139

140140
/* Variables for Dmesg */
@@ -3330,20 +3330,28 @@ KdbpCliMainLoop(
33303330
}
33313331
}
33323332

3333-
/*!\brief This function is called by KdbEnterDebuggerException...
3333+
/**
3334+
* @brief
3335+
* Interprets the KDBinit file from the \SystemRoot\System32\drivers\etc
3336+
* directory, that has been loaded by KdbpCliInit().
33343337
*
3335-
* Used to interpret the init file in a context with a trapframe setup
3336-
* (KdbpCliInit call KdbEnter which will call KdbEnterDebuggerException which will
3337-
* call this function if KdbInitFileBuffer is not NULL.
3338-
*/
3338+
* This function is used to interpret the init file in the debugger context
3339+
* with a trap frame set up. KdbpCliInit() enters the debugger by calling
3340+
* DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C). In turn, this will call
3341+
* KdbEnterDebuggerException() which will finally call this function if
3342+
* KdbInitFileBuffer is not NULL.
3343+
**/
33393344
VOID
33403345
KdbpCliInterpretInitFile(VOID)
33413346
{
33423347
PCHAR p1, p2;
33433348

3349+
p1 = InterlockedExchangePointer((PVOID*)&KdbInitFileBuffer, NULL);
3350+
if (!p1)
3351+
return;
3352+
33443353
/* Execute the commands in the init file */
3345-
DPRINT("KDB: Executing KDBinit file...\n");
3346-
p1 = KdbInitFileBuffer;
3354+
KdbPuts("KDB: Executing KDBinit file...\n");
33473355
while (p1[0] != '\0')
33483356
{
33493357
size_t i = strcspn(p1, "\r\n");
@@ -3360,11 +3368,12 @@ KdbpCliInterpretInitFile(VOID)
33603368
if (strncmp(p2, "break", sizeof("break")-1) == 0 &&
33613369
(p2[sizeof("break")-1] == '\0' || isspace(p2[sizeof("break")-1])))
33623370
{
3363-
/* break into the debugger */
3371+
/* Run the interactive debugger loop */
33643372
KdbpCliMainLoop(FALSE);
33653373
}
33663374
else if (p2[0] != '#' && p2[0] != '\0') /* Ignore empty lines and comments */
33673375
{
3376+
/* Invoke the command */
33683377
KdbpDoCommand(p1);
33693378
}
33703379

@@ -3375,14 +3384,14 @@ KdbpCliInterpretInitFile(VOID)
33753384
while (p1[0] == '\r' || p1[0] == '\n')
33763385
p1++;
33773386
}
3378-
DPRINT("KDB: KDBinit executed\n");
3387+
KdbPuts("KDB: KDBinit executed\n");
33793388
}
33803389

33813390
/**
33823391
* @brief Called when KDB is initialized.
33833392
*
3384-
* Reads the KDBinit file from the SystemRoot\System32\drivers\etc directory
3385-
* and executes it.
3393+
* Loads the KDBinit file from the \SystemRoot\System32\drivers\etc
3394+
* directory and interprets it, by calling back into the debugger.
33863395
**/
33873396
NTSTATUS
33883397
KdbpCliInit(VOID)
@@ -3393,9 +3402,8 @@ KdbpCliInit(VOID)
33933402
IO_STATUS_BLOCK Iosb;
33943403
FILE_STANDARD_INFORMATION FileStdInfo;
33953404
HANDLE hFile = NULL;
3396-
INT FileSize;
3405+
ULONG FileSize;
33973406
PCHAR FileBuffer;
3398-
ULONG OldEflags;
33993407

34003408
/* Don't load the KDBinit file if its buffer is already lying around */
34013409
if (KdbInitFileBuffer)
@@ -3416,7 +3424,7 @@ KdbpCliInit(VOID)
34163424
FILE_NO_INTERMEDIATE_BUFFERING);
34173425
if (!NT_SUCCESS(Status))
34183426
{
3419-
DPRINT1("Could not open \\SystemRoot\\System32\\drivers\\etc\\KDBinit (Status 0x%lx)\n", Status);
3427+
DPRINT("Could not open %wZ (Status 0x%lx)\n", &FileName, Status);
34203428
return Status;
34213429
}
34223430

@@ -3427,22 +3435,23 @@ KdbpCliInit(VOID)
34273435
if (!NT_SUCCESS(Status))
34283436
{
34293437
ZwClose(hFile);
3430-
DPRINT1("Could not query size of \\SystemRoot\\System32\\drivers\\etc\\KDBinit (Status 0x%lx)\n", Status);
3438+
DPRINT1("Could not query size of %wZ (Status 0x%lx)\n", &FileName, Status);
34313439
return Status;
34323440
}
34333441
FileSize = FileStdInfo.EndOfFile.u.LowPart;
34343442

3435-
/* Allocate memory for the file */
3436-
FileBuffer = ExAllocatePool(PagedPool, FileSize + 1); /* add 1 byte for terminating '\0' */
3443+
/* Allocate memory for the file (add 1 byte for terminating NUL) */
3444+
FileBuffer = ExAllocatePool(NonPagedPool, FileSize + 1);
34373445
if (!FileBuffer)
34383446
{
34393447
ZwClose(hFile);
3440-
DPRINT1("Could not allocate %d bytes for KDBinit file\n", FileSize);
3448+
DPRINT1("Could not allocate %lu bytes for KDBinit file\n", FileSize);
34413449
return Status;
34423450
}
34433451

34443452
/* Load file into memory */
3445-
Status = ZwReadFile(hFile, NULL, NULL, NULL, &Iosb, FileBuffer, FileSize, NULL, NULL);
3453+
Status = ZwReadFile(hFile, NULL, NULL, NULL, &Iosb,
3454+
FileBuffer, FileSize, NULL, NULL);
34463455
ZwClose(hFile);
34473456

34483457
if (!NT_SUCCESS(Status) && (Status != STATUS_END_OF_FILE))
@@ -3452,20 +3461,13 @@ KdbpCliInit(VOID)
34523461
return Status;
34533462
}
34543463

3455-
FileSize = min(FileSize, (INT)Iosb.Information);
3456-
FileBuffer[FileSize] = '\0';
3457-
3458-
/* Enter critical section */
3459-
OldEflags = __readeflags();
3460-
_disable();
3461-
3462-
/* Interpret the init file... */
3463-
KdbInitFileBuffer = FileBuffer;
3464-
//KdbEnter(); // FIXME, see commit baa47fa5e
3465-
KdbInitFileBuffer = NULL;
3464+
FileSize = min(FileSize, (ULONG)Iosb.Information);
3465+
FileBuffer[FileSize] = ANSI_NULL;
34663466

3467-
/* Leave critical section */
3468-
__writeeflags(OldEflags);
3467+
/* Interpret the KDBinit file by calling back into the debugger */
3468+
InterlockedExchangePointer((PVOID*)&KdbInitFileBuffer, FileBuffer);
3469+
DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
3470+
InterlockedExchangePointer((PVOID*)&KdbInitFileBuffer, NULL);
34693471

34703472
ExFreePool(FileBuffer);
34713473

@@ -3607,7 +3609,7 @@ KdbInitialize(
36073609

36083610
if (BootPhase >= 2)
36093611
{
3610-
/* I/O is now set up for disk access: Read KDB Data */
3612+
/* I/O is now set up for disk access: load the KDBinit file */
36113613
NTSTATUS Status = KdbpCliInit();
36123614

36133615
/* Schedule an I/O reinitialization if needed */

0 commit comments

Comments
 (0)