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.

723 lines
20 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] = {0};
  205. TCHAR *tszSuffix = TEXT("\r\n");
  206. DWORD dwLen = sizeof(tsz)/sizeof(tsz[0]) - lstrlen(tszSuffix) - 1;
  207. va_start(ap, ptsz);
  208. _vsnwprintf(tsz, dwLen, ptsz, ap);
  209. va_end(ap);
  210. lstrcat(tsz, tszSuffix);
  211. DebugOutPtsz(tsz);
  212. }
  213. }
  214. /*****************************************************************************
  215. *
  216. * AssertPtszPtszLn
  217. *
  218. * Something bad happened.
  219. *
  220. *****************************************************************************/
  221. int EXTERNAL
  222. AssertPtszPtszLn(LPCTSTR ptszExpr, LPCTSTR ptszFile, int iLine)
  223. {
  224. DebugOutPtszV(DbgFlAlways, TEXT("Assertion failed: `%s' at %s(%d)"),
  225. ptszExpr, ptszFile, iLine);
  226. DebugBreak();
  227. return 0;
  228. }
  229. /*****************************************************************************
  230. *
  231. * Procedure call tracing is gross because of the C preprocessor.
  232. *
  233. * Oh, if only we had support for m4...
  234. *
  235. *****************************************************************************/
  236. /*****************************************************************************
  237. *
  238. * ArgsPszV
  239. *
  240. * Collect arguments to a procedure.
  241. *
  242. * psz -> ASCIIZ format string
  243. * ... = argument list
  244. *
  245. * The characters in the format string are listed in EmitPal.
  246. *
  247. *****************************************************************************/
  248. void EXTERNAL
  249. ArgsPalPszV(PARGLIST pal, LPCSTR psz, ...)
  250. {
  251. va_list ap;
  252. va_start(ap, psz);
  253. if (psz) {
  254. PPV ppv;
  255. pal->pszFormat = psz;
  256. for (ppv = pal->rgpv; *psz; psz++) {
  257. *ppv++ = va_arg(ap, PV);
  258. }
  259. } else {
  260. pal->pszFormat = "";
  261. }
  262. }
  263. /*****************************************************************************
  264. *
  265. * EmitPal
  266. *
  267. * OutputDebugString the information, given a pal. No trailing
  268. * carriage return is emitted.
  269. *
  270. * pal -> place where info was saved
  271. *
  272. * Format characters:
  273. *
  274. * p - 32-bit flat pointer
  275. * x - 32-bit hex integer
  276. * s - TCHAR string
  277. * A - ANSI string
  278. * W - UNICODE string
  279. * G - GUID
  280. * u - unsigned integer
  281. * C - clipboard format
  282. *
  283. *****************************************************************************/
  284. void INTERNAL
  285. EmitPal(PARGLIST pal)
  286. {
  287. char sz[MAX_PATH];
  288. int i;
  289. DebugOutPtszA(pal->pszProc);
  290. DebugOutPtsz(TEXT("("));
  291. for (i = 0; pal->pszFormat[i]; i++) {
  292. if (i) {
  293. DebugOutPtsz(TEXT(", "));
  294. }
  295. switch (pal->pszFormat[i]) {
  296. case 'p': /* 32-bit flat pointer */
  297. case 'x': /* 32-bit hex */
  298. wsprintfA(sz, "%08x", (UINT_PTR) pal->rgpv[i]);
  299. DebugOutPtszA(sz);
  300. break;
  301. case 's': /* TCHAR string */
  302. if (pal->rgpv[i]) {
  303. DebugOutPtsz(pal->rgpv[i]);
  304. }
  305. break;
  306. case 'A': /* ANSI string */
  307. if (pal->rgpv[i]) {
  308. DebugOutPtszA(pal->rgpv[i]);
  309. }
  310. break;
  311. case 'W': /* UNICODE string */
  312. #ifdef UNICODE
  313. OutputDebugStringW(pal->rgpv[i]);
  314. #else
  315. WideCharToMultiByte(CP_ACP, 0, pal->rgpv[i], -1, sz, cA(sz), 0, 0);
  316. DebugOutPtszA(sz);
  317. #endif
  318. break;
  319. #ifndef _WIN64
  320. //
  321. // Ignore this option on SunDown
  322. //
  323. case 'G': /* GUID */
  324. wsprintfA(sz, "%08x",
  325. HIWORD(pal->rgpv[i]) ? *(LPDWORD)pal->rgpv[i]
  326. : (DWORD)pal->rgpv[i]);
  327. DebugOutPtszA(sz);
  328. break;
  329. case 'C':
  330. if (GetClipboardFormatNameA((UINT)pal->rgpv[i], sz, cA(sz))) {
  331. } else {
  332. wsprintfA(sz, "[%04x]", (UINT) pal->rgpv[i]);
  333. }
  334. DebugOutPtszA(sz);
  335. break;
  336. #endif
  337. case 'u': /* 32-bit unsigned decimal */
  338. wsprintfA(sz, "%u", (UINT_PTR) pal->rgpv[i]);
  339. DebugOutPtszA(sz);
  340. break;
  341. default: AssertF(0); /* Invalid */
  342. }
  343. }
  344. DebugOutPtsz(TEXT(")"));
  345. }
  346. /*****************************************************************************
  347. *
  348. * EnterDbgflPtsz
  349. *
  350. * Mark entry to a procedure. Arguments were already collected by
  351. * ArgsPszV.
  352. *
  353. * Dbgfl -> DebugOuty flags
  354. * pszProc -> procedure name
  355. * pal -> place to save the name and get the format/args
  356. *
  357. *****************************************************************************/
  358. void EXTERNAL
  359. EnterDbgflPszPal(DBGFL Dbgfl, LPCSTR pszProc, PARGLIST pal)
  360. {
  361. pal->pszProc = pszProc;
  362. if (Dbgfl == 0 || (Dbgfl & DbgflCur)) {
  363. EmitPal(pal);
  364. DebugOutPtsz(TEXT("\r\n"));
  365. }
  366. }
  367. /*****************************************************************************
  368. *
  369. * ExitDbgflPalHresPpv
  370. *
  371. * Mark exit from a procedure.
  372. *
  373. * pal -> argument list
  374. * hres -> exit result
  375. * ppv -> optional OUT pointer;
  376. * ppvDword means that hres is a dword
  377. * ppvBool means that hres is a boolean
  378. * ppvVoid means that hres is nothing at all
  379. *
  380. *****************************************************************************/
  381. void EXTERNAL
  382. ExitDbgflPalHresPpv(DBGFL Dbgfl, PARGLIST pal, HRESULT hres, PPV ppvObj)
  383. {
  384. BOOL fInternalError;
  385. DWORD le = GetLastError();
  386. fInternalError = 0;
  387. if (ppvObj == ppvVoid) {
  388. } else if (ppvObj == ppvBool) {
  389. if (hres == 0) {
  390. Dbgfl |= DbgFlError;
  391. }
  392. } else {
  393. if (FAILED(hres)) {
  394. if (fLimpFF(ppvObj && !IsBadWritePtr(ppvObj, cbX(*ppvObj)),
  395. *ppvObj == 0)) {
  396. } else {
  397. fInternalError = 1;
  398. }
  399. Dbgfl |= DbgFlError;
  400. }
  401. }
  402. if (Dbgfl == 0 || (Dbgfl & DbgflCur) || fInternalError) {
  403. EmitPal(pal);
  404. DebugOutPtsz(TEXT(" -> "));
  405. if (ppvObj != ppvVoid) {
  406. TCHAR tszBuf[32];
  407. wsprintf(tszBuf, TEXT("%08x"), hres);
  408. DebugOutPtsz(tszBuf);
  409. if (HIWORD(PtrToLong(ppvObj))) {
  410. wsprintf(tszBuf, TEXT(" [%08x]"), (UINT_PTR) *ppvObj);
  411. DebugOutPtsz(tszBuf);
  412. } else if (ppvObj == ppvDword) {
  413. wsprintf(tszBuf, TEXT(" [%08x]"), hres);
  414. DebugOutPtsz(tszBuf);
  415. } else if (ppvObj == ppvBool) {
  416. wsprintf(tszBuf, hres == S_OK ? TEXT(" OK ") :
  417. TEXT(" le=[%d]"), le);
  418. DebugOutPtsz(tszBuf);
  419. }
  420. }
  421. DebugOutPtsz(TEXT("\r\n"));
  422. AssertF(!fInternalError);
  423. }
  424. /*
  425. * This redundant test prevents a breakpoint on SetLastError()
  426. * from being hit constantly.
  427. */
  428. if (le != GetLastError()) {
  429. SetLastError(le);
  430. }
  431. }
  432. #endif
  433. #ifdef MAXDEBUG
  434. /*****************************************************************************
  435. *
  436. * @doc INTERNAL
  437. *
  438. * @func DWORD | Random |
  439. *
  440. * Returns a pseudorandom dword. The value doesn't need to be
  441. * statistically wonderful.
  442. *
  443. * @returns
  444. * A not very random dword.
  445. *
  446. *****************************************************************************/
  447. DWORD s_dwRandom = 1; /* Random number seed */
  448. DWORD INLINE
  449. Random(void)
  450. {
  451. s_dwRandom = s_dwRandom * 214013 + 2531011;
  452. return s_dwRandom;
  453. }
  454. /*****************************************************************************
  455. *
  456. * @doc INTERNAL
  457. *
  458. * @func void | ScrambleBuf |
  459. *
  460. * Fill a buffer with garbage. Used in RDEBUG to make sure
  461. * the caller is not relying on buffer data.
  462. *
  463. * Note: If the buffer is not a multiple of dwords in size,
  464. * the leftover bytes are not touched.
  465. *
  466. * @parm OUT LPVOID | pv |
  467. *
  468. * The buffer to be scrambled.
  469. *
  470. * @parm UINT | cb |
  471. *
  472. * The size of the buffer.
  473. *
  474. *****************************************************************************/
  475. void EXTERNAL
  476. ScrambleBuf(LPVOID pv, UINT cb)
  477. {
  478. UINT idw;
  479. UINT cdw = cb / 4;
  480. LPDWORD pdw = pv;
  481. for (idw = 0; idw < cdw; idw++) {
  482. pdw[idw] = Random();
  483. }
  484. }
  485. /*****************************************************************************
  486. *
  487. * @doc INTERNAL
  488. *
  489. * @func void | ScrambleBit |
  490. *
  491. * Randomly set or clear a bit.
  492. *
  493. * @parm OUT LPDWORD | pdw |
  494. *
  495. * The dword whose bit is to be set randomly.
  496. *
  497. * @parm UINT | flMask |
  498. *
  499. * Mask for the bits to scramble.
  500. *
  501. *****************************************************************************/
  502. void EXTERNAL ScrambleBit(LPDWORD pdw, DWORD flMask)
  503. {
  504. *pdw ^= (*pdw ^ Random()) & flMask;
  505. }
  506. /*****************************************************************************
  507. *
  508. * @doc INTERNAL
  509. *
  510. * @func BOOL | Callback_CompareContexts |
  511. *
  512. * Check if two <t CONTEXT> structures are substantially the same
  513. * to the extent required by the Win32 calling convention.
  514. *
  515. * This is necessary because lots of applications pass
  516. * incorrectly prototyped functions as callbacks. Others will
  517. * write callback functions that trash registers that are
  518. * supposed to be nonvolatile. Yuck!
  519. *
  520. * NOTE! Platform-dependent code!
  521. *
  522. * @parm LPCONTEXT | pctx1 |
  523. *
  524. * Context structure before we call the callback.
  525. *
  526. * @parm LPCONTEXT | pctx2 |
  527. *
  528. * Context structure after we call the callback.
  529. *
  530. * @returns
  531. *
  532. * Nonzero if the two contexts are substantially the same.
  533. *
  534. *****************************************************************************/
  535. BOOL INLINE
  536. Callback_CompareContexts(LPCONTEXT pctx1, LPCONTEXT pctx2)
  537. {
  538. #if defined(_X86_)
  539. return pctx1->Esp == pctx2->Esp; /* Stack pointer */
  540. #if 0
  541. /*
  542. * Can't test these registers because Win95 doesn't preserve
  543. * them properly. GetThreadContext() stashes what happens to
  544. * be in the registers when you finally reach the bowels of
  545. * kernel, at which point who knows what they contain...
  546. */
  547. pctx1->Ebx == pctx2->Ebx && /* Nonvolatile registers */
  548. pctx1->Esi == pctx2->Esi &&
  549. pctx1->Edi == pctx2->Edi &&
  550. pctx1->Ebp == pctx2->Ebp;
  551. #endif
  552. #elif defined(_ALPHA_)
  553. return pctx1->IntSp == pctx2->IntSp && /* Stack pointer */
  554. pctx1->IntS0 == pctx2->IntS0 && /* Nonvolatile registers */
  555. pctx1->IntS1 == pctx2->IntS1 &&
  556. pctx1->IntS2 == pctx2->IntS2 &&
  557. pctx1->IntS3 == pctx2->IntS3 &&
  558. pctx1->IntS4 == pctx2->IntS4 &&
  559. pctx1->IntS5 == pctx2->IntS5 &&
  560. pctx1->IntFp == pctx2->IntFp;
  561. #elif defined(_MIPS_)
  562. #pragma message("I hope this is correct for MIPS")
  563. return pctx1->IntSp == pctx2->IntSp && /* Stack pointer */
  564. pctx1->IntS0 == pctx2->IntS0 && /* Nonvolatile registers */
  565. pctx1->IntS1 == pctx2->IntS1 &&
  566. pctx1->IntS2 == pctx2->IntS2 &&
  567. pctx1->IntS3 == pctx2->IntS3 &&
  568. pctx1->IntS4 == pctx2->IntS4 &&
  569. pctx1->IntS6 == pctx2->IntS6 &&
  570. pctx1->IntS7 == pctx2->IntS7 &&
  571. pctx1->IntS8 == pctx2->IntS8;
  572. #elif defined(_PPC_)
  573. #pragma message("I don't know what the PPC calling conventions are")
  574. /* Just check the stack register */
  575. return pctx1->Gpr1 == pctx2->Gpr1;
  576. #else
  577. #pragma message("I don't know what the calling conventions are for this platform")
  578. return 1;
  579. #endif
  580. }
  581. /*****************************************************************************
  582. *
  583. * @doc INTERNAL
  584. *
  585. * @func BOOL | Callback |
  586. *
  587. * Perform a callback the paranoid way, checking that the
  588. * application used the correct calling convention and preserved
  589. * all nonvolatile registers.
  590. *
  591. * NOTE! Platform-dependent code!
  592. *
  593. * @parm STICALLBACKPROC | pfn |
  594. *
  595. * Procedure to call back.
  596. *
  597. * @parm PV | pv1 |
  598. *
  599. * First parameter to callback.
  600. *
  601. * @parm PV | pv2 |
  602. *
  603. * Second parameter to callback.
  604. *
  605. * @returns
  606. *
  607. * Whatever the callback returns.
  608. *
  609. *****************************************************************************/
  610. BOOL EXTERNAL
  611. Callback(STICALLBACKPROC pfn, PV pv1, PV pv2)
  612. {
  613. CONTEXT ctxPre; /* Thread context before call */
  614. CONTEXT ctxPost; /* Thread context after call */
  615. volatile BOOL fRc; /* To prevent compiler from enregistering */
  616. /* Get state of registers before the callback */
  617. ctxPre.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
  618. GetThreadContext(GetCurrentThread(), &ctxPre);
  619. fRc = pfn(pv1, pv2);
  620. ctxPost.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
  621. if (GetThreadContext(GetCurrentThread(), &ctxPost) &&
  622. !Callback_CompareContexts(&ctxPre, &ctxPost)) {
  623. RPF("STI: Incorrectly prototyped callback! Crash soon!");
  624. ValidationException();
  625. }
  626. return fRc;
  627. }
  628. #endif