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.

514 lines
14 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1998.
  5. //
  6. // File: assert.cxx
  7. //
  8. // Contents: Debugging output routines for idsmgr.dll
  9. //
  10. // Functions: Assert
  11. // PopUpError
  12. //
  13. // History: 23-Jul-91 KyleP Created.
  14. // 09-Oct-91 KevinRo Major changes and comments added
  15. // 18-Oct-91 vich moved debug print routines out
  16. // 10-Jun-92 BryanT Switched to w4crt.h instead of wchar.h
  17. // 30-Sep-93 KyleP DEVL obsolete
  18. //
  19. //----------------------------------------------------------------------------
  20. #include <pch.cxx>
  21. #pragma hdrstop
  22. //
  23. // This one file **always** uses debugging options
  24. //
  25. #if CIDBG == 1
  26. // needed for CT TOM assert events trapping
  27. #include <assert.hxx>
  28. #include <namesem.hxx>
  29. #include <smem.hxx>
  30. #include <ciregkey.hxx>
  31. #include <regacc.hxx>
  32. #include <dprintf.h> // w4printf, w4dprintf prototypes
  33. #include <cidllsem.hxx>
  34. #undef FAR
  35. #undef NEAR
  36. unsigned long Win4InfoLevel = DEF_INFOLEVEL;
  37. unsigned long Win4InfoMask = 0xffffffff;
  38. unsigned long Win4AssertLevel = ASSRT_MESSAGE | ASSRT_STRESSBREAK;
  39. extern char * aDebugBuf;
  40. //+---------------------------------------------------------------------------
  41. //
  42. // Function: _asdprintf
  43. //
  44. // Synopsis: Calls vdprintf to output a formatted message.
  45. //
  46. // History: 18-Oct-91 vich Created
  47. //
  48. //----------------------------------------------------------------------------
  49. inline void __cdecl
  50. _asdprintf(
  51. char const *pszfmt, ...)
  52. {
  53. va_list va;
  54. va_start(va, pszfmt);
  55. vdprintf(DEB_FORCE, "Assert", pszfmt, va);
  56. va_end(va);
  57. }
  58. //+---------------------------------------------------------------------------
  59. //
  60. // Function: _Win4Assert, private
  61. //
  62. // Synopsis: Display assertion information
  63. //
  64. // Effects: Called when an assertion is hit.
  65. //
  66. // History: 12-Jul-91 AlexT Created.
  67. // 05-Sep-91 AlexT Catch Throws and Catches
  68. // 19-Oct-92 HoiV Added events for TOM
  69. //
  70. //----------------------------------------------------------------------------
  71. EXPORTIMP void APINOT
  72. Win4AssertEx(
  73. char const * szFile,
  74. int iLine,
  75. char const * szMessage)
  76. {
  77. #if 0
  78. //
  79. // This code is for the CT Lab only. When running in the lab,
  80. // all assert popups will be trapped and notifications will
  81. // be sent to the manager. If running in the office (non-lab
  82. // mode), the event CTTOMTrapAssertEvent will not exist and
  83. // consequently, no event will be pulsed.
  84. //
  85. HANDLE hTrapAssertEvent,
  86. hThreadStartEvent;
  87. if (hTrapAssertEvent = OpenEvent(EVENT_ALL_ACCESS,
  88. FALSE,
  89. CAIRO_CT_TOM_TRAP_ASSERT_EVENT))
  90. {
  91. SetEvent(hTrapAssertEvent);
  92. //
  93. // This event is to allow TOM Manager time to perform
  94. // a CallBack to the dispatcher.
  95. //
  96. if (hThreadStartEvent = OpenEvent(EVENT_ALL_ACCESS,
  97. FALSE,
  98. CAIRO_CT_TOM_THREAD_START_EVENT))
  99. {
  100. //
  101. // Wait until it's ok to popup or until timed-out
  102. //
  103. WaitForSingleObject(hThreadStartEvent, TWO_MINUTES);
  104. }
  105. }
  106. #endif // 0
  107. //
  108. // Always check to make sure the assert flag hasn't changed.
  109. //
  110. CRegAccess regAdmin( RTL_REGISTRY_CONTROL, wcsRegAdmin );
  111. ULONG ulLevel = regAdmin.Read( wcsWin4AssertLevel, 0xFFFFFFFF );
  112. if (ulLevel != 0xFFFFFFFF )
  113. SetWin4AssertLevel( ulLevel );
  114. //
  115. // Do the assert
  116. //
  117. if (Win4AssertLevel & ASSRT_MESSAGE)
  118. {
  119. DWORD tid = GetCurrentThreadId();
  120. _asdprintf("%s File: %s Line: %u, thread id %d\n",
  121. szMessage, szFile, iLine, tid);
  122. }
  123. if (Win4AssertLevel & ASSRT_POPUP)
  124. {
  125. int id = PopUpError(szMessage,iLine,szFile);
  126. if (id == IDCANCEL)
  127. {
  128. DebugBreak();
  129. }
  130. }
  131. else if (Win4AssertLevel & ASSRT_STRESSBREAK)
  132. {
  133. //
  134. // See if a debugger is attachable. If not, then put up a popup.
  135. //
  136. BOOL fOk = FALSE;
  137. try
  138. {
  139. CRegAccess regAeDebug( RTL_REGISTRY_ABSOLUTE,
  140. L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" );
  141. WCHAR wcsTemp[100];
  142. regAeDebug.Get( L"Auto", wcsTemp, sizeof(wcsTemp)/sizeof(WCHAR) );
  143. if ( L'1' == wcsTemp[0] && 0 == wcsTemp[1] )
  144. {
  145. regAeDebug.Get( L"Debugger", wcsTemp, sizeof(wcsTemp)/sizeof(WCHAR) );
  146. if ( 0 != wcsTemp[0] && 0 == wcsstr( wcsTemp, L"drwtsn" ) )
  147. {
  148. fOk = TRUE;
  149. }
  150. }
  151. }
  152. catch( ... )
  153. {
  154. }
  155. //
  156. // Debugger is attachable, break in.
  157. //
  158. if ( fOk )
  159. {
  160. w4dprintf( "***\n***\n*** Restartable software exception used to activate user-mode\n" );
  161. w4dprintf( "*** debugger. Enter 'g' to continue past assert (if you can't wait).\n" );
  162. w4dprintf( "*** Please send mail to the NtQuery alias first. aDebugBuf = 0x%x\n***\n***\n", aDebugBuf );
  163. RaiseException( ASSRT_STRESSEXCEPTION, 0, 0, 0 );
  164. }
  165. //
  166. // No debugger. Put up a popup.
  167. //
  168. else
  169. {
  170. int id = PopUpError(szMessage,iLine,szFile);
  171. if (id == IDCANCEL)
  172. {
  173. DebugBreak();
  174. }
  175. }
  176. }
  177. else if (Win4AssertLevel & ASSRT_BREAK)
  178. {
  179. DebugBreak();
  180. }
  181. }
  182. //+------------------------------------------------------------
  183. // Function: SetWin4InfoLevel(unsigned long ulNewLevel)
  184. //
  185. // Synopsis: Sets the global info level for debugging output
  186. // Returns: Old info level
  187. //
  188. //-------------------------------------------------------------
  189. EXPORTIMP unsigned long APINOT
  190. SetWin4InfoLevel(
  191. unsigned long ulNewLevel)
  192. {
  193. unsigned long ul;
  194. ul = Win4InfoLevel;
  195. Win4InfoLevel = ulNewLevel;
  196. return(ul);
  197. }
  198. //+------------------------------------------------------------
  199. // Function: _SetWin4InfoMask(unsigned long ulNewMask)
  200. //
  201. // Synopsis: Sets the global info mask for debugging output
  202. // Returns: Old info mask
  203. //
  204. //-------------------------------------------------------------
  205. EXPORTIMP unsigned long APINOT
  206. SetWin4InfoMask(
  207. unsigned long ulNewMask)
  208. {
  209. unsigned long ul;
  210. ul = Win4InfoMask;
  211. Win4InfoMask = ulNewMask;
  212. return(ul);
  213. }
  214. //+------------------------------------------------------------
  215. // Function: _SetWin4AssertLevel(unsigned long ulNewLevel)
  216. //
  217. // Synopsis: Sets the global assert level for debugging output
  218. // Returns: Old assert level
  219. //
  220. //-------------------------------------------------------------
  221. EXPORTIMP unsigned long APINOT
  222. SetWin4AssertLevel(
  223. unsigned long ulNewLevel)
  224. {
  225. unsigned long ul;
  226. ul = Win4AssertLevel;
  227. Win4AssertLevel = ulNewLevel;
  228. return(ul);
  229. }
  230. //+------------------------------------------------------------
  231. // Function: PopUpError
  232. //
  233. // Synopsis: Displays a dialog box using provided text,
  234. // and presents the user with the option to
  235. // continue or cancel.
  236. //
  237. // Arguments:
  238. // szMsg -- The string to display in main body of dialog
  239. // iLine -- Line number of file in error
  240. // szFile -- Filename of file in error
  241. //
  242. // Returns:
  243. // IDCANCEL -- User selected the CANCEL button
  244. // IDOK -- User selected the OK button
  245. //-------------------------------------------------------------
  246. EXPORTIMP int APINOT
  247. PopUpError(
  248. char const *szMsg,
  249. int iLine,
  250. char const *szFile)
  251. {
  252. static char szAssertCaption[128];
  253. static char szModuleName[128];
  254. DWORD tid = GetCurrentThreadId();
  255. DWORD pid = GetCurrentProcessId();
  256. char * pszModuleName;
  257. if (GetModuleFileNameA(NULL, szModuleName, 128))
  258. {
  259. pszModuleName = strrchr(szModuleName, '\\');
  260. if ( 0 == pszModuleName )
  261. pszModuleName = szModuleName;
  262. else
  263. pszModuleName++;
  264. }
  265. else
  266. {
  267. pszModuleName = "Unknown";
  268. }
  269. sprintf( szAssertCaption,"Process: %s File: %s line %u, thread id %d.%d",
  270. pszModuleName, szFile, iLine, pid, tid);
  271. UINT uiOldMode = SetErrorMode( 0 );
  272. int id = MessageBoxA( 0,
  273. (char *) szMsg,
  274. (LPSTR) szAssertCaption,
  275. MB_SERVICE_NOTIFICATION |
  276. MB_TASKMODAL | MB_ICONEXCLAMATION | MB_OKCANCEL );
  277. SetErrorMode( uiOldMode );
  278. //
  279. // If id == 0, then an error occurred. There are two possibilities
  280. // that can cause the error: Access Denied, which means that this
  281. // process does not have access to the default desktop, and everything
  282. // else (usually out of memory).
  283. //
  284. if (!id)
  285. {
  286. if (GetLastError() == ERROR_ACCESS_DENIED)
  287. {
  288. //
  289. // Retry this one with the SERVICE_NOTIFICATION flag on. That
  290. // should get us to the right desktop.
  291. //
  292. id = MessageBoxA( NULL,
  293. (char *) szMsg,
  294. (LPSTR) szAssertCaption,
  295. MB_SETFOREGROUND | MB_SERVICE_NOTIFICATION |
  296. MB_TASKMODAL | MB_ICONEXCLAMATION | MB_OKCANCEL );
  297. }
  298. else
  299. {
  300. // default: break if you can't display the messagebox
  301. id = IDCANCEL;
  302. }
  303. }
  304. return id;
  305. }
  306. //+------------------------------------------------------------
  307. // Function: vdprintf
  308. //
  309. // Synopsis: Prints debug output using a pointer to the
  310. // variable information. Used primarily by the
  311. // xxDebugOut macros
  312. //
  313. // Arguements:
  314. // ulCompMask -- Component level mask used to determine
  315. // output ability
  316. // pszComp -- String const of component prefix.
  317. // ppszfmt -- Pointer to output format and data
  318. //
  319. //-------------------------------------------------------------
  320. //
  321. // This semaphore is *outside* vdprintf because the compiler isn't smart
  322. // enough to serialize access for construction if it's function-local and
  323. // protected by a guard variable.
  324. //
  325. // KyleP - 20 May, 1993
  326. //
  327. CDLLStaticMutexSem g_mxsAssert;
  328. CIPMutexSem mtxDebugBuf( L"CiDebugMtx", CIPMutexSem::AppendPid, FALSE, 0 );
  329. CNamedSharedMem memDebugBuf( L"CiDebugMem", CNamedSharedMem::AppendPid, 1024 * 32 );
  330. BOOL * pfUseDebugBuf = 0;
  331. BOOLEAN * pfIsBeingDebugged = 0;
  332. ULONG * piDebugBuf = 0;
  333. char * aDebugBuf = 0;
  334. //
  335. // Very special version of the debug allocator. Doesn't record allocation
  336. // in log. Failure to free is not considered a leak.
  337. //
  338. #if CIDBG == 1
  339. void * ciNewDebugNoRecord( size_t size );
  340. enum eAlloc { NoRecordAlloc };
  341. inline void * __cdecl operator new ( size_t size, eAlloc )
  342. {
  343. return ciNewDebugNoRecord( size );
  344. }
  345. #endif
  346. EXPORTIMP void APINOT
  347. vdprintf(
  348. unsigned long ulCompMask,
  349. char const *pszComp,
  350. char const *ppszfmt,
  351. va_list pargs)
  352. {
  353. if ((ulCompMask & DEB_FORCE) == DEB_FORCE ||
  354. ((ulCompMask | Win4InfoLevel) & Win4InfoMask))
  355. {
  356. DWORD tid = GetCurrentThreadId();
  357. DWORD pid = GetCurrentProcessId();
  358. g_mxsAssert.Request();
  359. if ( 0 == pfUseDebugBuf )
  360. {
  361. piDebugBuf = (ULONG *)memDebugBuf.Get();
  362. pfUseDebugBuf = (BOOL *)memDebugBuf.Get() + sizeof(*piDebugBuf);
  363. aDebugBuf = (char *)memDebugBuf.Get();
  364. //
  365. // We can look here to tell when a process is being debugged.
  366. //
  367. pfIsBeingDebugged = &NtCurrentPeb()->BeingDebugged;
  368. CIPLock lock( mtxDebugBuf );
  369. if ( 0 == *piDebugBuf )
  370. {
  371. *piDebugBuf = sizeof(*piDebugBuf) + sizeof(*pfUseDebugBuf);
  372. *pfUseDebugBuf = TRUE;
  373. }
  374. }
  375. BOOL fRequested = FALSE;
  376. if ( 0 != pfIsBeingDebugged && *pfUseDebugBuf && !*pfIsBeingDebugged )
  377. {
  378. mtxDebugBuf.Request();
  379. fRequested = TRUE;
  380. }
  381. //
  382. // Assume no debug message will be > 1K
  383. //
  384. if ( *pfUseDebugBuf && *piDebugBuf >= ( 31 * 1024 ) )
  385. *piDebugBuf = sizeof(*piDebugBuf) + sizeof(*pfUseDebugBuf);
  386. if ((Win4InfoLevel & (DEB_DBGOUT | DEB_STDOUT)) != DEB_STDOUT)
  387. {
  388. if (! (ulCompMask & DEB_NOCOMPNAME))
  389. {
  390. if ( 0 != pfIsBeingDebugged && *pfUseDebugBuf && !*pfIsBeingDebugged )
  391. {
  392. *piDebugBuf += sprintf( aDebugBuf + *piDebugBuf, "%d.%03d> ", pid, tid );
  393. *piDebugBuf += sprintf( aDebugBuf + *piDebugBuf, "%s: ", pszComp);
  394. }
  395. else
  396. {
  397. w4dprintf( "%d.%03d> ", pid, tid );
  398. w4dprintf("%s: ", pszComp);
  399. }
  400. }
  401. if ( 0 != pfIsBeingDebugged && *pfUseDebugBuf && !*pfIsBeingDebugged )
  402. *piDebugBuf += vsprintf( aDebugBuf + *piDebugBuf, ppszfmt, pargs );
  403. else
  404. w4vdprintf(ppszfmt, pargs);
  405. }
  406. if (Win4InfoLevel & DEB_STDOUT)
  407. {
  408. if (! (ulCompMask & DEB_NOCOMPNAME))
  409. {
  410. w4printf( "%03d> ", tid );
  411. w4printf("%s: ", pszComp);
  412. }
  413. w4vprintf(ppszfmt, pargs);
  414. }
  415. if ( fRequested )
  416. mtxDebugBuf.Release();
  417. g_mxsAssert.Release();
  418. }
  419. }
  420. #else
  421. int assertDontUseThisName(void)
  422. {
  423. return 1;
  424. }
  425. #endif // CIDBG == 1