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.

2601 lines
61 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. debug.c
  5. Abstract:
  6. This routine reads input from STDIN and initializes the debug structure.
  7. It reads a list of subsystems to debug and a severity level.
  8. Author:
  9. Billy Fuller
  10. Environment
  11. User mode, winnt32
  12. */
  13. #include <ntreppch.h>
  14. #pragma hdrstop
  15. #include "debug.h"
  16. // #include <imagehlp.h>
  17. #include <dbghelp.h>
  18. #include <frs.h>
  19. #include <winbase.h>
  20. #include <mapi.h>
  21. #include <ntfrsapi.h>
  22. #include <info.h>
  23. extern PCHAR LatestChanges[];
  24. //
  25. // Track the thread IDs of known threads for the debug log header.
  26. //
  27. typedef struct _KNOWN_THREAD {
  28. PWCHAR Name; // print Name of thread.
  29. DWORD Id; // Id returned by CreateThread()
  30. PTHREAD_START_ROUTINE EntryPoint; // entry point
  31. } KNOWN_THREAD, *PKNOWN_THREAD;
  32. KNOWN_THREAD KnownThreadArray[20];
  33. //
  34. // Send mail will not work if the Default User is unable to send
  35. // mail on this machine.
  36. //
  37. MapiRecipDesc Recips =
  38. {0, MAPI_TO, 0, 0, 0, NULL};
  39. MapiMessage Message =
  40. { 0, 0, 0, NULL, NULL, NULL, 0, 0, 1, &Recips, 0, 0 };
  41. LPMAPILOGON MailLogon;
  42. LPMAPILOGOFF MailLogoff;
  43. LPMAPISENDMAIL MailSend;
  44. HANDLE MailLib;
  45. LHANDLE MailSession;
  46. WCHAR DbgExePathW[MAX_PATH+1];
  47. CHAR DbgExePathA[MAX_PATH+1];
  48. CHAR DbgSearchPath[MAX_PATH+1];
  49. //
  50. // Flush the trace log every so many lines.
  51. //
  52. LONG DbgFlushInterval = 100000;
  53. #define DEFAULT_DEBUG_MAX_LOG (20000)
  54. LONG StackTraceCount = 100;
  55. LONG DbgRaiseCount = 50;
  56. OSVERSIONINFOEXW OsInfo;
  57. SYSTEM_INFO SystemInfo;
  58. PCHAR ProcessorArchName[10] = {"INTEL", "MIPS", "Alpha", "PPC", "SHX",
  59. "ARM", "IA64", "Alpha64", "MSIL", "???"};
  60. //
  61. // Suffixes for saved log files and saved assertion files
  62. // E.g., (ntfrs_0005.log)
  63. // (DebugInfo.LogFile, DebugInfo.LogFiles, LOG_FILE_SUFFIX)
  64. //
  65. #define LOG_FILE_FORMAT L"%ws_%04d%ws"
  66. #define LOG_FILE_SUFFIX L".log"
  67. #define ASSERT_FILE_SUFFIX L"_assert.log"
  68. //
  69. // Disable the generation of compressed staging files for any local changes.
  70. //
  71. BOOL DisableCompressionStageFiles;
  72. ULONG GOutLogRepeatInterval;
  73. //
  74. // Client side ldap search timeout in minutes. Reg value "Ldap Search Timeout In Minutes". Default is 10 minutes.
  75. //
  76. DWORD LdapSearchTimeoutInMinutes;
  77. //
  78. // Client side ldap_connect timeout in seconds. Reg value "Ldap Bind Timeout In Seconds". Default is 30 seconds.
  79. //
  80. DWORD LdapBindTimeoutInSeconds;
  81. SC_HANDLE
  82. FrsOpenServiceHandle(
  83. IN PTCHAR MachineName,
  84. IN PTCHAR ServiceName
  85. );
  86. VOID
  87. FrsPrintRpcStats(
  88. IN ULONG Severity,
  89. IN PNTFRSAPI_INFO Info, OPTIONAL
  90. IN DWORD Tabs
  91. );
  92. #if DBG
  93. //
  94. // Collection of debug info from the registry and the CLI
  95. //
  96. DEBUGARG DebugInfo;
  97. //
  98. // allow multiple servers on one machine
  99. //
  100. PWCHAR ServerName = NULL;
  101. PWCHAR IniFileName = NULL;
  102. GUID *ServerGuid = NULL;
  103. VOID
  104. DbgLogDisable(
  105. VOID
  106. )
  107. /*++
  108. Routine Description:
  109. Disable DPRINT log.
  110. Arguments:
  111. None.
  112. Return Value:
  113. None.
  114. --*/
  115. {
  116. #undef DEBSUB
  117. #define DEBSUB "DbgLogDisable:"
  118. DebLock();
  119. if (DebugInfo.LogFILE) {
  120. fflush(DebugInfo.LogFILE);
  121. DbgFlushInterval = DebugInfo.LogFlushInterval;
  122. fclose(DebugInfo.LogFILE);
  123. }
  124. DebugInfo.LogFILE = NULL;
  125. DebUnLock();
  126. }
  127. VOID
  128. DbgOpenLogFile(
  129. VOID
  130. )
  131. /*++
  132. Routine Description:
  133. Open the log file by creating names like ntfrs0001.log.
  134. NumFiles as a 4 digit decimal number and Suffix is like ".log".
  135. DebLock() must be held (DO NOT CALL DPRINT IN THIS FUNCTION!)
  136. Arguments:
  137. Base
  138. Suffix
  139. NumFiles
  140. Return Value:
  141. None.
  142. --*/
  143. {
  144. #undef DEBSUB
  145. #define DEBSUB "DbgOpenLogFile:"
  146. WCHAR LogPath[MAX_PATH + 1];
  147. if (DebugInfo.Disabled) {
  148. DebugInfo.LogFILE = NULL;
  149. return;
  150. }
  151. if (_snwprintf(LogPath, MAX_PATH, LOG_FILE_FORMAT, DebugInfo.LogFile,
  152. DebugInfo.LogFiles, LOG_FILE_SUFFIX) < 0) {
  153. DebugInfo.LogFILE = NULL;
  154. return;
  155. }
  156. DebugInfo.LogFILE = _wfopen(LogPath, L"wc");
  157. }
  158. VOID
  159. DbgShiftLogFiles(
  160. IN PWCHAR Base,
  161. IN PWCHAR Suffix,
  162. IN PWCHAR RemoteBase,
  163. IN ULONG NumFiles
  164. )
  165. /*++
  166. Routine Description:
  167. Shift the files through the range of log/assert file names
  168. (Base_5_Suffix -> Base_4_Suffix -> ... Base_0_Suffix
  169. DebLock() must be held (DO NOT CALL DPRINT IN THIS FUNCTION!)
  170. Arguments:
  171. Base
  172. Suffix
  173. NumFiles
  174. Return Value:
  175. None.
  176. --*/
  177. {
  178. #undef DEBSUB
  179. #define DEBSUB "DbgShiftLogFiles:"
  180. ULONG i;
  181. WCHAR FromPath[MAX_PATH + 1];
  182. WCHAR ToPath[MAX_PATH + 1];
  183. ULONGLONG Now;
  184. //
  185. // No history
  186. //
  187. if ((NumFiles < 2) || DebugInfo.Disabled) {
  188. return;
  189. }
  190. //
  191. // Save the log file as an assert file
  192. //
  193. for (i = 2; i <= NumFiles; ++i) {
  194. if (_snwprintf(ToPath, MAX_PATH, LOG_FILE_FORMAT, Base, i-1, Suffix) > 0) {
  195. if (_snwprintf(FromPath, MAX_PATH, LOG_FILE_FORMAT, Base, i, Suffix) > 0) {
  196. MoveFileEx(FromPath, ToPath, MOVEFILE_REPLACE_EXISTING |
  197. MOVEFILE_WRITE_THROUGH);
  198. }
  199. }
  200. }
  201. //
  202. // Copy the last log file to a remote share
  203. // WARN - the system time is used to create a unique file
  204. // name. This means that the remote share can
  205. // fill up!
  206. //
  207. if (!RemoteBase) {
  208. return;
  209. }
  210. GetSystemTimeAsFileTime((FILETIME *)&Now);
  211. if (_snwprintf(FromPath, MAX_PATH, LOG_FILE_FORMAT, Base, NumFiles-1, Suffix) > 0) {
  212. if (_snwprintf(ToPath,
  213. MAX_PATH,
  214. L"%ws%ws%08x%_%08x",
  215. RemoteBase,
  216. Suffix,
  217. PRINTQUAD(Now)) > 0) {
  218. CopyFileEx(FromPath, ToPath, NULL, NULL, FALSE, 0);
  219. }
  220. }
  221. }
  222. VOID
  223. DbgSendMail(
  224. IN PCHAR Subject,
  225. IN PCHAR Content
  226. )
  227. /*++
  228. Routine Description:
  229. Send mail as the default user.
  230. Arguments:
  231. Subject
  232. Message
  233. Return Value:
  234. None.
  235. --*/
  236. {
  237. #undef DEBSUB
  238. #define DEBSUB "DbgSendMail:"
  239. DWORD MStatus;
  240. //
  241. // Nobody to send mail to
  242. //
  243. if (!DebugInfo.Recipients) {
  244. return;
  245. }
  246. //
  247. // Load the mail library and find our entry points
  248. //
  249. MailLib = LoadLibrary(L"mapi32.dll");
  250. if(!HANDLE_IS_VALID(MailLib)) {
  251. DPRINT_WS(0, ":S: Load mapi32.dll failed;", GetLastError());
  252. return;
  253. }
  254. MailLogon = (LPMAPILOGON)GetProcAddress(MailLib, "MAPILogon");
  255. MailLogoff = (LPMAPILOGOFF)GetProcAddress(MailLib, "MAPILogoff");
  256. MailSend = (LPMAPISENDMAIL)GetProcAddress(MailLib, "MAPISendMail");
  257. if (!MailLogon || !MailLogoff || !MailSend) {
  258. DPRINT(0, ":S: ERROR - Could not find mail symbols in mapi32.dll\n");
  259. FreeLibrary(MailLib);
  260. return;
  261. }
  262. //
  263. // Log on with the specified profile
  264. //
  265. MStatus = MailLogon(0, DebugInfo.Profile, 0, 0, 0, &MailSession);
  266. if(MStatus) {
  267. DPRINT1_WS(0, ":S: ERROR - MailLogon failed; MStatus %d;",
  268. MStatus, GetLastError());
  269. FreeLibrary(MailLib);
  270. return;
  271. }
  272. //
  273. // Send the mail
  274. //
  275. Recips.lpszName = DebugInfo.Recipients;
  276. Message.lpszSubject = Subject;
  277. Message.lpszNoteText = Content;
  278. MStatus = MailSend(MailSession, 0, &Message, 0, 0);
  279. if(MStatus) {
  280. DPRINT1_WS(0, ":S: ERROR - MailSend failed MStatus %d;", MStatus, GetLastError());
  281. }
  282. //
  283. // Log off and free the library
  284. //
  285. MailLogoff(MailSession, 0, 0, 0);
  286. FreeLibrary(MailLib);
  287. }
  288. VOID
  289. DbgSymbolPrint(
  290. IN ULONG Severity,
  291. IN PCHAR Debsub,
  292. IN UINT LineNo,
  293. IN ULONG_PTR Addr
  294. )
  295. /*++
  296. Routine Description:
  297. Print a symbol
  298. Arguments:
  299. Addr
  300. Return Value:
  301. None.
  302. --*/
  303. {
  304. #undef DEBSUB
  305. #define DEBSUB "DbgSymbolPrint:"
  306. ULONG_PTR Displacement = 0;
  307. struct MyMymbol {
  308. IMAGEHLP_SYMBOL Symbol;
  309. char Path[MAX_PATH];
  310. } MySymbol;
  311. try {
  312. ZeroMemory(&MySymbol, sizeof(MySymbol));
  313. MySymbol.Symbol.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  314. MySymbol.Symbol.MaxNameLength = MAX_PATH;
  315. if (!SymGetSymFromAddr(ProcessHandle, Addr, &Displacement, &MySymbol.Symbol)) {
  316. DebPrint(Severity, "++ \t 0x%08x: Unknown Symbol (WStatus %s)\n",
  317. Debsub, LineNo, Addr, ErrLabelW32(GetLastError()));
  318. } else
  319. DebPrint(Severity, "++ \t 0x%08x: %s\n",
  320. Debsub, LineNo, Addr, MySymbol.Symbol.Name);
  321. } except (EXCEPTION_EXECUTE_HANDLER) {
  322. DebPrint(Severity, "++ \t 0x%08x: Unknown Symbol (WStatus %s)\n",
  323. Debsub, LineNo, Addr, ErrLabelW32(GetExceptionCode()));
  324. /* FALL THROUGH */
  325. }
  326. }
  327. VOID
  328. DbgModulePrint(
  329. IN PWCHAR Prepense,
  330. IN ULONG Addr
  331. )
  332. /*++
  333. Routine Description:
  334. Print info about a module containing Addr
  335. Arguments:
  336. Prepense - prettypring; printed at the beginning of each line
  337. Addr
  338. Return Value:
  339. None.
  340. --*/
  341. {
  342. #undef DEBSUB
  343. #define DEBSUB "DbgModulePrint:"
  344. IMAGEHLP_MODULE mi;
  345. try {
  346. ZeroMemory(&mi, sizeof(mi));
  347. mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  348. if (!SymGetModuleInfo(ProcessHandle, Addr, &mi)) {
  349. DPRINT1_WS(0, "++ %ws <unknown module;", Prepense, GetLastError());
  350. } else
  351. DPRINT2(0, "++ %ws Module is %ws\n", Prepense, mi.ModuleName);
  352. } except (EXCEPTION_EXECUTE_HANDLER) {
  353. /* FALL THROUGH */
  354. }
  355. }
  356. VOID
  357. DbgStackPrint(
  358. IN ULONG Severity,
  359. IN PCHAR Debsub,
  360. IN UINT LineNo,
  361. IN PULONG_PTR Stack,
  362. IN ULONG Depth
  363. )
  364. /*++
  365. Routine Description:
  366. Print the previously acquired stack trace.
  367. Arguments:
  368. Prepense - prettypring; printed at the beginning of each line
  369. Stack - "return PC" from each frame
  370. Depth - Only this many frames
  371. Return Value:
  372. None.
  373. --*/
  374. {
  375. #undef DEBSUB
  376. #define DEBSUB "DbgStackPrint:"
  377. ULONG i;
  378. try {
  379. for (i = 0; i < Depth && *Stack; ++i, ++Stack) {
  380. DbgSymbolPrint(Severity, Debsub, LineNo, *Stack);
  381. }
  382. } except (EXCEPTION_EXECUTE_HANDLER) {
  383. /* FALL THROUGH */
  384. }
  385. }
  386. VOID
  387. DbgStackTrace(
  388. IN PULONG_PTR Stack,
  389. IN ULONG Depth
  390. )
  391. /*++
  392. Routine Description:
  393. Trace the stack back up to Depth frames. The current frame is included.
  394. Arguments:
  395. Stack - Saves the "return PC" from each frame
  396. Depth - Only this many frames
  397. Return Value:
  398. None.
  399. --*/
  400. {
  401. #undef DEBSUB
  402. #define DEBSUB "DbgStackTrace:"
  403. ULONG WStatus;
  404. HANDLE ThreadHandle;
  405. STACKFRAME Frame;
  406. ULONG i = 0;
  407. CONTEXT Context;
  408. ULONG FrameAddr;
  409. //
  410. // I don't know how to generate a stack for an alpha, yet. So, just
  411. // to get into the build, disable the stack trace on alphas.
  412. //
  413. if (Stack) {
  414. *Stack = 0;
  415. }
  416. #if ALPHA
  417. return;
  418. #elif IA64
  419. //
  420. // Need stack dump init for IA64.
  421. //
  422. return;
  423. #else
  424. //
  425. // init
  426. //
  427. ZeroMemory(&Context, sizeof(Context));
  428. ThreadHandle = GetCurrentThread();
  429. try { try {
  430. Context.ContextFlags = CONTEXT_FULL;
  431. if (!GetThreadContext(ThreadHandle, &Context)) {
  432. DPRINT_WS(0, "++ Can't get context;", GetLastError());
  433. }
  434. //
  435. // let's start clean
  436. //
  437. ZeroMemory(&Frame, sizeof(STACKFRAME));
  438. //
  439. // from nt\private\windows\screg\winreg\server\stkwalk.c
  440. //
  441. Frame.AddrPC.Segment = 0;
  442. Frame.AddrPC.Mode = AddrModeFlat;
  443. #ifdef _M_IX86
  444. Frame.AddrFrame.Offset = Context.Ebp;
  445. Frame.AddrFrame.Mode = AddrModeFlat;
  446. Frame.AddrStack.Offset = Context.Esp;
  447. Frame.AddrStack.Mode = AddrModeFlat;
  448. Frame.AddrPC.Offset = (DWORD)Context.Eip;
  449. #elif defined(_M_MRX000)
  450. Frame.AddrPC.Offset = (DWORD)Context.Fir;
  451. #elif defined(_M_ALPHA)
  452. Frame.AddrPC.Offset = (DWORD)Context.Fir;
  453. #endif
  454. #if 0
  455. //
  456. // setup the program counter
  457. //
  458. Frame.AddrPC.Mode = AddrModeFlat;
  459. Frame.AddrPC.Segment = (WORD)Context.SegCs;
  460. Frame.AddrPC.Offset = (ULONG)Context.Eip;
  461. //
  462. // setup the frame pointer
  463. //
  464. Frame.AddrFrame.Mode = AddrModeFlat;
  465. Frame.AddrFrame.Segment = (WORD)Context.SegSs;
  466. Frame.AddrFrame.Offset = (ULONG)Context.Ebp;
  467. //
  468. // setup the stack pointer
  469. //
  470. Frame.AddrStack.Mode = AddrModeFlat;
  471. Frame.AddrStack.Segment = (WORD)Context.SegSs;
  472. Frame.AddrStack.Offset = (ULONG)Context.Esp;
  473. #endif
  474. for (i = 0; i < (Depth - 1); ++i) {
  475. if (!StackWalk(
  476. IMAGE_FILE_MACHINE_I386, // DWORD MachineType
  477. ProcessHandle, // HANDLE hProcess
  478. ThreadHandle, // HANDLE hThread
  479. &Frame, // LPSTACKFRAME StackFrame
  480. NULL, //(PVOID)&Context, // PVOID ContextRecord
  481. NULL, // PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine
  482. SymFunctionTableAccess, // PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine
  483. SymGetModuleBase, // PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine
  484. NULL)) { // PTRANSLATE_ADDRESS_ROUTINE TranslateAddress
  485. WStatus = GetLastError();
  486. //DPRINT1_WS(0, "++ Can't get stack address for level %d;", i, WStatus);
  487. break;
  488. }
  489. if (StackTraceCount-- > 0) {
  490. DPRINT1(5, "++ Frame.AddrReturn.Offset: %08x \n", Frame.AddrReturn.Offset);
  491. DbgSymbolPrint(5, DEBSUB, __LINE__, Frame.AddrReturn.Offset);
  492. //DPRINT1(5, "++ Frame.AddrPC.Offset: %08x \n", Frame.AddrPC.Offset);
  493. //DbgSymbolPrint(5, DEBSUB, __LINE__, Frame.AddrPC.Offset);
  494. }
  495. *Stack++ = Frame.AddrReturn.Offset;
  496. *Stack = 0;
  497. //
  498. // Base of stack?
  499. //
  500. if (!Frame.AddrReturn.Offset) {
  501. break;
  502. }
  503. }
  504. } except (EXCEPTION_EXECUTE_HANDLER) {
  505. /* FALL THROUGH */
  506. } } finally {
  507. FRS_CLOSE(ThreadHandle);
  508. }
  509. return;
  510. #endif ALPHA
  511. }
  512. VOID
  513. DbgPrintStackTrace(
  514. IN ULONG Severity,
  515. IN PCHAR Debsub,
  516. IN UINT LineNo
  517. )
  518. /*++
  519. Routine Description:
  520. Acquire and print the stack
  521. Arguments:
  522. Severity
  523. Debsub
  524. Return Value:
  525. None.
  526. --*/
  527. {
  528. #undef DEBSUB
  529. #define DEBSUB "DbgPrintStackTrace:"
  530. ULONG_PTR Stack[32];
  531. DbgStackTrace(Stack, ARRAY_SZ(Stack) );
  532. DbgStackPrint(Severity, Debsub, LineNo, Stack, ARRAY_SZ(Stack) );
  533. }
  534. VOID
  535. DbgStackInit(
  536. VOID
  537. )
  538. /*++
  539. Routine Description:
  540. Initialize anything necessary to get a stack trace
  541. Arguments:
  542. None.
  543. Return Value:
  544. None.
  545. --*/
  546. {
  547. #undef DEBSUB
  548. #define DEBSUB "DbgStackInit:"
  549. //
  550. // Initialize the symbol subsystem
  551. //
  552. if (!SymInitialize(ProcessHandle, NULL, FALSE)) {
  553. DPRINT_WS(0, ":S: Could not initialize symbol subsystem (imagehlp)" ,GetLastError());
  554. }
  555. //
  556. // Load our symbols
  557. //
  558. if (!SymLoadModule(ProcessHandle, NULL, DbgExePathA, "FRS", 0, 0)) {
  559. DPRINT1_WS(0, ":S: Could not load symbols for %s", DbgExePathA ,GetLastError());
  560. }
  561. //
  562. // Search path
  563. //
  564. if (!SymGetSearchPath(ProcessHandle, DbgSearchPath, MAX_PATH)) {
  565. DPRINT_WS(0, ":S: Can't get search path; error %s", GetLastError());
  566. } else {
  567. DPRINT1(0, ":S: Symbol search path is %s\n", DbgSearchPath);
  568. }
  569. }
  570. void
  571. DbgShowConfig(
  572. VOID
  573. )
  574. /*++
  575. Routine Description:
  576. Display the OS Version info and the Processor Architecture info.
  577. Arguments:
  578. None.
  579. Return Value:
  580. None.
  581. --*/
  582. {
  583. #undef DEBSUB
  584. #define DEBSUB "DbgShowConfig:"
  585. ULONG ProductType;
  586. ULONG Arch;
  587. if (DebugInfo.BuildLab != NULL) {
  588. DPRINT1(0, ":H: BuildLab : %s\n", DebugInfo.BuildLab);
  589. }
  590. DPRINT4(0, ":H: OS Version %d.%d (%d) - %w\n",
  591. OsInfo.dwMajorVersion,OsInfo.dwMinorVersion,OsInfo.dwBuildNumber,OsInfo.szCSDVersion);
  592. ProductType = (ULONG) OsInfo.wProductType;
  593. DPRINT4(0, ":H: SP (%hd.%hd) SM: 0x%04hx PT: 0x%02x\n",
  594. OsInfo.wServicePackMajor,OsInfo.wServicePackMinor,OsInfo.wSuiteMask, ProductType);
  595. Arch = SystemInfo.wProcessorArchitecture;
  596. if (Arch >= ARRAY_SZ(ProcessorArchName)) {
  597. Arch = ARRAY_SZ(ProcessorArchName)-1;
  598. }
  599. DPRINT5(0, ":H: Processor: %s Level: 0x%04hx Revision: 0x%04hx Processor num/mask: %d/%08x\n",
  600. ProcessorArchName[Arch], SystemInfo.wProcessorLevel,
  601. SystemInfo.wProcessorRevision, SystemInfo.dwNumberOfProcessors,
  602. SystemInfo.dwActiveProcessorMask);
  603. }
  604. VOID
  605. DbgCaptureThreadInfo(
  606. PWCHAR ArgName,
  607. PTHREAD_START_ROUTINE EntryPoint
  608. )
  609. /*++
  610. Routine Description:
  611. Search the KnownThreadArray for an entry with a matching name. If not found,
  612. Search the FRS Thread list for the thread with the matching entry point.
  613. If found make an entry in the KnownThreadArray so it is available when
  614. printing out the debug log header.
  615. Arguments:
  616. ArgName -- Printable name of thread.
  617. Main -- Entry point of thread.
  618. Return Value:
  619. None.
  620. --*/
  621. {
  622. #undef DEBSUB
  623. #define DEBSUB "DbgCaptureThreadInfo:"
  624. PFRS_THREAD FrsThread;
  625. ULONG i;
  626. if (ArgName == NULL) {
  627. return;
  628. }
  629. for (i = 0; i < ARRAY_SZ(KnownThreadArray); i++) {
  630. //
  631. // Any room left?
  632. //
  633. if ((KnownThreadArray[i].Name == NULL) ||
  634. (WSTR_EQ(ArgName, KnownThreadArray[i].Name))) {
  635. FrsThread = ThSupGetThread(EntryPoint);
  636. if (FrsThread == NULL) {
  637. return;
  638. }
  639. KnownThreadArray[i].EntryPoint = FrsThread->Main;
  640. KnownThreadArray[i].Id = FrsThread->Id;
  641. KnownThreadArray[i].Name = ArgName;
  642. ThSupReleaseRef(FrsThread);
  643. break;
  644. }
  645. }
  646. }
  647. VOID
  648. DbgCaptureThreadInfo2(
  649. PWCHAR ArgName,
  650. PTHREAD_START_ROUTINE EntryPoint,
  651. ULONG ThreadId
  652. )
  653. /*++
  654. Routine Description:
  655. Search the KnownThreadArray for an entry with a matching name.
  656. If found make an entry in the KnownThreadArray so it is available when
  657. printing out the debug log header.
  658. Arguments:
  659. ArgName -- Printable name of thread.
  660. Main -- Entry point of thread.
  661. ThreadId - Thread ID of the thread to add to the list.
  662. Return Value:
  663. None.
  664. --*/
  665. {
  666. #undef DEBSUB
  667. #define DEBSUB "DbgCaptureThreadInfo2:"
  668. ULONG i;
  669. if (ArgName == NULL) {
  670. return;
  671. }
  672. for (i = 0; i < ARRAY_SZ(KnownThreadArray); i++) {
  673. //
  674. // Any room left or
  675. // See if we already have this one and update the thread ID if so.
  676. // If it was a cmd server thread it may have exited after timeout.
  677. //
  678. if ((KnownThreadArray[i].Name == NULL) ||
  679. (WSTR_EQ(ArgName, KnownThreadArray[i].Name))) {
  680. KnownThreadArray[i].EntryPoint = EntryPoint;
  681. KnownThreadArray[i].Id = ThreadId;
  682. KnownThreadArray[i].Name = ArgName;
  683. break;
  684. }
  685. }
  686. }
  687. VOID
  688. DbgPrintThreadIds(
  689. IN ULONG Severity
  690. )
  691. /*++
  692. Routine Description:
  693. Print the known thread IDs.
  694. Arguments:
  695. Severity
  696. Return Value:
  697. None.
  698. --*/
  699. {
  700. #undef DEBSUB
  701. #define DEBSUB "DbgPrintThreadIds:"
  702. ULONG i;
  703. DPRINT(Severity, ":H: Known thread IDs -\n");
  704. //
  705. // Dump the known thread IDs.
  706. //
  707. for (i = 0; i < ARRAY_SZ(KnownThreadArray); i++) {
  708. if (KnownThreadArray[i].Name != NULL) {
  709. DPRINT2(Severity, ":H: %-20ws : %d\n",
  710. KnownThreadArray[i].Name, KnownThreadArray[i].Id);
  711. }
  712. }
  713. }
  714. VOID
  715. DbgPrintInfo(
  716. IN ULONG Severity
  717. )
  718. /*++
  719. Routine Description:
  720. Print the debug info struct
  721. Arguments:
  722. Severity
  723. Return Value:
  724. None.
  725. --*/
  726. {
  727. #undef DEBSUB
  728. #define DEBSUB "DbgPrintInfo:"
  729. WCHAR TimeBuf[MAX_PATH];
  730. WCHAR Uname[MAX_PATH + 1];
  731. ULONG Unamesize = MAX_PATH + 1;
  732. ULONG i;
  733. //
  734. // Username
  735. //
  736. if (!GetUserName(Uname, &Unamesize)) {
  737. Uname[0] = L'\0';
  738. }
  739. TimeBuf[0] = L'\0';
  740. GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, TimeBuf, MAX_PATH);
  741. DPRINT3(Severity, ":H: Service running on %ws as %ws at %ws\n",
  742. ComputerName, Uname, TimeBuf);
  743. DPRINT(Severity, "\n");
  744. DPRINT(Severity, ":H: ***** COMPILE INFORMATION:\n");
  745. DPRINT1(Severity, ":H: \tModule %s\n", NtFrsModule);
  746. DPRINT2(Severity, ":H: \tCompile Date %s %s\n", NtFrsDate, NtFrsTime);
  747. i = 0;
  748. while (LatestChanges[i] != NULL) {
  749. DPRINT1(Severity, ":H: %s\n", LatestChanges[i]);
  750. i++;
  751. }
  752. DPRINT(Severity, "\n");
  753. DbgShowConfig();
  754. DPRINT(Severity, "\n");
  755. DPRINT(Severity, ":H: ***** DEBUG INFORMATION:\n");
  756. DPRINT1(Severity, ":H: Total Log Lines: %d\n", DebugInfo.TotalLogLines);
  757. DPRINT1(Severity, ":H: Severity : %d\n", DebugInfo.Severity);
  758. DPRINT1(Severity, ":H: Log Severity : %d\n", DebugInfo.LogSeverity);
  759. DPRINT1(Severity, ":H: Log Flush Int. : %d\n", DebugInfo.LogFlushInterval);
  760. DPRINT1(Severity, ":H: Systems : %ws\n", DebugInfo.Systems);
  761. DPRINT1(Severity, ":H: Thread Id : %d\n", DebugInfo.ThreadId);
  762. DPRINT1(Severity, ":H: Disabled : %s\n", (DebugInfo.Disabled) ? "TRUE" : "FALSE");
  763. DPRINT1(Severity, ":H: Suppress : %s\n", (DebugInfo.Suppress) ? "TRUE" : "FALSE");
  764. DPRINT1(Severity, ":H: Log File : %ws\n", DebugInfo.LogFile);
  765. DPRINT1(Severity, ":H: Max Log Lines : %d\n", DebugInfo.MaxLogLines);
  766. DPRINT1(Severity, ":H: Log Lines : %d\n", DebugInfo.LogLines);
  767. DPRINT1(Severity, ":H: Interval : %d\n", DebugInfo.Interval);
  768. DPRINT1(Severity, ":H: TestFid : %d\n", DebugInfo.TestFid);
  769. DPRINT1(Severity, ":H: Recipients : %s\n", DebugInfo.Recipients);
  770. DPRINT1(Severity, ":H: Profile : %s\n", DebugInfo.Profile);
  771. DPRINT1(Severity, ":H: Assert Share : %ws\n", DebugInfo.AssertShare);
  772. DPRINT1(Severity, ":H: Copy Logs : %s\n", (DebugInfo.CopyLogs) ? "TRUE" : "FALSE");
  773. DPRINT1(Severity, ":H: Assert Files : %d\n", DebugInfo.AssertFiles);
  774. DPRINT1(Severity, ":H: Log Files : %d\n", DebugInfo.LogFiles);
  775. DPRINT1(Severity, ":H: UnjoinTrigger : %d\n", DebugInfo.UnjoinTrigger);
  776. DPRINT1(Severity, ":H: Force VvJoin : %s\n", (DebugInfo.ForceVvJoin) ? "TRUE" : "FALSE");
  777. DPRINT1(Severity, ":H: Check Mem : %s\n", (DebugInfo.Mem) ? "TRUE" : "FALSE");
  778. DPRINT1(Severity, ":H: Compact Mem : %s\n", (DebugInfo.MemCompact) ? "TRUE" : "FALSE");
  779. DPRINT1(Severity, ":H: Check Queues : %s\n", (DebugInfo.Queues) ? "TRUE" : "FALSE");
  780. if (DebugInfo.AssertSeconds) {
  781. DPRINT1(Severity, ":H: Assert Seconds : Assert after %d seconds\n",
  782. DebugInfo.AssertSeconds);
  783. } else {
  784. DPRINT(Severity, ":H: Assert Seconds : Don't force an assert\n");
  785. }
  786. if (DebugInfo.RestartSeconds) {
  787. DPRINT1(Severity, ":H: Restart Seconds: Restart if assert after "
  788. "%d seconds\n", DebugInfo.RestartSeconds);
  789. } else {
  790. DPRINT(Severity, ":H: Restart Seconds: Don't Restart\n");
  791. }
  792. DPRINT1(Severity, ":H: Restart : %s\n", (DebugInfo.Restart) ? "TRUE" : "FALSE");
  793. DPRINT1(Severity, ":H: VvJoinTests : %s\n", (DebugInfo.VvJoinTests) ? "TRUE" : "FALSE");
  794. // DPRINT1(Severity, ":H: Command Line : %ws\n", DebugInfo.CommandLine);
  795. DPRINT1(Severity, ":H: FetchRetryTrigger : %d\n", DebugInfo.FetchRetryTrigger);
  796. DPRINT1(Severity, ":H: FetchRetryReset : %d\n", DebugInfo.FetchRetryReset);
  797. DPRINT1(Severity, ":H: FetchRetryResetInc : %d\n", DebugInfo.FetchRetryInc);
  798. DPRINT(Severity, "\n");
  799. DbgPrintThreadIds(Severity);
  800. DEBUG_FLUSH();
  801. }
  802. VOID
  803. DbgPrintAllStats(
  804. VOID
  805. )
  806. /*++
  807. Routine Description:
  808. Print the stats we know about
  809. Arguments:
  810. None.
  811. Return Value:
  812. None.
  813. --*/
  814. {
  815. #undef DEBSUB
  816. #define DEBSUB "DbgPrintAllStats:"
  817. DbgPrintInfo(DebugInfo.LogSeverity);
  818. FrsPrintAllocStats(DebugInfo.LogSeverity, NULL, 0);
  819. FrsPrintRpcStats(DebugInfo.LogSeverity, NULL, 0);
  820. }
  821. VOID
  822. DbgFlush(
  823. VOID
  824. )
  825. /*++
  826. Routine Description:
  827. Flush the output buffers
  828. Arguments:
  829. None.
  830. Return Value:
  831. None.
  832. --*/
  833. {
  834. #undef DEBSUB
  835. #define DEBSUB "DbgFlush:"
  836. DebLock();
  837. if (DebugInfo.LogFILE) {
  838. fflush(DebugInfo.LogFILE);
  839. DbgFlushInterval = DebugInfo.LogFlushInterval;
  840. }
  841. DebUnLock();
  842. }
  843. VOID
  844. DbgStartService(
  845. IN PWCHAR ServiceName
  846. )
  847. /*++
  848. Routine Description:
  849. Start a service on this machine.
  850. Arguments:
  851. ServiceName - the service to start
  852. Return Value:
  853. None.
  854. --*/
  855. {
  856. #undef DEBSUB
  857. #define DEBSUB "DbgStartService:"
  858. SC_HANDLE ServiceHandle;
  859. //
  860. // Open the service.
  861. //
  862. ServiceHandle = FrsOpenServiceHandle(NULL, ServiceName);
  863. if (!HANDLE_IS_VALID(ServiceHandle)) {
  864. DPRINT1(0, ":S: Couldn't open service %ws\n", ServiceName);
  865. return;
  866. }
  867. //
  868. // Start the service
  869. //
  870. if (!StartService(ServiceHandle, 0, NULL)) {
  871. DPRINT1_WS(0, ":S: Couldn't start %ws;", ServiceName, GetLastError());
  872. CloseServiceHandle(ServiceHandle);
  873. return;
  874. }
  875. CloseServiceHandle(ServiceHandle);
  876. DPRINT1(4, ":S: Started %ws\n", ServiceName);
  877. }
  878. VOID
  879. DbgStopService(
  880. IN PWCHAR ServiceName
  881. )
  882. /*++
  883. Routine Description:
  884. Stop a service on this machine.
  885. Arguments:
  886. ServiceName - the service to stop
  887. Return Value:
  888. None.
  889. --*/
  890. {
  891. #undef DEBSUB
  892. #define DEBSUB "DbgStopService:"
  893. BOOL Status;
  894. SC_HANDLE ServiceHandle;
  895. SERVICE_STATUS ServiceStatus;
  896. //
  897. // Open the service.
  898. //
  899. ServiceHandle = FrsOpenServiceHandle(NULL, ServiceName);
  900. if (!HANDLE_IS_VALID(ServiceHandle)) {
  901. DPRINT1(0, ":S: Couldn't stop service %ws\n", ServiceName);
  902. return;
  903. }
  904. //
  905. // Stop the service
  906. //
  907. Status = ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
  908. if (!WIN_SUCCESS(Status)) {
  909. DPRINT1_WS(0, ":S: Couldn't stop %ws;", ServiceName, GetLastError());
  910. CloseServiceHandle(ServiceHandle);
  911. return;
  912. }
  913. CloseServiceHandle(ServiceHandle);
  914. DPRINT1(4, ":S: Stopped %ws\n", ServiceName);
  915. }
  916. ULONG
  917. DbgForceAssert(
  918. IN PVOID Ignored
  919. )
  920. /*++
  921. Routine Description:
  922. Force an assert after some seconds
  923. Arguments:
  924. Ignored
  925. Return Value:
  926. ERROR_SUCCESS
  927. --*/
  928. {
  929. #undef DEBSUB
  930. #define DEBSUB "DbgForceAssert:"
  931. BOOL ForcingAssert = TRUE;
  932. //
  933. // Wait for a shutdown event
  934. //
  935. WaitForSingleObject(ShutDownEvent, DebugInfo.AssertSeconds * 1000);
  936. if (!FrsIsShuttingDown) {
  937. DPRINT(0, ":S: FORCING ASSERT\n");
  938. FRS_ASSERT(!ForcingAssert);
  939. }
  940. return STATUS_SUCCESS;
  941. }
  942. VOID
  943. DbgQueryLogParams(
  944. )
  945. /*++
  946. Routine Description:
  947. Read the registry for new values for the logging params.
  948. Arguments:
  949. Return Value:
  950. None.
  951. --*/
  952. {
  953. #undef DEBSUB
  954. #define DEBSUB "DbgQueryLogParams:"
  955. PWCHAR WStr, WStr1;
  956. PCHAR AStr;
  957. PWCHAR NewLogDirStr = NULL;
  958. PWCHAR File;
  959. DWORD WStatus;
  960. DWORD NewDisabled;
  961. BOOL OpenNewLog = FALSE;
  962. ULARGE_INTEGER FreeBytes;
  963. ULARGE_INTEGER TotalBytes;
  964. //
  965. // Get new state before taking debug lock since function does DPRINTs.
  966. //
  967. CfgRegReadDWord(FKC_DEBUG_DISABLE, NULL, 0, &NewDisabled);
  968. //
  969. // Check for a change in Disable Debug
  970. //
  971. DebLock();
  972. if ((BOOL)NewDisabled != DebugInfo.Disabled) {
  973. DebugInfo.Disabled = NewDisabled;
  974. if (DebugInfo.Disabled) {
  975. //
  976. // Stop logging.
  977. //
  978. if (DebugInfo.LogFILE) {
  979. fflush(DebugInfo.LogFILE);
  980. DbgFlushInterval = DebugInfo.LogFlushInterval;
  981. fclose(DebugInfo.LogFILE);
  982. }
  983. DebugInfo.LogFILE = NULL;
  984. } else {
  985. //
  986. // Start logging.
  987. //
  988. OpenNewLog = TRUE;
  989. }
  990. }
  991. DebUnLock();
  992. //
  993. // Quit now if logging is disabled.
  994. //
  995. if (DebugInfo.Disabled) {
  996. return;
  997. }
  998. //
  999. // Log File Directory (only if not running multiple servers on one machine)
  1000. //
  1001. if (ServerName == NULL) {
  1002. CfgRegReadString(FKC_DEBUG_LOG_FILE, NULL, 0, &NewLogDirStr);
  1003. if (NewLogDirStr != NULL) {
  1004. if ((DebugInfo.LogDir == NULL) ||
  1005. WSTR_NE(NewLogDirStr, DebugInfo.LogDir)) {
  1006. OpenNewLog = TRUE;
  1007. } else {
  1008. NewLogDirStr = FrsFree(NewLogDirStr);
  1009. }
  1010. }
  1011. }
  1012. //
  1013. // Number of log files
  1014. //
  1015. CfgRegReadDWord(FKC_DEBUG_LOG_FILES, NULL, 0, &DebugInfo.LogFiles);
  1016. //
  1017. // Flush the trace log after every n lines.
  1018. //
  1019. CfgRegReadDWord(FKC_DEBUG_LOG_FLUSH_INTERVAL, NULL, 0, &DebugInfo.LogFlushInterval);
  1020. //
  1021. // Severity for console print.
  1022. //
  1023. CfgRegReadDWord(FKC_DEBUG_SEVERITY, NULL, 0, &DebugInfo.Severity);
  1024. //
  1025. // Log Severity
  1026. //
  1027. CfgRegReadDWord(FKC_DEBUG_LOG_SEVERITY, NULL, 0, &DebugInfo.LogSeverity);
  1028. //
  1029. // Systems - selected list of functions to trace. trace all if NULL.
  1030. //
  1031. CfgRegReadString(FKC_DEBUG_SYSTEMS, NULL, 0, &WStr);
  1032. if (WStr != NULL) {
  1033. AStr = DebugInfo.Systems;
  1034. DebLock();
  1035. DebugInfo.Systems = (wcslen(WStr)) ? FrsWtoA(WStr) : NULL;
  1036. DebUnLock();
  1037. WStr = FrsFree(WStr);
  1038. AStr = FrsFree(AStr);
  1039. }
  1040. //
  1041. // Maximum Log Messages
  1042. //
  1043. CfgRegReadDWord(FKC_DEBUG_MAX_LOG, NULL, 0, &DebugInfo.MaxLogLines);
  1044. //
  1045. // Debugger serial line Print (assume suppress so no dprints leak out)
  1046. //
  1047. DebugInfo.Suppress = TRUE;
  1048. CfgRegReadDWord(FKC_DEBUG_SUPPRESS, NULL, 0, &DebugInfo.Suppress);
  1049. //
  1050. // Enable break into debugger if present.
  1051. //
  1052. CfgRegReadDWord(FKC_DEBUG_BREAK, NULL, 0, &DebugInfo.Break);
  1053. //
  1054. // Open a new log if logging was just turned on or if we were.
  1055. // having trouble logging due to errors like out of disk space.
  1056. // Save old log files and open a new log file.
  1057. //
  1058. if ((OpenNewLog || DebugInfo.LogFILE == NULL) &&
  1059. ((DebugInfo.LogFile != NULL) || (NewLogDirStr != NULL))) {
  1060. WStr = DebugInfo.LogFile;
  1061. WStr1 = DebugInfo.LogDir;
  1062. DebLock();
  1063. if (NewLogDirStr != NULL) {
  1064. //
  1065. // Add the filename prefix to the end of the dir path.
  1066. //
  1067. DebugInfo.LogDir = NewLogDirStr;
  1068. DebugInfo.LogFile = FrsWcsCat(NewLogDirStr, NTFRS_DBG_LOG_FILE);
  1069. }
  1070. //
  1071. // Create new debug directory
  1072. //
  1073. if (!CreateDirectory(DebugInfo.LogDir, NULL)) {
  1074. WStatus = GetLastError();
  1075. if (!WIN_ALREADY_EXISTS(WStatus)) {
  1076. DebugInfo.LogFile = FrsFree(DebugInfo.LogFile);
  1077. DebugInfo.LogDir = FrsFree(DebugInfo.LogDir);
  1078. }
  1079. }
  1080. if (DebugInfo.LogFile != NULL) {
  1081. if (DebugInfo.LogFILE) {
  1082. fclose(DebugInfo.LogFILE);
  1083. }
  1084. DbgShiftLogFiles(DebugInfo.LogFile,
  1085. LOG_FILE_SUFFIX,
  1086. (DebugInfo.CopyLogs) ? DebugInfo.AssertShare : NULL,
  1087. DebugInfo.LogFiles);
  1088. DbgOpenLogFile();
  1089. }
  1090. DebUnLock();
  1091. if (NewLogDirStr != NULL) {
  1092. WStr = FrsFree(WStr);
  1093. WStr1 = FrsFree(WStr1);
  1094. }
  1095. }
  1096. //
  1097. // Raise a eventlog message if there isn't enough disk space on the logging volume
  1098. // to accomodate all the log files.
  1099. //
  1100. if (DebugInfo.LogDir != NULL) {
  1101. FreeBytes.QuadPart = QUADZERO;
  1102. TotalBytes.QuadPart = QUADZERO;
  1103. if (GetDiskFreeSpaceEx(DebugInfo.LogDir,
  1104. &FreeBytes,
  1105. &TotalBytes,
  1106. NULL)) {
  1107. //
  1108. // Complain if we have less than 10 MB free.
  1109. //
  1110. if (FreeBytes.QuadPart < (10 * 1000 * 1000)) {
  1111. EPRINT1(EVENT_FRS_LOG_SPACE, DebugInfo.LogDir);
  1112. }
  1113. }
  1114. }
  1115. }
  1116. VOID
  1117. DbgQueryDynamicConfigParams(
  1118. )
  1119. /*++
  1120. Routine Description:
  1121. Read the registry for new values for config params that can change
  1122. while service is running.
  1123. Arguments:
  1124. Return Value:
  1125. None.
  1126. --*/
  1127. {
  1128. #undef DEBSUB
  1129. #define DEBSUB "DbgQueryDynamicConfigParams:"
  1130. DWORD CompressStagingFiles = 1;
  1131. //
  1132. // Pick up new debug logging related parameters.
  1133. //
  1134. DbgQueryLogParams();
  1135. //
  1136. // Read the new value for the compression parameter.
  1137. //
  1138. CfgRegReadDWord(FKC_DISABLE_COMPRESSION_STAGING_FILE, NULL, 0, &DisableCompressionStageFiles);
  1139. CfgRegReadDWord(FKC_COMPRESS_STAGING_FILES, NULL, 0, &CompressStagingFiles);
  1140. //
  1141. // Note: The key FKC_DISABLE_COMPRESSION_STAGING_FILE will be removed and
  1142. // replaced by FKC_COMPRESS_STAGING_FILES. For now look at both and use the
  1143. // new key as an override.
  1144. //
  1145. if (CompressStagingFiles != 0) {
  1146. DisableCompressionStageFiles = FALSE;
  1147. } else {
  1148. DisableCompressionStageFiles = TRUE;
  1149. }
  1150. //
  1151. // Pick up the Outlog file repeat interval.
  1152. //
  1153. CfgRegReadDWord(FKC_OUTLOG_REPEAT_INTERVAL, NULL, 0, &GOutLogRepeatInterval);
  1154. }
  1155. VOID
  1156. DbgInitLogTraceFile(
  1157. IN LONG argc,
  1158. IN PWCHAR *argv
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. Initialize enough of the debug subsystem to start the log file.
  1163. The rest can wait until we have synced up with the service controller.
  1164. Arguments:
  1165. argc - from main
  1166. argv - from main; in wide char format
  1167. Return Value:
  1168. None.
  1169. --*/
  1170. {
  1171. #undef DEBSUB
  1172. #define DEBSUB "DbgInitLogTraceFile:"
  1173. PWCHAR WStr;
  1174. PWCHAR File;
  1175. DWORD WStatus;
  1176. InitializeCriticalSection(&DebugInfo.Lock);
  1177. InitializeCriticalSection(&DebugInfo.DbsOutOfSpaceLock);
  1178. //
  1179. // Configure initial debug params until we read registry.
  1180. //
  1181. DebugInfo.AssertSeconds = 0;
  1182. DebugInfo.RestartSeconds = 0;
  1183. DebugInfo.Queues = 0;
  1184. DebugInfo.DbsOutOfSpace = DBG_DBS_OUT_OF_SPACE_OP_NONE;
  1185. DebugInfo.DbsOutOfSpaceTrigger = 0;
  1186. //
  1187. // Get the logging config params.
  1188. // Registry overrides defaults and CLI overrides registry.
  1189. //
  1190. //
  1191. // Disable Debug
  1192. //
  1193. CfgRegReadDWord(FKC_DEBUG_DISABLE, NULL, 0, &DebugInfo.Disabled);
  1194. if (FrsSearchArgv(argc, argv, L"disabledebug", NULL)) {
  1195. DebugInfo.Disabled = TRUE;
  1196. }
  1197. //
  1198. // Log File (really the dir containing the log files)
  1199. //
  1200. FrsSearchArgv(argc, argv, L"logfile", &DebugInfo.LogDir);
  1201. if (DebugInfo.LogDir == NULL) {
  1202. CfgRegReadString(FKC_DEBUG_LOG_FILE, NULL, 0, &DebugInfo.LogDir);
  1203. }
  1204. if (DebugInfo.LogDir != NULL) {
  1205. //
  1206. // Add the filename prefix to the end of the dir path.
  1207. //
  1208. DebugInfo.LogFile = FrsWcsCat(DebugInfo.LogDir, NTFRS_DBG_LOG_FILE);
  1209. } else {
  1210. DebugInfo.LogFile = NULL;
  1211. }
  1212. //
  1213. // Share for copying log/assert files
  1214. //
  1215. FrsSearchArgv(argc, argv, L"assertshare", &DebugInfo.AssertShare);
  1216. if (DebugInfo.AssertShare == NULL) {
  1217. CfgRegReadString(FKC_DEBUG_ASSERT_SHARE, NULL, 0, &DebugInfo.AssertShare);
  1218. }
  1219. //
  1220. // Copy log files into assert share
  1221. //
  1222. CfgRegReadDWord(FKC_DEBUG_COPY_LOG_FILES, NULL, 0, &DebugInfo.CopyLogs);
  1223. //
  1224. // Number of assert files
  1225. //
  1226. if (!FrsSearchArgvDWord(argc, argv, L"assertfiles", &DebugInfo.AssertFiles)) {
  1227. CfgRegReadDWord(FKC_DEBUG_ASSERT_FILES, NULL, 0, &DebugInfo.AssertFiles);
  1228. }
  1229. //
  1230. // Number of log files
  1231. //
  1232. if (!FrsSearchArgvDWord(argc, argv, L"logfiles", &DebugInfo.LogFiles)) {
  1233. CfgRegReadDWord(FKC_DEBUG_LOG_FILES, NULL, 0, &DebugInfo.LogFiles);
  1234. }
  1235. //
  1236. // Flush the trace log after every n lines.
  1237. //
  1238. if (!FrsSearchArgvDWord(argc, argv, L"logflushinterval", &DebugInfo.LogFlushInterval)) {
  1239. CfgRegReadDWord(FKC_DEBUG_LOG_FLUSH_INTERVAL, NULL, 0, &DebugInfo.LogFlushInterval);
  1240. }
  1241. //
  1242. // Create the dir path to the share where Assert Logs are copied.
  1243. //
  1244. if ((DebugInfo.AssertShare != NULL) &&
  1245. wcslen(DebugInfo.AssertShare) && wcslen(ComputerName)) {
  1246. WStr = FrsWcsCat3(DebugInfo.AssertShare, L"\\", ComputerName);
  1247. FrsFree(DebugInfo.AssertShare);
  1248. DebugInfo.AssertShare = WStr;
  1249. WStr = NULL;
  1250. }
  1251. //
  1252. // Severity for console print.
  1253. //
  1254. if (!FrsSearchArgvDWord(argc, argv, L"severity", &DebugInfo.Severity)) {
  1255. CfgRegReadDWord(FKC_DEBUG_SEVERITY, NULL, 0, &DebugInfo.Severity);
  1256. }
  1257. //
  1258. // Log Severity
  1259. //
  1260. if (!FrsSearchArgvDWord(argc, argv, L"logseverity", &DebugInfo.LogSeverity)) {
  1261. CfgRegReadDWord(FKC_DEBUG_LOG_SEVERITY, NULL, 0, &DebugInfo.LogSeverity);
  1262. }
  1263. //
  1264. // Systems - selected list of functions to trace. trace all if NULL.
  1265. //
  1266. DebugInfo.Systems = NULL;
  1267. if (!FrsSearchArgv(argc, argv, L"systems", &WStr)) {
  1268. CfgRegReadString(FKC_DEBUG_SYSTEMS, NULL, 0, &WStr);
  1269. }
  1270. if (WStr != NULL) {
  1271. DebugInfo.Systems = (wcslen(WStr)) ? FrsWtoA(WStr) : NULL;
  1272. WStr = FrsFree(WStr);
  1273. }
  1274. //
  1275. // Maximum Log Messages
  1276. //
  1277. DebugInfo.MaxLogLines = DEFAULT_DEBUG_MAX_LOG;
  1278. if (!FrsSearchArgvDWord(argc, argv, L"maxloglines", &DebugInfo.MaxLogLines)) {
  1279. CfgRegReadDWord(FKC_DEBUG_MAX_LOG, NULL, 0, &DebugInfo.MaxLogLines);
  1280. }
  1281. //
  1282. // Debugger serial line Print (assume suppress so no dprints leak out)
  1283. //
  1284. DebugInfo.Suppress = TRUE;
  1285. if (!FrsSearchArgv(argc, argv, L"debuggerprint", NULL)) {
  1286. CfgRegReadDWord(FKC_DEBUG_SUPPRESS, NULL, 0, &DebugInfo.Suppress);
  1287. } else {
  1288. DebugInfo.Suppress = FALSE;
  1289. }
  1290. //
  1291. // Enable break into debugger if present.
  1292. //
  1293. DebugInfo.Break = TRUE;
  1294. if (!FrsSearchArgv(argc, argv, L"break", NULL)) {
  1295. CfgRegReadDWord(FKC_DEBUG_BREAK, NULL, 0, &DebugInfo.Break);
  1296. }
  1297. //
  1298. // Turn on debug log if desired.
  1299. // Save old log files and open a new log file.
  1300. //
  1301. if (DebugInfo.LogFile != NULL) {
  1302. //
  1303. // Create the debug directory
  1304. //
  1305. if (!CreateDirectory(DebugInfo.LogDir, NULL)) {
  1306. WStatus = GetLastError();
  1307. if (!WIN_ALREADY_EXISTS(WStatus)) {
  1308. //
  1309. // Need some way to report the following.
  1310. //
  1311. //DPRINT1_WS(0, ":S: CreateDirectory(Logfile) %ws -- failed;",
  1312. // DebugInfo.LogFile, WStatus);
  1313. DebugInfo.LogFile = FrsFree(DebugInfo.LogFile);
  1314. DebugInfo.LogDir = FrsFree(DebugInfo.LogDir);
  1315. }
  1316. }
  1317. if (DebugInfo.LogFile != NULL) {
  1318. DbgShiftLogFiles(DebugInfo.LogFile,
  1319. LOG_FILE_SUFFIX,
  1320. (DebugInfo.CopyLogs) ? DebugInfo.AssertShare : NULL,
  1321. DebugInfo.LogFiles);
  1322. DbgOpenLogFile();
  1323. }
  1324. }
  1325. //
  1326. // Executable's full path for symbols.
  1327. //
  1328. DbgExePathW[0] = L'\0';
  1329. if (GetFullPathNameW(argv[0], MAX_PATH-4, DbgExePathW, &File) == 0) {
  1330. DPRINT1(0, ":S: Could not get the full pathname for %ws\n", argv[0]);
  1331. }
  1332. if (!wcsstr(DbgExePathW, L".exe")) {
  1333. wcscat(DbgExePathW, L".exe");
  1334. }
  1335. DPRINT1(0, ":S: Full pathname for %ws\n", DbgExePathW);
  1336. if (_snprintf(DbgExePathA, MAX_PATH, "%ws", DbgExePathW) < 0) {
  1337. DPRINT1(0, ":S: Image path too long to get symbols for traceback: %ws\n", DbgExePathW);
  1338. return;
  1339. }
  1340. //
  1341. // Init the symbol support for stack traceback if we are tracking mem allocs.
  1342. // Don't use the memory subsystem until symbols are enabled
  1343. //
  1344. if (DebugInfo.Mem) {
  1345. DbgStackInit();
  1346. }
  1347. }
  1348. VOID
  1349. DbgMustInit(
  1350. IN LONG argc,
  1351. IN PWCHAR *argv
  1352. )
  1353. /*++
  1354. Routine Description:
  1355. Initialize the debug subsystem
  1356. Arguments:
  1357. argc - from main
  1358. argv - from main; in wide char format
  1359. Return Value:
  1360. None.
  1361. --*/
  1362. {
  1363. #undef DEBSUB
  1364. #define DEBSUB "DbgMustInit:"
  1365. ULONG Len;
  1366. LONG i;
  1367. PWCHAR Wcs;
  1368. PWCHAR WStr;
  1369. DWORD WStatus;
  1370. //
  1371. // Init the known thread array.
  1372. //
  1373. for (i = 0; i < ARRAY_SZ(KnownThreadArray); i++) {
  1374. KnownThreadArray[i].Name = NULL;
  1375. }
  1376. DbgCaptureThreadInfo2(L"First", NULL, GetCurrentThreadId());
  1377. //
  1378. // Get some config info for the debug log header.
  1379. //
  1380. OsInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
  1381. GetVersionExW((POSVERSIONINFOW) &OsInfo);
  1382. GetSystemInfo(&SystemInfo);
  1383. //
  1384. // When not running as a service, the exe will restart itself
  1385. // after an assertion failure. When running as a service, the
  1386. // service controller will restart the service.
  1387. //
  1388. // Rebuild the command line for restart.
  1389. //
  1390. if (!RunningAsAService) {
  1391. #define RESTART_PARAM L" /restart"
  1392. Len = wcslen(RESTART_PARAM) + (2 * sizeof(WCHAR));
  1393. for (i = 0; i < argc; ++i) {
  1394. Len += wcslen(argv[i]) + sizeof(WCHAR);
  1395. }
  1396. DebugInfo.CommandLine = FrsAlloc(Len * sizeof(WCHAR));
  1397. for (i = 0; i < argc; ++i) {
  1398. //
  1399. // Give our parent process time to die so that it will
  1400. // release its handles on the journal, database, ...
  1401. //
  1402. if (wcsstr(argv[i], L"restart")) {
  1403. Sleep(5 * 1000);
  1404. continue;
  1405. }
  1406. wcscat(DebugInfo.CommandLine, argv[i]);
  1407. wcscat(DebugInfo.CommandLine, L" ");
  1408. }
  1409. wcscat(DebugInfo.CommandLine, RESTART_PARAM);
  1410. }
  1411. //
  1412. // Get rest of config params. Command line takes precedence over registrr.
  1413. //
  1414. //
  1415. // Restart the service iff it has asserted and has run at least this long
  1416. // to avoid assert loops.
  1417. //
  1418. if (!FrsSearchArgvDWord(argc, argv, L"restartseconds", &DebugInfo.RestartSeconds)) {
  1419. CfgRegReadDWord(FKC_DEBUG_RESTART_SECONDS, NULL, 0, &DebugInfo.RestartSeconds);
  1420. }
  1421. //
  1422. // Sendmail recipient (future)
  1423. //
  1424. DebugInfo.Recipients = NULL;
  1425. CfgRegReadString(FKC_DEBUG_RECIPIENTS, NULL, 0, &WStr);
  1426. if (WStr != NULL) {
  1427. DebugInfo.Recipients = (wcslen(WStr)) ? FrsWtoA(WStr) : NULL;
  1428. WStr = FrsFree(WStr);
  1429. }
  1430. //
  1431. // Sendmail Profile (future)
  1432. //
  1433. DebugInfo.Profile = NULL;
  1434. CfgRegReadString(FKC_DEBUG_PROFILE, NULL, 0, &WStr);
  1435. if (WStr != NULL) {
  1436. DebugInfo.Profile = (wcslen(WStr)) ? FrsWtoA(WStr) : NULL;
  1437. WStr = FrsFree(WStr);
  1438. }
  1439. //
  1440. // Buildlab info
  1441. //
  1442. DebugInfo.BuildLab = NULL;
  1443. CfgRegReadString(FKC_DEBUG_BUILDLAB, NULL, 0, &WStr);
  1444. if (WStr != NULL) {
  1445. DebugInfo.BuildLab = (wcslen(WStr)) ? FrsWtoA(WStr) : NULL;
  1446. WStr = FrsFree(WStr);
  1447. }
  1448. //
  1449. // Use the hardwired config file if there is no Directory Service.
  1450. //
  1451. if (FrsSearchArgv(argc, argv, L"nods", &WStr)) {
  1452. NoDs = TRUE;
  1453. if (WStr != NULL) {
  1454. IniFileName = wcslen(WStr) ? WStr : NULL;
  1455. }
  1456. }
  1457. //
  1458. // Single machine is pretending to be several machines
  1459. //
  1460. if (FrsSearchArgv(argc, argv, L"server", &WStr)) {
  1461. if ((WStr != NULL) && (wcslen(WStr) > 0)) {
  1462. NoDs = TRUE;
  1463. ServerName = WStr;
  1464. }
  1465. }
  1466. //
  1467. // The following parameters are testing / debugging.
  1468. //
  1469. //
  1470. // Check queues
  1471. //
  1472. DebugInfo.Queues = TRUE;
  1473. if (!FrsSearchArgv(argc, argv, L"queues", NULL)) {
  1474. CfgRegReadDWord(FKC_DEBUG_QUEUES, NULL, 0, &DebugInfo.Queues);
  1475. }
  1476. //
  1477. // Enable VvJoin Tests
  1478. //
  1479. DebugInfo.VvJoinTests = FrsSearchArgv(argc, argv, L"vvjointests", NULL);
  1480. //
  1481. // forcevvjoin on every join
  1482. //
  1483. DebugInfo.ForceVvJoin = FrsSearchArgv(argc, argv, L"vvjoin", NULL);
  1484. //
  1485. // Enable rename fid test
  1486. //
  1487. DebugInfo.TestFid = FrsSearchArgv(argc, argv, L"testfid", NULL);
  1488. //
  1489. // forceunjoin on one cxtion after N remote co's
  1490. //
  1491. DebugInfo.UnjoinTrigger = 0;
  1492. FrsSearchArgvDWord(argc, argv, L"unjoin", &DebugInfo.UnjoinTrigger);
  1493. //
  1494. // forceunjoin on one cxtion after N remote co's
  1495. //
  1496. DebugInfo.FetchRetryReset = 0;
  1497. if (!FrsSearchArgvDWord(argc, argv, L"fetchretry", &DebugInfo.FetchRetryReset)) {
  1498. }
  1499. DebugInfo.FetchRetryTrigger = DebugInfo.FetchRetryReset;
  1500. DebugInfo.FetchRetryInc = DebugInfo.FetchRetryReset;
  1501. //
  1502. // Set interval for toggling the schedule
  1503. //
  1504. FrsSearchArgvDWord(argc, argv, L"interval", &DebugInfo.Interval);
  1505. //
  1506. // Force an assert after N seconds (0 == don't assert)
  1507. //
  1508. DebugInfo.AssertSeconds = 0;
  1509. if (!FrsSearchArgvDWord(argc, argv, L"assertseconds", &DebugInfo.AssertSeconds)) {
  1510. CfgRegReadDWord(FKC_DEBUG_ASSERT_SECONDS, NULL, 0, &DebugInfo.AssertSeconds);
  1511. }
  1512. //
  1513. // Force REAL out of space errors on database operations
  1514. //
  1515. DebugInfo.DbsOutOfSpace = 0;
  1516. if (!FrsSearchArgvDWord(argc, argv, L"dbsoutOfSpace", &DebugInfo.DbsOutOfSpace)) {
  1517. CfgRegReadDWord(FKC_DEBUG_DBS_OUT_OF_SPACE, NULL, 0, &DebugInfo.DbsOutOfSpace);
  1518. }
  1519. //
  1520. // Trigger phoney out of space errors on database operations
  1521. //
  1522. DebugInfo.DbsOutOfSpaceTrigger = 0;
  1523. if (!FrsSearchArgvDWord(argc, argv, L"outofspacetrigger", &DebugInfo.DbsOutOfSpaceTrigger)) {
  1524. CfgRegReadDWord(FKC_DEBUG_DBS_OUT_OF_SPACE_TRIGGER, NULL, 0, &DebugInfo.DbsOutOfSpaceTrigger);
  1525. }
  1526. //
  1527. // Enable compression. Default will be on.
  1528. //
  1529. CfgRegReadDWord(FKC_DEBUG_DISABLE_COMPRESSION, NULL, 0, &DebugInfo.DisableCompression);
  1530. //
  1531. // Ldap Search timeout. Default is 10 minutes.
  1532. //
  1533. CfgRegReadDWord(FKC_LDAP_SEARCH_TIMEOUT_IN_MINUTES, NULL, 0, &LdapSearchTimeoutInMinutes);
  1534. //
  1535. // Ldap Bind timeout. Default is 30 seconds.
  1536. //
  1537. CfgRegReadDWord(FKC_LDAP_BIND_TIMEOUT_IN_SECONDS, NULL, 0, &LdapBindTimeoutInSeconds);
  1538. //
  1539. // Display the debug parameters.
  1540. //
  1541. DbgPrintInfo(0);
  1542. //
  1543. // Remember our start time (in minutes)
  1544. //
  1545. // 100-nsecs / (10 (microsecs) * 1000 (msecs) * 1000 (secs) * 60 (min)
  1546. //
  1547. GetSystemTimeAsFileTime((FILETIME *)&DebugInfo.StartSeconds);
  1548. DebugInfo.StartSeconds /= (10 * 1000 * 1000);
  1549. }
  1550. VOID
  1551. DbgMinimumInit(
  1552. VOID
  1553. )
  1554. /*++
  1555. Routine Description:
  1556. Called at the beginning of MainMinimumInit()
  1557. Arguments:
  1558. None.
  1559. Return Value:
  1560. None.
  1561. --*/
  1562. {
  1563. #undef DEBSUB
  1564. #define DEBSUB "DbgMinimumInit:"
  1565. HANDLE ThreadHandle;
  1566. DWORD ThreadId;
  1567. //
  1568. // This thread forces an assert after DebugInfo.AssertSeconds
  1569. //
  1570. if (DebugInfo.AssertSeconds) {
  1571. ThreadHandle = (HANDLE)CreateThread(NULL,
  1572. 10000,
  1573. DbgForceAssert,
  1574. NULL,
  1575. 0,
  1576. &ThreadId);
  1577. FRS_ASSERT(HANDLE_IS_VALID(ThreadHandle));
  1578. DbgCaptureThreadInfo2(L"ForceAssert", DbgForceAssert, ThreadId);
  1579. FRS_CLOSE(ThreadHandle);
  1580. }
  1581. }
  1582. BOOL
  1583. DoDebug(
  1584. IN ULONG Sev,
  1585. IN UCHAR *DebSub
  1586. )
  1587. /*++
  1588. Routine Description:
  1589. Should we print this line
  1590. Arguments:
  1591. sev
  1592. debsub
  1593. Return Value:
  1594. None.
  1595. --*/
  1596. {
  1597. #undef DEBSUB
  1598. #define DEBSUB "DoDebug:"
  1599. //
  1600. // Debugging has been disabled
  1601. //
  1602. if (DebugInfo.Disabled) {
  1603. return FALSE;
  1604. }
  1605. //
  1606. // Not important enough
  1607. //
  1608. if (Sev > DebugInfo.Severity && Sev > DebugInfo.LogSeverity) {
  1609. return FALSE;
  1610. }
  1611. //
  1612. // Not tracing this subsystem
  1613. //
  1614. if (DebSub &&
  1615. DebugInfo.Systems &&
  1616. (strstr(DebugInfo.Systems, DebSub) == NULL)) {
  1617. return FALSE;
  1618. }
  1619. //
  1620. // Not tracing this thread
  1621. //
  1622. if (DebugInfo.ThreadId &&
  1623. GetCurrentThreadId() != DebugInfo.ThreadId) {
  1624. return FALSE;
  1625. }
  1626. return TRUE;
  1627. }
  1628. VOID
  1629. DebPrintLine(
  1630. IN ULONG Sev,
  1631. IN PCHAR Line
  1632. )
  1633. /*++
  1634. Routine Description:
  1635. Print a line of debug output to various combinations
  1636. of standard out, debugger, kernel debugger, and a log file.
  1637. Arguments:
  1638. Sev
  1639. Line
  1640. Return Value:
  1641. None.
  1642. --*/
  1643. {
  1644. #undef DEBSUB
  1645. #define DEBSUB "DebPrintLine:"
  1646. //
  1647. // stdout
  1648. //
  1649. if ((Sev <= DebugInfo.Severity) && !RunningAsAService) {
  1650. printf("%s", Line);
  1651. }
  1652. //
  1653. // log file
  1654. //
  1655. if (DebugInfo.LogFILE && Sev <= DebugInfo.LogSeverity) {
  1656. //
  1657. // Number of messages exceeded; save the old file and
  1658. // start afresh. The existing old file is deleted.
  1659. //
  1660. if (DebugInfo.LogLines > DebugInfo.MaxLogLines) {
  1661. fflush(DebugInfo.LogFILE);
  1662. DbgFlushInterval = DebugInfo.LogFlushInterval;
  1663. fclose(DebugInfo.LogFILE);
  1664. DbgShiftLogFiles(DebugInfo.LogFile,
  1665. LOG_FILE_SUFFIX,
  1666. (DebugInfo.CopyLogs) ? DebugInfo.AssertShare : NULL,
  1667. DebugInfo.LogFiles);
  1668. DbgOpenLogFile();
  1669. DebugInfo.LogLines = 0;
  1670. DebugInfo.PrintStats = TRUE;
  1671. }
  1672. if (DebugInfo.LogFILE) {
  1673. fprintf(DebugInfo.LogFILE, "%s", Line);
  1674. //
  1675. // Flush the log file every DebugInfo.LogFlushInterval lines and on
  1676. // every severity 0 message.
  1677. //
  1678. if ((--DbgFlushInterval < 0) || (Sev ==0)) {
  1679. if (fflush(DebugInfo.LogFILE) == EOF) {
  1680. fclose(DebugInfo.LogFILE);
  1681. DebugInfo.LogFILE = NULL;
  1682. }
  1683. DbgFlushInterval = DebugInfo.LogFlushInterval;
  1684. }
  1685. }
  1686. }
  1687. //
  1688. // debugger
  1689. //
  1690. if ((Sev <= DebugInfo.Severity) && !DebugInfo.Suppress) {
  1691. OutputDebugStringA(Line);
  1692. }
  1693. }
  1694. BOOL
  1695. DebFormatLine(
  1696. IN ULONG Sev,
  1697. IN BOOL Format,
  1698. IN PCHAR DebSub,
  1699. IN UINT LineNo,
  1700. IN PCHAR Line,
  1701. IN ULONG LineSize,
  1702. IN PUCHAR Str,
  1703. IN va_list argptr
  1704. )
  1705. /*++
  1706. Routine Description:
  1707. Format the line of output
  1708. Arguments:
  1709. DebSub
  1710. LineNo
  1711. Line
  1712. LineSize
  1713. Str
  1714. Return Value:
  1715. None.
  1716. --*/
  1717. {
  1718. #undef DEBSUB
  1719. #define DEBSUB "DebFormatLine:"
  1720. ULONG LineUsed;
  1721. SYSTEMTIME SystemTime;
  1722. BOOL Ret = TRUE;
  1723. try {
  1724. if (Format) {
  1725. //
  1726. // Increment the line count here to prevent counting
  1727. // the several DPRINTs that don't have a newline.
  1728. //
  1729. ++DebugInfo.LogLines;
  1730. ++DebugInfo.TotalLogLines;
  1731. GetLocalTime(&SystemTime);
  1732. if (_snprintf(Line,
  1733. LineSize,
  1734. "<%-31s%4u: %5u: S%1u: %02d:%02d:%02d> ",
  1735. (DebSub) ? DebSub : "NoName",
  1736. GetCurrentThreadId(),
  1737. LineNo,
  1738. Sev,
  1739. SystemTime.wHour,
  1740. SystemTime.wMinute,
  1741. SystemTime.wSecond) < 0) {
  1742. Ret = FALSE;
  1743. } else {
  1744. LineUsed = strlen(Line);
  1745. }
  1746. } else {
  1747. LineUsed = 0;
  1748. }
  1749. if (Ret) {
  1750. if (((LineUsed + 1) >= LineSize) ||
  1751. (_vsnprintf(Line + LineUsed, LineSize - LineUsed, Str, argptr) < 0)) {
  1752. Ret = FALSE;
  1753. }
  1754. }
  1755. } except(EXCEPTION_EXECUTE_HANDLER) {
  1756. Ret = FALSE;
  1757. }
  1758. return Ret;
  1759. }
  1760. BOOL
  1761. DebFormatTrackingLine(
  1762. IN PCHAR Line,
  1763. IN ULONG LineSize,
  1764. IN PUCHAR Str,
  1765. IN va_list argptr
  1766. )
  1767. /*++
  1768. Routine Description:
  1769. Format the line of output
  1770. Arguments:
  1771. Line
  1772. LineSize
  1773. Str
  1774. Return Value:
  1775. None.
  1776. --*/
  1777. {
  1778. #undef DEBSUB
  1779. #define DEBSUB "DebFormatTrackingLine:"
  1780. ULONG LineUsed = 0;
  1781. SYSTEMTIME SystemTime;
  1782. BOOL Ret = TRUE;
  1783. try {
  1784. //
  1785. // Increment the line count here to prevent counting
  1786. // the several DPRINTs that don't have a newline.
  1787. //
  1788. ++DebugInfo.LogLines;
  1789. ++DebugInfo.TotalLogLines;
  1790. GetLocalTime(&SystemTime);
  1791. if (_snprintf(Line,
  1792. LineSize,
  1793. "%2d/%2d-%02d:%02d:%02d ",
  1794. SystemTime.wMonth,
  1795. SystemTime.wDay,
  1796. SystemTime.wHour,
  1797. SystemTime.wMinute,
  1798. SystemTime.wSecond) < 0) {
  1799. Ret = FALSE;
  1800. } else {
  1801. LineUsed = strlen(Line);
  1802. }
  1803. if (Ret) {
  1804. if (((LineUsed + 1) >= LineSize) ||
  1805. (_vsnprintf(Line + LineUsed, LineSize - LineUsed, Str, argptr) < 0)) {
  1806. Ret = FALSE;
  1807. }
  1808. }
  1809. } except(EXCEPTION_EXECUTE_HANDLER) {
  1810. Ret = FALSE;
  1811. }
  1812. return Ret;
  1813. }
  1814. VOID
  1815. DebPrintTrackingNoLock(
  1816. IN ULONG Sev,
  1817. IN PUCHAR Str,
  1818. IN ... )
  1819. /*++
  1820. Routine Description:
  1821. Format and print a line of tracking output to various combinations
  1822. of standard out, debugger, kernel debugger, and a log file. The
  1823. debug print lock is held and the caller filtered lines that
  1824. shouldn't be printed.
  1825. Arguments:
  1826. Sev - severity level
  1827. Str - printf format
  1828. Return Value:
  1829. None.
  1830. --*/
  1831. {
  1832. #undef DEBSUB
  1833. #define DEBSUB "DebPrintTrackingNoLock:"
  1834. CHAR Buf[512];
  1835. DWORD BufUsed = 0;
  1836. //
  1837. // varargs stuff
  1838. //
  1839. va_list argptr;
  1840. va_start(argptr, Str);
  1841. //
  1842. // Print the line to some combination of stdout, file, and debugger
  1843. //
  1844. if (DebFormatTrackingLine(Buf, sizeof(Buf), Str, argptr)) {
  1845. DebPrintLine(Sev, Buf);
  1846. }
  1847. va_end(argptr);
  1848. }
  1849. VOID
  1850. DebLock(
  1851. VOID
  1852. )
  1853. /*++
  1854. Routine Description:
  1855. Acquire the print lock
  1856. Arguments:
  1857. None.
  1858. Return Value:
  1859. None.
  1860. --*/
  1861. {
  1862. #undef DEBSUB
  1863. #define DEBSUB "DebLock:"
  1864. EnterCriticalSection(&DebugInfo.Lock);
  1865. }
  1866. VOID
  1867. DebUnLock(
  1868. VOID
  1869. )
  1870. /*++
  1871. Routine Description:
  1872. Release the print lock
  1873. Arguments:
  1874. None.
  1875. Return Value:
  1876. None.
  1877. --*/
  1878. {
  1879. #undef DEBSUB
  1880. #define DEBSUB "DebUnLock:"
  1881. BOOL PrintStats;
  1882. //
  1883. // Print summary stats close to the beginning of each
  1884. // log file. The stats may show up a few lines into
  1885. // the new log file when callers hold the DebLock() across
  1886. // several lines.
  1887. //
  1888. // Be careful not to recurse if MaxLogLines is smaller
  1889. // than the number of lines in the stats.
  1890. //
  1891. if (DebugInfo.PrintStats) {
  1892. if (DebugInfo.PrintingStats) {
  1893. DebugInfo.PrintStats = FALSE;
  1894. } else {
  1895. DebugInfo.PrintingStats = TRUE;
  1896. }
  1897. }
  1898. PrintStats = DebugInfo.PrintStats;
  1899. LeaveCriticalSection(&DebugInfo.Lock);
  1900. if (PrintStats) {
  1901. DbgPrintAllStats();
  1902. EnterCriticalSection(&DebugInfo.Lock);
  1903. DebugInfo.PrintingStats = FALSE;
  1904. LeaveCriticalSection(&DebugInfo.Lock);
  1905. }
  1906. }
  1907. VOID
  1908. DebPrintNoLock(
  1909. IN ULONG Sev,
  1910. IN BOOL Format,
  1911. IN PUCHAR Str,
  1912. IN PCHAR DebSub,
  1913. IN UINT LineNo,
  1914. IN ... )
  1915. /*++
  1916. Routine Description:
  1917. Format and print a line of debug output to various combinations
  1918. of standard out, debugger, kernel debugger, and a log file. The
  1919. debug print lock is held and the caller filtered lines that
  1920. shouldn't be printed.
  1921. Arguments:
  1922. Sev - severity filter
  1923. Format - Add format info?
  1924. Str - printf format
  1925. DebSub - module name
  1926. LineNo
  1927. Return Value:
  1928. None.
  1929. --*/
  1930. {
  1931. #undef DEBSUB
  1932. #define DEBSUB "DebPrintNoLock:"
  1933. CHAR Buf[512];
  1934. DWORD BufUsed = 0;
  1935. //
  1936. // varargs stuff
  1937. //
  1938. va_list argptr;
  1939. va_start(argptr, LineNo);
  1940. //
  1941. // Print the line to some combination of stdout, file, and debugger
  1942. //
  1943. if (DebFormatLine(Sev, Format, DebSub, LineNo, Buf, sizeof(Buf), Str, argptr)) {
  1944. DebPrintLine(Sev, Buf);
  1945. }
  1946. va_end(argptr);
  1947. }
  1948. VOID
  1949. DebPrint(
  1950. IN ULONG Sev,
  1951. IN PUCHAR Str,
  1952. IN PCHAR DebSub,
  1953. IN UINT LineNo,
  1954. IN ... )
  1955. /*++
  1956. Routine Description:
  1957. Format and print a line of debug output to various combinations
  1958. of standard out, debugger, kernel debugger, and a log file.
  1959. Arguments:
  1960. sev - severity filter
  1961. str - printf format
  1962. debsub - module name
  1963. LineNo
  1964. Return Value:
  1965. None.
  1966. --*/
  1967. {
  1968. #undef DEBSUB
  1969. #define DEBSUB "DebPrint:"
  1970. CHAR Buf[512];
  1971. DWORD BufUsed = 0;
  1972. //
  1973. // varargs stuff
  1974. //
  1975. va_list argptr;
  1976. va_start(argptr, LineNo);
  1977. //
  1978. // Don't print this
  1979. //
  1980. if (!DoDebug(Sev, DebSub)) {
  1981. return;
  1982. }
  1983. //
  1984. // Print the line to some combination of stdout, file, and debugger
  1985. //
  1986. DebLock();
  1987. if (DebFormatLine(Sev, TRUE, DebSub, LineNo, Buf, sizeof(Buf), Str, argptr)) {
  1988. DebPrintLine(Sev, Buf);
  1989. }
  1990. DebUnLock();
  1991. va_end(argptr);
  1992. #if 0
  1993. static int failedload = FALSE;
  1994. static TRANSMITSPECIALFRAME_FN lpfnTransmitSpecialFrame = NULL;
  1995. //
  1996. // Calling nal.dll from inside lsa causes a deadlock during startup
  1997. //
  1998. if ( /* (!RunningAsAService) &&*/ // davidor - lets try it.
  1999. (NmDebugTest(sev, DebSub)))
  2000. {
  2001. if (failedload == FALSE) {
  2002. //
  2003. // Only try to load the NetMon trace routine once.
  2004. //
  2005. if (!lpfnTransmitSpecialFrame) {
  2006. HINSTANCE hInst;
  2007. hInst = LoadLibrary (L"NAL.DLL" );
  2008. if (hInst) {
  2009. lpfnTransmitSpecialFrame =
  2010. (TRANSMITSPECIALFRAME_FN)GetProcAddress ( hInst, "TransmitSpecialFrame" );
  2011. }
  2012. }
  2013. if (lpfnTransmitSpecialFrame) {
  2014. int length;
  2015. int length2;
  2016. unsigned char buff[256];
  2017. if (DebSub) {
  2018. length = _snprintf(buff, sizeof(buff), "<%s%u:%u> ", DebSub, tid, uLineNo);
  2019. } else {
  2020. length = 0;
  2021. }
  2022. length2 = _vsnprintf(buff + length, sizeof(buff) - length, str, argptr );
  2023. lpfnTransmitSpecialFrame(FRAME_TYPE_COMMENT,
  2024. 0,
  2025. buff,
  2026. length + length2 + 1 );
  2027. } else {
  2028. failedload = TRUE; // that was our one and only try to load the routine.
  2029. }
  2030. }
  2031. }
  2032. #endif 0
  2033. }
  2034. VOID
  2035. DbgDoAssert(
  2036. IN PCHAR Exp,
  2037. IN UINT Line,
  2038. IN PCHAR Debsub
  2039. )
  2040. /*++
  2041. Routine Description:
  2042. Assertion failure; print a message and exit after allowing some
  2043. time for shutdown.
  2044. Arguments:
  2045. Exp - failing assertion expression
  2046. Line - line number of failing expression
  2047. Debsub - module name of failing expression
  2048. Return Value:
  2049. Doesn't return
  2050. --*/
  2051. {
  2052. #undef DEBSUB
  2053. #define DEBSUB "DbgDoAssert:"
  2054. PWCHAR ExpW;
  2055. PWCHAR DebsubW;
  2056. WCHAR LineW[32];
  2057. //
  2058. // Inform the world
  2059. //
  2060. FrsIsAsserting = TRUE;
  2061. ExpW = FrsAtoW(Exp);
  2062. DebsubW = FrsAtoW(Debsub);
  2063. _snwprintf(LineW, 32, L"%d", Line);
  2064. //
  2065. // Post an error log entry followed by recovery steps.
  2066. //
  2067. EPRINT3(EVENT_FRS_ASSERT, DebsubW, LineW, ExpW);
  2068. EPRINT1(EVENT_FRS_IN_ERROR_STATE, JetPath);
  2069. FrsFree(ExpW);
  2070. FrsFree(DebsubW);
  2071. //
  2072. // Stack trace
  2073. //
  2074. if (!DebugInfo.Mem) {
  2075. //
  2076. // Init the symbols here since mem alloc tracing is off.
  2077. //
  2078. DbgStackInit();
  2079. }
  2080. DbgPrintStackTrace(0, Debsub, Line);
  2081. //
  2082. // Failing expression
  2083. //
  2084. DebPrint(0, ":S: ASSERTION FAILURE: %s\n", Debsub, Line, Exp);
  2085. //
  2086. // Save the log file as an assert file
  2087. //
  2088. #if 0
  2089. // disable saving assert logs under separate name; too confusing
  2090. //
  2091. if (DebugInfo.LogFILE) {
  2092. DebLock();
  2093. fflush(DebugInfo.LogFILE);
  2094. DbgFlushInterval = DebugInfo.LogFlushInterval;
  2095. fclose(DebugInfo.LogFILE);
  2096. DbgShiftLogFiles(DebugInfo.LogFile,
  2097. ASSERT_FILE_SUFFIX,
  2098. DebugInfo.AssertShare,
  2099. DebugInfo.AssertFiles);
  2100. DebugInfo.LogFILE = _wfopen(DebugInfo.LogFile, L"wc");
  2101. DebugInfo.LogLines = 0;
  2102. DebugInfo.PrintStats = TRUE;
  2103. DebUnLock();
  2104. }
  2105. #endif 0
  2106. DEBUG_FLUSH();
  2107. //
  2108. // Break into the debugger, if any
  2109. //
  2110. if (DebugInfo.Break && IsDebuggerPresent()) {
  2111. DebugBreak();
  2112. }
  2113. //
  2114. // Shutting down during an assert seldom completes; a critical thread
  2115. // is usually the thread that has asserted. One can't simply return
  2116. // from an assert. So exit the process and trust jet and ntfrs to
  2117. // recover at start up.
  2118. //
  2119. // FrsIsShuttingDown = TRUE;
  2120. // SetEvent(ShutDownEvent);
  2121. // ExitThread(1);
  2122. //
  2123. // Raise an exception.
  2124. //
  2125. if (--DbgRaiseCount <= 0) {
  2126. exit(1);
  2127. }
  2128. XRAISEGENEXCEPTION( ERROR_OPERATION_ABORTED );
  2129. }
  2130. #endif