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.

271 lines
8.3 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2001 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. * 08/13/2001 masonb Created
  12. *
  13. ***************************************************************************/
  14. #include "dncmni.h"
  15. #ifdef DBG
  16. #ifndef DPNBUILD_NOIMAGEHLP
  17. #define _IMAGEHLP_SOURCE_
  18. #include <Imagehlp.h>
  19. #endif // !DPNBUILD_NOIMAGEHLP
  20. //**********************************************************************
  21. // Constant definitions
  22. //**********************************************************************
  23. //**********************************************************************
  24. // Macro definitions
  25. //**********************************************************************
  26. //**********************************************************************
  27. // Structure definitions
  28. //**********************************************************************
  29. //**********************************************************************
  30. // Variable definitions
  31. //**********************************************************************
  32. //**********************************************************************
  33. // Function prototypes
  34. //**********************************************************************
  35. #ifndef DPNBUILD_NOIMAGEHLP
  36. //
  37. // prototypes for ImageHlp.DLL functions we get from LoadLibrary().
  38. //
  39. typedef DWORD (__stdcall * PIMAGEHELP_SYMGETOPTIONS)( void );
  40. typedef DWORD (__stdcall * PIMAGEHELP_SYMSETOPTIONS)( DWORD SymOptions );
  41. typedef BOOL (__stdcall * PIMAGEHELP_SYMINITIALIZE)( HANDLE hProcess, PSTR pUserSearchPath, BOOL fInvadeProcess );
  42. typedef BOOL (__stdcall * PIMAGEHELP_SYMGETSYMFROMADDR)( HANDLE hProcess, DWORD dwAddress, PDWORD pdwDisplacement, PIMAGEHLP_SYMBOL pSymbol );
  43. typedef BOOL (__stdcall * PIMAGEHELP_SYMGETSYMFROMADDR64)( HANDLE hProcess, DWORD_PTR dwAddress, PDWORD_PTR pdwDisplacement, PIMAGEHLP_SYMBOL64 pSymbol );
  44. #endif // !DPNBUILD_NOIMAGEHLP
  45. //**********************************************************************
  46. // Class function definitions
  47. //**********************************************************************
  48. void CCallStack::NoteCurrentCallStack( void )
  49. {
  50. void **CallersEBP = NULL;
  51. void *ReturnAddr;
  52. UINT_PTR i,iCount;
  53. const void *StackTop;
  54. const void *StackBottom;
  55. static const void *const min_dll_base = NULL;
  56. StackTop = GetStackTop();
  57. StackBottom = GetStackBottom();
  58. memset( m_CallStack, 0x00, sizeof( m_CallStack ) );
  59. #ifdef _X86_
  60. _asm
  61. {
  62. mov eax,[ebp]
  63. mov CallersEBP,eax
  64. }
  65. #endif // _X86_
  66. _try
  67. {
  68. //
  69. // this code can generate exception if it steps back too far...
  70. //
  71. for ( i = 0, iCount = 0; i < CALLSTACK_DEPTH; iCount++ )
  72. {
  73. if ( ( CallersEBP < StackBottom ) || ( CallersEBP >= StackTop ) )
  74. break;
  75. ReturnAddr = CallersEBP[ 1 ];
  76. if ( ( iCount > 0 ) || ( ReturnAddr >= min_dll_base ) ) // iCount check skips memory_alloc_debug
  77. m_CallStack[ i++ ] = ReturnAddr;
  78. CallersEBP = reinterpret_cast<void**>( *CallersEBP ); // get callers callers ebp
  79. }
  80. }
  81. _except(EXCEPTION_EXECUTE_HANDLER) // went too far back on the stack, rest of array is filled with zeros
  82. {
  83. // DPFX(DPFPREP, 0, "Benign access violation creating return address stack." );
  84. }
  85. }
  86. const void* CCallStack::GetStackTop( void ) const
  87. {
  88. void *pReturn = NULL;
  89. #ifdef _X86_
  90. _asm mov eax,dword ptr fs:[4]
  91. _asm mov pReturn, eax
  92. #endif // _X86_
  93. return pReturn;
  94. }
  95. const void *CCallStack::GetStackBottom( void ) const
  96. {
  97. void *pReturn = NULL;
  98. #ifdef _X86_
  99. _asm mov eax,dword ptr fs:[8]
  100. _asm mov pReturn, eax
  101. #endif // _X86_
  102. return pReturn;
  103. }
  104. void CCallStack::GetCallStackString( TCHAR *const pOutputString ) const
  105. {
  106. static const TCHAR CallStackTitle[] = _T("\nCALL STACK:\n");
  107. static const TCHAR CallStackTitleWithSymbols[] = _T("\nCALL STACK:\tFUNCTION DETAILS:\n");
  108. #ifndef DPNBUILD_NOIMAGEHLP
  109. static enum
  110. {
  111. IMAGEHELP_STATUS_UNKNOWN,
  112. IMAGEHELP_STATUS_LOADED,
  113. IMAGEHELP_STATUS_LOAD_FAILED
  114. } ImageHelpStatus = IMAGEHELP_STATUS_UNKNOWN;
  115. static HINSTANCE hImageHelp = NULL;
  116. static PIMAGEHELP_SYMGETOPTIONS pSymGetOptions = NULL;
  117. static PIMAGEHELP_SYMSETOPTIONS pSymSetOptions = NULL;
  118. static PIMAGEHELP_SYMINITIALIZE pSymInitialize = NULL;
  119. #ifndef _WIN64
  120. static PIMAGEHELP_SYMGETSYMFROMADDR pSymGetSymFromAddr = NULL;
  121. #else
  122. static PIMAGEHELP_SYMGETSYMFROMADDR64 pSymGetSymFromAddr = NULL;
  123. #endif // _WIN64
  124. //
  125. // if ImageHelp isn't loaded attempt to load it
  126. //
  127. if ( ImageHelpStatus == IMAGEHELP_STATUS_UNKNOWN )
  128. {
  129. ImageHelpStatus = IMAGEHELP_STATUS_LOAD_FAILED;
  130. hImageHelp = LoadLibrary( _T("ImageHLP.DLL") );
  131. if ( hImageHelp == NULL )
  132. {
  133. goto FailedImageHelpLoad;
  134. }
  135. pSymGetOptions = reinterpret_cast<PIMAGEHELP_SYMGETOPTIONS>( GetProcAddress( hImageHelp, "SymGetOptions" ) );
  136. pSymSetOptions = reinterpret_cast<PIMAGEHELP_SYMSETOPTIONS>( GetProcAddress( hImageHelp, "SymSetOptions" ) );
  137. pSymInitialize = reinterpret_cast<PIMAGEHELP_SYMINITIALIZE>( GetProcAddress( hImageHelp, "SymInitialize" ) );
  138. #ifndef _WIN64
  139. pSymGetSymFromAddr = reinterpret_cast<PIMAGEHELP_SYMGETSYMFROMADDR>( GetProcAddress( hImageHelp, "SymGetSymFromAddr" ) );
  140. #else // _WIN64
  141. pSymGetSymFromAddr = reinterpret_cast<PIMAGEHELP_SYMGETSYMFROMADDR64>( GetProcAddress( hImageHelp, "SymGetSymFromAddr64" ) );
  142. #endif // _WIN64
  143. if ( ( pSymGetOptions == NULL ) ||
  144. ( pSymSetOptions == NULL ) ||
  145. ( pSymInitialize == NULL ) ||
  146. ( pSymGetSymFromAddr == NULL ) )
  147. {
  148. goto FailedImageHelpLoad;
  149. }
  150. pSymSetOptions( SYMOPT_DEFERRED_LOADS | pSymGetOptions() );
  151. if ( pSymInitialize( GetCurrentProcess(), NULL, TRUE ) == FALSE )
  152. {
  153. if ( pSymInitialize( GetCurrentProcess(), NULL, FALSE ) == FALSE )
  154. {
  155. goto FailedImageHelpLoad;
  156. }
  157. }
  158. ImageHelpStatus = IMAGEHELP_STATUS_LOADED;
  159. }
  160. FailedImageHelpLoad:
  161. if ( ImageHelpStatus == IMAGEHELP_STATUS_LOADED )
  162. {
  163. memcpy( pOutputString, CallStackTitleWithSymbols, sizeof( CallStackTitleWithSymbols ) );
  164. }
  165. else
  166. #endif // !DPNBUILD_NOIMAGEHLP
  167. {
  168. memcpy( pOutputString, CallStackTitle, sizeof( CallStackTitle ) );
  169. }
  170. for ( DWORD dwIndex = 0; ( ( dwIndex < CALLSTACK_DEPTH ) && ( m_CallStack[ dwIndex ] != NULL ) ); dwIndex++ )
  171. {
  172. TCHAR AddressBuffer[ CALLSTACK_BUFFER_SIZE ];
  173. #ifndef DPNBUILD_NOIMAGEHLP
  174. if ( ImageHelpStatus == IMAGEHELP_STATUS_LOADED )
  175. {
  176. TCHAR ImageBuffer[ CALLSTACK_BUFFER_SIZE + sizeof(IMAGEHLP_SYMBOL) ];
  177. DWORD_PTR dwFunctionDisplacement;
  178. #ifndef _WIN64
  179. IMAGEHLP_SYMBOL *const pImageHelpSymbol = reinterpret_cast<IMAGEHLP_SYMBOL*>( ImageBuffer );
  180. #else // _WIN64
  181. IMAGEHLP_SYMBOL64 *const pImageHelpSymbol = reinterpret_cast<IMAGEHLP_SYMBOL64*>( ImageBuffer );
  182. #endif // _WIN64
  183. pImageHelpSymbol->SizeOfStruct = sizeof( *pImageHelpSymbol );
  184. pImageHelpSymbol->Flags = 0;
  185. pImageHelpSymbol->Address = reinterpret_cast<DWORD_PTR>( m_CallStack[ dwIndex ] );
  186. pImageHelpSymbol->MaxNameLength = sizeof( ImageBuffer ) - sizeof( *pImageHelpSymbol ) - 14; // account for \t%s+0x00000000\n\0
  187. if ( pSymGetSymFromAddr( GetCurrentProcess(),
  188. reinterpret_cast<DWORD_PTR>( m_CallStack[ dwIndex ] ),
  189. &dwFunctionDisplacement,
  190. pImageHelpSymbol
  191. ) != FALSE )
  192. {
  193. if ( dwFunctionDisplacement != 0 )
  194. {
  195. #ifdef _X86_
  196. wsprintf( AddressBuffer, _T("0x%x\t%hs+0x%x\n"), (DWORD)m_CallStack[ dwIndex ], pImageHelpSymbol->Name, dwFunctionDisplacement );
  197. #else
  198. wsprintf( AddressBuffer, _T("0x%p\t%hs+0x%x\n"), m_CallStack[ dwIndex ], pImageHelpSymbol->Name, dwFunctionDisplacement );
  199. #endif // _X86_
  200. }
  201. else
  202. {
  203. #ifdef _X86_
  204. wsprintf( AddressBuffer, _T("0x%x\t%hs\n"), (DWORD)m_CallStack[ dwIndex ], pImageHelpSymbol->Name );
  205. #else
  206. wsprintf( AddressBuffer, _T("0x%p\t%hs\n"), m_CallStack[ dwIndex ], pImageHelpSymbol->Name );
  207. #endif // _X86_
  208. }
  209. _tcscat( pOutputString, AddressBuffer );
  210. //
  211. // continue FOR loop
  212. //
  213. continue;
  214. }
  215. }
  216. #endif // !DPNBUILD_NOIMAGEHLP
  217. #ifdef _X86_
  218. wsprintf( AddressBuffer, _T("0x%08x\n"), (DWORD)m_CallStack[ dwIndex ] );
  219. #else
  220. wsprintf( AddressBuffer, _T("0x%p\n"), m_CallStack[ dwIndex ] );
  221. #endif // _X86_
  222. _tcscat( pOutputString, AddressBuffer );
  223. }
  224. return;
  225. }
  226. //**********************************************************************
  227. #endif // DBG