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.

414 lines
10 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: D E B U G X . C P P
  7. //
  8. // Contents: Implementation of debug support routines.
  9. //
  10. // Notes:
  11. //
  12. // Author: danielwe 16 Feb 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.h>
  16. #pragma hdrstop
  17. #ifdef DBG
  18. #include "ncdebug.h"
  19. #include "ncdefine.h"
  20. static int nAssertLevel = 0;
  21. static PFNASSERTHOOK pfnAssertHook = DefAssertSzFn;
  22. #define MAX_ASSERT_TEXT_SIZE 4096
  23. //
  24. // We can only do memory tracking if we've included crtdbg.h and
  25. // _DEBUG is defined.
  26. //
  27. #if defined(_INC_CRTDBG) && defined(_DEBUG)
  28. struct DBG_SHARED_MEM
  29. {
  30. _CrtMemState crtState;
  31. DWORD cRef;
  32. };
  33. DBG_SHARED_MEM * g_pMem = NULL;
  34. HANDLE g_hMap = NULL;
  35. static const WCHAR c_szSharedMem[] = L"DBG_NetCfgSharedMemory";
  36. //+---------------------------------------------------------------------------
  37. //
  38. // Function: InitDbgState
  39. //
  40. // Purpose: Initializes the memory leak detection code.
  41. //
  42. // Arguments:
  43. // (none)
  44. //
  45. // Returns: Nothing.
  46. //
  47. // Author: danielwe 13 May 1997
  48. //
  49. // Notes:
  50. //
  51. VOID InitDbgState()
  52. {
  53. g_hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
  54. 0, sizeof(DBG_SHARED_MEM), c_szSharedMem);
  55. if (g_hMap)
  56. {
  57. LPVOID pvMem;
  58. BOOL fExisted = (GetLastError() == ERROR_ALREADY_EXISTS);
  59. pvMem = MapViewOfFile(g_hMap, FILE_MAP_WRITE, 0, 0, 0);
  60. g_pMem = reinterpret_cast<DBG_SHARED_MEM *>(pvMem);
  61. if (!fExisted)
  62. {
  63. // First time creating the file mapping. Initialize things.
  64. g_pMem->cRef = 0;
  65. // start looking for leaks now
  66. _CrtMemCheckpoint(&g_pMem->crtState);
  67. }
  68. g_pMem->cRef++;
  69. TraceTag(ttidDefault, "DBGMEM: Init Refcount on shared mem is now %d",
  70. g_pMem->cRef);
  71. }
  72. }
  73. //+---------------------------------------------------------------------------
  74. //
  75. // Function: UnInitDbgState
  76. //
  77. // Purpose: Uninitializes the memory leak detection code.
  78. //
  79. // Arguments:
  80. // (none)
  81. //
  82. // Returns: Nothing.
  83. //
  84. // Author: danielwe 13 May 1997
  85. //
  86. // Notes:
  87. //
  88. VOID UnInitDbgState()
  89. {
  90. if (g_pMem)
  91. {
  92. g_pMem->cRef--;
  93. TraceTag(ttidDefault, "DBGMEM: Uninit Refcount on shared mem is now %d",
  94. g_pMem->cRef);
  95. if (!g_pMem->cRef)
  96. {
  97. // manually force dump of leaks when refcount goes to 0
  98. _CrtMemDumpAllObjectsSince(&g_pMem->crtState);
  99. }
  100. UnmapViewOfFile(reinterpret_cast<LPVOID>(g_pMem));
  101. CloseHandle(g_hMap);
  102. }
  103. }
  104. #endif
  105. BOOL WINAPI FInAssert(VOID)
  106. {
  107. return nAssertLevel > 0;
  108. }
  109. VOID WINAPIV AssertFmt(BOOL fExp, PCSTR pszaFile, int nLine, PCSTR pszaFmt, ...)
  110. {
  111. CHAR rgch[MAX_ASSERT_TEXT_SIZE];
  112. if (!fExp)
  113. {
  114. va_list valMarker;
  115. va_start(valMarker, pszaFmt);
  116. wvsprintfA(rgch, pszaFmt, valMarker);
  117. va_end(valMarker);
  118. AssertSzFn(rgch, pszaFile, nLine);
  119. }
  120. }
  121. VOID WINAPI AssertSzFn(PCSTR pszaMsg, PCSTR pszaFile, INT nLine)
  122. {
  123. CHAR rgch[MAX_ASSERT_TEXT_SIZE];
  124. ++nAssertLevel;
  125. if (pszaFile)
  126. {
  127. if (pszaMsg)
  128. {
  129. wsprintfA(rgch, "Net Config Assert Failure:\r\n File %s, line %d:\r\n %s\r\n",
  130. pszaFile, nLine, pszaMsg);
  131. }
  132. else
  133. {
  134. wsprintfA(rgch, "Net Config Assert Failure:\r\n File %s, line %d.\r\n",
  135. pszaFile, nLine);
  136. }
  137. }
  138. else
  139. {
  140. if (pszaMsg)
  141. {
  142. wsprintfA(rgch, "Net Config Assert Failure:\r\n:\r\n %s\r\n",
  143. pszaMsg);
  144. }
  145. else
  146. {
  147. wsprintfA(rgch, "Net Config Assert Failure\r\n");
  148. }
  149. }
  150. OutputDebugStringA(rgch);
  151. if (pfnAssertHook)
  152. {
  153. (*pfnAssertHook)(pszaMsg, pszaFile, nLine);
  154. }
  155. --nAssertLevel;
  156. }
  157. VOID WINAPI AssertSzFn(PCSTR pszaMsg, PCSTR pszaFile, INT nLine, PCSTR pszaFunc)
  158. {
  159. CHAR rgch[MAX_ASSERT_TEXT_SIZE];
  160. ++nAssertLevel;
  161. if (pszaFile)
  162. {
  163. if (pszaMsg)
  164. {
  165. wsprintfA(rgch, "Net Config Assert Failure:\r\n File %s, line %d, Func: %s:\r\n %s\r\n",
  166. pszaFile, nLine, pszaFunc, pszaMsg );
  167. }
  168. else
  169. {
  170. wsprintfA(rgch, "Net Config Assert Failure:\r\n File %s, line %d, Func: %s:.\r\n",
  171. pszaFile, nLine, pszaFunc ) ;
  172. }
  173. }
  174. else
  175. {
  176. if (pszaMsg)
  177. {
  178. wsprintfA(rgch, "Net Config Assert Failure:\r\n:\r\n %s\r\n",
  179. pszaMsg);
  180. }
  181. else
  182. {
  183. wsprintfA(rgch, "Net Config Assert Failure\r\n");
  184. }
  185. }
  186. OutputDebugStringA(rgch);
  187. if (pfnAssertHook)
  188. {
  189. (*pfnAssertHook)(pszaMsg, pszaFile, nLine);
  190. }
  191. --nAssertLevel;
  192. }
  193. VOID WINAPI AssertSzFnWithDbgPrompt(BOOL fPromptIgnore, PCSTR pszaMsg, PCSTR pszaFile, INT nLine, PCSTR pszaFunc)
  194. {
  195. CHAR rgch[MAX_ASSERT_TEXT_SIZE];
  196. DWORD dwProcId = GetCurrentProcessId();
  197. if (fPromptIgnore)
  198. {
  199. wsprintfA(rgch, "%s.\r\nPlease attach a kernel mode debugger, or (if you have local access to symbols) a user mode debugger to process id %d (decimal) and hit IGNORE to debug the problem\r\nE.g. use ntsd -Gg -p %d, (or ntsd -d -Gg -p %d) and then hit IGNORE.", pszaMsg, dwProcId, dwProcId, dwProcId);
  200. }
  201. else
  202. {
  203. wsprintfA(rgch, "%s.\r\nPlease attach a user mode debugger to process id %d (decimal) and hit RETRY to debug the problem\r\nE.g. use ntsd -Gg -p %d, (or ntsd -d -Gg -p %d) and then hit RETRY.", pszaMsg, dwProcId, dwProcId, dwProcId);
  204. }
  205. AssertSzFn(rgch, pszaFile, nLine, pszaFunc);
  206. };
  207. VOID CALLBACK DefAssertSzFn(PCSTR pszaMsg, PCSTR pszaFile, INT nLine)
  208. {
  209. CHAR rgch[2048];
  210. INT nID;
  211. int cch;
  212. PSTR pch;
  213. BOOL fNYIWarning = FALSE;
  214. CHAR szaNYI[] = "NYI:";
  215. if (pszaFile)
  216. {
  217. wsprintfA(rgch, "File %s, line %d\r\n\r\n", pszaFile, nLine);
  218. }
  219. else
  220. {
  221. rgch[0] = 0;
  222. }
  223. if (pszaMsg)
  224. {
  225. // Check to see if this is an NYI alert. If so, then we'll want
  226. // to use a different MessageBox title
  227. if (strncmp(pszaMsg, szaNYI, strlen(szaNYI)) == 0)
  228. {
  229. fNYIWarning = TRUE;
  230. }
  231. lstrcatA(rgch, pszaMsg);
  232. }
  233. cch = lstrlenA(rgch);
  234. pch = &rgch[cch];
  235. if (cch < celems(rgch))
  236. {
  237. lstrcpynA(pch, "\n\nPress Abort to crash, Retry to debug, or Ignore to ignore."
  238. "\nHold down Shift to copy the assert text to the "
  239. "clipboard before the action is taken.", celems(rgch) - cch - 1);
  240. }
  241. MessageBeep(MB_ICONHAND);
  242. nID = MessageBoxA(NULL, rgch,
  243. fNYIWarning ? "Net Config -- Not Yet Implemented" : "Net Config Assert Failure",
  244. MB_ABORTRETRYIGNORE | MB_DEFBUTTON3 | MB_ICONHAND |
  245. MB_SETFOREGROUND | MB_TASKMODAL | MB_SERVICE_NOTIFICATION);
  246. if (nID == IDRETRY)
  247. {
  248. DebugBreak();
  249. }
  250. // if cancelling, force a hard exit w/ a GP-fault so that Dr. Watson
  251. // generates a nice stack trace log.
  252. if (nID == IDABORT)
  253. {
  254. *(BYTE *) 0 = 1; // write to address 0 causes GP-fault
  255. }
  256. }
  257. VOID WINAPI SetAssertFn(PFNASSERTHOOK pfn)
  258. {
  259. pfnAssertHook = pfn;
  260. }
  261. //+---------------------------------------------------------------------------
  262. // To be called during DLL_PROCESS_DETACH for a DLL which implements COM
  263. // objects or hands out references to objects which can be tracked.
  264. // Call this function with the name of the DLL (so that it can be traced
  265. // to the debugger) and the lock count of the DLL. If the lock count is
  266. // non-zero, it means the DLL is being unloaded prematurley. When this
  267. // condition is detected, a message is printed to the debugger and a
  268. // DebugBreak will be invoked if the debug flag dfidBreakOnPrematureDllUnload
  269. // is set.
  270. //
  271. // Assumptions:
  272. // Trace and debugging features have not been uninitialized.
  273. //
  274. //
  275. VOID
  276. DbgCheckPrematureDllUnload (
  277. PCSTR pszaDllName,
  278. UINT ModuleLockCount)
  279. {
  280. if (0 != ModuleLockCount)
  281. {
  282. TraceTag(ttidNetcfgBase, "ModuleLockCount == %d. "
  283. "%s is being unloaded with clients still holding references!",
  284. ModuleLockCount,
  285. pszaDllName);
  286. if (FIsDebugFlagSet(dfidBreakOnPrematureDllUnload))
  287. {
  288. DebugBreak ();
  289. }
  290. }
  291. }
  292. #endif //! DBG
  293. //+---------------------------------------------------------------------------
  294. //
  295. // Function: InitializeDebugging
  296. //
  297. // Purpose: Called by every DLL or EXE to initialize the debugging
  298. // objects (Trace and DebugFlag tables)
  299. //
  300. // Arguments:
  301. // (none)
  302. //
  303. // Returns:
  304. //
  305. // Author: jeffspr 23 Sep 1997
  306. //
  307. // Notes:
  308. //
  309. NOTHROW void InitializeDebugging()
  310. {
  311. // For debug builds or if we have retail tracing enabled we need to
  312. // include the tracing code.
  313. // Ignore the error return, since we don't return it here anyway.
  314. //
  315. #ifdef ENABLETRACE
  316. (void) HrInitTracing();
  317. #endif
  318. #if defined(DBG) && defined(_INC_CRTDBG) && defined(_DEBUG)
  319. if (FIsDebugFlagSet (dfidDumpLeaks))
  320. {
  321. InitDbgState();
  322. }
  323. #endif
  324. }
  325. //+---------------------------------------------------------------------------
  326. //
  327. // Function: UnInitializeDebugging
  328. //
  329. // Purpose: Uninitialize the debugging objects (Tracing and DbgFlags)
  330. //
  331. // Arguments:
  332. // (none)
  333. //
  334. // Returns:
  335. //
  336. // Author: jeffspr 23 Sep 1997
  337. //
  338. // Notes:
  339. //
  340. NOTHROW void UnInitializeDebugging()
  341. {
  342. // For debug builds or if we have retail tracing enabled we will have
  343. // included the tracing code. We now need to uninitialize it.
  344. // Ignore the error return, since we don't return it here anyway.
  345. //
  346. #ifdef ENABLETRACE
  347. (void) HrUnInitTracing();
  348. #endif
  349. #if defined(DBG) && defined(_INC_CRTDBG) && defined(_DEBUG)
  350. if (FIsDebugFlagSet (dfidDumpLeaks))
  351. {
  352. UnInitDbgState();
  353. }
  354. #endif
  355. }