From fe7669dea4b4b91ac2b42868f9ace1ef6700a874 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Mon, 1 Oct 2007 17:58:49 +0000 Subject: [PATCH] - KeRosCaptureUserStackBackTrace is now created, which calls RtlWalkFrameChain with the user-mode flag, meaning that bugchecks finally show the user-mode stack again! - KeRosDumpStackFrames is fixed so that if the EIP can't be found in a module list, it's still displayed (just without the module name). Previously the EIP would not be shown, resulting in code running on the heap/stack/somewhere else not being shown as part of the trace. svn path=/trunk/; revision=29332 --- reactos/dll/ntdll/rtl/libsupp.c | 13 ++ reactos/include/ndk/rtlfuncs.h | 9 ++ reactos/lib/rtl/exception.c | 104 ------------- reactos/ntoskrnl/ke/bug.c | 122 ++++++++++++++++ reactos/ntoskrnl/rtl/libsupp.c | 138 ++++++++++++++++++ reactos/subsystems/win32/win32k/ntuser/misc.c | 3 +- 6 files changed, 283 insertions(+), 106 deletions(-) diff --git a/reactos/dll/ntdll/rtl/libsupp.c b/reactos/dll/ntdll/rtl/libsupp.c index 82342befd5f..82d911e1aba 100644 --- a/reactos/dll/ntdll/rtl/libsupp.c +++ b/reactos/dll/ntdll/rtl/libsupp.c @@ -15,6 +15,19 @@ /* FUNCTIONS ***************************************************************/ +/* + * @implemented + */ +ULONG +NTAPI +RtlWalkFrameChain(OUT PVOID *Callers, + IN ULONG Count, + IN ULONG Flags) +{ + /* Not implemented for user-mode */ + return 0; +} + BOOLEAN NTAPI RtlpCheckForActiveDebugger(BOOLEAN Type) diff --git a/reactos/include/ndk/rtlfuncs.h b/reactos/include/ndk/rtlfuncs.h index a43f9971369..dedf53a24c9 100644 --- a/reactos/include/ndk/rtlfuncs.h +++ b/reactos/include/ndk/rtlfuncs.h @@ -448,6 +448,15 @@ RtlUnwind( // // Tracing Functions // +NTSYSAPI +ULONG +NTAPI +RtlWalkFrameChain( + OUT PVOID *Callers, + IN ULONG Count, + IN ULONG Flags +); + NTSYSAPI USHORT NTAPI diff --git a/reactos/lib/rtl/exception.c b/reactos/lib/rtl/exception.c index b320b75ca6f..ce0f0a5e80c 100644 --- a/reactos/lib/rtl/exception.c +++ b/reactos/lib/rtl/exception.c @@ -113,110 +113,6 @@ RtlRaiseStatus(NTSTATUS Status) RtlRaiseStatus(Status); } -/* - * @implemented - */ -ULONG -NTAPI -RtlWalkFrameChain(OUT PVOID *Callers, - IN ULONG Count, - IN ULONG Flags) -{ - ULONG_PTR Stack, NewStack, StackBegin, StackEnd; - ULONG Eip; - BOOLEAN Result, StopSearch = FALSE; - ULONG i = 0; - - /* Get current EBP */ -#if defined(_M_IX86) -#if defined __GNUC__ - __asm__("mov %%ebp, %0" : "=r" (Stack) : ); -#elif defined(_MSC_VER) - __asm mov Stack, ebp -#endif -#elif defined(_M_MIPS) - __asm__("move $sp, %0" : "=r" (Stack) : ); -#elif defined(_M_PPC) - __asm__("mr %0,1" : "=r" (Stack) : ); -#else -#error Unknown architecture -#endif - - /* Set it as the stack begin limit as well */ - StackBegin = (ULONG_PTR)Stack; - - /* Check if we're called for non-logging mode */ - if (!Flags) - { - /* Get the actual safe limits */ - Result = RtlpCaptureStackLimits((ULONG_PTR)Stack, - &StackBegin, - &StackEnd); - if (!Result) return 0; - } - - /* Use a SEH block for maximum protection */ - _SEH_TRY - { - /* Loop the frames */ - for (i = 0; i < Count; i++) - { - /* - * Leave if we're past the stack, - * if we're before the stack, - * or if we've reached ourselves. - */ - if ((Stack >= StackEnd) || - (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) || - ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR)))) - { - /* We're done or hit a bad address */ - break; - } - - /* Get new stack and EIP */ - NewStack = *(PULONG_PTR)Stack; - Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR)); - - /* Check if the new pointer is above the oldone and past the end */ - if (!((Stack < NewStack) && (NewStack < StackEnd))) - { - /* Stop searching after this entry */ - StopSearch = TRUE; - } - - /* Also make sure that the EIP isn't a stack address */ - if ((StackBegin < Eip) && (Eip < StackEnd)) break; - - /* Check if we reached a user-mode address */ - if (!(Flags) && !(Eip & 0x80000000)) break; - - /* Save this frame */ - Callers[i] = (PVOID)Eip; - - /* Check if we should continue */ - if (StopSearch) - { - /* Return the next index */ - i++; - break; - } - - /* Move to the next stack */ - Stack = NewStack; - } - } - _SEH_HANDLE - { - /* No index */ - i = 0; - } - _SEH_END; - - /* Return frames parsed */ - return i; -} - /* * @implemented */ diff --git a/reactos/ntoskrnl/ke/bug.c b/reactos/ntoskrnl/ke/bug.c index 0bf887aab7d..f88741f2363 100644 --- a/reactos/ntoskrnl/ke/bug.c +++ b/reactos/ntoskrnl/ke/bug.c @@ -136,6 +136,97 @@ KiRosPrintAddress(PVOID address) return(FALSE); } +PVOID +NTAPI +KiRosPcToUserFileHeader(IN PVOID Eip, + OUT PLDR_DATA_TABLE_ENTRY *LdrEntry) +{ + PVOID ImageBase, EipBase = NULL; + PLDR_DATA_TABLE_ENTRY Entry; + PLIST_ENTRY ListHead, NextEntry; + + /* + * We know this is valid because we should only be called after a + * succesfull address from RtlWalkFrameChain for UserMode, which + * validates everything for us. + */ + ListHead = &KeGetCurrentThread()-> + Teb->ProcessEnvironmentBlock->Ldr->InLoadOrderModuleList; + + /* Set list pointers and make sure it's valid */ + NextEntry = ListHead->Flink; + if (NextEntry) + { + /* Start loop */ + while (NextEntry != ListHead) + { + /* Get the loader entry */ + Entry = CONTAINING_RECORD(NextEntry, + LDR_DATA_TABLE_ENTRY, + InLoadOrderLinks); + + /* Move to the next entry */ + NextEntry = NextEntry->Flink; + ImageBase = Entry->DllBase; + + /* Check if this is the right one */ + if (((ULONG_PTR)Eip >= (ULONG_PTR)Entry->DllBase) && + ((ULONG_PTR)Eip < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage))) + { + /* Return this entry */ + *LdrEntry = Entry; + EipBase = ImageBase; + break; + } + } + } + + /* Return the base address */ + return EipBase; +} + +USHORT +NTAPI +KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip, + IN ULONG FramesToCapture, + OUT PVOID *BackTrace, + OUT PULONG BackTraceHash OPTIONAL) +{ + PVOID Frames[2 * 64]; + ULONG FrameCount; + ULONG Hash = 0, i; + + /* Skip a frame for the caller */ + FramesToSkip++; + + /* Don't go past the limit */ + if ((FramesToCapture + FramesToSkip) >= 128) return 0; + + /* Do the back trace */ + FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 1); + + /* Make sure we're not skipping all of them */ + if (FrameCount <= FramesToSkip) return 0; + + /* Loop all the frames */ + for (i = 0; i < FramesToCapture; i++) + { + /* Don't go past the limit */ + if ((FramesToSkip + i) >= FrameCount) break; + + /* Save this entry and hash it */ + BackTrace[i] = Frames[FramesToSkip + i]; + Hash += PtrToUlong(BackTrace[i]); + } + + /* Write the hash */ + if (BackTraceHash) *BackTraceHash = Hash; + + /* Clear the other entries and return count */ + RtlFillMemoryUlong(Frames, 128, 0); + return (USHORT)i; +} + VOID NTAPI KeRosDumpStackFrames(IN PULONG Frame OPTIONAL, @@ -176,10 +267,41 @@ KeRosDumpStackFrames(IN PULONG Frame OPTIONAL, Addr -= (ULONG_PTR)LdrEntry->DllBase; DbgPrint("<%wZ: %x>", &LdrEntry->FullDllName, Addr); } + else if (Addr) + { + /* Print only the address */ + DbgPrint("<%x>", Addr); + } /* Go to the next frame */ DbgPrint("\n"); } + + /* Get the current frames */ + FrameCount = KeRosCaptureUserStackBackTrace(-1, 32, (PVOID*)Frames, NULL); + + /* Now loop them */ + for (i = 0; i < FrameCount; i++) + { + /* Get the EIP */ + Addr = Frames[i]; + + /* Get the base for this file */ + if (KiRosPcToUserFileHeader((PVOID)Addr, &LdrEntry)) + { + /* Print out the module name */ + Addr -= (ULONG_PTR)LdrEntry->DllBase; + DbgPrint("<%wZ: %x>", &LdrEntry->FullDllName, Addr); + } + else if (Addr) + { + /* Print only the address */ + DbgPrint("<%x>", Addr); + } + + /* Go to the next frame */ + DbgPrint("\n"); + } /* Finish the output */ DbgPrint("\n"); diff --git a/reactos/ntoskrnl/rtl/libsupp.c b/reactos/ntoskrnl/rtl/libsupp.c index 412f39b8bc8..5a0eff2a041 100644 --- a/reactos/ntoskrnl/rtl/libsupp.c +++ b/reactos/ntoskrnl/rtl/libsupp.c @@ -255,6 +255,144 @@ RtlpCaptureStackLimits(IN ULONG_PTR Ebp, return TRUE; } +/* + * @implemented + */ +ULONG +NTAPI +RtlWalkFrameChain(OUT PVOID *Callers, + IN ULONG Count, + IN ULONG Flags) +{ + ULONG_PTR Stack, NewStack, StackBegin, StackEnd; + ULONG Eip; + BOOLEAN Result, StopSearch = FALSE; + ULONG i = 0; + PKTHREAD Thread = KeGetCurrentThread(); + PTEB Teb; + PKTRAP_FRAME TrapFrame; + + /* Get current EBP */ +#if defined(_M_IX86) +#if defined __GNUC__ + __asm__("mov %%ebp, %0" : "=r" (Stack) : ); +#elif defined(_MSC_VER) + __asm mov Stack, ebp +#endif +#elif defined(_M_MIPS) + __asm__("move $sp, %0" : "=r" (Stack) : ); +#elif defined(_M_PPC) + __asm__("mr %0,1" : "=r" (Stack) : ); +#else +#error Unknown architecture +#endif + + /* Set it as the stack begin limit as well */ + StackBegin = (ULONG_PTR)Stack; + + /* Check if we're called for non-logging mode */ + if (!Flags) + { + /* Get the actual safe limits */ + Result = RtlpCaptureStackLimits((ULONG_PTR)Stack, + &StackBegin, + &StackEnd); + if (!Result) return 0; + } + + /* Use a SEH block for maximum protection */ + _SEH_TRY + { + /* Check if we want the user-mode stack frame */ + if (Flags == 1) + { + /* Get the trap frame and TEB */ + TrapFrame = Thread->TrapFrame; + Teb = Thread->Teb; + + /* Make sure we can trust the TEB and trap frame */ + if (!(Teb) || + !((PVOID)((ULONG_PTR)TrapFrame & 0x80000000)) || + ((PVOID)TrapFrame <= (PVOID)Thread->StackLimit) || + ((PVOID)TrapFrame >= (PVOID)Thread->StackBase) || + (KeIsAttachedProcess()) || + (KeGetCurrentIrql() >= DISPATCH_LEVEL)) + { + /* Invalid or unsafe attempt to get the stack */ + return 0; + } + + /* Get the stack limits */ + StackBegin = (ULONG_PTR)Teb->Tib.StackLimit; + StackEnd = (ULONG_PTR)Teb->Tib.StackBase; + Stack = TrapFrame->Ebp; + + /* Validate them */ + if (StackEnd <= StackBegin) return 0; + ProbeForRead((PVOID)StackBegin, + StackEnd - StackBegin, + sizeof(CHAR)); + } + + /* Loop the frames */ + for (i = 0; i < Count; i++) + { + /* + * Leave if we're past the stack, + * if we're before the stack, + * or if we've reached ourselves. + */ + if ((Stack >= StackEnd) || + (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) || + ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR)))) + { + /* We're done or hit a bad address */ + break; + } + + /* Get new stack and EIP */ + NewStack = *(PULONG_PTR)Stack; + Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR)); + + /* Check if the new pointer is above the oldone and past the end */ + if (!((Stack < NewStack) && (NewStack < StackEnd))) + { + /* Stop searching after this entry */ + StopSearch = TRUE; + } + + /* Also make sure that the EIP isn't a stack address */ + if ((StackBegin < Eip) && (Eip < StackEnd)) break; + + /* Check if we reached a user-mode address */ + if (!(Flags) && !(Eip & 0x80000000)) break; + + /* Save this frame */ + Callers[i] = (PVOID)Eip; + + /* Check if we should continue */ + if (StopSearch) + { + /* Return the next index */ + i++; + break; + } + + /* Move to the next stack */ + Stack = NewStack; + } + } + _SEH_HANDLE + { + /* No index */ + i = 0; + } + _SEH_END; + + /* Return frames parsed */ + return i; +} + /* RTL Atom Tables ************************************************************/ NTSTATUS diff --git a/reactos/subsystems/win32/win32k/ntuser/misc.c b/reactos/subsystems/win32/win32k/ntuser/misc.c index e103e5e0a31..dc58002dd90 100644 --- a/reactos/subsystems/win32/win32k/ntuser/misc.c +++ b/reactos/subsystems/win32/win32k/ntuser/misc.c @@ -1543,8 +1543,7 @@ UserSystemParametersInfo_StructGet( { NTSTATUS Status = STATUS_SUCCESS; - /* remove this when all spi are implement */ - DPRINT1("UserSystemParametersInfo_StructGet SPI Action 0x%x (uiParam: 0x%x, fWinIni: 0x%x)\n",uiAction, uiParam, fWinIni); + DPRINT("UserSystemParametersInfo_StructGet SPI Action 0x%x (uiParam: 0x%x, fWinIni: 0x%x)\n",uiAction, uiParam, fWinIni); _SEH_TRY {