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.

723 lines
19 KiB

  1. /*****************************************************************************
  2. *
  3. * Assert.c
  4. *
  5. * Copyright (c) 1996 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 "dinputpr.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_szPrefix[] = TEXT("DINPUT8: ");
  31. #pragma END_CONST_DATA
  32. void EXTERNAL
  33. WarnPszV(LPCSTR ptsz, ...)
  34. {
  35. va_list ap;
  36. CHAR sz[1024];
  37. lstrcpyA(sz, "DINPUT8: ");
  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 each %p with %x
  46. wvsprintfA(sz + cA(c_szPrefix) - 1, szDfs, ap); // use the local format string
  47. }
  48. #else
  49. {
  50. wvsprintfA(sz + cA(c_szPrefix) - 1, ptsz, ap);
  51. }
  52. #endif
  53. va_end(ap);
  54. lstrcatA(sz, "\r\n");
  55. OutputDebugStringA(sz);
  56. }
  57. #endif
  58. #ifdef DEBUG
  59. /*****************************************************************************
  60. *
  61. * Globals
  62. *
  63. *****************************************************************************/
  64. BYTE g_rgbSqfl[sqflMaxArea];
  65. extern TCHAR g_tszLogFile[];
  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("dinput"));
  89. g_rgbSqfl[sqfl] = (BYTE)
  90. GetProfileInt(TEXT("DEBUG"), tsz, HIWORD(0x0));
  91. for (sqfl = 0; sqfl < sqflMaxArea; sqfl++) {
  92. wsprintf(tsz, TEXT("dinput.%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 each %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(c_szPrefix);
  182. SquirtPtsz(tsz);
  183. }
  184. }
  185. /*****************************************************************************
  186. *
  187. * AssertPtszPtszLn
  188. *
  189. * Something bad happened.
  190. *
  191. *****************************************************************************/
  192. int EXTERNAL
  193. AssertPtszPtszLn(LPCTSTR ptszExpr, LPCTSTR ptszFile, int iLine)
  194. {
  195. SquirtSqflPtszV(sqflAlways, TEXT("Assertion failed: `%s' at %s(%d)"),
  196. ptszExpr, ptszFile, iLine);
  197. DebugBreak();
  198. return 0;
  199. }
  200. /*****************************************************************************
  201. *
  202. * Procedure call tracing is gross because the C preprocessor.
  203. *
  204. * Oh, if only we had support for m4...
  205. *
  206. *****************************************************************************/
  207. /*****************************************************************************
  208. *
  209. * dwSafeGetPdw
  210. *
  211. * Deference a dword, but don't barf if the dword is bad.
  212. *
  213. *****************************************************************************/
  214. DWORD INTERNAL
  215. dwSafeGetPdw(LPDWORD pdw)
  216. {
  217. if (IsBadReadPtr(pdw, cbX(*pdw))) {
  218. return 0xBAADBAAD;
  219. } else {
  220. return *pdw;
  221. }
  222. }
  223. /*****************************************************************************
  224. *
  225. * ArgsPszV
  226. *
  227. * Collect arguments to a procedure.
  228. *
  229. * psz -> ASCIIZ format string
  230. * ... = argument list
  231. *
  232. * The characters in the format string are listed in EmitPal.
  233. *
  234. *****************************************************************************/
  235. void EXTERNAL
  236. ArgsPalPszV(PARGLIST pal, LPCSTR psz, ...)
  237. {
  238. va_list ap;
  239. va_start(ap, psz);
  240. if (psz) {
  241. PPV ppv;
  242. int i;
  243. pal->pszFormat = psz;
  244. for (ppv = pal->rgpv, i = 0; i < cpvArgMax, *psz; i++, psz++) {
  245. *ppv++ = va_arg(ap, PV);
  246. }
  247. } else {
  248. pal->pszFormat = "";
  249. }
  250. }
  251. /*****************************************************************************
  252. *
  253. * EmitPal
  254. *
  255. * OutputDebugString the information, given a pal. No trailing
  256. * carriage return is emitted.
  257. *
  258. * pal -> place where info was saved
  259. *
  260. * Format characters:
  261. *
  262. * p - 32 or 64 bit flat pointer
  263. * x - 32-bit hex integer
  264. * s - TCHAR string
  265. * S - SCHAR string
  266. * A - ANSI string
  267. * W - UNICODE string
  268. * G - GUID
  269. * u - unsigned integer
  270. * C - clipboard format
  271. *
  272. *****************************************************************************/
  273. void INTERNAL
  274. EmitPal(PARGLIST pal)
  275. {
  276. char sz[MAX_PATH];
  277. int i;
  278. SquirtPtsz(c_szPrefix);
  279. SquirtPtszA(pal->pszProc);
  280. SquirtPtsz(TEXT("("));
  281. for (i = 0; pal->pszFormat[i]; i++) {
  282. if (i) {
  283. SquirtPtsz(TEXT(", "));
  284. }
  285. switch (pal->pszFormat[i]) {
  286. case 'p': /* flat pointer */
  287. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  288. #ifdef WIN95
  289. wsprintfA(sz, "%08x", pal->rgpv[i]);
  290. #else
  291. wsprintfA(sz, "%p", pal->rgpv[i]);
  292. #endif
  293. SquirtPtszA(sz);
  294. break;
  295. case 'x': /* 32-bit hex */
  296. wsprintfA(sz, "%08x", pal->rgpv[i]);
  297. SquirtPtszA(sz);
  298. break;
  299. case 's': /* TCHAR string */
  300. if (pal->rgpv[i] && lstrlen(pal->rgpv[i])) {
  301. SquirtPtsz(pal->rgpv[i]);
  302. }
  303. break;
  304. #ifdef UNICODE
  305. case 'S': /* SCHAR string */
  306. #endif
  307. case 'A': /* ANSI string */
  308. if (pal->rgpv[i] && lstrlenA(pal->rgpv[i])) {
  309. SquirtPtszA(pal->rgpv[i]);
  310. }
  311. break;
  312. #ifndef UNICODE
  313. case 'S': /* SCHAR string */
  314. #endif
  315. case 'W': /* UNICODE string */
  316. if (pal->rgpv[i] && lstrlenW(pal->rgpv[i])) {
  317. #ifdef UNICODE
  318. OutputDebugStringW(pal->rgpv[i]);
  319. #else
  320. UToA(sz, cA(sz), pal->rgpv[i]);
  321. SquirtPtszA(sz);
  322. #endif
  323. }
  324. break;
  325. case 'G': /* GUID */
  326. #if 1
  327. wsprintfA(sz, "%08x",
  328. HIWORD((DWORD)(UINT_PTR)pal->rgpv[i])
  329. ? dwSafeGetPdw((LPDWORD)pal->rgpv[i])
  330. : (UINT_PTR)pal->rgpv[i]);
  331. SquirtPtszA(sz);
  332. #else
  333. if( HIWORD((DWORD)(UINT_PTR)pal->rgpv[i])
  334. && !(IsBadReadPtr( pal->rgpv[i], cbX(pal->rgpv[i]) ) ) )
  335. {
  336. NameFromGUID( (PTCHAR)sz, pal->rgpv[i] );
  337. #ifdef UNICODE
  338. SquirtPtsz( &((PWCHAR)sz)[ctchNamePrefix]);
  339. #else
  340. SquirtPtszA( &sz[ctchNamePrefix] );
  341. #endif
  342. }
  343. else
  344. {
  345. wsprintfA(sz, "%08x",(UINT_PTR)pal->rgpv[i]);
  346. SquirtPtszA(sz);
  347. }
  348. #endif
  349. break;
  350. case 'u': /* 32-bit unsigned decimal */
  351. wsprintfA(sz, "%u", pal->rgpv[i]);
  352. SquirtPtszA(sz);
  353. break;
  354. case 'C':
  355. if (GetClipboardFormatNameA((UINT)(UINT_PTR)pal->rgpv[i], sz, cA(sz))) {
  356. } else {
  357. wsprintfA(sz, "[%04x]", pal->rgpv[i]);
  358. }
  359. SquirtPtszA(sz);
  360. break;
  361. default: AssertF(! TEXT("Invalid character format code")); /* Invalid */
  362. }
  363. }
  364. SquirtPtsz(TEXT(")"));
  365. }
  366. /*****************************************************************************
  367. *
  368. * EnterSqflPtsz
  369. *
  370. * Mark entry to a procedure. Arguments were already collected by
  371. * ArgsPszV.
  372. *
  373. * If sqfl contains the sqflBenign flag, then any error we detect
  374. * should be classified as sqflBenign and not sqflError.
  375. *
  376. * sqfl -> squirty flags
  377. * pszProc -> procedure name
  378. * pal -> place to save the name and get the format/args
  379. *
  380. *****************************************************************************/
  381. void EXTERNAL
  382. EnterSqflPszPal(SQFL sqfl, LPCSTR pszProc, PARGLIST pal)
  383. {
  384. pal->pszProc = pszProc;
  385. sqfl |= sqflIn;
  386. if (IsSqflSet(sqfl)) {
  387. EmitPal(pal);
  388. SquirtPtsz(TEXT("\r\n"));
  389. }
  390. }
  391. void EXTERNAL
  392. ExitSqflPalHresPpv(SQFL sqfl, PARGLIST pal, HRESULT hres, PPV ppvObj)
  393. {
  394. BOOL fInternalError;
  395. SQFL sqflIsError;
  396. DWORD le = GetLastError();
  397. if (sqfl & sqflBenign) {
  398. sqfl &= ~sqflBenign;
  399. sqflIsError = sqflBenign;
  400. } else {
  401. sqflIsError = sqflError;
  402. }
  403. sqfl |= sqflOut;
  404. fInternalError = 0;
  405. if (ppvObj == ppvVoid || ppvObj == ppvDword) {
  406. } else if (ppvObj == ppvBool) {
  407. if (hres == 0) {
  408. sqfl |= sqflIsError;
  409. }
  410. } else {
  411. if (FAILED(hres)) {
  412. if (fLimpFF(ppvObj && !IsBadWritePtr(ppvObj, cbX(*ppvObj)),
  413. *ppvObj == 0)) {
  414. } else {
  415. fInternalError = 1;
  416. }
  417. if (hres == E_NOTIMPL) { /* E_NOTIMPL is always benign */
  418. sqfl |= sqflBenign;
  419. } else {
  420. sqfl |= sqflIsError;
  421. }
  422. }
  423. }
  424. if (IsSqflSet(sqfl) || fInternalError) {
  425. EmitPal(pal);
  426. SquirtPtsz(TEXT(" -> "));
  427. if (ppvObj != ppvVoid) {
  428. TCHAR tszBuf[32];
  429. wsprintf(tszBuf, TEXT("%08x"), hres);
  430. SquirtPtsz(tszBuf);
  431. if (HIWORD((UINT_PTR)ppvObj)) {
  432. wsprintf(tszBuf, TEXT(" [%08x]"),
  433. dwSafeGetPdw((LPDWORD)ppvObj));
  434. SquirtPtsz(tszBuf);
  435. } else if (ppvObj == ppvDword) {
  436. wsprintf(tszBuf, TEXT(" [%08x]"), hres);
  437. SquirtPtsz(tszBuf);
  438. } else if (ppvObj == ppvBool) {
  439. wsprintf(tszBuf, hres ? TEXT(" OK ") :
  440. TEXT(" le=[%d]"), le);
  441. SquirtPtsz(tszBuf);
  442. }
  443. }
  444. SquirtPtsz(TEXT("\r\n"));
  445. AssertF(!fInternalError);
  446. }
  447. /*
  448. * This redundant test prevents a breakpoint on SetLastError()
  449. * from being hit constantly.
  450. */
  451. if (le != GetLastError()) {
  452. SetLastError(le);
  453. }
  454. }
  455. #endif
  456. #ifdef XDEBUG
  457. /*****************************************************************************
  458. *
  459. * @doc INTERNAL
  460. *
  461. * @func DWORD | Random |
  462. *
  463. * Returns a pseudorandom dword. The value doesn't need to be
  464. * statistically wonderful.
  465. *
  466. * @returns
  467. * A not very random dword.
  468. *
  469. *****************************************************************************/
  470. DWORD s_dwRandom = 1; /* Random number seed */
  471. DWORD INLINE
  472. Random(void)
  473. {
  474. s_dwRandom = s_dwRandom * 214013 + 2531011;
  475. return s_dwRandom;
  476. }
  477. /*****************************************************************************
  478. *
  479. * @doc INTERNAL
  480. *
  481. * @func void | ScrambleBuf |
  482. *
  483. * Fill a buffer with garbage. Used in RDEBUG to make sure
  484. * the caller is not relying on buffer data.
  485. *
  486. * Note: If the buffer is not a multiple of dwords in size,
  487. * the leftover bytes are not touched.
  488. *
  489. * @parm OUT LPVOID | pv |
  490. *
  491. * The buffer to be scrambled.
  492. *
  493. * @parm UINT | cb |
  494. *
  495. * The size of the buffer.
  496. *
  497. *****************************************************************************/
  498. void EXTERNAL
  499. ScrambleBuf(LPVOID pv, UINT cb)
  500. {
  501. UINT idw;
  502. UINT cdw = cb / 4;
  503. LPDWORD pdw = pv;
  504. for (idw = 0; idw < cdw; idw++) {
  505. pdw[idw] = Random();
  506. }
  507. }
  508. /*****************************************************************************
  509. *
  510. * @doc INTERNAL
  511. *
  512. * @func void | ScrambleBit |
  513. *
  514. * Randomly set or clear a bit.
  515. *
  516. * @parm OUT LPDWORD | pdw |
  517. *
  518. * The dword whose bit is to be set randomly.
  519. *
  520. * @parm UINT | flMask |
  521. *
  522. * Mask for the bits to scramble.
  523. *
  524. *****************************************************************************/
  525. void EXTERNAL ScrambleBit(LPDWORD pdw, DWORD flMask)
  526. {
  527. *pdw ^= (*pdw ^ Random()) & flMask;
  528. }
  529. /*****************************************************************************
  530. *
  531. * @doc INTERNAL
  532. *
  533. * @func BOOL | Callback_CompareContexts |
  534. *
  535. * Check if two <t CONTEXT> structures are substantially the same
  536. * to the extent required by the Win32 calling convention.
  537. *
  538. * This is necessary because lots of applications pass
  539. * incorrectly prototyped functions as callbacks. Others will
  540. * write callback functions that trash registers that are
  541. * supposed to be nonvolatile.
  542. *
  543. * NOTE! Platform-dependent code!
  544. *
  545. * @parm LPCONTEXT | pctx1 |
  546. *
  547. * Context structure before we call the callback.
  548. *
  549. * @parm LPCONTEXT | pctx2 |
  550. *
  551. * Context structure after we call the callback.
  552. *
  553. * @returns
  554. *
  555. * Nonzero if the two contexts are substantially the same.
  556. *
  557. *****************************************************************************/
  558. BOOL INLINE
  559. Callback_CompareContexts(LPCONTEXT pctx1, LPCONTEXT pctx2)
  560. {
  561. #if defined(_X86_)
  562. return pctx1->Esp == pctx2->Esp; /* Stack pointer */
  563. #if 0
  564. /*
  565. * Can't test these registers because Win95 doesn't preserve
  566. * them properly. GetThreadContext() stashes what happens to
  567. * be in the registers when you finally reach the bowels of
  568. * kernel, at which point who knows what they contain...
  569. */
  570. pctx1->Ebx == pctx2->Ebx && /* Nonvolatile registers */
  571. pctx1->Esi == pctx2->Esi &&
  572. pctx1->Edi == pctx2->Edi &&
  573. pctx1->Ebp == pctx2->Ebp;
  574. #endif
  575. #elif defined(_AMD64_)
  576. return pctx1->Rbx == pctx2->Rbx &&
  577. pctx1->Rbp == pctx2->Rbp &&
  578. pctx1->Rsp == pctx2->Rsp &&
  579. pctx1->Rdi == pctx2->Rdi &&
  580. pctx1->Rsi == pctx2->Rsi &&
  581. pctx1->R12 == pctx2->R12 &&
  582. pctx1->R13 == pctx2->R13 &&
  583. pctx1->R14 == pctx2->R14 &&
  584. pctx1->R15 == pctx2->R15;
  585. #elif defined(_IA64_)
  586. return pctx1->IntSp == pctx2->IntSp && /* Stack pointer */
  587. pctx1->RsBSP == pctx2->RsBSP && /* Backing store pointer */
  588. pctx1->IntS0 == pctx2->IntS0 && /* Nonvolatile registers */
  589. pctx1->IntS1 == pctx2->IntS1 &&
  590. pctx1->IntS2 == pctx2->IntS2 &&
  591. pctx1->IntS3 == pctx2->IntS3;
  592. #else
  593. #error "No Target Architecture"
  594. #endif
  595. }
  596. /*****************************************************************************
  597. *
  598. * @doc INTERNAL
  599. *
  600. * @func BOOL | Callback |
  601. *
  602. * Perform a callback the paranoid way, checking that the
  603. * application used the correct calling convention and preserved
  604. * all nonvolatile registers.
  605. *
  606. * NOTE! Platform-dependent code!
  607. *
  608. * @parm DICALLBACKPROC | pfn |
  609. *
  610. * Procedure to call back.
  611. *
  612. * @parm PV | pv1 |
  613. *
  614. * First parameter to callback.
  615. *
  616. * @parm PV | pv2 |
  617. *
  618. * Second parameter to callback.
  619. *
  620. * @returns
  621. *
  622. * Whatever the callback returns.
  623. *
  624. *****************************************************************************/
  625. BOOL EXTERNAL
  626. Callback(DICALLBACKPROC pfn, PV pv1, PV pv2)
  627. {
  628. CONTEXT ctxPre; /* Thread context before call */
  629. CONTEXT ctxPost; /* Thread context after call */
  630. volatile BOOL fRc; /* To prevent compiler from enregistering */
  631. /* Get state of registers before the callback */
  632. ctxPre.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
  633. GetThreadContext(GetCurrentThread(), &ctxPre);
  634. fRc = pfn(pv1, pv2);
  635. ctxPost.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
  636. if (GetThreadContext(GetCurrentThread(), &ctxPost) &&
  637. !Callback_CompareContexts(&ctxPre, &ctxPost)) {
  638. RPF("Incorrectly prototyped callback! Crash soon!");
  639. ValidationException();
  640. }
  641. return fRc;
  642. }
  643. #endif