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.

721 lines
19 KiB

  1. /*****************************************************************************
  2. *
  3. * CAssert.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Assertions and debug output routines
  10. * Based on Raymond's assertion code as it looks quite useful
  11. *
  12. *
  13. * Contents:
  14. *
  15. * DebugOutPtszV
  16. * AssertPtszPtszLn
  17. * ArgsPalPszV
  18. * EnterDbgflPszPal
  19. * ExitDbgflPalHresPpv
  20. *
  21. *****************************************************************************/
  22. /*
  23. #include <windows.h>
  24. #include <windowsx.h>
  25. #include <objbase.h>
  26. #include <regstr.h>
  27. #include <setupapi.h>
  28. #include <cfgmgr32.h>
  29. #include <devguid.h>
  30. #include <stdio.h>
  31. #include <stilog.h>
  32. #include <stiregi.h>
  33. #include <sti.h>
  34. #include <stierr.h>
  35. #include <stiusd.h>
  36. #include "wia.h"
  37. #include "stipriv.h"
  38. #include "stiapi.h"
  39. #include "stirc.h"
  40. #include "debug.h"
  41. */
  42. #include "sticomm.h"
  43. #ifdef MAXDEBUG
  44. /*****************************************************************************
  45. *
  46. * WarnPszV
  47. *
  48. * Display a message, suitable for framing.
  49. *
  50. *****************************************************************************/
  51. #pragma BEGIN_CONST_DATA
  52. CHAR c_szPrefix[] = "STI: ";
  53. #pragma END_CONST_DATA
  54. void EXTERNAL
  55. WarnPszV(LPCSTR psz, ...)
  56. {
  57. va_list ap;
  58. CHAR sz[1024];
  59. lstrcpyA(sz, c_szPrefix);
  60. va_start(ap, psz);
  61. wvsprintfA(sz + cA(c_szPrefix) - 1, psz, ap);
  62. va_end(ap);
  63. lstrcatA(sz, "\r\n");
  64. OutputDebugStringA(sz);
  65. }
  66. #endif
  67. #ifdef DEBUG
  68. /*****************************************************************************
  69. *
  70. * Globals
  71. *
  72. *****************************************************************************/
  73. DBGFL DbgflCur;
  74. TCHAR g_tszLogFile[MAX_PATH] = {'\0'};
  75. /*****************************************************************************
  76. *
  77. * Set current trace parameters
  78. *
  79. * This routine is not thread safe
  80. *
  81. *****************************************************************************/
  82. VOID InitializeDebuggingSupport(VOID)
  83. {
  84. HKEY hStiSettingsKey;
  85. DWORD dwErr;
  86. DWORD dwType;
  87. CHAR szLogFile[MAX_PATH];
  88. UINT cbBuffer ;
  89. DBGFL dwFlags = 0;
  90. dwErr = OSUtil_RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  91. REGSTR_PATH_STICONTROL_W,
  92. 0L,KEY_READ,
  93. &hStiSettingsKey
  94. );
  95. if (NOERROR != dwErr) {
  96. return;
  97. }
  98. cbBuffer = MAX_PATH;
  99. ZeroX(szLogFile);
  100. dwErr = RegQueryValueExA( hStiSettingsKey,
  101. REGSTR_VAL_DEBUG_FILE_A,
  102. NULL,
  103. &dwType,
  104. (LPBYTE)szLogFile,
  105. &cbBuffer );
  106. if( ( dwErr == NO_ERROR ) || ( dwErr == ERROR_MORE_DATA ) ) {
  107. if( ( dwType != REG_SZ ) &&
  108. ( dwType != REG_MULTI_SZ ) &&
  109. ( dwType != REG_EXPAND_SZ ) ) {
  110. dwErr = ERROR_FILE_NOT_FOUND;
  111. }
  112. else {
  113. SetDebugLogFileA(szLogFile);
  114. }
  115. }
  116. dwFlags = ReadRegistryDwordW(hStiSettingsKey,
  117. REGSTR_VAL_DEBUG_FLAGS_W,
  118. 0L);
  119. SetCurrentDebugFlags(dwFlags ) ;
  120. RegCloseKey(hStiSettingsKey);
  121. return ;
  122. }
  123. DBGFL SetCurrentDebugFlags(DBGFL NewFlags) {
  124. DBGFL OldFlags = DbgflCur;
  125. DbgflCur = NewFlags;
  126. return OldFlags;
  127. }
  128. VOID SetDebugLogFileA(CHAR *pszLogFileName)
  129. {
  130. if (!pszLogFileName || !*pszLogFileName) {
  131. *g_tszLogFile = '\0';
  132. return;
  133. }
  134. lstrcpyA((CHAR*)g_tszLogFile,pszLogFileName);
  135. return;
  136. }
  137. /*****************************************************************************
  138. *
  139. * DebugOutPtsz
  140. *
  141. * Writes a message to the debugger and maybe a log file.
  142. *
  143. *****************************************************************************/
  144. void INTERNAL
  145. DebugOutPtsz(LPCTSTR ptsz)
  146. {
  147. DWORD cbWritten;
  148. OutputDebugString(ptsz);
  149. if (g_tszLogFile[0]) {
  150. HANDLE h = CreateFile(g_tszLogFile, GENERIC_WRITE,
  151. FILE_SHARE_READ | FILE_SHARE_WRITE,
  152. 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  153. if (h != INVALID_HANDLE_VALUE) {
  154. #ifdef UNICODE
  155. CHAR szBuf[1024];
  156. #endif
  157. SetFilePointer(h, 0, 0, FILE_END);
  158. #ifdef UNICODE
  159. WriteFile(h, szBuf, UToA(szBuf, cA(szBuf), ptsz),&cbWritten,NULL);
  160. #else
  161. WriteFile(h, ptsz, cbCtch(lstrlen(ptsz)),&cbWritten,NULL);
  162. #endif
  163. CloseHandle(h);
  164. }
  165. }
  166. }
  167. /*****************************************************************************
  168. *
  169. * DebugOutPtszA
  170. *
  171. * DebugOut an ANSI message to the debugger and maybe a log file.
  172. *
  173. *****************************************************************************/
  174. #ifdef UNICODE
  175. void INTERNAL
  176. DebugOutPtszA(LPCSTR psz)
  177. {
  178. OutputDebugStringA(psz);
  179. if (g_tszLogFile[0]) {
  180. HANDLE h = CreateFile(g_tszLogFile, GENERIC_WRITE,
  181. FILE_SHARE_READ | FILE_SHARE_WRITE,
  182. 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  183. if (h != INVALID_HANDLE_VALUE) {
  184. _lwrite((HFILE)(LONG_PTR)h, psz, cbCch(lstrlenA(psz)));
  185. CloseHandle(h);
  186. }
  187. }
  188. }
  189. #else
  190. #define DebugOutPtszA DebugOutPtsz
  191. #endif
  192. /*****************************************************************************
  193. *
  194. * DebugOutPtszV
  195. *
  196. * DebugOut a message with a trailing crlf.
  197. *
  198. *****************************************************************************/
  199. void EXTERNAL
  200. DebugOutPtszV(DBGFL Dbgfl, LPCTSTR ptsz, ...)
  201. {
  202. if (Dbgfl == 0 || (Dbgfl & DbgflCur)) {
  203. va_list ap;
  204. TCHAR tsz[1024];
  205. va_start(ap, ptsz);
  206. wvsprintf(tsz, ptsz, ap);
  207. va_end(ap);
  208. lstrcat(tsz, TEXT("\r\n"));
  209. DebugOutPtsz(tsz);
  210. }
  211. }
  212. /*****************************************************************************
  213. *
  214. * AssertPtszPtszLn
  215. *
  216. * Something bad happened.
  217. *
  218. *****************************************************************************/
  219. int EXTERNAL
  220. AssertPtszPtszLn(LPCTSTR ptszExpr, LPCTSTR ptszFile, int iLine)
  221. {
  222. DebugOutPtszV(DbgFlAlways, TEXT("Assertion failed: `%s' at %s(%d)"),
  223. ptszExpr, ptszFile, iLine);
  224. DebugBreak();
  225. return 0;
  226. }
  227. /*****************************************************************************
  228. *
  229. * Procedure call tracing is gross because of the C preprocessor.
  230. *
  231. * Oh, if only we had support for m4...
  232. *
  233. *****************************************************************************/
  234. /*****************************************************************************
  235. *
  236. * ArgsPszV
  237. *
  238. * Collect arguments to a procedure.
  239. *
  240. * psz -> ASCIIZ format string
  241. * ... = argument list
  242. *
  243. * The characters in the format string are listed in EmitPal.
  244. *
  245. *****************************************************************************/
  246. void EXTERNAL
  247. ArgsPalPszV(PARGLIST pal, LPCSTR psz, ...)
  248. {
  249. va_list ap;
  250. va_start(ap, psz);
  251. if (psz) {
  252. PPV ppv;
  253. pal->pszFormat = psz;
  254. for (ppv = pal->rgpv; *psz; psz++) {
  255. *ppv++ = va_arg(ap, PV);
  256. }
  257. } else {
  258. pal->pszFormat = "";
  259. }
  260. }
  261. /*****************************************************************************
  262. *
  263. * EmitPal
  264. *
  265. * OutputDebugString the information, given a pal. No trailing
  266. * carriage return is emitted.
  267. *
  268. * pal -> place where info was saved
  269. *
  270. * Format characters:
  271. *
  272. * p - 32-bit flat pointer
  273. * x - 32-bit hex integer
  274. * s - TCHAR string
  275. * A - ANSI string
  276. * W - UNICODE string
  277. * G - GUID
  278. * u - unsigned integer
  279. * C - clipboard format
  280. *
  281. *****************************************************************************/
  282. void INTERNAL
  283. EmitPal(PARGLIST pal)
  284. {
  285. char sz[MAX_PATH];
  286. int i;
  287. DebugOutPtszA(pal->pszProc);
  288. DebugOutPtsz(TEXT("("));
  289. for (i = 0; pal->pszFormat[i]; i++) {
  290. if (i) {
  291. DebugOutPtsz(TEXT(", "));
  292. }
  293. switch (pal->pszFormat[i]) {
  294. case 'p': /* 32-bit flat pointer */
  295. case 'x': /* 32-bit hex */
  296. wsprintfA(sz, "%08x", pal->rgpv[i]);
  297. DebugOutPtszA(sz);
  298. break;
  299. case 's': /* TCHAR string */
  300. if (pal->rgpv[i]) {
  301. DebugOutPtsz(pal->rgpv[i]);
  302. }
  303. break;
  304. case 'A': /* ANSI string */
  305. if (pal->rgpv[i]) {
  306. DebugOutPtszA(pal->rgpv[i]);
  307. }
  308. break;
  309. case 'W': /* UNICODE string */
  310. #ifdef UNICODE
  311. OutputDebugStringW(pal->rgpv[i]);
  312. #else
  313. WideCharToMultiByte(CP_ACP, 0, pal->rgpv[i], -1, sz, cA(sz), 0, 0);
  314. DebugOutPtszA(sz);
  315. #endif
  316. break;
  317. #ifndef _WIN64
  318. //
  319. // Ignore this option on SunDown
  320. //
  321. case 'G': /* GUID */
  322. wsprintfA(sz, "%08x",
  323. HIWORD(pal->rgpv[i]) ? *(LPDWORD)pal->rgpv[i]
  324. : (DWORD)pal->rgpv[i]);
  325. DebugOutPtszA(sz);
  326. break;
  327. case 'C':
  328. if (GetClipboardFormatNameA((UINT)pal->rgpv[i], sz, cA(sz))) {
  329. } else {
  330. wsprintfA(sz, "[%04x]", pal->rgpv[i]);
  331. }
  332. DebugOutPtszA(sz);
  333. break;
  334. #endif
  335. case 'u': /* 32-bit unsigned decimal */
  336. wsprintfA(sz, "%u", pal->rgpv[i]);
  337. DebugOutPtszA(sz);
  338. break;
  339. default: AssertF(0); /* Invalid */
  340. }
  341. }
  342. DebugOutPtsz(TEXT(")"));
  343. }
  344. /*****************************************************************************
  345. *
  346. * EnterDbgflPtsz
  347. *
  348. * Mark entry to a procedure. Arguments were already collected by
  349. * ArgsPszV.
  350. *
  351. * Dbgfl -> DebugOuty flags
  352. * pszProc -> procedure name
  353. * pal -> place to save the name and get the format/args
  354. *
  355. *****************************************************************************/
  356. void EXTERNAL
  357. EnterDbgflPszPal(DBGFL Dbgfl, LPCSTR pszProc, PARGLIST pal)
  358. {
  359. pal->pszProc = pszProc;
  360. if (Dbgfl == 0 || (Dbgfl & DbgflCur)) {
  361. EmitPal(pal);
  362. DebugOutPtsz(TEXT("\r\n"));
  363. }
  364. }
  365. /*****************************************************************************
  366. *
  367. * ExitDbgflPalHresPpv
  368. *
  369. * Mark exit from a procedure.
  370. *
  371. * pal -> argument list
  372. * hres -> exit result
  373. * ppv -> optional OUT pointer;
  374. * ppvDword means that hres is a dword
  375. * ppvBool means that hres is a boolean
  376. * ppvVoid means that hres is nothing at all
  377. *
  378. *****************************************************************************/
  379. void EXTERNAL
  380. ExitDbgflPalHresPpv(DBGFL Dbgfl, PARGLIST pal, HRESULT hres, PPV ppvObj)
  381. {
  382. BOOL fInternalError;
  383. DWORD le = GetLastError();
  384. fInternalError = 0;
  385. if (ppvObj == ppvVoid) {
  386. } else if (ppvObj == ppvBool) {
  387. if (hres == 0) {
  388. Dbgfl |= DbgFlError;
  389. }
  390. } else {
  391. if (FAILED(hres)) {
  392. if (fLimpFF(ppvObj && !IsBadWritePtr(ppvObj, cbX(*ppvObj)),
  393. *ppvObj == 0)) {
  394. } else {
  395. fInternalError = 1;
  396. }
  397. Dbgfl |= DbgFlError;
  398. }
  399. }
  400. if (Dbgfl == 0 || (Dbgfl & DbgflCur) || fInternalError) {
  401. EmitPal(pal);
  402. DebugOutPtsz(TEXT(" -> "));
  403. if (ppvObj != ppvVoid) {
  404. TCHAR tszBuf[32];
  405. wsprintf(tszBuf, TEXT("%08x"), hres);
  406. DebugOutPtsz(tszBuf);
  407. if (HIWORD(PtrToLong(ppvObj))) {
  408. wsprintf(tszBuf, TEXT(" [%08x]"), *ppvObj);
  409. DebugOutPtsz(tszBuf);
  410. } else if (ppvObj == ppvDword) {
  411. wsprintf(tszBuf, TEXT(" [%08x]"), hres);
  412. DebugOutPtsz(tszBuf);
  413. } else if (ppvObj == ppvBool) {
  414. wsprintf(tszBuf, hres ? TEXT(" OK ") :
  415. TEXT(" le=[%d]"), le);
  416. DebugOutPtsz(tszBuf);
  417. }
  418. }
  419. DebugOutPtsz(TEXT("\r\n"));
  420. AssertF(!fInternalError);
  421. }
  422. /*
  423. * This redundant test prevents a breakpoint on SetLastError()
  424. * from being hit constantly.
  425. */
  426. if (le != GetLastError()) {
  427. SetLastError(le);
  428. }
  429. }
  430. #endif
  431. #ifdef MAXDEBUG
  432. /*****************************************************************************
  433. *
  434. * @doc INTERNAL
  435. *
  436. * @func DWORD | Random |
  437. *
  438. * Returns a pseudorandom dword. The value doesn't need to be
  439. * statistically wonderful.
  440. *
  441. * @returns
  442. * A not very random dword.
  443. *
  444. *****************************************************************************/
  445. DWORD s_dwRandom = 1; /* Random number seed */
  446. DWORD INLINE
  447. Random(void)
  448. {
  449. s_dwRandom = s_dwRandom * 214013 + 2531011;
  450. return s_dwRandom;
  451. }
  452. /*****************************************************************************
  453. *
  454. * @doc INTERNAL
  455. *
  456. * @func void | ScrambleBuf |
  457. *
  458. * Fill a buffer with garbage. Used in RDEBUG to make sure
  459. * the caller is not relying on buffer data.
  460. *
  461. * Note: If the buffer is not a multiple of dwords in size,
  462. * the leftover bytes are not touched.
  463. *
  464. * @parm OUT LPVOID | pv |
  465. *
  466. * The buffer to be scrambled.
  467. *
  468. * @parm UINT | cb |
  469. *
  470. * The size of the buffer.
  471. *
  472. *****************************************************************************/
  473. void EXTERNAL
  474. ScrambleBuf(LPVOID pv, UINT cb)
  475. {
  476. UINT idw;
  477. UINT cdw = cb / 4;
  478. LPDWORD pdw = pv;
  479. for (idw = 0; idw < cdw; idw++) {
  480. pdw[idw] = Random();
  481. }
  482. }
  483. /*****************************************************************************
  484. *
  485. * @doc INTERNAL
  486. *
  487. * @func void | ScrambleBit |
  488. *
  489. * Randomly set or clear a bit.
  490. *
  491. * @parm OUT LPDWORD | pdw |
  492. *
  493. * The dword whose bit is to be set randomly.
  494. *
  495. * @parm UINT | flMask |
  496. *
  497. * Mask for the bits to scramble.
  498. *
  499. *****************************************************************************/
  500. void EXTERNAL ScrambleBit(LPDWORD pdw, DWORD flMask)
  501. {
  502. *pdw ^= (*pdw ^ Random()) & flMask;
  503. }
  504. /*****************************************************************************
  505. *
  506. * @doc INTERNAL
  507. *
  508. * @func BOOL | Callback_CompareContexts |
  509. *
  510. * Check if two <t CONTEXT> structures are substantially the same
  511. * to the extent required by the Win32 calling convention.
  512. *
  513. * This is necessary because lots of applications pass
  514. * incorrectly prototyped functions as callbacks. Others will
  515. * write callback functions that trash registers that are
  516. * supposed to be nonvolatile. Yuck!
  517. *
  518. * NOTE! Platform-dependent code!
  519. *
  520. * @parm LPCONTEXT | pctx1 |
  521. *
  522. * Context structure before we call the callback.
  523. *
  524. * @parm LPCONTEXT | pctx2 |
  525. *
  526. * Context structure after we call the callback.
  527. *
  528. * @returns
  529. *
  530. * Nonzero if the two contexts are substantially the same.
  531. *
  532. *****************************************************************************/
  533. BOOL INLINE
  534. Callback_CompareContexts(LPCONTEXT pctx1, LPCONTEXT pctx2)
  535. {
  536. #if defined(_X86_)
  537. return pctx1->Esp == pctx2->Esp; /* Stack pointer */
  538. #if 0
  539. /*
  540. * Can't test these registers because Win95 doesn't preserve
  541. * them properly. GetThreadContext() stashes what happens to
  542. * be in the registers when you finally reach the bowels of
  543. * kernel, at which point who knows what they contain...
  544. */
  545. pctx1->Ebx == pctx2->Ebx && /* Nonvolatile registers */
  546. pctx1->Esi == pctx2->Esi &&
  547. pctx1->Edi == pctx2->Edi &&
  548. pctx1->Ebp == pctx2->Ebp;
  549. #endif
  550. #elif defined(_ALPHA_)
  551. return pctx1->IntSp == pctx2->IntSp && /* Stack pointer */
  552. pctx1->IntS0 == pctx2->IntS0 && /* Nonvolatile registers */
  553. pctx1->IntS1 == pctx2->IntS1 &&
  554. pctx1->IntS2 == pctx2->IntS2 &&
  555. pctx1->IntS3 == pctx2->IntS3 &&
  556. pctx1->IntS4 == pctx2->IntS4 &&
  557. pctx1->IntS5 == pctx2->IntS5 &&
  558. pctx1->IntFp == pctx2->IntFp;
  559. #elif defined(_MIPS_)
  560. #pragma message("I hope this is correct for MIPS")
  561. return pctx1->IntSp == pctx2->IntSp && /* Stack pointer */
  562. pctx1->IntS0 == pctx2->IntS0 && /* Nonvolatile registers */
  563. pctx1->IntS1 == pctx2->IntS1 &&
  564. pctx1->IntS2 == pctx2->IntS2 &&
  565. pctx1->IntS3 == pctx2->IntS3 &&
  566. pctx1->IntS4 == pctx2->IntS4 &&
  567. pctx1->IntS6 == pctx2->IntS6 &&
  568. pctx1->IntS7 == pctx2->IntS7 &&
  569. pctx1->IntS8 == pctx2->IntS8;
  570. #elif defined(_PPC_)
  571. #pragma message("I don't know what the PPC calling conventions are")
  572. /* Just check the stack register */
  573. return pctx1->Gpr1 == pctx2->Gpr1;
  574. #else
  575. #pragma message("I don't know what the calling conventions are for this platform")
  576. return 1;
  577. #endif
  578. }
  579. /*****************************************************************************
  580. *
  581. * @doc INTERNAL
  582. *
  583. * @func BOOL | Callback |
  584. *
  585. * Perform a callback the paranoid way, checking that the
  586. * application used the correct calling convention and preserved
  587. * all nonvolatile registers.
  588. *
  589. * NOTE! Platform-dependent code!
  590. *
  591. * @parm STICALLBACKPROC | pfn |
  592. *
  593. * Procedure to call back.
  594. *
  595. * @parm PV | pv1 |
  596. *
  597. * First parameter to callback.
  598. *
  599. * @parm PV | pv2 |
  600. *
  601. * Second parameter to callback.
  602. *
  603. * @returns
  604. *
  605. * Whatever the callback returns.
  606. *
  607. *****************************************************************************/
  608. BOOL EXTERNAL
  609. Callback(STICALLBACKPROC pfn, PV pv1, PV pv2)
  610. {
  611. CONTEXT ctxPre; /* Thread context before call */
  612. CONTEXT ctxPost; /* Thread context after call */
  613. volatile BOOL fRc; /* To prevent compiler from enregistering */
  614. /* Get state of registers before the callback */
  615. ctxPre.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
  616. GetThreadContext(GetCurrentThread(), &ctxPre);
  617. fRc = pfn(pv1, pv2);
  618. ctxPost.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
  619. if (GetThreadContext(GetCurrentThread(), &ctxPost) &&
  620. !Callback_CompareContexts(&ctxPre, &ctxPost)) {
  621. RPF("STI: Incorrectly prototyped callback! Crash soon!");
  622. ValidationException();
  623. }
  624. return fRc;
  625. }
  626. #endif