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.

634 lines
18 KiB

  1. //+---------------------------------------------------------------------------
  2. // Copyright (C) 1991-1994, Microsoft Corporation.
  3. //
  4. // File: assert.cpp
  5. //
  6. // Contents: Debugging output routines
  7. //
  8. // History: 23-Jul-91 KyleP Created.
  9. // 09-Oct-91 KevinRo Major changes and comments added
  10. // 18-Oct-91 vich moved debug print routines out
  11. // 10-Jun-92 BryanT Switched to w4crt.h instead of wchar.h
  12. // 7-Oct-94 BruceFo Ripped out all kernel, non-FLAT,
  13. // DLL-specific, non-Win32 functionality.
  14. // Now it's basically "print to the
  15. // debugger" code.
  16. // 20-Oct-95 EricB Set component debug level in the
  17. // registry.
  18. //
  19. //----------------------------------------------------------------------------
  20. #include <objbase.h>
  21. #include <basetyps.h>
  22. #include <tchar.h>
  23. #include <vector> // to keep mmcdebug.h happy
  24. #include "mmcdebug.h"
  25. //############################################################################
  26. //############################################################################
  27. //
  28. // The safer string handling routines
  29. //
  30. //############################################################################
  31. //############################################################################
  32. #include <strsafe.h>
  33. #ifdef DBG
  34. #define new DEBUG_NEW
  35. #include "..\inc\admindbg.h"
  36. #include "malloc.h" // alloca
  37. //
  38. // Globals
  39. //
  40. ULONG AdminInfoLevel = DEF_INFOLEVEL;
  41. ULONG AdminInfoMask = 0xffffffff;
  42. ULONG AdminAssertLevel = ASSRT_MESSAGE | ASSRT_BREAK | ASSRT_POPUP;
  43. BOOL fCritSecInit = FALSE;
  44. static CRITICAL_SECTION s_csMessageBuf;
  45. const size_t g_cchMessageBuf = 500; // size of the message buffer in chars
  46. static TCHAR g_szMessageBuf[500]; // this is the message buffer
  47. //
  48. // Forward declration of local functions
  49. //
  50. LPSTR AnsiPathFindFileName(LPSTR pPath);
  51. void InitializeDebugging(void);
  52. void CleanUpDebugging(void);
  53. void smprintf(ULONG ulCompMask, LPTSTR pszComp, LPTSTR ppszfmt, va_list pargs);
  54. int w4dprintf(LPTSTR format, ...);
  55. int w4smprintf(LPTSTR format, va_list arglist);
  56. //+---------------------------------------------------------------------------
  57. //
  58. // Function: w4dprintf
  59. //
  60. // Synopsis: Calls w4smprintf to output a formatted message.
  61. //
  62. //----------------------------------------------------------------------------
  63. static int w4dprintf(LPTSTR format, ...)
  64. {
  65. int ret;
  66. va_list va;
  67. va_start(va, format);
  68. ret = w4smprintf(format, va);
  69. va_end(va);
  70. return ret;
  71. }
  72. //+---------------------------------------------------------------------------
  73. //
  74. // Function: w4smprintf
  75. //
  76. // Synopsis: Calls OutputDebugStringA to output a formatted message.
  77. //
  78. //----------------------------------------------------------------------------
  79. static int w4smprintf(LPTSTR format, va_list arglist)
  80. {
  81. EnterCriticalSection(&s_csMessageBuf);
  82. HRESULT hr = StringCchVPrintf(g_szMessageBuf, g_cchMessageBuf, format, arglist);
  83. if(FAILED(hr))
  84. return -1;
  85. OutputDebugString(g_szMessageBuf);
  86. LeaveCriticalSection(&s_csMessageBuf);
  87. return lstrlen(g_szMessageBuf);
  88. }
  89. //+------------------------------------------------------------
  90. // Function: SetAdminInfoLevel(ULONG ulNewLevel)
  91. //
  92. // Synopsis: Sets the global info level for debugging output
  93. //
  94. // Returns: Old info level
  95. //
  96. //-------------------------------------------------------------
  97. ULONG SetAdminInfoLevel(ULONG ulNewLevel)
  98. {
  99. ULONG ul;
  100. ul = AdminInfoLevel;
  101. AdminInfoLevel = ulNewLevel;
  102. return(ul);
  103. }
  104. //+------------------------------------------------------------
  105. // Function: SetAdminInfoMask(ULONG ulNewMask)
  106. //
  107. // Synopsis: Sets the global info mask for debugging output
  108. //
  109. // Returns: Old info mask
  110. //
  111. //-------------------------------------------------------------
  112. ULONG SetAdminInfoMask(ULONG ulNewMask)
  113. {
  114. ULONG ul;
  115. ul = AdminInfoMask;
  116. AdminInfoMask = ulNewMask;
  117. return(ul);
  118. }
  119. //+------------------------------------------------------------
  120. // Function: SetAdminAssertLevel(ULONG ulNewLevel)
  121. //
  122. // Synopsis: Sets the global assert level for debugging output
  123. //
  124. // Returns: Old assert level
  125. //
  126. //-------------------------------------------------------------
  127. ULONG SetAdminAssertLevel(ULONG ulNewLevel)
  128. {
  129. ULONG ul;
  130. ul = AdminAssertLevel;
  131. AdminAssertLevel = ulNewLevel;
  132. return(ul);
  133. }
  134. //+------------------------------------------------------------
  135. // Function: smprintf
  136. //
  137. // Synopsis: Prints debug output using a pointer to the
  138. // variable information. Used primarily by the
  139. // xxDebugOut macros
  140. //
  141. // Arguements:
  142. // ulCompMask -- Component level mask used to determine
  143. // output ability
  144. // pszComp -- String const of component prefix.
  145. // ppszfmt -- Pointer to output format and data
  146. //
  147. //-------------------------------------------------------------
  148. static CRITICAL_SECTION s_csDebugPrint;
  149. void smprintf(ULONG ulCompMask, LPTSTR pszComp, LPTSTR ppszfmt, va_list pargs)
  150. {
  151. if ((ulCompMask & DEB_FORCE) == DEB_FORCE ||
  152. ((ulCompMask | AdminInfoLevel) & AdminInfoMask))
  153. {
  154. EnterCriticalSection(&s_csDebugPrint);
  155. DWORD tid = GetCurrentThreadId();
  156. DWORD pid = GetCurrentProcessId();
  157. if ((AdminInfoLevel & (DEB_DBGOUT | DEB_STDOUT)) != DEB_STDOUT)
  158. {
  159. if (! (ulCompMask & DEB_NOCOMPNAME))
  160. {
  161. w4dprintf(_T("%x.%03x> %s: "), pid, tid, pszComp);
  162. }
  163. w4smprintf(ppszfmt, pargs);
  164. }
  165. //if (AdminInfoLevel & DEB_STDOUT)
  166. //{
  167. // if (! (ulCompMask & DEB_NOCOMPNAME))
  168. // {
  169. // printf("%x.%03x> %s: ", pid, tid, pszComp);
  170. // }
  171. // vprintf(ppszfmt, pargs);
  172. //}
  173. LeaveCriticalSection(&s_csDebugPrint);
  174. }
  175. }
  176. //+----------------------------------------------------------------------------
  177. //
  178. // Admin debuggging library inititalization.
  179. //
  180. // To set a non-default debug info level outside of the debugger, create the
  181. // below registry key and in it create a value whose name is the component's
  182. // debugging tag name (the "comp" parameter to the DECLARE_INFOLEVEL macro) and
  183. // whose data is the desired infolevel in REG_DWORD format.
  184. //-----------------------------------------------------------------------------
  185. #define CURRENT_VERSION_KEY _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")
  186. #define ADMINDEBUGKEY _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AdminDebug")
  187. #define ADMINDEBUG _T("AdminDebug")
  188. //+----------------------------------------------------------------------------
  189. // Function: CheckInit
  190. //
  191. // Synopsis: Performs debugging library initialization
  192. // including reading the registry for the desired infolevel
  193. //
  194. //-----------------------------------------------------------------------------
  195. void CheckInit(LPTSTR pInfoLevelString, ULONG * pulInfoLevel)
  196. {
  197. HKEY hKey;
  198. LONG lRet;
  199. DWORD dwSize;
  200. if (!fCritSecInit) InitializeDebugging();
  201. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADMINDEBUGKEY, 0,
  202. KEY_QUERY_VALUE | KEY_SET_VALUE, &hKey);
  203. if (lRet == ERROR_FILE_NOT_FOUND)
  204. {
  205. HKEY hkCV;
  206. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, CURRENT_VERSION_KEY, 0,
  207. KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY, &hkCV);
  208. if (lRet == ERROR_SUCCESS)
  209. {
  210. lRet = RegCreateKeyEx(hkCV, ADMINDEBUG, 0, _T(""),
  211. REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL,
  212. &hKey, NULL);
  213. RegCloseKey(hkCV);
  214. }
  215. }
  216. if (lRet == ERROR_SUCCESS)
  217. {
  218. dwSize = sizeof(ULONG);
  219. lRet = RegQueryValueEx(hKey, pInfoLevelString, NULL, NULL,
  220. (LPBYTE)pulInfoLevel, &dwSize);
  221. if (lRet != ERROR_SUCCESS)
  222. {
  223. *pulInfoLevel = DEF_INFOLEVEL;
  224. lRet = RegSetValueEx(hKey, pInfoLevelString, 0, REG_DWORD,
  225. (CONST BYTE *)pulInfoLevel, sizeof(ULONG));
  226. }
  227. RegCloseKey(hKey);
  228. }
  229. }
  230. void InitializeDebugging(void)
  231. {
  232. if (fCritSecInit) return;
  233. InitializeCriticalSection(&s_csMessageBuf);
  234. InitializeCriticalSection(&s_csDebugPrint);
  235. fCritSecInit = TRUE;
  236. }
  237. void CleanUpDebugging(void)
  238. {
  239. if (fCritSecInit)
  240. {
  241. DeleteCriticalSection(&s_csMessageBuf);
  242. DeleteCriticalSection(&s_csDebugPrint);
  243. }
  244. }
  245. // Returns a pointer to the last component of a path string.
  246. //
  247. // in:
  248. // path name, either fully qualified or not
  249. //
  250. // returns:
  251. // pointer into the path where the path is. if none is found
  252. // returns a poiter to the start of the path
  253. //
  254. // c:\foo\bar -> bar
  255. // c:\foo -> foo
  256. // c:\foo\ -> c:\foo\ (REVIEW: is this case busted?)
  257. // c:\ -> c:\ (REVIEW: this case is strange)
  258. // c: -> c:
  259. // foo -> foo
  260. LPSTR AnsiPathFindFileName(LPSTR pPath)
  261. {
  262. LPSTR pT;
  263. for (pT = pPath; *pPath; pPath = CharNextA(pPath)) {
  264. if ((pPath[0] == '\\' || pPath[0] == ':')
  265. && pPath[1] && (pPath[1] != '\\'))
  266. pT = pPath + 1;
  267. }
  268. return (LPSTR)pT; // const -> non const
  269. }
  270. /////////////////////////////////////////////////////////////////////////////
  271. /////////////////////////////////////////////////////////////////////////////
  272. ////////////// ASSERT CODE //////////////////////////////////////////////
  273. /////////////////////////////////////////////////////////////////////////////
  274. /////////////////////////////////////////////////////////////////////////////
  275. //+------------------------------------------------------------
  276. // Function: PopUpError
  277. //
  278. // Synopsis: Displays a dialog box using provided text,
  279. // and presents the user with the option to
  280. // continue or cancel.
  281. //
  282. // Arguments:
  283. // szMsg -- The string to display in main body of dialog
  284. // iLine -- Line number of file in error
  285. // szFile -- Filename of file in error
  286. //
  287. // Returns:
  288. // IDCANCEL -- User selected the CANCEL button
  289. // IDOK -- User selected the OK button
  290. //-------------------------------------------------------------
  291. int PopUpError(LPTSTR szMsg, int iLine, LPSTR szFile)
  292. {
  293. //
  294. // Create caption
  295. //
  296. static TCHAR szAssertCaption[128];
  297. static int cchAssertCaption = 128;
  298. //
  299. // get process
  300. //
  301. static CHAR szModuleName[128];
  302. LPSTR pszModuleName;
  303. if (GetModuleFileNameA(NULL, szModuleName, 128))
  304. {
  305. pszModuleName = szModuleName;
  306. }
  307. else
  308. {
  309. pszModuleName = "Unknown";
  310. }
  311. LPSTR pProcess = AnsiPathFindFileName(pszModuleName);
  312. StringCchPrintf(szAssertCaption, cchAssertCaption, _T("%hs: Assertion Failed"), pProcess);
  313. //
  314. // Create details.
  315. //
  316. TCHAR szDetails[1024];
  317. int cchDetails = 1024;
  318. DWORD tid = GetCurrentThreadId();
  319. DWORD pid = GetCurrentProcessId();
  320. StringCchPrintf(szDetails, cchDetails,
  321. _T(" Assertion:\t %s\n\n")
  322. _T(" File: \t\t %hs\n")
  323. _T(" Line: \t\t %d\n\n")
  324. _T(" Module: \t %hs\n")
  325. _T(" Thread ID:\t %d.%d\n\n")
  326. _T(" Press Cancel to debug the application\n")
  327. _T(" Press OK to ignore the assertion"),
  328. szMsg, szFile, iLine, pszModuleName, pid, tid);
  329. int id = MessageBox(NULL,
  330. szDetails,
  331. szAssertCaption,
  332. MB_SETFOREGROUND
  333. | MB_TASKMODAL
  334. | MB_ICONEXCLAMATION
  335. | MB_OKCANCEL);
  336. //
  337. // If id == 0, then an error occurred. There are two possibilities
  338. // that can cause the error: Access Denied, which means that this
  339. // process does not have access to the default desktop, and everything
  340. // else (usually out of memory).
  341. //
  342. if (0 == id)
  343. {
  344. if (GetLastError() == ERROR_ACCESS_DENIED)
  345. {
  346. //
  347. // Retry this one with the SERVICE_NOTIFICATION flag on. That
  348. // should get us to the right desktop.
  349. //
  350. id = MessageBox(NULL,
  351. szMsg,
  352. szAssertCaption,
  353. MB_SETFOREGROUND
  354. | MB_TASKMODAL
  355. | MB_ICONEXCLAMATION
  356. | MB_OKCANCEL);
  357. }
  358. }
  359. return id;
  360. }
  361. //+---------------------------------------------------------------------------
  362. //
  363. // Function: _asdprintf
  364. //
  365. // Synopsis: Calls smprintf to output a formatted message.
  366. //
  367. // History: 18-Oct-91 vich Created
  368. //
  369. //----------------------------------------------------------------------------
  370. inline void _asdprintf(LPTSTR pszfmt, ...)
  371. {
  372. va_list va;
  373. va_start(va, pszfmt);
  374. smprintf(DEB_FORCE, _T("Assert"), pszfmt, va);
  375. va_end(va);
  376. }
  377. //+---------------------------------------------------------------------------
  378. //
  379. // Function: AdminAssertEx, private
  380. //
  381. // Synopsis: Display assertion information
  382. //
  383. // Effects: Called when an assertion is hit.
  384. //
  385. //----------------------------------------------------------------------------
  386. void AdminAssertEx(LPSTR szFile, int iLine, LPTSTR szMessage)
  387. {
  388. if (AdminAssertLevel & ASSRT_MESSAGE)
  389. {
  390. DWORD tid = GetCurrentThreadId();
  391. LPSTR pszFileName = AnsiPathFindFileName(szFile);
  392. _asdprintf(_T("%s <%hs, l %u, thread %d>\n"),
  393. szMessage, pszFileName, iLine, tid);
  394. }
  395. if (AdminAssertLevel & ASSRT_POPUP)
  396. {
  397. int id = PopUpError(szMessage,iLine,szFile);
  398. if (id == IDCANCEL)
  399. {
  400. MMCDebugBreak();
  401. }
  402. }
  403. else if (AdminAssertLevel & ASSRT_BREAK)
  404. {
  405. MMCDebugBreak();
  406. }
  407. }
  408. //____________________________________________________________________________
  409. //____________________________________________________________________________
  410. //________________ _________________________________________
  411. //________________ class CDbg _________________________________________
  412. //________________ _________________________________________
  413. //____________________________________________________________________________
  414. //____________________________________________________________________________
  415. // Initialize the number of CDbg instances.
  416. long CDbg::s_cCDbgObjCount = 0;
  417. CDbg::CDbg(LPTSTR str)
  418. :
  419. m_InfoLevelString(str),
  420. m_InfoLevel(DEF_INFOLEVEL)
  421. {
  422. CheckInit(m_InfoLevelString, &m_InfoLevel);
  423. // Increment # of CDbg instances.
  424. InterlockedIncrement(&s_cCDbgObjCount);
  425. }
  426. CDbg::~CDbg()
  427. {
  428. // If this is last CDbg instance destroy the
  429. // static objects.
  430. if (InterlockedDecrement(&s_cCDbgObjCount) == 0)
  431. CleanUpDebugging();
  432. }
  433. void CDbg::DebugOut(ULONG fDebugMask, LPSTR pszfmt, ...)
  434. {
  435. if(NULL == pszfmt)
  436. {
  437. MMCDebugBreak();
  438. return;
  439. }
  440. #ifdef UNICODE
  441. int cbFormatBuffer = (strlen(pszfmt) + 1) * sizeof(WCHAR);
  442. LPWSTR pszFormatBuffer = (LPWSTR)alloca(cbFormatBuffer);
  443. if(NULL == pszFormatBuffer)
  444. {
  445. MMCDebugBreak();
  446. return;
  447. }
  448. pszFormatBuffer[0] = '\0';
  449. (void) MultiByteToWideChar(CP_ACP, 0, pszfmt, -1, pszFormatBuffer, cbFormatBuffer);
  450. #else
  451. LPSTR pszFormatBuffer = pszfmt;
  452. #endif
  453. if (m_InfoLevel & fDebugMask)
  454. {
  455. va_list va;
  456. va_start (va, pszfmt);
  457. smprintf(DEB_TRACE, m_InfoLevelString, pszFormatBuffer, va);
  458. va_end(va);
  459. }
  460. }
  461. void CDbg::DebugOut(ULONG fDebugMask, LPWSTR pwszfmt, ...)
  462. {
  463. if(NULL == pwszfmt)
  464. {
  465. MMCDebugBreak();
  466. return;
  467. }
  468. #ifndef UNICODE
  469. int cbFormatBuffer = (wcslen(pwszfmt) + 1) * sizeof(CHAR);
  470. LPTSTR pszFormatBuffer = (LPSTR)alloca(cbFormatBuffer);
  471. if(NULL == pszFormatBuffer)
  472. {
  473. MMCDebugBreak();
  474. return;
  475. }
  476. pszFormatBuffer[0] = '\0';
  477. (void) WideCharToMultiByte(CP_ACP, 0, pwszfmt, -1, pszFormatBuffer, cbFormatBuffer, NULL, NULL);
  478. #else
  479. LPTSTR pszFormatBuffer = pwszfmt;
  480. #endif
  481. if (m_InfoLevel & fDebugMask)
  482. {
  483. va_list va;
  484. va_start (va, pwszfmt);
  485. smprintf(DEB_TRACE, m_InfoLevelString, pszFormatBuffer, va);
  486. va_end(va);
  487. }
  488. }
  489. void CDbg::DebugErrorX(LPSTR file, ULONG line, LONG err)
  490. {
  491. if (m_InfoLevel & DEB_ERROR)
  492. {
  493. file = AnsiPathFindFileName(file);
  494. this->DebugOut(DEB_ERROR, "error<0x%08x> %hs, l %u\n",
  495. err, file, line);
  496. }
  497. }
  498. void CDbg::DebugErrorL(LPSTR file, ULONG line, LONG err)
  499. {
  500. if (m_InfoLevel & DEB_ERROR)
  501. {
  502. file = AnsiPathFindFileName(file);
  503. this->DebugOut(DEB_ERROR, "error<%uL> %hs, l %u\n", err, file, line);
  504. }
  505. }
  506. void CDbg::DebugMsg(LPSTR file, ULONG line, LPSTR msg)
  507. {
  508. file = AnsiPathFindFileName(file);
  509. this->DebugOut(DEB_FORCE, "asrt %hs, l %u, <%s>\n", file, line, msg);
  510. }
  511. void CDbg::DebugMsg(LPSTR file, ULONG line, LPWSTR msg)
  512. {
  513. file = AnsiPathFindFileName(file);
  514. this->DebugOut(DEB_FORCE, _T("asrt %hs, l %u, <%s>\n"), file, line, msg);
  515. }
  516. void CDbg::AssertEx(LPSTR pszFile, int iLine, LPTSTR pszMsg)
  517. {
  518. AdminAssertEx(pszFile, iLine, pszMsg);
  519. }
  520. #endif // DBG