Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

stktrace.c File Reference

#include <ntos.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <zwapi.h>
#include <stktrace.h>
#include <heap.h>
#include <heappriv.h>

Go to the source code of this file.

Defines

#define _KERNEL_MODE_STACK_TRACES_   0
#define _COLLECT_FRAME_WALK_STATISTICS_   0
#define SIZE_1_KB   ((ULONG_PTR) 0x400)
#define SIZE_1_GB   ((ULONG_PTR) 0x40000000)
#define PAGE_START(address)   (((ULONG_PTR)address) & ~((ULONG_PTR)PAGE_SIZE - 1))

Functions

BOOLEAN NtdllOkayToLockRoutine (IN PVOID Lock)
VOID CollectFrameWalkStatistics (ULONG Index)
ULONG RtlWalkFrameChain (OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags)


Define Documentation

#define _COLLECT_FRAME_WALK_STATISTICS_   0
 

Definition at line 726 of file stktrace.c.

#define _KERNEL_MODE_STACK_TRACES_   0
 

Definition at line 725 of file stktrace.c.

#define PAGE_START address   )     (((ULONG_PTR)address) & ~((ULONG_PTR)PAGE_SIZE - 1))
 

Definition at line 732 of file stktrace.c.

Referenced by RtlWalkFrameChain().

#define SIZE_1_GB   ((ULONG_PTR) 0x40000000)
 

Definition at line 730 of file stktrace.c.

#define SIZE_1_KB   ((ULONG_PTR) 0x400)
 

Definition at line 729 of file stktrace.c.

Referenced by RtlWalkFrameChain().


Function Documentation

VOID CollectFrameWalkStatistics ULONG  Index  ) 
 

Referenced by RtlWalkFrameChain().

BOOLEAN NtdllOkayToLockRoutine IN PVOID  Lock  ) 
 

Definition at line 236 of file dll/resource.c.

References TRUE.

00239 { 00240 return TRUE; 00241 }

ULONG RtlWalkFrameChain OUT PVOID *  Callers,
IN ULONG  Count,
IN ULONG  Flags
 

Definition at line 741 of file stktrace.c.

References CollectFrameWalkStatistics(), Count, DbgPrint, EXCEPTION_EXECUTE_HANDLER, Index, KeGetCurrentThread, MmIsAddressValid(), PAGE_SIZE, PAGE_START, and SIZE_1_KB.

