Leaked source code of windows server 2003
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.

454 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. stkwalk.c
  5. Abstract:
  6. This module contains memory debug routines for catching memory leaks and memory
  7. overwrites.
  8. Author:
  9. Stolen from dbgmem.c
  10. Jim Stewart/Ramesh Pabbati January 8, 1996
  11. Fixed up for regleaks
  12. UShaji Dec 11th, 1998
  13. Revision History:
  14. --*/
  15. #ifdef LOCAL
  16. #ifdef LEAK_TRACK
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <windows.h>
  21. #include <stdio.h>
  22. #include<imagehlp.h>
  23. #include "regleak.h"
  24. #include "stkwalk.h"
  25. DWORD MachineType; // the architecutre we are on
  26. HANDLE OurProcess; // the process that we are running as a part of
  27. // typedefs from imagehlp.dll
  28. typedef BOOL (WINAPI * PFNSYMINITIALIZE)(HANDLE hProcess,
  29. PSTR UserSearchPath,
  30. BOOL fInvadeProcess);
  31. typedef BOOL (WINAPI * PFNSYMCLEANUP)(HANDLE hProcess);
  32. typedef BOOL (WINAPI * PFNSTACKWALK)(DWORD MachineType,
  33. HANDLE hProcess,
  34. HANDLE hThread,
  35. LPSTACKFRAME StackFrame,
  36. PVOID ContextRecord,
  37. PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
  38. PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
  39. PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
  40. PTRANSLATE_ADDRESS_ROUTINE TranslateAddress);
  41. typedef BOOL (WINAPI * PFNSYMGETSYMFROMADDR)(HANDLE hProcess,
  42. DWORD_PTR Address,
  43. PDWORD_PTR Displacement,
  44. PIMAGEHLP_SYMBOL Symbol);
  45. typedef DWORD_PTR (WINAPI * PFNSYMGETMODULEBASE)(HANDLE hProcess,
  46. DWORD_PTR dwAddr);
  47. typedef PVOID (WINAPI * PFNSYMFUNCTIONTABLEACCESS)(HANDLE hProcess,
  48. DWORD_PTR AddrBase);
  49. // imagehlp function pointers
  50. PFNSYMINITIALIZE g_pfnSymInitialize=NULL;
  51. PFNSYMCLEANUP g_pfnSymCleanup=NULL;
  52. PFNSTACKWALK g_pfnStackWalk=NULL;
  53. PFNSYMGETSYMFROMADDR g_pfnSymGetSymFromAddr=NULL;
  54. PFNSYMFUNCTIONTABLEACCESS g_pfnSymFunctionTableAccess=NULL;
  55. PFNSYMGETMODULEBASE g_pfnSymGetModuleBase=NULL;
  56. HINSTANCE g_hImagehlpInstance=NULL;
  57. BOOL fDebugInitialised = FALSE;
  58. BOOL
  59. InitDebug(
  60. );
  61. DWORD GetStack(
  62. IN EXCEPTION_POINTERS *exp,
  63. IN PCALLER_SYM Caller,
  64. IN int Skip,
  65. IN int cFind,
  66. IN int fResolveSymbols
  67. );
  68. BOOL LoadImageHLP()
  69. {
  70. g_hImagehlpInstance = LoadLibrary ("imagehlp.dll");
  71. if (!g_hImagehlpInstance) {
  72. return FALSE;
  73. }
  74. g_pfnSymInitialize = (PFNSYMINITIALIZE) GetProcAddress (g_hImagehlpInstance,
  75. "SymInitialize");
  76. if (!g_pfnSymInitialize) {
  77. return FALSE;
  78. }
  79. g_pfnSymCleanup = (PFNSYMCLEANUP) GetProcAddress (g_hImagehlpInstance,
  80. "SymCleanup");
  81. if (!g_pfnSymCleanup) {
  82. return FALSE;
  83. }
  84. g_pfnStackWalk = (PFNSTACKWALK) GetProcAddress (g_hImagehlpInstance,
  85. "StackWalk");
  86. if (!g_pfnStackWalk) {
  87. return FALSE;
  88. }
  89. g_pfnSymGetSymFromAddr = (PFNSYMGETSYMFROMADDR) GetProcAddress (g_hImagehlpInstance,
  90. "SymGetSymFromAddr");
  91. if (!g_pfnSymGetSymFromAddr) {
  92. return FALSE;
  93. }
  94. g_pfnSymFunctionTableAccess = (PFNSYMFUNCTIONTABLEACCESS) GetProcAddress (g_hImagehlpInstance,
  95. "SymFunctionTableAccess");
  96. if (!g_pfnSymFunctionTableAccess) {
  97. return FALSE;
  98. }
  99. g_pfnSymGetModuleBase = (PFNSYMGETMODULEBASE) GetProcAddress (g_hImagehlpInstance,
  100. "SymGetModuleBase");
  101. if (!g_pfnSymGetModuleBase) {
  102. return FALSE;
  103. }
  104. return TRUE;
  105. }
  106. BOOL
  107. InitDebug(
  108. )
  109. /*++
  110. Description:
  111. This routine initializes the debug memory functionality.
  112. Arguments:
  113. none
  114. Return Value:
  115. BOOL - pass or fail
  116. --*/
  117. {
  118. BOOL status;
  119. SYSTEM_INFO SysInfo;
  120. if (fDebugInitialised)
  121. return TRUE;
  122. status = RtlEnterCriticalSection(&(g_RegLeakTraceInfo.StackInitCriticalSection));
  123. ASSERT( NT_SUCCESS( status ) );
  124. if (fDebugInitialised)
  125. return TRUE;
  126. OurProcess = GetCurrentProcess();
  127. g_RegLeakTraceInfo.szSymPath = (LPTSTR) RtlAllocateHeap(
  128. RtlProcessHeap(),
  129. 0,
  130. SYM_PATH_MAX_SIZE*sizeof(TCHAR));
  131. if (!g_RegLeakTraceInfo.szSymPath) {
  132. // looks like machine already doesn't have enough memory
  133. // disable leak tracking
  134. g_RegLeakTraceInfo.bEnableLeakTrack = 0;
  135. return FALSE;
  136. }
  137. g_RegLeakTraceInfo.dwMaxStackDepth = GetProfileInt(TEXT("RegistryLeak"), TEXT("StackDepth"), MAX_LEAK_STACK_DEPTH);
  138. GetProfileString(TEXT("RegistryLeak"), TEXT("SymbolPath"), TEXT(""), g_RegLeakTraceInfo.szSymPath, SYM_PATH_MAX_SIZE);
  139. if (!(*g_RegLeakTraceInfo.szSymPath)) {
  140. RtlFreeHeap(
  141. RtlProcessHeap(),
  142. 0,
  143. g_RegLeakTraceInfo.szSymPath);
  144. g_RegLeakTraceInfo.szSymPath = NULL;
  145. }
  146. if (!LoadImageHLP()) {
  147. g_RegLeakTraceInfo.bEnableLeakTrack = FALSE;
  148. status = RtlLeaveCriticalSection(&(g_RegLeakTraceInfo.StackInitCriticalSection));
  149. return FALSE;
  150. }
  151. GetSystemInfo( &SysInfo );
  152. switch (SysInfo.wProcessorArchitecture) {
  153. default:
  154. case PROCESSOR_ARCHITECTURE_INTEL:
  155. MachineType = IMAGE_FILE_MACHINE_I386;
  156. break;
  157. case PROCESSOR_ARCHITECTURE_MIPS:
  158. //
  159. // note this may not detect R10000 machines correctly
  160. //
  161. MachineType = IMAGE_FILE_MACHINE_R4000;
  162. break;
  163. case PROCESSOR_ARCHITECTURE_ALPHA:
  164. MachineType = IMAGE_FILE_MACHINE_ALPHA;
  165. break;
  166. case PROCESSOR_ARCHITECTURE_PPC:
  167. MachineType = IMAGE_FILE_MACHINE_POWERPC;
  168. break;
  169. }
  170. // symbols from Current directory/Environment variable _NT_SYMBOL_PATH
  171. // Environment variable _NT_ALTERNATE_SYMBOL_PATH or Environment variable SYSTEMROOT
  172. status = g_pfnSymInitialize ( OurProcess, g_RegLeakTraceInfo.szSymPath, FALSE );
  173. fDebugInitialised = TRUE;
  174. status = RtlLeaveCriticalSection(&(g_RegLeakTraceInfo.StackInitCriticalSection));
  175. return( TRUE );
  176. }
  177. BOOL
  178. StopDebug()
  179. {
  180. if (fDebugInitialised) {
  181. BOOL fSuccess;
  182. fSuccess = g_pfnSymCleanup(OurProcess);
  183. fDebugInitialised = FALSE;
  184. FreeLibrary(g_hImagehlpInstance);
  185. if (g_RegLeakTraceInfo.szSymPath) {
  186. RtlFreeHeap(
  187. RtlProcessHeap(),
  188. 0,
  189. g_RegLeakTraceInfo.szSymPath);
  190. }
  191. return fSuccess;
  192. }
  193. return TRUE;
  194. }
  195. BOOL
  196. ReadMem(
  197. IN HANDLE hProcess,
  198. IN LPCVOID BaseAddr,
  199. IN LPVOID Buffer,
  200. IN DWORD Size,
  201. IN LPDWORD NumBytes )
  202. /*++
  203. Description:
  204. This is a callback routine that StackWalk uses - it just calls teh system ReadProcessMemory
  205. routine with this process's handle
  206. Arguments:
  207. Return Value:
  208. none
  209. --*/
  210. {
  211. BOOL status;
  212. SIZE_T RealNumberBytesRead;
  213. status = ReadProcessMemory( GetCurrentProcess(),BaseAddr,Buffer,Size,&RealNumberBytesRead );
  214. *NumBytes = (DWORD)RealNumberBytesRead;
  215. return( status );
  216. }
  217. VOID
  218. GetCallStack(
  219. IN PCALLER_SYM Caller,
  220. IN int Skip,
  221. IN int cFind,
  222. IN int fResolveSymbols
  223. )
  224. /*++
  225. Description:
  226. This routine walks te stack to find the return address of caller. The number of callers
  227. and the number of callers on top to be skipped can be specified.
  228. Arguments:
  229. pdwCaller array of DWORD to return callers
  230. return addresses
  231. Skip no. of callers to skip
  232. cFInd no. of callers to find
  233. Return Value:
  234. none
  235. --*/
  236. {
  237. if (!g_RegLeakTraceInfo.bEnableLeakTrack) {
  238. return;
  239. }
  240. if (!InitDebug()) {
  241. return;
  242. }
  243. __try {
  244. memset(Caller, 0, cFind * sizeof(CALLER_SYM));
  245. RaiseException(MY_DBG_EXCEPTION, 0, 0, NULL);
  246. // raise an exception to get the exception record to start the stack walk
  247. //
  248. }
  249. __except(GetStack(GetExceptionInformation(), Caller, Skip, cFind, fResolveSymbols)) {
  250. }
  251. }
  252. DWORD GetStack(
  253. IN EXCEPTION_POINTERS *exp,
  254. IN PCALLER_SYM Caller,
  255. IN int Skip,
  256. IN int cFind,
  257. IN int fResolveSymbols
  258. )
  259. {
  260. BOOL status;
  261. CONTEXT ContextRecord;
  262. PUCHAR Buffer[sizeof(IMAGEHLP_SYMBOL)-1 + MAX_FUNCTION_INFO_SIZE]; // symbol info
  263. PIMAGEHLP_SYMBOL Symbol = (PIMAGEHLP_SYMBOL)Buffer;
  264. STACKFRAME StackFrame;
  265. INT i;
  266. DWORD Count;
  267. memcpy(&ContextRecord, exp->ContextRecord, sizeof(CONTEXT));
  268. ZeroMemory( &StackFrame,sizeof(STACKFRAME) );
  269. StackFrame.AddrPC.Segment = 0;
  270. StackFrame.AddrPC.Mode = AddrModeFlat;
  271. #ifdef _M_IX86
  272. StackFrame.AddrFrame.Offset = ContextRecord.Ebp;
  273. StackFrame.AddrFrame.Mode = AddrModeFlat;
  274. StackFrame.AddrStack.Offset = ContextRecord.Esp;
  275. StackFrame.AddrStack.Mode = AddrModeFlat;
  276. StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Eip;
  277. #elif defined(_M_MRX000)
  278. StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Fir;
  279. #elif defined(_M_ALPHA)
  280. StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Fir;
  281. #elif defined(_M_PPC)
  282. StackFrame.AddrPC.Offset = (DWORD)ContextRecord.Iar;
  283. #endif
  284. Count = 0;
  285. for (i=0;i<cFind+Skip ;i++ ) {
  286. status = g_pfnStackWalk( MachineType,
  287. OurProcess,
  288. GetCurrentThread(),
  289. &StackFrame,
  290. (PVOID)&ContextRecord,
  291. (PREAD_PROCESS_MEMORY_ROUTINE)ReadMem,
  292. g_pfnSymFunctionTableAccess,
  293. g_pfnSymGetModuleBase,
  294. NULL );
  295. if (status) {
  296. if ( i >= Skip) {
  297. DWORD Displacement;
  298. ZeroMemory( Symbol,sizeof(IMAGEHLP_SYMBOL)-1 + MAX_FUNCTION_INFO_SIZE );
  299. Symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  300. Symbol->Address = StackFrame.AddrPC.Offset;
  301. Symbol->MaxNameLength = MAX_FUNCTION_INFO_SIZE-1;
  302. Symbol->Flags = SYMF_OMAP_GENERATED;
  303. if (fResolveSymbols)
  304. status = g_pfnSymGetSymFromAddr( OurProcess,StackFrame.AddrPC.Offset,(DWORD_PTR*)&Displacement,Symbol );
  305. //
  306. // save the name of the function and the displacement into it for later printing
  307. //
  308. Caller[Count].Addr = (PVOID)StackFrame.AddrPC.Offset;
  309. if (status) {
  310. strcpy( Caller[Count].Buff,Symbol->Name );
  311. Caller[Count].Displacement = Displacement;
  312. }
  313. Count++;
  314. }
  315. } else {
  316. break;
  317. }
  318. }
  319. return EXCEPTION_CONTINUE_EXECUTION;
  320. // done with exceptions
  321. }
  322. #endif // LEAK_TRACK
  323. #endif // LOCAL