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.

489 lines
12 KiB

  1. /*****************************************************************************
  2. *
  3. * Assert.c
  4. *
  5. * Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Assertions and squirties.
  10. *
  11. * Contents:
  12. *
  13. * SquirtSqflPtszV
  14. * AssertPtszPtszLn
  15. * ArgsPalPszV
  16. * EnterSqflPszPal
  17. * ExitSqflPalHresPpv
  18. *
  19. *****************************************************************************/
  20. #include "pidpr.h"
  21. #ifdef XDEBUG
  22. /*****************************************************************************
  23. *
  24. * WarnPszV
  25. *
  26. * Display a message, suitable for framing.
  27. *
  28. *****************************************************************************/
  29. #pragma BEGIN_CONST_DATA
  30. TCHAR c_tszPrefix[] = TEXT("PID: ");
  31. #pragma END_CONST_DATA
  32. void EXTERNAL
  33. WarnPtszV(LPCTSTR ptsz, ...)
  34. {
  35. va_list ap;
  36. TCHAR tsz[1024];
  37. lstrcpy(tsz, c_tszPrefix);
  38. va_start(ap, ptsz);
  39. #ifdef WIN95
  40. {
  41. char *psz = NULL;
  42. char szDfs[1024]={0};
  43. strcpy(szDfs,ptsz); // make a local copy of format string
  44. while (psz = strstr(szDfs,"%p")) // find each %p
  45. *(psz+1) = 'x'; // replace %p with %x
  46. wvsprintf(tsz + cA(c_tszPrefix) - 1, szDfs, ap); // use the local format string
  47. }
  48. #else
  49. {
  50. wvsprintf(tsz + cA(c_tszPrefix) - 1, ptsz, ap);
  51. }
  52. #endif
  53. va_end(ap);
  54. lstrcat(tsz, TEXT("\r\n"));
  55. OutputDebugString(tsz);
  56. }
  57. #endif
  58. #ifdef DEBUG
  59. /*****************************************************************************
  60. *
  61. * Globals
  62. *
  63. *****************************************************************************/
  64. BYTE g_rgbSqfl[sqflMaxArea];
  65. TCHAR g_tszLogFile[MAX_PATH];
  66. /*****************************************************************************
  67. *
  68. * Sqfl_Init
  69. *
  70. * Load our initial Sqfl settings from win.ini[debug].
  71. *
  72. * We take one sqfl for each area, of the form
  73. *
  74. * dinput.n=v
  75. *
  76. * where n = 0, ..., sqflMaxArea-1, and where v is one of the
  77. * hiword sqfl values.
  78. *
  79. * The default value for all areas is to squirt only errors.
  80. *
  81. *****************************************************************************/
  82. void EXTERNAL
  83. Sqfl_Init(void)
  84. {
  85. int sqfl;
  86. TCHAR tsz[20];
  87. sqfl = 0x0;
  88. wsprintf(tsz, TEXT("PID"));
  89. g_rgbSqfl[sqfl] = (BYTE)
  90. GetProfileInt(TEXT("DEBUG"), tsz, HIWORD(0x0));
  91. for (sqfl = 0; sqfl < sqflMaxArea; sqfl++) {
  92. wsprintf(tsz, TEXT("PID.%d"), sqfl);
  93. g_rgbSqfl[sqfl] = (BYTE)
  94. GetProfileInt(TEXT("DEBUG"), tsz, g_rgbSqfl[0]);
  95. }
  96. }
  97. /*****************************************************************************
  98. *
  99. * SquirtPtsz
  100. *
  101. * Squirt a message to the debugger and maybe a log file.
  102. *
  103. *****************************************************************************/
  104. void INTERNAL
  105. SquirtPtsz(LPCTSTR ptsz)
  106. {
  107. OutputDebugString(ptsz);
  108. if (g_tszLogFile[0]) {
  109. HANDLE h = CreateFile(g_tszLogFile, GENERIC_WRITE,
  110. FILE_SHARE_READ | FILE_SHARE_WRITE,
  111. 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  112. if (h != INVALID_HANDLE_VALUE) {
  113. #ifdef UNICODE
  114. CHAR szBuf[1024];
  115. #endif
  116. SetFilePointer(h, 0, 0, FILE_END);
  117. #ifdef UNICODE
  118. _lwrite((HFILE)(UINT_PTR)h, szBuf, UToA(szBuf, cA(szBuf), ptsz));
  119. #else
  120. _lwrite((HFILE)(UINT_PTR)h, ptsz, cbCtch(lstrlen(ptsz)));
  121. #endif
  122. CloseHandle(h);
  123. }
  124. }
  125. }
  126. /*****************************************************************************
  127. *
  128. * SquirtPtszA
  129. *
  130. * Squirt an ANSI message to the debugger and maybe a log file.
  131. *
  132. *****************************************************************************/
  133. #ifdef UNICODE
  134. void INTERNAL
  135. SquirtPtszA(LPCSTR psz)
  136. {
  137. OutputDebugStringA(psz);
  138. if (g_tszLogFile[0]) {
  139. HANDLE h = CreateFile(g_tszLogFile, GENERIC_WRITE,
  140. FILE_SHARE_READ | FILE_SHARE_WRITE,
  141. 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  142. if (h != INVALID_HANDLE_VALUE) {
  143. _lwrite((HFILE)(UINT_PTR)h, psz, cbCch(lstrlenA(psz)));
  144. CloseHandle(h);
  145. }
  146. }
  147. }
  148. #else
  149. #define SquirtPtszA SquirtPtsz
  150. #endif
  151. /*****************************************************************************
  152. *
  153. * SquirtSqflPtszV
  154. *
  155. * Squirt a message with a trailing crlf.
  156. *
  157. *****************************************************************************/
  158. void EXTERNAL
  159. SquirtSqflPtszV(SQFL sqfl, LPCTSTR ptsz, ...)
  160. {
  161. if (IsSqflSet(sqfl)) {
  162. va_list ap;
  163. TCHAR tsz[1024];
  164. va_start(ap, ptsz);
  165. #ifdef WIN95
  166. {
  167. char *psz = NULL;
  168. char szDfs[1024]={0};
  169. strcpy(szDfs,ptsz); // make a local copy of format string
  170. while (psz = strstr(szDfs,"%p")) // find each %p
  171. *(psz+1) = 'x'; // replace %p with %x
  172. wvsprintf(tsz, szDfs, ap); // use the local format string
  173. }
  174. #else
  175. {
  176. wvsprintf(tsz, ptsz, ap);
  177. }
  178. #endif
  179. va_end(ap);
  180. lstrcat(tsz, TEXT("\r\n"));
  181. SquirtPtsz(tsz);
  182. }
  183. }
  184. /*****************************************************************************
  185. *
  186. * AssertPtszPtszLn
  187. *
  188. * Something bad happened.
  189. *
  190. *****************************************************************************/
  191. int EXTERNAL
  192. AssertPtszPtszLn(LPCTSTR ptszExpr, LPCTSTR ptszFile, int iLine)
  193. {
  194. SquirtSqflPtszV(sqflAlways, TEXT("Assertion failed: `%s' at %s(%d)"),
  195. ptszExpr, ptszFile, iLine);
  196. DebugBreak();
  197. return 0;
  198. }
  199. /*****************************************************************************
  200. *
  201. * Procedure call tracing is gross because of the C preprocessor.
  202. *
  203. * Oh, if only we had support for m4...
  204. *
  205. *****************************************************************************/
  206. /*****************************************************************************
  207. *
  208. * dwSafeGetPdw
  209. *
  210. * Deference a dword, but don't barf if the dword is bad.
  211. *
  212. *****************************************************************************/
  213. DWORD INTERNAL
  214. dwSafeGetPdw(LPDWORD pdw)
  215. {
  216. if (IsBadReadPtr(pdw, cbX(*pdw))) {
  217. return 0xBAADBAAD;
  218. } else {
  219. return *pdw;
  220. }
  221. }
  222. /*****************************************************************************
  223. *
  224. * ArgsPszV
  225. *
  226. * Collect arguments to a procedure.
  227. *
  228. * psz -> ASCIIZ format string
  229. * ... = argument list
  230. *
  231. * The characters in the format string are listed in EmitPal.
  232. *
  233. *****************************************************************************/
  234. void EXTERNAL
  235. ArgsPalPszV(PARGLIST pal, LPCSTR psz, ...)
  236. {
  237. va_list ap;
  238. va_start(ap, psz);
  239. if (psz) {
  240. PPV ppv;
  241. pal->pszFormat = psz;
  242. for (ppv = pal->rgpv; *psz; psz++) {
  243. *ppv++ = va_arg(ap, PV);
  244. }
  245. } else {
  246. pal->pszFormat = "";
  247. }
  248. }
  249. /*****************************************************************************
  250. *
  251. * EmitPal
  252. *
  253. * OutputDebugString the information, given a pal. No trailing
  254. * carriage return is emitted.
  255. *
  256. * pal -> place where info was saved
  257. *
  258. * Format characters:
  259. *
  260. * p - 32-bit flat pointer
  261. * x - 32-bit hex integer
  262. * s - TCHAR string
  263. * S - SCHAR string
  264. * A - ANSI string
  265. * W - UNICODE string
  266. * G - GUID
  267. * u - unsigned integer
  268. * C - clipboard format
  269. *
  270. *****************************************************************************/
  271. void INTERNAL
  272. EmitPal(PARGLIST pal)
  273. {
  274. char sz[MAX_PATH];
  275. int i;
  276. SquirtPtsz(pal->ptszProc);
  277. SquirtPtsz(TEXT("("));
  278. for (i = 0; pal->pszFormat[i]; i++) {
  279. if (i) {
  280. SquirtPtsz(TEXT(", "));
  281. }
  282. switch (pal->pszFormat[i]) {
  283. case 'p': /* flat pointer */
  284. // 7/18/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  285. #ifdef WIN95
  286. wsprintfA(sz, "%x", pal->rgpv[i]);
  287. #else
  288. wsprintfA(sz, "%p", pal->rgpv[i]);
  289. #endif
  290. SquirtPtszA(sz);
  291. break;
  292. case 'x': /* hex */
  293. wsprintfA(sz, "%x", pal->rgpv[i]);
  294. SquirtPtszA(sz);
  295. break;
  296. case 's': /* TCHAR string */
  297. if (pal->rgpv[i] && lstrlen(pal->rgpv[i])) {
  298. SquirtPtsz(pal->rgpv[i]);
  299. }
  300. break;
  301. #ifdef UNICODE
  302. case 'S': /* SCHAR string */
  303. #endif
  304. case 'A': /* ANSI string */
  305. if (pal->rgpv[i] && lstrlenA(pal->rgpv[i])) {
  306. SquirtPtszA(pal->rgpv[i]);
  307. }
  308. break;
  309. #ifndef UNICODE
  310. case 'S': /* SCHAR string */
  311. #endif
  312. case 'W': /* UNICODE string */
  313. if (pal->rgpv[i] && lstrlenW(pal->rgpv[i])) {
  314. #ifdef UNICODE
  315. OutputDebugStringW(pal->rgpv[i]);
  316. #else
  317. UToA(sz, cA(sz), pal->rgpv[i]);
  318. SquirtPtszA(sz);
  319. #endif
  320. }
  321. break;
  322. case 'G': /* GUID */
  323. wsprintfA(sz, "%08x",
  324. HIWORD((DWORD)(UINT_PTR)pal->rgpv[i])
  325. ? dwSafeGetPdw((LPDWORD)pal->rgpv[i])
  326. : (UINT_PTR)pal->rgpv[i]);
  327. SquirtPtszA(sz);
  328. break;
  329. case 'u': /* 32-bit unsigned decimal */
  330. wsprintfA(sz, "%u", pal->rgpv[i]);
  331. SquirtPtszA(sz);
  332. break;
  333. case 'C':
  334. if (GetClipboardFormatNameA((UINT)(UINT_PTR)pal->rgpv[i], sz, cA(sz))) {
  335. } else {
  336. wsprintfA(sz, "[%04x]", pal->rgpv[i]);
  337. }
  338. SquirtPtszA(sz);
  339. break;
  340. default: AssertF(0); /* Invalid */
  341. }
  342. }
  343. SquirtPtsz(TEXT(")"));
  344. }
  345. /*****************************************************************************
  346. *
  347. * EnterSqflPtsz
  348. *
  349. * Mark entry to a procedure. Arguments were already collected by
  350. * ArgsPszV.
  351. *
  352. * If sqfl contains the sqflBenign flag, then any error we detect
  353. * should be classified as sqflBenign and not sqflError.
  354. *
  355. * sqfl -> squirty flags
  356. * ptszProc -> procedure name
  357. * pal -> place to save the name and get the format/args
  358. *
  359. *****************************************************************************/
  360. void EXTERNAL
  361. EnterSqflPszPal(SQFL sqfl, LPCTSTR ptszProc, PARGLIST pal)
  362. {
  363. pal->ptszProc = ptszProc;
  364. sqfl |= sqflIn;
  365. if (IsSqflSet(sqfl)) {
  366. EmitPal(pal);
  367. SquirtPtsz(TEXT("\r\n"));
  368. }
  369. }
  370. void EXTERNAL
  371. ExitSqflPalHresPpv(SQFL sqfl, PARGLIST pal, HRESULT hres, PPV ppvObj)
  372. {
  373. BOOL fInternalError;
  374. SQFL sqflIsError;
  375. DWORD le = GetLastError();
  376. if (sqfl & sqflBenign) {
  377. sqfl &= ~sqflBenign;
  378. sqflIsError = sqflBenign;
  379. } else {
  380. sqflIsError = sqflError;
  381. }
  382. sqfl |= sqflOut;
  383. fInternalError = 0;
  384. if (ppvObj == ppvVoid || ppvObj == ppvDword) {
  385. } else if (ppvObj == ppvBool) {
  386. if (hres == 0) {
  387. sqfl |= sqflIsError;
  388. }
  389. } else {
  390. if (FAILED(hres)) {
  391. if (fLimpFF(ppvObj && !IsBadWritePtr(ppvObj, cbX(*ppvObj)),
  392. *ppvObj == 0)) {
  393. } else {
  394. fInternalError = 1;
  395. }
  396. if (hres == E_NOTIMPL) { /* E_NOTIMPL is always benign */
  397. sqfl |= sqflBenign;
  398. } else {
  399. sqfl |= sqflIsError;
  400. }
  401. }
  402. }
  403. if (IsSqflSet(sqfl) || fInternalError) {
  404. EmitPal(pal);
  405. SquirtPtsz(TEXT(" -> "));
  406. if (ppvObj != ppvVoid) {
  407. TCHAR tszBuf[32];
  408. wsprintf(tszBuf, TEXT("%08x"), hres);
  409. SquirtPtsz(tszBuf);
  410. if (HIWORD((UINT_PTR)ppvObj)) {
  411. wsprintf(tszBuf, TEXT(" [%08x]"),
  412. dwSafeGetPdw((LPDWORD)ppvObj));
  413. SquirtPtsz(tszBuf);
  414. } else if (ppvObj == ppvDword) {
  415. wsprintf(tszBuf, TEXT(" [%08x]"), hres);
  416. SquirtPtsz(tszBuf);
  417. } else if (ppvObj == ppvBool) {
  418. wsprintf(tszBuf, hres ? TEXT(" OK ") :
  419. TEXT(" le=[%d]"), le);
  420. SquirtPtsz(tszBuf);
  421. }
  422. }
  423. SquirtPtsz(TEXT("\r\n"));
  424. AssertF(!fInternalError);
  425. }
  426. /*
  427. * This redundant test prevents a breakpoint on SetLastError()
  428. * from being hit constantly.
  429. */
  430. if (le != GetLastError()) {
  431. SetLastError(le);
  432. }
  433. }
  434. #endif