- 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:
Aleksey Bragin 2007-10-01 17:58:49 +00:00
parent bb7d880c70
commit fe7669dea4
6 changed files with 283 additions and 106 deletions

View file

@ -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)

View file

@ -448,6 +448,15 @@ RtlUnwind(
//
// Tracing Functions
//
NTSYSAPI
ULONG
NTAPI
RtlWalkFrameChain(
OUT PVOID *Callers,
IN ULONG Count,
IN ULONG Flags
);
NTSYSAPI
USHORT
NTAPI

View file

@ -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
*/

View file

@ -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");

View file

@ -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

View file

@ -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
{