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.

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