00749 : 00750 00751 RtlWalkFrameChain 00752 00753 Description: 00754 00755 This function tries to walk the EBP chain and fill out a vector of 00756 return addresses. The function works only on x86. It is possible that 00757 the function cannot fill the requested number of callers because somewhere 00758 on the stack we have a function compiled FPO (the frame register (EBP) is 00759 used as a normal register. In this case the function will just return with 00760 a less then requested count. In kernel mode the function should not take 00761 any exceptions (page faults) because it can be called at all sorts of 00762 irql levels. 00763 00764 The `Flags' parameter is used for future extensions. A zero value will be 00765 compatible with new stack walking algorithms. 00766 00767 Note. The algorithm can be somewhat improved by unassembling the return 00768 addresses identified. However this is impractical in kernel mode because 00769 the function might get called at high irql levels where page faults are 00770 not allowed. 00771 00772 Return value: 00773 00774 The number of identified return addresses on the stack. This can be less 00775 then the Count requested if the stack ends or we encounter a FPO compiled 00776 function. 00777 00778 --*/ 00779 00780 { 00781 #if defined(_X86_) 00782 00783 ULONG_PTR Fp, NewFp, ReturnAddress; 00784 ULONG Index; 00785 ULONG_PTR StackEnd, StackStart; 00786 BOOLEAN Result; 00787 00788 // 00789 // Get the current EBP pointer which is supposed to 00790 // be the start of the EBP chain. 00791 // 00792 00793 _asm mov Fp, EBP; 00794 00795 StackStart = Fp; 00796 00797 #if _KERNEL_MODE_STACK_TRACES_ 00798 00799 StackEnd = (ULONG_PTR)(KeGetCurrentThread()->StackBase); 00800 00801 // 00802 // bugbug: find a reliable way to get the stack limit in kernel mode. 00803 // `StackBase' is not a reliable way to get the stack end in kernel 00804 // mode because we might execute a DPC routine on thread's behalf. 00805 // There are a few other reasons why we cannot trust this completely. 00806 // 00807 // Note. The condition `PAGE_START(StackEnd) - PAGE_START(StackStart) > PAGE_SIZE' 00808 // is not totally safe. We can encounter a situation where in this case we 00809 // do not have the same stack. Can we? 00810 // 00811 // The DPC stack is actually the stack of the idle thread corresponding to 00812 // the current processor. Based on that we probably can figure out in almost 00813 // all contexts what are the real limits of the stack. 00814 // 00815 00816 if ((StackStart > StackEnd) 00817 || (PAGE_START(StackEnd) - PAGE_START(StackStart) > PAGE_SIZE)) { 00818 00819 StackEnd = (StackStart + PAGE_SIZE) & ~((ULONG_PTR)PAGE_SIZE - 1); 00820 00821 // 00822 // Try to get one more page if possible. Note that this is not 00823 // 100% reliable because a non faulting address can fault if 00824 // appropriate locks are not held. 00825 // 00826 00827 if (MmIsAddressValid ((PVOID)StackEnd)) { 00828 StackEnd += PAGE_SIZE; 00829 } 00830 } 00831 00832 #else 00833 00834 StackEnd = (ULONG_PTR)(NtCurrentTeb()->NtTib.StackBase); 00835 00836 #endif // #if _KERNEL_MODE_STACK_TRACES_ 00837 00838 try { 00839 00840 for (Index = 0; Index < Count; Index++) { 00841 00842 if (Fp + sizeof(ULONG_PTR) >= StackEnd) { 00843 break; 00844 } 00845 00846 NewFp = *((PULONG_PTR)(Fp + 0)); 00847 ReturnAddress = *((PULONG_PTR)(Fp + sizeof(ULONG_PTR))); 00848 00849 // 00850 // Figure out if the new frame pointer is ok. This validation 00851 // should avoid all exceptions in kernel mode because we always 00852 // read within the current thread's stack and the stack is 00853 // guaranteed to be in memory (no page faults). It is also guaranteed 00854 // that we do not take random exceptions in user mode because we always 00855 // keep the frame pointer within stack limits. 00856 // 00857 00858 if (! (Fp < NewFp && NewFp < StackEnd)) { 00859 break; 00860 } 00861 00862 // 00863 // Figure out if the return address is ok. If return address 00864 // is a stack address or <64k then something is wrong. There is 00865 // no reason to return garbage to the caller therefore we stop. 00866 // 00867 00868 if (StackStart < ReturnAddress && ReturnAddress < StackEnd) { 00869 break; 00870 } 00871 00872 if (ReturnAddress < 64 * SIZE_1_KB) { 00873 break; 00874 } 00875 00876 // 00877 // Store new fp and return address and move on. 00878 // 00879 00880 Fp = NewFp; 00881 Callers[Index] = (PVOID)ReturnAddress; 00882 } 00883 } 00884 except (EXCEPTION_EXECUTE_HANDLER) { 00885 00886 // 00887 // The frame traversal algorithm is written so that we should 00888 // not get any exception. Therefore if we get some exception 00889 // we better debug it. 00890 // 00891 // bugbug: enable bkpt only on checked builds 00892 // After we get some coverage on this we should leave it active 00893 // only on checked builds. 00894 // 00895 00896 DbgPrint ("Unexpected exception in RtlWalkFrameChain ...\n"); 00897 DbgBreakPoint (); 00898 } 00899 00900 // 00901 // Return the number of return addresses identified on the stack. 00902 // 00903 00904 #if _COLLECT_FRAME_WALK_STATISTICS_ 00905 CollectFrameWalkStatistics (Index); 00906 #endif // #if _COLLECT_FRAME_WALK_STATISTICS_ 00907 00908 return Index; 00909 00910 #else 00911 00912 return 0; 00913 00914 #endif // #if defined(_X86_) 00915 }


Generated on Sat May 15 19:45:41 2004 for test by doxygen 1.3.7