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.

616 lines
17 KiB

  1. #include "stdinc.h"
  2. #include "debmacro.h"
  3. #include <stdio.h>
  4. #include <stdarg.h>
  5. #include "fusionbuffer.h"
  6. #include "setupapi.h"
  7. #include "shlwapi.h"
  8. #if !defined(NT_INCLUDED)
  9. #define DPFLTR_FUSION_ID 54
  10. #endif
  11. extern "C" { const extern char FusionpIsPrint_Data[256]; }
  12. #define PRINTABLE(_ch) (FusionpIsPrint_Data[(_ch) & 0xff] ? (_ch) : '.')
  13. #if !defined(FUSION_DEFAULT_DBG_LEVEL_MASK)
  14. #define FUSION_DEFAULT_DBG_LEVEL_MASK (0x00000000)
  15. #endif
  16. extern "C" DWORD kd_fusion_mask = (FUSION_DEFAULT_DBG_LEVEL_MASK & ~DPFLTR_MASK);
  17. extern "C" DWORD kd_kernel_fusion_mask = 0;
  18. extern "C" bool g_FusionEnterExitTracingEnabled = false;
  19. typedef ULONG (NTAPI* RTL_V_DBG_PRINT_EX_FUNCTION)(
  20. IN ULONG ComponentId,
  21. IN ULONG Level,
  22. IN PCH Format,
  23. va_list arglist
  24. );
  25. typedef ULONG (*RTL_V_DBG_PRINT_EX_WITH_PREFIX_FUNCTION)(
  26. IN PCH Prefix,
  27. IN ULONG ComponentId,
  28. IN ULONG Level,
  29. IN PCH Format,
  30. va_list arglist
  31. );
  32. RTL_V_DBG_PRINT_EX_FUNCTION g_pfnvDbgPrintEx;
  33. RTL_V_DBG_PRINT_EX_WITH_PREFIX_FUNCTION g_pfnvDbgPrintExWithPrefix;
  34. VOID
  35. FusionpvDbgPrintToSetupLog(
  36. IN LogSeverity Severity,
  37. IN PCSTR Format,
  38. IN va_list ap
  39. );
  40. void
  41. FusionpReportCondition(
  42. bool fBreak,
  43. PCSTR pszFormat,
  44. ...
  45. )
  46. {
  47. char rgach[128];
  48. char rgach2[128];
  49. FRAME_INFO FrameInfo;
  50. va_list ap;
  51. va_start(ap, pszFormat);
  52. ::_vsnprintf(rgach, NUMBER_OF(rgach), pszFormat, ap);
  53. rgach[NUMBER_OF(rgach) - 1] = '\0';
  54. ::FusionpGetActiveFrameInfo(FrameInfo);
  55. ::_snprintf(
  56. rgach2,
  57. NUMBER_OF(rgach2),
  58. "%s(%d): Break-in requested:\n"
  59. " %s\n",
  60. FrameInfo.pszFile,
  61. FrameInfo.nLine,
  62. rgach);
  63. rgach2[NUMBER_OF(rgach2) - 1] = '\0';
  64. if (::IsDebuggerPresent())
  65. {
  66. ::OutputDebugStringA(rgach2);
  67. }
  68. if (fBreak)
  69. {
  70. #if DBG
  71. ::FusionpRtlAssert(
  72. const_cast<PVOID>(reinterpret_cast<const void*>("Break-in requested")),
  73. const_cast<PVOID>(reinterpret_cast<const void*>(FrameInfo.pszFile)),
  74. FrameInfo.nLine,
  75. const_cast<PSTR>(rgach));
  76. #endif
  77. }
  78. va_end(ap);
  79. return;
  80. }
  81. #if DBG
  82. bool
  83. FusionpAssertionFailed(
  84. const FRAME_INFO &rFrameInfo,
  85. PCSTR pszExpression,
  86. PCSTR pszText
  87. )
  88. {
  89. CSxsPreserveLastError ple;
  90. if (::IsDebuggerPresent())
  91. {
  92. char rgach[512];
  93. // c:\foo.cpp(35): Assertion Failure. Expression: "m_cch != 0". Text: "Must have nonzero length"
  94. static const char szFormatWithText[] = "%s(%d): Assertion failure in %s. Expression: \"%s\". Text: \"%s\"\n";
  95. static const char szFormatNoText[] = "%s(%d): Assertion failure in %s. Expression: \"%s\".\n";
  96. PCSTR pszFormat = ((pszText == NULL) || (pszText == pszExpression)) ? szFormatNoText : szFormatWithText;
  97. ::_snprintf(
  98. rgach,
  99. NUMBER_OF(rgach),
  100. pszFormat,
  101. rFrameInfo.pszFile,
  102. rFrameInfo.nLine,
  103. rFrameInfo.pszFunction,
  104. pszExpression,
  105. pszText);
  106. rgach[NUMBER_OF(rgach) - 1] = '\0';
  107. ::OutputDebugStringA(rgach);
  108. ple.Restore();
  109. return true;
  110. }
  111. ::FusionpRtlAssert(
  112. const_cast<PVOID>(reinterpret_cast<const void*>(pszExpression)),
  113. const_cast<PVOID>(reinterpret_cast<const void*>(rFrameInfo.pszFile)),
  114. rFrameInfo.nLine,
  115. const_cast<PSTR>(pszText));
  116. ple.Restore();
  117. return false;
  118. }
  119. bool
  120. FusionpAssertionFailed(
  121. PCSTR pszFile,
  122. PCSTR pszFunctionName,
  123. INT nLine,
  124. PCSTR pszExpression,
  125. PCSTR pszText
  126. )
  127. {
  128. FRAME_INFO FrameInfo;
  129. ::FusionpPopulateFrameInfo(FrameInfo, pszFile, pszFunctionName, nLine);
  130. return ::FusionpAssertionFailed(FrameInfo, pszExpression, pszText);
  131. }
  132. #endif // DBG
  133. VOID
  134. FusionpSoftAssertFailed(
  135. const FRAME_INFO &rFrameInfo,
  136. PCSTR pszExpression,
  137. PCSTR pszMessage
  138. )
  139. {
  140. CSxsPreserveLastError ple;
  141. char rgach[256];
  142. // c:\foo.cpp(35): [Fusion] Soft Assertion Failure. Expression: "m_cch != 0". Text: "Must have nonzero length"
  143. static const char szFormatWithText[] = "%s(%d): Soft Assertion Failure in %s! Log a bug!\n Expression: %s\n Message: %s\n";
  144. static const char szFormatNoText[] = "%s(%d): Soft Assertion Failure in %s! Log a bug!\n Expression: %s\n";
  145. PCSTR pszFormat = ((pszMessage == NULL) || (pszMessage == pszExpression)) ? szFormatNoText : szFormatWithText;
  146. ::_snprintf(rgach, NUMBER_OF(rgach), pszFormat, rFrameInfo.pszFile, rFrameInfo.nLine, rFrameInfo.pszFunction, pszExpression, pszMessage);
  147. rgach[NUMBER_OF(rgach) - 1] = '\0';
  148. ::OutputDebugStringA(rgach);
  149. ple.Restore();
  150. }
  151. VOID
  152. FusionpSoftAssertFailed(
  153. PCSTR pszFile,
  154. PCSTR pszFunction,
  155. INT nLine,
  156. PCSTR pszExpression,
  157. PCSTR pszMessage
  158. )
  159. {
  160. FRAME_INFO FrameInfo;
  161. ::FusionpPopulateFrameInfo(FrameInfo, pszFile, pszFunction, nLine);
  162. ::FusionpSoftAssertFailed(FrameInfo, pszExpression, pszMessage);
  163. }
  164. VOID
  165. FusionpSoftAssertFailed(
  166. PCSTR pszExpression,
  167. PCSTR pszMessage
  168. )
  169. {
  170. FRAME_INFO FrameInfo;
  171. ::FusionpGetActiveFrameInfo(FrameInfo);
  172. ::FusionpSoftAssertFailed(FrameInfo, pszExpression, pszMessage);
  173. }
  174. ULONG
  175. FusionpvDbgPrintExNoNTDLL(
  176. IN ULONG ComponentId,
  177. IN ULONG Level,
  178. IN PCH Format,
  179. va_list arglist
  180. )
  181. {
  182. if ((ComponentId == DPFLTR_FUSION_ID) &&
  183. (((Level < 32) &&
  184. (((1 << Level) & kd_fusion_mask) != 0)) ||
  185. ((Level >= 32) &&
  186. ((Level & kd_fusion_mask) != 0))))
  187. {
  188. CSxsPreserveLastError ple;
  189. CHAR rgchBuffer[512];
  190. ULONG n = ::_vsnprintf(rgchBuffer, NUMBER_OF(rgchBuffer), Format, arglist);
  191. rgchBuffer[NUMBER_OF(rgchBuffer) - 1] = '\0';
  192. ::OutputDebugStringA(rgchBuffer);
  193. ple.Restore();
  194. return n;
  195. }
  196. return 0;
  197. }
  198. HMODULE g_setupapiDll = NULL;
  199. typedef BOOL (WINAPI * PSETUPCLOSELOG_ROUTINE)(
  200. );
  201. typedef BOOL (WINAPI * PSETUPLOGERRORA_ROUTINE)(
  202. IN LPCSTR MessageString,
  203. IN LogSeverity Severity
  204. );
  205. typedef BOOL (WINAPI * PSETUPLOGERRORW_ROUTINE)(
  206. IN LPCWSTR MessageString,
  207. IN LogSeverity Severity
  208. );
  209. typedef BOOL (WINAPI * PSETUPOPENLOG_ROUTINE)(
  210. BOOL Erase
  211. );
  212. PSETUPLOGERRORA_ROUTINE g_pfnSetupLogError;
  213. PSETUPCLOSELOG_ROUTINE g_pfnSetupCloseLog;
  214. BOOL
  215. WINAPI
  216. DllStartup_SetupLog(
  217. HINSTANCE Module,
  218. DWORD Reason,
  219. PVOID Reserved
  220. )
  221. {
  222. BOOL fSuccess = FALSE;
  223. if ((Reason == DLL_PROCESS_DETACH) &&
  224. (g_setupapiDll != NULL))
  225. {
  226. if (Reserved != NULL)
  227. {
  228. if (g_pfnSetupCloseLog != NULL)
  229. {
  230. (*g_pfnSetupCloseLog)();
  231. }
  232. if (!FreeLibrary(g_setupapiDll))
  233. {
  234. ::FusionpDbgPrint("SXS.DLL : FreeLibrary failed to free setupapi.dll with LastError = %d\n", ::FusionpGetLastWin32Error());
  235. }
  236. }
  237. g_pfnSetupCloseLog = NULL;
  238. g_pfnSetupLogError = NULL;
  239. g_setupapiDll = NULL;
  240. }
  241. fSuccess = TRUE;
  242. return fSuccess;
  243. }
  244. VOID
  245. FusionpvDbgPrintToSetupLog(
  246. IN LogSeverity Severity,
  247. IN PCSTR Format,
  248. IN va_list ap
  249. )
  250. {
  251. //
  252. // first, let us check whether this is ActCtxGen (by csrss.exe) or Setup Installation(by setup.exe)
  253. // during GUI mode setup; do not log for ActCtxGen, only setup
  254. //
  255. if (::GetModuleHandleW(L"csrss.exe") != NULL)
  256. return;
  257. static BOOL s_fEverBeenCalled = FALSE;
  258. PCSTR ProcName = "";
  259. if ((g_pfnSetupLogError == NULL) && !s_fEverBeenCalled)
  260. {
  261. g_setupapiDll = ::LoadLibraryW(L"SETUPAPI.DLL");
  262. if (g_setupapiDll == NULL)
  263. {
  264. ::FusionpDbgPrint("SXS.DLL : Loadlibrary Failed to load setupapi.dll with LastError = %d\n", ::FusionpGetLastWin32Error());
  265. goto Exit;
  266. }
  267. ProcName = "SetupOpenLog";
  268. PSETUPOPENLOG_ROUTINE pfnOpenSetupLog = (PSETUPOPENLOG_ROUTINE) ::GetProcAddress(g_setupapiDll, ProcName);
  269. if (pfnOpenSetupLog == NULL)
  270. {
  271. goto GetProcAddressFailed;
  272. }
  273. ProcName = "SetupLogErrorA";
  274. PSETUPLOGERRORA_ROUTINE pfnSetupLogError = (PSETUPLOGERRORA_ROUTINE) ::GetProcAddress(g_setupapiDll, ProcName);
  275. if (pfnSetupLogError == NULL)
  276. {
  277. goto GetProcAddressFailed;
  278. }
  279. ProcName = "SetupCloseLog";
  280. PSETUPCLOSELOG_ROUTINE pfnSetupCloseLog = (PSETUPCLOSELOG_ROUTINE) ::GetProcAddress(g_setupapiDll, "SetupCloseLog");
  281. if (pfnSetupLogError == NULL)
  282. {
  283. goto GetProcAddressFailed;
  284. }
  285. if (!(*pfnOpenSetupLog)(FALSE))
  286. {
  287. ::FusionpDbgPrint("SXS.DLL : SetupOpenLog failed with LastError = %d\n", ::FusionpGetLastWin32Error());
  288. goto Exit;
  289. }
  290. g_pfnSetupCloseLog = pfnSetupCloseLog;
  291. g_pfnSetupLogError = pfnSetupLogError;
  292. }
  293. if (g_pfnSetupLogError != NULL)
  294. {
  295. CHAR rgchBuffer[512];
  296. ::_vsnprintf(rgchBuffer, NUMBER_OF(rgchBuffer), Format, ap);
  297. rgchBuffer[NUMBER_OF(rgchBuffer) - 1] = '\0';
  298. if (!(*g_pfnSetupLogError)(rgchBuffer, Severity))
  299. {
  300. ::FusionpDbgPrint("SXS.DLL : SetupLogErrorA failed with LastError = %d\n", ::FusionpGetLastWin32Error());
  301. }
  302. }
  303. return;
  304. Exit:
  305. s_fEverBeenCalled = TRUE;
  306. return;
  307. GetProcAddressFailed:
  308. ::FusionpDbgPrint("SXS.DLL : %s failed to be located in setupapi.dll with LastError = %d\n", ProcName, ::FusionpGetLastWin32Error());
  309. goto Exit;
  310. }
  311. ULONG
  312. FusionpvDbgPrintEx(
  313. ULONG Level,
  314. PCSTR Format,
  315. va_list ap
  316. )
  317. {
  318. CSxsPreserveLastError ple;
  319. ULONG ulResult = 0;
  320. if (g_pfnvDbgPrintEx == NULL)
  321. {
  322. HINSTANCE hInstNTDLL = ::GetModuleHandleW(L"NTDLL.DLL");
  323. if (hInstNTDLL != NULL)
  324. g_pfnvDbgPrintEx = (RTL_V_DBG_PRINT_EX_FUNCTION)(::GetProcAddress(hInstNTDLL, "vDbgPrintEx"));
  325. if (g_pfnvDbgPrintEx == NULL)
  326. g_pfnvDbgPrintEx = &::FusionpvDbgPrintExNoNTDLL;
  327. }
  328. if (g_pfnvDbgPrintEx)
  329. {
  330. ulResult = (*g_pfnvDbgPrintEx)(
  331. DPFLTR_FUSION_ID,
  332. Level,
  333. const_cast<PSTR>(Format),
  334. ap);
  335. }
  336. if (::IsDebuggerPresent())
  337. {
  338. ulResult = ::FusionpvDbgPrintExNoNTDLL(DPFLTR_FUSION_ID, Level, const_cast<PSTR>(Format), ap);
  339. // Gross, but msdev chokes under too much debug output
  340. if (ulResult != 0)
  341. ::Sleep(10);
  342. }
  343. // Special handling of reflection out to the setup log...
  344. if (Level & FUSION_DBG_LEVEL_SETUPLOG & ~DPFLTR_MASK)
  345. ::FusionpvDbgPrintToSetupLog(
  346. (Level== FUSION_DBG_LEVEL_ERROR) || (Level & FUSION_DBG_LEVEL_ERROR & ~DPFLTR_MASK) ? LogSevError : LogSevInformation,
  347. Format, ap);
  348. ple.Restore();
  349. return ulResult;
  350. }
  351. ULONG
  352. FusionpDbgPrintEx(
  353. ULONG Level,
  354. PCSTR Format,
  355. ...
  356. )
  357. {
  358. ULONG rv = 0;
  359. va_list ap;
  360. va_start(ap, Format);
  361. if ((Level & FUSION_DBG_LEVEL_SETUPLOG) || (::FusionpDbgWouldPrintAtFilterLevel(Level)))
  362. {
  363. rv = ::FusionpvDbgPrintEx(Level, Format, ap);
  364. }
  365. va_end(ap);
  366. return rv;
  367. }
  368. // Finds out whether or not the given level would print, given our
  369. // current mask. Knows to look at kd_fusion_mask both in nt as well
  370. // as in the current process.
  371. #define RECHECK_INTERVAL (1000)
  372. #if DBG
  373. EXTERN_C BOOL g_fIgnoreSystemLevelFilterMask = FALSE;
  374. #endif
  375. bool
  376. FusionpDbgWouldPrintAtFilterLevel(
  377. ULONG Level
  378. )
  379. {
  380. // The time quanta here is milliseconds (1000 per second)
  381. #if DBG
  382. if ( !g_fIgnoreSystemLevelFilterMask )
  383. {
  384. #endif
  385. static ULONG s_ulNextTimeToCheck;
  386. ULONG ulCapturedNextTimeToCheck = s_ulNextTimeToCheck;
  387. ULONG ulCurrentTime = NtGetTickCount();
  388. // Look for either the tick count to have wrapped or to be over the next time to check.
  389. // There's some opportunity for loss here if we only run this function every 49 days but
  390. // that's pretty darned unlikely.
  391. if ((ulCurrentTime >= ulCapturedNextTimeToCheck) ||
  392. ((ulCapturedNextTimeToCheck > RECHECK_INTERVAL) &&
  393. (ulCurrentTime < (ulCapturedNextTimeToCheck - RECHECK_INTERVAL))))
  394. {
  395. DWORD dwNewFusionMask = 0;
  396. ULONG i;
  397. // Time to check again...
  398. for (i=0; i<31; i++)
  399. {
  400. if (::FusionpNtQueryDebugFilterState(DPFLTR_FUSION_ID, (DPFLTR_MASK | (1 << i))) == TRUE)
  401. dwNewFusionMask |= (1 << i);
  402. }
  403. if (s_ulNextTimeToCheck == ulCapturedNextTimeToCheck)
  404. {
  405. // Check again in 1000ms (1 second)
  406. s_ulNextTimeToCheck = (ulCurrentTime + RECHECK_INTERVAL);
  407. // Nobody got in before us. Let's write it...
  408. kd_kernel_fusion_mask = dwNewFusionMask;
  409. g_FusionEnterExitTracingEnabled = (((kd_fusion_mask | kd_kernel_fusion_mask) & FUSION_DBG_LEVEL_ENTEREXIT) != 0);
  410. }
  411. }
  412. #if DBG
  413. }
  414. #endif
  415. ULONG mask = Level;
  416. // If level < 32, it's actually a single-bit test
  417. if (Level < 32)
  418. mask = (1 << Level);
  419. // Are these bits set in our mask?
  420. return (((kd_fusion_mask | kd_kernel_fusion_mask) & mask) != 0);
  421. }
  422. VOID
  423. FusionppDbgPrintBlob(
  424. ULONG Level,
  425. PVOID Data,
  426. SIZE_T Length,
  427. PCWSTR PerLinePrefix
  428. )
  429. {
  430. ULONG Offset = 0;
  431. if (PerLinePrefix == NULL)
  432. PerLinePrefix = L"";
  433. // we'll output in 8-byte chunks as shown:
  434. //
  435. // [prefix] 00000000: xx-xx-xx-xx-xx-xx-xx-xx (........)
  436. // [prefix] 00000008: xx-xx-xx-xx-xx-xx-xx-xx (........)
  437. // [prefix] 00000010: xx-xx-xx-xx-xx-xx-xx-xx (........)
  438. //
  439. while (Length >= 16)
  440. {
  441. BYTE *pb = (BYTE *) (((ULONG_PTR) Data) + Offset);
  442. ::FusionpDbgPrintEx(
  443. Level,
  444. "%S%08lx: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x (%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c)\n",
  445. PerLinePrefix,
  446. Offset,
  447. pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7],
  448. pb[8], pb[9], pb[10], pb[11], pb[12], pb[13], pb[14], pb[15],
  449. PRINTABLE(pb[0]),
  450. PRINTABLE(pb[1]),
  451. PRINTABLE(pb[2]),
  452. PRINTABLE(pb[3]),
  453. PRINTABLE(pb[4]),
  454. PRINTABLE(pb[5]),
  455. PRINTABLE(pb[6]),
  456. PRINTABLE(pb[7]),
  457. PRINTABLE(pb[8]),
  458. PRINTABLE(pb[9]),
  459. PRINTABLE(pb[10]),
  460. PRINTABLE(pb[11]),
  461. PRINTABLE(pb[12]),
  462. PRINTABLE(pb[13]),
  463. PRINTABLE(pb[14]),
  464. PRINTABLE(pb[15]));
  465. Offset += 16;
  466. Length -= 16;
  467. }
  468. if (Length != 0)
  469. {
  470. WCHAR wchLeft[64], wchRight[64];
  471. WCHAR rgTemp2[16]; // arbitrary big enough size
  472. bool First = true;
  473. ULONG i;
  474. BYTE *pb = (BYTE *) (((ULONG_PTR) Data) + Offset);
  475. // init output buffers
  476. wchLeft[0] = 0;
  477. ::wcscpy( wchRight, L" (" );
  478. for (i=0; i<16; i++)
  479. {
  480. if (Length > 0)
  481. {
  482. // left
  483. ::_snwprintf(rgTemp2, NUMBER_OF(rgTemp2), L"%ls%02x", First ? L" " : L"-", pb[i]);
  484. rgTemp2[NUMBER_OF(rgTemp2) - 1] = L'\0';
  485. First = false;
  486. ::wcscat(wchLeft, rgTemp2);
  487. // right
  488. ::_snwprintf(rgTemp2, NUMBER_OF(rgTemp2), L"%c", PRINTABLE(pb[i]));
  489. rgTemp2[NUMBER_OF(rgTemp2) - 1] = L'\0';
  490. wcscat(wchRight, rgTemp2);
  491. Length--;
  492. }
  493. else
  494. {
  495. ::wcscat(wchLeft, L" ");
  496. }
  497. }
  498. ::wcscat(wchRight, L")");
  499. ::FusionpDbgPrintEx(
  500. Level,
  501. "%S %08lx:%ls%ls\n",
  502. PerLinePrefix,
  503. Offset,
  504. wchLeft,
  505. wchRight);
  506. }
  507. }
  508. VOID
  509. FusionpDbgPrintBlob(
  510. ULONG Level,
  511. PVOID Data,
  512. SIZE_T Length,
  513. PCWSTR PerLinePrefix
  514. )
  515. {
  516. //
  517. // This extra function reduces stack usage when the data
  518. // isn't actually printed (and increases stack usage slightly otherwise).
  519. //
  520. if (!::FusionpDbgWouldPrintAtFilterLevel(Level))
  521. return;
  522. ::FusionppDbgPrintBlob(Level, Data, Length, PerLinePrefix);
  523. }