mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 17:05:46 +00:00
- 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
This commit is contained in:
parent
bb7d880c70
commit
fe7669dea4
6 changed files with 283 additions and 106 deletions
|
@ -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)
|
||||
|
|
|
@ -448,6 +448,15 @@ RtlUnwind(
|
|||
//
|
||||
// Tracing Functions
|
||||
//
|
||||
NTSYSAPI
|
||||
ULONG
|
||||
NTAPI
|
||||
RtlWalkFrameChain(
|
||||
OUT PVOID *Callers,
|
||||
IN ULONG Count,
|
||||
IN ULONG Flags
|
||||
);
|
||||
|
||||
NTSYSAPI
|
||||
USHORT
|
||||
NTAPI
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue