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.

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