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.

537 lines
12 KiB

  1. /***
  2. *DbgRpt.c - Debug Cluster Reporting Functions
  3. *
  4. * Copyright (c) 1988-1998, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *******************************************************************************/
  9. #include <malloc.h>
  10. #include <mbstring.h>
  11. #include <stdarg.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <signal.h>
  15. #include <string.h>
  16. #include <windows.h>
  17. #define CLRTL_INCLUDE_DEBUG_REPORTING
  18. #include "ClRtlDbg.h"
  19. #define _ClRtlInterlockedIncrement InterlockedIncrement
  20. #define _ClRtlInterlockedDecrement InterlockedDecrement
  21. /*---------------------------------------------------------------------------
  22. *
  23. * Debug Reporting
  24. *
  25. --------------------------------------------------------------------------*/
  26. static int ClRtlMessageWindow(
  27. int,
  28. const char *,
  29. const char *,
  30. const char *,
  31. const char *
  32. );
  33. static int __clrtlMessageBoxA(
  34. LPCSTR lpText,
  35. LPCSTR lpCaption,
  36. UINT uType
  37. );
  38. extern "C"
  39. {
  40. _CLRTL_REPORT_HOOK _pfnReportHook;
  41. long _clrtlAssertBusy = -1;
  42. int _ClRtlDbgMode[_CLRTLDBG_ERRCNT] = {
  43. _CLRTLDBG_MODE_DEBUG,
  44. _CLRTLDBG_MODE_DEBUG | _CLRTLDBG_MODE_WNDW,
  45. _CLRTLDBG_MODE_DEBUG | _CLRTLDBG_MODE_WNDW
  46. };
  47. _HFILE _ClRtlDbgFile[_CLRTLDBG_ERRCNT] = {
  48. _CLRTLDBG_INVALID_HFILE,
  49. _CLRTLDBG_INVALID_HFILE,
  50. _CLRTLDBG_INVALID_HFILE
  51. };
  52. }
  53. static const char * _ClRtlDbgModeMsg[_CLRTLDBG_ERRCNT] = { "Warning", "Error", "Assertion Failed" };
  54. /***
  55. *void _ClRtlDebugBreak - call OS-specific debug function
  56. *
  57. *Purpose:
  58. * call OS-specific debug function
  59. *
  60. *Entry:
  61. *
  62. *Exit:
  63. *
  64. *Exceptions:
  65. *
  66. *******************************************************************************/
  67. #undef _ClRtlDbgBreak
  68. extern "C" void _cdecl _ClRtlDbgBreak(
  69. void
  70. )
  71. {
  72. DebugBreak();
  73. } //*** _ClRtlDbgBreak()
  74. /***
  75. *int _ClRtlSetReportMode - set the reporting mode for a given report type
  76. *
  77. *Purpose:
  78. * set the reporting mode for a given report type
  79. *
  80. *Entry:
  81. * int nRptType - the report type
  82. * int fMode - new mode for given report type
  83. *
  84. *Exit:
  85. * previous mode for given report type
  86. *
  87. *Exceptions:
  88. *
  89. *******************************************************************************/
  90. extern "C" int __cdecl _ClRtlSetReportMode(
  91. int nRptType,
  92. int fMode
  93. )
  94. {
  95. int oldMode;
  96. if (nRptType < 0 || nRptType >= _CLRTLDBG_ERRCNT)
  97. return -1;
  98. if (fMode == _CLRTLDBG_REPORT_MODE)
  99. return _ClRtlDbgMode[nRptType];
  100. /* verify flags values */
  101. if (fMode & ~(_CLRTLDBG_MODE_FILE | _CLRTLDBG_MODE_DEBUG | _CLRTLDBG_MODE_WNDW))
  102. return -1;
  103. oldMode = _ClRtlDbgMode[nRptType];
  104. _ClRtlDbgMode[nRptType] = fMode;
  105. return oldMode;
  106. } //*** _ClRtlSetReportMode()
  107. /***
  108. *int _ClRtlSetReportFile - set the reporting file for a given report type
  109. *
  110. *Purpose:
  111. * set the reporting file for a given report type
  112. *
  113. *Entry:
  114. * int nRptType - the report type
  115. * _HFILE hFile - new file for given report type
  116. *
  117. *Exit:
  118. * previous file for given report type
  119. *
  120. *Exceptions:
  121. *
  122. *******************************************************************************/
  123. extern "C" _HFILE __cdecl _ClRtlSetReportFile(
  124. int nRptType,
  125. _HFILE hFile
  126. )
  127. {
  128. _HFILE oldFile;
  129. if (nRptType < 0 || nRptType >= _CLRTLDBG_ERRCNT)
  130. return _CLRTLDBG_HFILE_ERROR;
  131. if (hFile == _CLRTLDBG_REPORT_FILE)
  132. return _ClRtlDbgFile[nRptType];
  133. oldFile = _ClRtlDbgFile[nRptType];
  134. if (_CLRTLDBG_FILE_STDOUT == hFile)
  135. _ClRtlDbgFile[nRptType] = GetStdHandle(STD_OUTPUT_HANDLE);
  136. else if (_CLRTLDBG_FILE_STDERR == hFile)
  137. _ClRtlDbgFile[nRptType] = GetStdHandle(STD_ERROR_HANDLE);
  138. else
  139. _ClRtlDbgFile[nRptType] = hFile;
  140. return oldFile;
  141. } //*** _ClRtlSetReportFile()
  142. /***
  143. *_CLRTL_REPORT_HOOK _ClRtlSetReportHook() - set client report hook
  144. *
  145. *Purpose:
  146. * set client report hook
  147. *
  148. *Entry:
  149. * _CLRTL_REPORT_HOOK pfnNewHook - new report hook
  150. *
  151. *Exit:
  152. * return previous hook
  153. *
  154. *Exceptions:
  155. *
  156. *******************************************************************************/
  157. extern "C" _CLRTL_REPORT_HOOK __cdecl _ClRtlSetReportHook(
  158. _CLRTL_REPORT_HOOK pfnNewHook
  159. )
  160. {
  161. _CLRTL_REPORT_HOOK pfnOldHook = _pfnReportHook;
  162. _pfnReportHook = pfnNewHook;
  163. return pfnOldHook;
  164. } //*** _ClRtlSetReportHook()
  165. #define MAXLINELEN 64
  166. #define MAX_MSG 4096
  167. #define TOOLONGMSG "_ClRtlDbgReport: String too long or IO Error"
  168. /***
  169. *int _ClRtlDbgReport() - primary reporting function
  170. *
  171. *Purpose:
  172. * Display a message window with the following format.
  173. *
  174. * ================= Microsft Visual C++ Debug Library ================
  175. *
  176. * {Warning! | Error! | Assertion Failed!}
  177. *
  178. * Program: c:\test\mytest\foo.exe
  179. * [Module: c:\test\mytest\bar.dll]
  180. * [File: c:\test\mytest\bar.c]
  181. * [Line: 69]
  182. *
  183. * {<warning or error message> | Expression: <expression>}
  184. *
  185. * [For information on how your program can cause an assertion
  186. * failure, see the Visual C++ documentation on asserts]
  187. *
  188. * (Press Retry to debug the application)
  189. *
  190. * ===================================================================
  191. *
  192. *Entry:
  193. * int nRptType - report type
  194. * const char * szFile - file name
  195. * int nLine - line number
  196. * const char * szModule - module name
  197. * const char * szFormat - format string
  198. * ... - var args
  199. *
  200. *Exit:
  201. * if (MessageBox)
  202. * {
  203. * Abort -> aborts
  204. * Retry -> return TRUE
  205. * Ignore-> return FALSE
  206. * }
  207. * else
  208. * return FALSE
  209. *
  210. *Exceptions:
  211. *
  212. *******************************************************************************/
  213. extern "C" int __cdecl _ClRtlDbgReport(
  214. int nRptType,
  215. const char * szFile,
  216. int nLine,
  217. const char * szModule,
  218. const char * szFormat,
  219. ...
  220. )
  221. {
  222. int retval;
  223. va_list arglist;
  224. char szLineMessage[MAX_MSG] = {0};
  225. char szOutMessage[MAX_MSG] = {0};
  226. char szUserMessage[MAX_MSG] = {0};
  227. #define ASSERTINTRO1 "Assertion failed: "
  228. #define ASSERTINTRO2 "Assertion failed!"
  229. va_start(arglist, szFormat);
  230. if (nRptType < 0 || nRptType >= _CLRTLDBG_ERRCNT)
  231. return -1;
  232. /*
  233. * handle the (hopefully rare) case of
  234. *
  235. * 1) ASSERT while already dealing with an ASSERT
  236. * or
  237. * 2) two threads asserting at the same time
  238. */
  239. if (_CLRTLDBG_ASSERT == nRptType && _ClRtlInterlockedIncrement(&_clrtlAssertBusy) > 0)
  240. {
  241. /* use only 'safe' functions -- must not assert in here! */
  242. static int (APIENTRY *pfnwsprintfA)(LPSTR, LPCSTR, ...) = NULL;
  243. if (NULL == pfnwsprintfA)
  244. {
  245. HINSTANCE hlib = LoadLibraryA("user32.dll");
  246. if (NULL == hlib || NULL == (pfnwsprintfA =
  247. (int (APIENTRY *)(LPSTR, LPCSTR, ...))
  248. GetProcAddress(hlib, "wsprintfA")))
  249. return -1;
  250. }
  251. (*pfnwsprintfA)( szOutMessage,
  252. "Second Chance Assertion Failed: File %s, Line %d\n",
  253. szFile, nLine);
  254. OutputDebugStringA(szOutMessage);
  255. _ClRtlInterlockedDecrement(&_clrtlAssertBusy);
  256. _ClRtlDbgBreak();
  257. return -1;
  258. }
  259. if (szFormat && _vsnprintf(szUserMessage,
  260. MAX_MSG-max(sizeof(ASSERTINTRO1),sizeof(ASSERTINTRO2)),
  261. szFormat,
  262. arglist) < 0)
  263. strcpy(szUserMessage, TOOLONGMSG);
  264. if (_CLRTLDBG_ASSERT == nRptType)
  265. strcpy(szLineMessage, szFormat ? ASSERTINTRO1 : ASSERTINTRO2);
  266. strcat(szLineMessage, szUserMessage);
  267. if (_CLRTLDBG_ASSERT == nRptType)
  268. {
  269. if (_ClRtlDbgMode[nRptType] & _CLRTLDBG_MODE_FILE)
  270. strcat(szLineMessage, "\r");
  271. strcat(szLineMessage, "\n");
  272. }
  273. if (szFile)
  274. {
  275. if (_snprintf(szOutMessage, MAX_MSG, "%s(%d) : %s",
  276. szFile, nLine, szLineMessage) < 0)
  277. strcpy(szOutMessage, TOOLONGMSG);
  278. }
  279. else
  280. strcpy(szOutMessage, szLineMessage);
  281. /* user hook may handle report */
  282. if (_pfnReportHook && (*_pfnReportHook)(nRptType, szOutMessage, &retval))
  283. {
  284. if (_CLRTLDBG_ASSERT == nRptType)
  285. _ClRtlInterlockedDecrement(&_clrtlAssertBusy);
  286. return retval;
  287. }
  288. if (_ClRtlDbgMode[nRptType] & _CLRTLDBG_MODE_FILE)
  289. {
  290. if (_ClRtlDbgFile[nRptType] != _CLRTLDBG_INVALID_HFILE)
  291. {
  292. DWORD written;
  293. WriteFile(_ClRtlDbgFile[nRptType], szOutMessage, strlen(szOutMessage), &written, NULL);
  294. }
  295. }
  296. if (_ClRtlDbgMode[nRptType] & _CLRTLDBG_MODE_DEBUG)
  297. {
  298. OutputDebugStringA(szOutMessage);
  299. }
  300. if (_ClRtlDbgMode[nRptType] & _CLRTLDBG_MODE_WNDW)
  301. {
  302. char szLine[20];
  303. retval = ClRtlMessageWindow(nRptType, szFile, nLine ? _itoa(nLine, szLine, 10) : NULL, szModule, szUserMessage);
  304. if (_CLRTLDBG_ASSERT == nRptType)
  305. _ClRtlInterlockedDecrement(&_clrtlAssertBusy);
  306. return retval;
  307. }
  308. if (_CLRTLDBG_ASSERT == nRptType)
  309. _ClRtlInterlockedDecrement(&_clrtlAssertBusy);
  310. /* ignore */
  311. return FALSE;
  312. } //*** _ClRtlDbgReport()
  313. /***
  314. *static int ClRtlMessageWindow() - report to a message window
  315. *
  316. *Purpose:
  317. * put report into message window, allow user to choose action to take
  318. *
  319. *Entry:
  320. * int nRptType - report type
  321. * const char * szFile - file name
  322. * const char * szLine - line number
  323. * const char * szModule - module name
  324. * const char * szUserMessage - user message
  325. *
  326. *Exit:
  327. * if (MessageBox)
  328. * {
  329. * Abort -> aborts
  330. * Retry -> return TRUE
  331. * Ignore-> return FALSE
  332. * }
  333. * else
  334. * return FALSE
  335. *
  336. *Exceptions:
  337. *
  338. *******************************************************************************/
  339. static int ClRtlMessageWindow(
  340. int nRptType,
  341. const char * szFile,
  342. const char * szLine,
  343. const char * szModule,
  344. const char * szUserMessage
  345. )
  346. {
  347. int nCode;
  348. char *szShortProgName;
  349. char *szShortModuleName;
  350. char szExeName[MAX_PATH];
  351. char szOutMessage[MAX_MSG];
  352. _CLRTL_ASSERTE(szUserMessage != NULL);
  353. /* Shorten program name */
  354. if (!GetModuleFileNameA(NULL, szExeName, MAX_PATH))
  355. strcpy(szExeName, "<program name unknown>");
  356. szShortProgName = szExeName;
  357. if (strlen(szShortProgName) > MAXLINELEN)
  358. {
  359. szShortProgName += strlen(szShortProgName) - MAXLINELEN;
  360. strncpy(szShortProgName, "...", 3);
  361. }
  362. /* Shorten module name */
  363. szShortModuleName = (char *) szModule;
  364. if (szShortModuleName && strlen(szShortModuleName) > MAXLINELEN)
  365. {
  366. szShortModuleName += strlen(szShortModuleName) - MAXLINELEN;
  367. strncpy(szShortModuleName, "...", 3);
  368. }
  369. if (_snprintf(szOutMessage, MAX_MSG,
  370. "Debug %s!\n\nProgram: %s%s%s%s%s%s%s%s%s%s%s"
  371. "\n\n(Press Retry to debug the application)",
  372. _ClRtlDbgModeMsg[nRptType],
  373. szShortProgName,
  374. szShortModuleName ? "\nModule: " : "",
  375. szShortModuleName ? szShortModuleName : "",
  376. szFile ? "\nFile: " : "",
  377. szFile ? szFile : "",
  378. szLine ? "\nLine: " : "",
  379. szLine ? szLine : "",
  380. szUserMessage[0] ? "\n\n" : "",
  381. szUserMessage[0] && _CLRTLDBG_ASSERT == nRptType ? "Expression: " : "",
  382. szUserMessage[0] ? szUserMessage : "",
  383. 0 /*_CLRTLDBG_ASSERT == nRptType*/ ? // Don't display this text, it's superfluous
  384. "\n\nFor information on how your program can cause an assertion"
  385. "\nfailure, see the Visual C++ documentation on asserts."
  386. : "") < 0)
  387. strcpy(szOutMessage, TOOLONGMSG);
  388. /* Report the warning/error */
  389. nCode = __clrtlMessageBoxA(
  390. szOutMessage,
  391. "Microsoft Visual C++ Debug Library",
  392. MB_TASKMODAL|MB_ICONHAND|MB_ABORTRETRYIGNORE|MB_SETFOREGROUND);
  393. /* Abort: abort the program */
  394. if (IDABORT == nCode)
  395. {
  396. /* raise abort signal */
  397. raise(SIGABRT);
  398. /* We usually won't get here, but it's possible that
  399. SIGABRT was ignored. So exit the program anyway. */
  400. _exit(3);
  401. }
  402. /* Retry: return 1 to call the debugger */
  403. if (IDRETRY == nCode)
  404. return 1;
  405. /* Ignore: continue execution */
  406. return 0;
  407. } //*** ClRtlMessageWindow()
  408. /***
  409. *__clrtlMessageBoxA - call MessageBoxA dynamically.
  410. *
  411. *Purpose:
  412. * Avoid static link with user32.dll. Only load it when actually needed.
  413. *
  414. *Entry:
  415. * see MessageBoxA docs.
  416. *
  417. *Exit:
  418. * see MessageBoxA docs.
  419. *
  420. *Exceptions:
  421. *
  422. *******************************************************************************/
  423. static int __clrtlMessageBoxA(
  424. LPCSTR lpText,
  425. LPCSTR lpCaption,
  426. UINT uType
  427. )
  428. {
  429. static int (APIENTRY *pfnMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT) = NULL;
  430. static HWND (APIENTRY *pfnGetActiveWindow)(void) = NULL;
  431. static HWND (APIENTRY *pfnGetLastActivePopup)(HWND) = NULL;
  432. HWND hWndParent = NULL;
  433. if (NULL == pfnMessageBoxA)
  434. {
  435. HINSTANCE hlib = LoadLibraryA("user32.dll");
  436. if (NULL == hlib || NULL == (pfnMessageBoxA =
  437. (int (APIENTRY *)(HWND, LPCSTR, LPCSTR, UINT))
  438. GetProcAddress(hlib, "MessageBoxA")))
  439. return 0;
  440. pfnGetActiveWindow = (HWND (APIENTRY *)(void))
  441. GetProcAddress(hlib, "GetActiveWindow");
  442. pfnGetLastActivePopup = (HWND (APIENTRY *)(HWND))
  443. GetProcAddress(hlib, "GetLastActivePopup");
  444. }
  445. if (pfnGetActiveWindow)
  446. hWndParent = (*pfnGetActiveWindow)();
  447. if (hWndParent != NULL && pfnGetLastActivePopup)
  448. hWndParent = (*pfnGetLastActivePopup)(hWndParent);
  449. return (*pfnMessageBoxA)(hWndParent, lpText, lpCaption, uType);
  450. } //*** __clrtlMessageBoxA()