Add possibility to make KDB break on module-loads. Fix handling of breakpoints in usermode with KDB. Set ExceptionRecord->ExceptionFlags to 0 for breakpoints/singlesteps and noncontinuable for everything else. Fix WriteProcessMemory.

svn path=/trunk/; revision=12973
This commit is contained in:
Gregor Anich 2005-01-12 19:04:06 +00:00
parent 030b0867f6
commit d0a2f448f4
7 changed files with 210 additions and 69 deletions

View file

@ -60,8 +60,9 @@ static KDB_ACTIVE_BREAKPOINT
static BOOLEAN KdbHandleUmode = FALSE;
static BOOLEAN KdbHandleHandled = FALSE;
static BOOLEAN KdbIgnoreNextSingleStep = FALSE;
static BOOLEAN KdbBreakOnModuleLoad = FALSE;
static BOOLEAN KdbIgnoreNextSingleStep = FALSE;
static ULONG KdbLastSingleStepFrom = 0xFFFFFFFF;
static BOOLEAN KdbEnteredOnSingleStep = FALSE;
@ -75,6 +76,8 @@ DbgContCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgStopCondition(ULONG Aargc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgModuleLoadedAction(ULONG Aargc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgEchoToggle(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
ULONG
DbgRegsCommand(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf);
@ -129,7 +132,8 @@ struct
{"cont", "cont", "Exit the debugger", DbgContCommand},
{"echo", "echo", "Toggle serial echo", DbgEchoToggle},
{"condition", "condition [all|umode|kmode]", "Kdbg enter condition", DbgStopCondition},
{"module-loaded", "module-loaded [break|continue]", "Module-loaded action", DbgModuleLoadedAction},
{"regs", "regs", "Display general purpose registers", DbgRegsCommand},
{"dregs", "dregs", "Display debug registers", DbgDRegsCommand},
{"cregs", "cregs", "Display control registers", DbgCRegsCommand},
@ -909,9 +913,8 @@ DbgPrintBackTrace(PULONG Frame, ULONG_PTR StackBase, ULONG_PTR StackLimit)
{
PVOID Address;
DbgPrint("Frames: ");
while (Frame != NULL && (ULONG_PTR)Frame >= StackLimit &&
(ULONG_PTR)Frame < StackBase) /* FIXME: why limit this to StackBase/StackLimit? */
DbgPrint("Frames:\n");
while (Frame != NULL)
{
if (!NT_SUCCESS(KdbpSafeReadMemory(&Address, Frame + 1, sizeof (Address))))
{
@ -1352,6 +1355,32 @@ DbgStopCondition(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
return(TRUE);
}
ULONG
DbgModuleLoadedAction(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
{
if (Argc == 1)
{
if (KdbBreakOnModuleLoad)
DbgPrint("Current setting: break\n");
else
DbgPrint("Current setting: continue\n");
}
else if (!strcmp(Argv[1], "break"))
{
KdbBreakOnModuleLoad = TRUE;
}
else if (!strcmp(Argv[1], "continue"))
{
KdbBreakOnModuleLoad = FALSE;
}
else
{
DbgPrint("Unknown setting: %s\n", Argv[1]);
}
return(TRUE);
}
ULONG
DbgEchoToggle(ULONG Argc, PCH Argv[], PKTRAP_FRAME Tf)
{
@ -1656,23 +1685,24 @@ KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
LONG BreakPointNr;
ULONG ExpNr = (ULONG)TrapFrame->DebugArgMark;
/* Always handle beakpoints */
if (ExpNr != 1 && ExpNr != 3)
{
DbgPrint(":KDBG:Entered:%s:%s\n",
PreviousMode==KernelMode ? "kmode" : "umode",
AlwaysHandle ? "always" : "if-unhandled");
}
/* If we aren't handling umode exceptions then return */
if (PreviousMode == UserMode && !KdbHandleUmode && !AlwaysHandle)
{
return kdContinue;
}
/* If the exception would be unhandled (and we care) then handle it */
if (PreviousMode == KernelMode && !KdbHandleHandled && !AlwaysHandle)
{
return kdContinue;
/* If we aren't handling umode exceptions then return */
if (PreviousMode == UserMode && !KdbHandleUmode && !AlwaysHandle)
{
return kdHandleException;
}
/* If the exception would be unhandled (and we care) then handle it */
if (PreviousMode == KernelMode && !KdbHandleHandled && !AlwaysHandle)
{
return kdHandleException;
}
}
/* Exception inside the debugger? Game over. */
@ -1772,3 +1802,14 @@ KdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
return(kdContinue);
}
}
VOID
KdbModuleLoaded(IN PUNICODE_STRING Name)
{
if (!KdbBreakOnModuleLoad)
return;
DbgPrint("Module %wZ loaded.\n", Name);
DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
}

View file

@ -72,6 +72,10 @@ KdbEnableProfiling();
VOID
KdbProfileInterrupt(ULONG_PTR Eip);
VOID
KdbModuleLoaded(IN PUNICODE_STRING Name);
struct KDB_BPINFO {
DWORD Addr;
DWORD Type;

View file

@ -816,6 +816,9 @@ KdbpSymLoadModuleSymbols(IN PUNICODE_STRING FileName,
PSYMBOLFILE_HEADER SymbolFileHeader;
PIMAGE_SYMBOL_INFO_CACHE CachedSymbolFile;
/* Allow KDB to break on module load */
KdbModuleLoaded(FileName);
/* Get the path to the symbol store */
wcscpy(TmpFileName, L"\\SystemRoot\\symbols\\");

View file

@ -50,6 +50,7 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
DPRINT("KiDispatchException() called\n");
/* PCR->KeExceptionDispatchCount++; */
if (Context == NULL)
@ -95,8 +96,12 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
NTSTATUS StatusOfCopy;
#ifdef KDBG
KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
Context, Tf, FALSE);
Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
Context, Tf, FALSE);
if (Action == kdContinue)
{
return;
}
#endif
/* FIXME: Forward exception to user mode debugger */
@ -141,8 +146,12 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
/* FIXME: Forward the exception to the process exception port */
#ifdef KDBG
KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
Context, Tf, TRUE);
Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
Context, Tf, TRUE);
if (Action == kdContinue)
{
return;
}
#endif
/* Terminate the offending thread */
@ -153,8 +162,12 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
{
/* PreviousMode == KernelMode */
#ifdef KDBG
KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
Context, Tf, FALSE);
Action = KdbEnterDebuggerException (ExceptionRecord, PreviousMode,
Context, Tf, FALSE);
if (Action == kdContinue)
{
return;
}
#endif
Value = RtlpDispatchException (ExceptionRecord, Context);

View file

@ -190,9 +190,9 @@ KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
Er.NumberParameters = 0;
}
Er.ExceptionFlags = ((NTSTATUS) STATUS_SINGLE_STEP == (NTSTATUS) Er.ExceptionCode
|| (NTSTATUS) STATUS_BREAKPOINT == (NTSTATUS) Er.ExceptionCode) ?
EXCEPTION_NONCONTINUABLE : 0;
Er.ExceptionFlags = (STATUS_SINGLE_STEP == Er.ExceptionCode ||
STATUS_BREAKPOINT == Er.ExceptionCode) ?
0 : EXCEPTION_NONCONTINUABLE;
KiDispatchException(&Er, 0, Tf, KernelMode, TRUE);

View file

@ -132,9 +132,9 @@ KiUserTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
}
Er.ExceptionFlags = ((NTSTATUS) STATUS_SINGLE_STEP == (NTSTATUS) Er.ExceptionCode ||
(NTSTATUS) STATUS_BREAKPOINT == (NTSTATUS) Er.ExceptionCode) ?
EXCEPTION_NONCONTINUABLE : 0;
Er.ExceptionFlags = (STATUS_SINGLE_STEP == Er.ExceptionCode ||
STATUS_BREAKPOINT == Er.ExceptionCode) ?
0 : EXCEPTION_NONCONTINUABLE;
KiDispatchException(&Er, 0, Tf, UserMode, TRUE);
return(0);

View file

@ -350,6 +350,56 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
}
NTSTATUS STDCALL
MiProtectVirtualMemory(IN PEPROCESS Process,
IN OUT PVOID *BaseAddress,
IN OUT PULONG NumberOfBytesToProtect,
IN ULONG NewAccessProtection,
OUT PULONG OldAccessProtection OPTIONAL)
{
PMEMORY_AREA MemoryArea;
PMADDRESS_SPACE AddressSpace;
ULONG OldAccessProtection_;
NTSTATUS Status;
*NumberOfBytesToProtect =
PAGE_ROUND_UP((*BaseAddress) + (*NumberOfBytesToProtect)) -
PAGE_ROUND_DOWN(*BaseAddress);
*BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
AddressSpace = &Process->AddressSpace;
MmLockAddressSpace(AddressSpace);
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
if (MemoryArea == NULL)
{
MmUnlockAddressSpace(AddressSpace);
return STATUS_UNSUCCESSFUL;
}
if (OldAccessProtection == NULL)
OldAccessProtection = &OldAccessProtection_;
if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
{
Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress,
*NumberOfBytesToProtect, NewAccessProtection,
OldAccessProtection);
}
else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
{
Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress,
*NumberOfBytesToProtect,
NewAccessProtection,
OldAccessProtection);
}
MmUnlockAddressSpace(AddressSpace);
return Status;
}
/* (tMk 2004.II.5)
* FUNCTION:
* Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
@ -357,15 +407,13 @@ NtQueryVirtualMemory (IN HANDLE ProcessHandle,
*/
NTSTATUS STDCALL
NtProtectVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID *UnsafeBaseAddress,
IN ULONG *UnsafeNumberOfBytesToProtect,
IN OUT PVOID *UnsafeBaseAddress,
IN OUT ULONG *UnsafeNumberOfBytesToProtect,
IN ULONG NewAccessProtection,
OUT PULONG UnsafeOldAccessProtection)
{
PMEMORY_AREA MemoryArea;
PEPROCESS Process;
NTSTATUS Status;
PMADDRESS_SPACE AddressSpace;
ULONG OldAccessProtection;
PVOID BaseAddress;
ULONG NumberOfBytesToProtect;
@ -377,18 +425,14 @@ NtProtectVirtualMemory(IN HANDLE ProcessHandle,
if (!NT_SUCCESS(Status))
return Status;
// (tMk 2004.II.5) in Microsoft SDK I read:
// 'if this parameter is NULL or does not point to a valid variable, the function fails'
/* (tMk 2004.II.5) in Microsoft SDK I read:
* 'if this parameter is NULL or does not point to a valid variable, the function fails'
*/
if(UnsafeOldAccessProtection == NULL)
{
return(STATUS_INVALID_PARAMETER);
}
NumberOfBytesToProtect =
PAGE_ROUND_UP(BaseAddress + NumberOfBytesToProtect) -
PAGE_ROUND_DOWN(BaseAddress);
BaseAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_VM_OPERATION,
PsProcessType,
@ -401,32 +445,12 @@ NtProtectVirtualMemory(IN HANDLE ProcessHandle,
return(Status);
}
AddressSpace = &Process->AddressSpace;
Status = MiProtectVirtualMemory(Process,
&BaseAddress,
&NumberOfBytesToProtect,
NewAccessProtection,
&OldAccessProtection);
MmLockAddressSpace(AddressSpace);
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
if (MemoryArea == NULL)
{
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
return(STATUS_UNSUCCESSFUL);
}
if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
{
Status = MmProtectAnonMem(AddressSpace, MemoryArea, BaseAddress,
NumberOfBytesToProtect, NewAccessProtection,
&OldAccessProtection);
}
else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
{
Status = MmProtectSectionView(AddressSpace, MemoryArea, BaseAddress,
NumberOfBytesToProtect,
NewAccessProtection,
&OldAccessProtection);
}
MmUnlockAddressSpace(AddressSpace);
ObDereferenceObject(Process);
MmCopyToCaller(UnsafeOldAccessProtection, &OldAccessProtection, sizeof(ULONG));
@ -590,12 +614,15 @@ NtWriteVirtualMemory(IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN PVOID Buffer,
IN ULONG NumberOfBytesToWrite,
OUT PULONG NumberOfBytesWritten)
OUT PULONG NumberOfBytesWritten OPTIONAL)
{
NTSTATUS Status;
PMDL Mdl;
PVOID SystemAddress;
PEPROCESS Process;
ULONG OldProtection = 0;
PVOID ProtectBaseAddress;
ULONG ProtectNumberOfBytes;
DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
"Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
@ -612,23 +639,62 @@ NtWriteVirtualMemory(IN HANDLE ProcessHandle,
return(Status);
}
/* We have to make sure the target memory is writable.
*
* I am not sure if it is correct to do this in any case, but it has to be
* done at least in some cases because you can use WriteProcessMemory to
* write into the .text section of a module where memcpy() would crash.
* -blight (2005/01/09)
*/
ProtectBaseAddress = BaseAddress;
ProtectNumberOfBytes = NumberOfBytesToWrite;
/* Write memory */
if (Process == PsGetCurrentProcess())
{
Status = MiProtectVirtualMemory(Process,
&ProtectBaseAddress,
&ProtectNumberOfBytes,
PAGE_READWRITE,
&OldProtection);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Process);
return Status;
}
memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
}
else
{
/* Create MDL describing the source buffer. */
Mdl = MmCreateMdl(NULL,
Buffer,
NumberOfBytesToWrite);
MmProbeAndLockPages(Mdl,
UserMode,
IoReadAccess);
if(Mdl == NULL)
{
ObDereferenceObject(Process);
return(STATUS_NO_MEMORY);
}
/* Make the target area writable. */
Status = MiProtectVirtualMemory(Process,
&ProtectBaseAddress,
&ProtectNumberOfBytes,
PAGE_READWRITE,
&OldProtection);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Process);
ExFreePool(Mdl);
return Status;
}
/* Map the MDL. */
MmProbeAndLockPages(Mdl,
UserMode,
IoReadAccess);
/* Copy memory from the mapped MDL into the target buffer. */
KeAttachProcess(&Process->Pcb);
SystemAddress = MmGetSystemAddressForMdl(Mdl);
@ -636,6 +702,7 @@ NtWriteVirtualMemory(IN HANDLE ProcessHandle,
KeDetachProcess();
/* Free the MDL. */
if (Mdl->MappedSystemVa != NULL)
{
MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
@ -644,9 +711,22 @@ NtWriteVirtualMemory(IN HANDLE ProcessHandle,
ExFreePool(Mdl);
}
/* Reset the protection of the target memory. */
Status = MiProtectVirtualMemory(Process,
&ProtectBaseAddress,
&ProtectNumberOfBytes,
OldProtection,
&OldProtection);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to reset protection of the target memory! (Status 0x%x)\n", Status);
/* FIXME: Should we bugcheck here? */
}
ObDereferenceObject(Process);
*NumberOfBytesWritten = NumberOfBytesToWrite;
if (NumberOfBytesWritten != NULL)
MmCopyToCaller(NumberOfBytesWritten, &NumberOfBytesToWrite, sizeof(ULONG));
return(STATUS_SUCCESS);
}