Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

344 lines
10 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: CallStack.cpp
  6. * Content: Call stack tracking class
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 11/23/99 jtk Derived from OSInd.cpp
  12. ***************************************************************************/
  13. #ifndef __CALLSTACK_H__
  14. #define __CALLSTACK_H__
  15. #define _IMAGEHLP_SOURCE_
  16. #include <Imagehlp.h>
  17. //**********************************************************************
  18. // Constant definitions
  19. //**********************************************************************
  20. //
  21. // Size of temp buffer to build strings into.
  22. // If the call stack depth is increased, increase the size of the buffer
  23. // to prevent stack corruption with long symbol names.
  24. //
  25. #define CALLSTACK_BUFFER_SIZE 8192
  26. //**********************************************************************
  27. // Macro definitions
  28. //**********************************************************************
  29. //**********************************************************************
  30. // Structure definitions
  31. //**********************************************************************
  32. //**********************************************************************
  33. // Variable definitions
  34. //**********************************************************************
  35. //**********************************************************************
  36. // Function prototypes
  37. //**********************************************************************
  38. //
  39. // prototypes for ImageHlp.DLL functions we get from LoadLibrary().
  40. //
  41. typedef DWORD (__stdcall * PIMAGEHELP_SYMGETOPTIONS)( void );
  42. typedef DWORD (__stdcall * PIMAGEHELP_SYMSETOPTIONS)( DWORD SymOptions );
  43. typedef BOOL (__stdcall * PIMAGEHELP_SYMINITIALIZE)( HANDLE hProcess, PSTR pUserSearchPath, BOOL fInvadeProcess );
  44. typedef BOOL (__stdcall * PIMAGEHELP_SYMGETSYMFROMADDR)( HANDLE hProcess, DWORD dwAddress, PDWORD pdwDisplacement, PIMAGEHLP_SYMBOL pSymbol );
  45. typedef BOOL (__stdcall * PIMAGEHELP_SYMGETSYMFROMADDR64)( HANDLE hProcess, DWORD_PTR dwAddress, PDWORD_PTR pdwDisplacement, PIMAGEHLP_SYMBOL64 pSymbol );
  46. //**********************************************************************
  47. // Class definitions
  48. //**********************************************************************
  49. template< UINT_PTR uStackDepth >
  50. class CCallStack
  51. {
  52. public:
  53. CCallStack(){}
  54. ~CCallStack(){}
  55. void NoteCurrentCallStack( void );
  56. void GetCallStackString( char *const pOutputString ) const;
  57. private:
  58. const void *m_CallStack[ uStackDepth ];
  59. const void *GetStackTop( void ) const;
  60. const void *GetStackBottom( void ) const;
  61. const UINT_PTR GetCallStackDepth( void ) const { return uStackDepth; }
  62. //
  63. // make copy constructor and assignment operator private and unimplemented
  64. // to prevent unwarranted copies
  65. //
  66. CCallStack( const CCallStack & );
  67. CCallStack& operator=( const CCallStack & );
  68. };
  69. //**********************************************************************
  70. // Class function definitions
  71. //**********************************************************************
  72. //**********************************************************************
  73. // ------------------------------
  74. // CCallStack::NoteCurrentCallStack - get a call stack
  75. //
  76. // Entry: Nothing
  77. //
  78. // Exit: Nothing
  79. // ------------------------------
  80. template< UINT_PTR uStackDepth >
  81. void CCallStack< uStackDepth >::NoteCurrentCallStack( void )
  82. {
  83. void **CallersEBP = NULL;
  84. void *ReturnAddr;
  85. UINT_PTR i,iCount;
  86. const void *StackTop;
  87. const void *StackBottom;
  88. static const void *const min_dll_base = NULL;
  89. StackTop = GetStackTop();
  90. StackBottom = GetStackBottom();
  91. memset( m_CallStack, 0x00, sizeof( m_CallStack ) );
  92. #ifdef _X86_
  93. _asm
  94. {
  95. mov eax,[ebp]
  96. mov CallersEBP,eax
  97. }
  98. #endif // _X86_
  99. __try
  100. {
  101. //
  102. // this code can generate exception if it steps back too far...
  103. //
  104. for ( i = 0, iCount = 0; i < GetCallStackDepth(); iCount++ )
  105. {
  106. if ( ( CallersEBP < StackBottom ) || ( CallersEBP >= StackTop ) )
  107. break;
  108. ReturnAddr = CallersEBP[ 1 ];
  109. if ( ( iCount > 0 ) || ( ReturnAddr >= min_dll_base ) ) // iCount check skips memory_alloc_debug
  110. m_CallStack[ i++ ] = ReturnAddr;
  111. CallersEBP = reinterpret_cast<void**>( *CallersEBP ); // get callers callers ebp
  112. }
  113. }
  114. __except( 1 ) // went too far back on the stack, rest of array is filled with zeros
  115. {
  116. // DPFX(DPFPREP, 0, "Benign access violation creating return address stack." );
  117. }
  118. }
  119. //**********************************************************************
  120. //**********************************************************************
  121. // ------------------------------
  122. // CCallStack::GetStackTop - return pointer to top of stack
  123. //
  124. // Entry: Nothing
  125. //
  126. // Exit: Pointer to top of stack
  127. // ------------------------------
  128. template< UINT_PTR uStackDepth >
  129. const void *CCallStack< uStackDepth >::GetStackTop( void ) const
  130. {
  131. void *pReturn = NULL;
  132. #ifdef _X86_
  133. _asm mov eax,dword ptr fs:[4]
  134. _asm mov pReturn, eax
  135. #endif // _X86_
  136. return pReturn;
  137. }
  138. //**********************************************************************
  139. //**********************************************************************
  140. // ------------------------------
  141. // CCallStack::GetStackBottom - return pointer to bottom of call stack
  142. //
  143. // Entry: Nothing
  144. //
  145. // Exit: Pointer to bottom of call stack
  146. // ------------------------------
  147. template< UINT_PTR uStackDepth >
  148. const void *CCallStack< uStackDepth >::GetStackBottom( void ) const
  149. {
  150. void *pReturn = NULL;
  151. #ifdef _X86_
  152. _asm mov eax,dword ptr fs:[8]
  153. _asm mov pReturn, eax
  154. #endif // _X86_
  155. return pReturn;
  156. }
  157. //**********************************************************************
  158. //**********************************************************************
  159. // ------------------------------
  160. // CCallStack::GetCallStack - return pointer to bottom of call stack
  161. //
  162. // Entry: Pointer to destination string
  163. //
  164. // Exit: Nothing
  165. // ------------------------------
  166. template< UINT_PTR uStackDepth >
  167. void CCallStack< uStackDepth >::GetCallStackString( char *const pOutputString ) const
  168. {
  169. static const char CallStackTitle[] = "\nCALL STACK:\n";
  170. static const char CallStackTitleWithSymbols[] = "\nCALL STACK:\tFUNCTION DETAILS:\n";
  171. static enum
  172. {
  173. IMAGEHELP_STATUS_UNKNOWN,
  174. IMAGEHELP_STATUS_LOADED,
  175. IMAGEHELP_STATUS_LOAD_FAILED
  176. } ImageHelpStatus = IMAGEHELP_STATUS_UNKNOWN;
  177. static HINSTANCE hImageHelp = NULL;
  178. static PIMAGEHELP_SYMGETOPTIONS pSymGetOptions = NULL;
  179. static PIMAGEHELP_SYMSETOPTIONS pSymSetOptions = NULL;
  180. static PIMAGEHELP_SYMINITIALIZE pSymInitialize = NULL;
  181. #ifndef _WIN64
  182. static PIMAGEHELP_SYMGETSYMFROMADDR pSymGetSymFromAddr = NULL;
  183. #else
  184. static PIMAGEHELP_SYMGETSYMFROMADDR64 pSymGetSymFromAddr = NULL;
  185. #endif // _WIN64
  186. UINT_PTR uIndex;
  187. //
  188. // if ImageHelp isn't loaded attempt to load it
  189. //
  190. if ( ImageHelpStatus == IMAGEHELP_STATUS_UNKNOWN )
  191. {
  192. ImageHelpStatus = IMAGEHELP_STATUS_LOAD_FAILED;
  193. hImageHelp = LoadLibrary( "ImageHLP.DLL" );
  194. if ( hImageHelp == NULL )
  195. {
  196. goto FailedImageHelpLoad;
  197. }
  198. pSymGetOptions = reinterpret_cast<PIMAGEHELP_SYMGETOPTIONS>( GetProcAddress( hImageHelp, "SymGetOptions" ) );
  199. pSymSetOptions = reinterpret_cast<PIMAGEHELP_SYMSETOPTIONS>( GetProcAddress( hImageHelp, "SymSetOptions" ) );
  200. pSymInitialize = reinterpret_cast<PIMAGEHELP_SYMINITIALIZE>( GetProcAddress( hImageHelp, "SymInitialize" ) );
  201. #ifndef _WIN64
  202. pSymGetSymFromAddr = reinterpret_cast<PIMAGEHELP_SYMGETSYMFROMADDR>( GetProcAddress( hImageHelp, "SymGetSymFromAddr" ) );
  203. #else // _WIN64
  204. pSymGetSymFromAddr = reinterpret_cast<PIMAGEHELP_SYMGETSYMFROMADDR64>( GetProcAddress( hImageHelp, "SymGetSymFromAddr64" ) );
  205. #endif // _WIN64
  206. if ( ( pSymGetOptions == NULL ) ||
  207. ( pSymSetOptions == NULL ) ||
  208. ( pSymInitialize == NULL ) ||
  209. ( pSymGetSymFromAddr == NULL ) )
  210. {
  211. goto FailedImageHelpLoad;
  212. }
  213. pSymSetOptions( SYMOPT_DEFERRED_LOADS | pSymGetOptions() );
  214. if ( pSymInitialize( GetCurrentProcess(), NULL, TRUE ) == FALSE )
  215. {
  216. if ( pSymInitialize( GetCurrentProcess(), NULL, FALSE ) == FALSE )
  217. {
  218. goto FailedImageHelpLoad;
  219. }
  220. }
  221. ImageHelpStatus = IMAGEHELP_STATUS_LOADED;
  222. }
  223. FailedImageHelpLoad:
  224. if ( ImageHelpStatus == IMAGEHELP_STATUS_LOADED )
  225. {
  226. memcpy( pOutputString, CallStackTitleWithSymbols, sizeof( CallStackTitleWithSymbols ) );
  227. }
  228. else
  229. {
  230. memcpy( pOutputString, CallStackTitle, sizeof( CallStackTitle ) );
  231. }
  232. for ( uIndex = 0; ( ( uIndex < GetCallStackDepth() ) && ( m_CallStack[ uIndex ] != NULL ) ); uIndex++ )
  233. {
  234. char AddressBuffer[ CALLSTACK_BUFFER_SIZE ];
  235. if ( ImageHelpStatus == IMAGEHELP_STATUS_LOADED )
  236. {
  237. char ImageBuffer[ CALLSTACK_BUFFER_SIZE + sizeof(IMAGEHLP_SYMBOL) ];
  238. DWORD_PTR dwFunctionDisplacement;
  239. #ifndef _WIN64
  240. IMAGEHLP_SYMBOL *const pImageHelpSymbol = reinterpret_cast<IMAGEHLP_SYMBOL*>( ImageBuffer );
  241. #else // _WIN64
  242. IMAGEHLP_SYMBOL64 *const pImageHelpSymbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>( ImageBuffer );
  243. #endif // _WIN64
  244. pImageHelpSymbol->SizeOfStruct = sizeof( *pImageHelpSymbol );
  245. pImageHelpSymbol->Flags = 0;
  246. pImageHelpSymbol->Address = reinterpret_cast<DWORD_PTR>( m_CallStack[ uIndex ] );
  247. pImageHelpSymbol->MaxNameLength = sizeof( ImageBuffer ) - sizeof( *pImageHelpSymbol ) - 14; // account for \t%s+0x00000000\n\0
  248. if ( pSymGetSymFromAddr( GetCurrentProcess(),
  249. reinterpret_cast<DWORD_PTR>( m_CallStack[ uIndex ] ),
  250. &dwFunctionDisplacement,
  251. pImageHelpSymbol
  252. ) != FALSE )
  253. {
  254. if ( dwFunctionDisplacement != 0 )
  255. {
  256. #ifdef _X86_
  257. wsprintf( AddressBuffer, "0x%x\t%s+0x%x\n", m_CallStack[ uIndex ], pImageHelpSymbol->Name, dwFunctionDisplacement );
  258. #else
  259. wsprintf( AddressBuffer, "0x%p\t%s+0x%x\n", m_CallStack[ uIndex ], pImageHelpSymbol->Name, dwFunctionDisplacement );
  260. #endif
  261. }
  262. else
  263. {
  264. #ifdef _X86_
  265. wsprintf( AddressBuffer, "0x%x\t%s\n", m_CallStack[ uIndex ], pImageHelpSymbol->Name );
  266. #else
  267. wsprintf( AddressBuffer, "0x%p\t%s\n", m_CallStack[ uIndex ], pImageHelpSymbol->Name );
  268. #endif
  269. }
  270. strcat( pOutputString, AddressBuffer );
  271. //
  272. // continue FOR loop
  273. //
  274. continue;
  275. }
  276. }
  277. #ifdef _X86_
  278. wsprintf( AddressBuffer, "0x08%x\n", m_CallStack[ uIndex ] );
  279. #else
  280. wsprintf( AddressBuffer, "0x%p\n", m_CallStack[ uIndex ] );
  281. #endif
  282. strcat( pOutputString, AddressBuffer );
  283. }
  284. return;
  285. }
  286. //**********************************************************************
  287. #endif // __CALLSTACK_H__