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.

1082 lines
28 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Console input and output.
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "pch.cpp"
  9. #pragma hdrstop
  10. #include <stdarg.h>
  11. #include <process.h>
  12. #include "conio.hpp"
  13. #include "engine.hpp"
  14. #include "main.hpp"
  15. #define CONTROL_A 1
  16. #define CONTROL_B 2
  17. #define CONTROL_D 4
  18. #define CONTROL_E 5
  19. #define CONTROL_F 6
  20. #define CONTROL_K 11
  21. #define CONTROL_P 16
  22. #define CONTROL_R 18
  23. #define CONTROL_V 22
  24. #define CONTROL_W 23
  25. #define CONTROL_X 24
  26. HANDLE g_ConInput, g_ConOutput;
  27. HANDLE g_PromptInput;
  28. HANDLE g_AllowInput;
  29. ConInputCallbacks g_ConInputCb;
  30. ConOutputCallbacks g_ConOutputCb;
  31. BOOL g_IoInitialized;
  32. BOOL g_ConInitialized;
  33. char g_Buffer[MAX_COMMAND];
  34. LONG g_Lines;
  35. HANDLE g_PipeWrite;
  36. OVERLAPPED g_PipeWriteOverlapped;
  37. CRITICAL_SECTION g_InputLock;
  38. BOOL g_InputStarted;
  39. // Input thread interfaces for direct input thread calls.
  40. IDebugClient* g_ConClient;
  41. IDebugControl* g_ConControl;
  42. //----------------------------------------------------------------------------
  43. //
  44. // Default input callbacks implementation, provides IUnknown.
  45. //
  46. //----------------------------------------------------------------------------
  47. STDMETHODIMP
  48. DefInputCallbacks::QueryInterface(
  49. THIS_
  50. IN REFIID InterfaceId,
  51. OUT PVOID* Interface
  52. )
  53. {
  54. *Interface = NULL;
  55. if (IsEqualIID(InterfaceId, IID_IUnknown) ||
  56. IsEqualIID(InterfaceId, IID_IDebugInputCallbacks))
  57. {
  58. *Interface = (IDebugInputCallbacks *)this;
  59. AddRef();
  60. return S_OK;
  61. }
  62. else
  63. {
  64. return E_NOINTERFACE;
  65. }
  66. }
  67. STDMETHODIMP_(ULONG)
  68. DefInputCallbacks::AddRef(
  69. THIS
  70. )
  71. {
  72. // This class is designed to be static so
  73. // there's no true refcount.
  74. return 1;
  75. }
  76. STDMETHODIMP_(ULONG)
  77. DefInputCallbacks::Release(
  78. THIS
  79. )
  80. {
  81. // This class is designed to be static so
  82. // there's no true refcount.
  83. return 0;
  84. }
  85. //----------------------------------------------------------------------------
  86. //
  87. // Console input callbacks.
  88. //
  89. //----------------------------------------------------------------------------
  90. STDMETHODIMP
  91. ConInputCallbacks::StartInput(
  92. THIS_
  93. IN ULONG BufferSize
  94. )
  95. {
  96. if (!g_IoInitialized || g_IoMode == IO_NONE)
  97. {
  98. // Ignore input requests.
  99. return S_OK;
  100. }
  101. EnterCriticalSection(&g_InputLock);
  102. if (g_ConControl == NULL)
  103. {
  104. // If we're not remoted we aren't running a separate input
  105. // thread so we need to block here until we get some input.
  106. while (!ConIn(g_Buffer, sizeof(g_Buffer), TRUE))
  107. {
  108. ; // Wait.
  109. }
  110. g_DbgControl->ReturnInput(g_Buffer);
  111. }
  112. else if (ConIn(g_Buffer, sizeof(g_Buffer), FALSE))
  113. {
  114. g_ConControl->ReturnInput(g_Buffer);
  115. }
  116. else
  117. {
  118. g_InputStarted = TRUE;
  119. #ifndef KERNEL
  120. // Wake up the input thread if necessary.
  121. SetEvent(g_AllowInput);
  122. #endif
  123. }
  124. LeaveCriticalSection(&g_InputLock);
  125. return S_OK;
  126. }
  127. STDMETHODIMP
  128. ConInputCallbacks::EndInput(
  129. THIS
  130. )
  131. {
  132. g_InputStarted = FALSE;
  133. return S_OK;
  134. }
  135. //----------------------------------------------------------------------------
  136. //
  137. // Default output callbacks implementation, provides IUnknown.
  138. //
  139. //----------------------------------------------------------------------------
  140. STDMETHODIMP
  141. DefOutputCallbacks::QueryInterface(
  142. THIS_
  143. IN REFIID InterfaceId,
  144. OUT PVOID* Interface
  145. )
  146. {
  147. *Interface = NULL;
  148. if (IsEqualIID(InterfaceId, IID_IUnknown) ||
  149. IsEqualIID(InterfaceId, IID_IDebugOutputCallbacks))
  150. {
  151. *Interface = (IDebugOutputCallbacks *)this;
  152. AddRef();
  153. return S_OK;
  154. }
  155. else
  156. {
  157. return E_NOINTERFACE;
  158. }
  159. }
  160. STDMETHODIMP_(ULONG)
  161. DefOutputCallbacks::AddRef(
  162. THIS
  163. )
  164. {
  165. // This class is designed to be static so
  166. // there's no true refcount.
  167. return 1;
  168. }
  169. STDMETHODIMP_(ULONG)
  170. DefOutputCallbacks::Release(
  171. THIS
  172. )
  173. {
  174. // This class is designed to be static so
  175. // there's no true refcount.
  176. return 0;
  177. }
  178. //----------------------------------------------------------------------------
  179. //
  180. // Console output callbacks.
  181. //
  182. //----------------------------------------------------------------------------
  183. STDMETHODIMP
  184. ConOutputCallbacks::Output(
  185. THIS_
  186. IN ULONG Mask,
  187. IN PCSTR Text
  188. )
  189. {
  190. ConOutStr(Text);
  191. return S_OK;
  192. }
  193. //----------------------------------------------------------------------------
  194. //
  195. // Functions
  196. //
  197. //----------------------------------------------------------------------------
  198. void
  199. InitializeIo(PCSTR InputFile)
  200. {
  201. __try
  202. {
  203. InitializeCriticalSection(&g_InputLock);
  204. }
  205. __except(EXCEPTION_EXECUTE_HANDLER)
  206. {
  207. ErrorExit("Unable to initialize lock\n");
  208. }
  209. // The input file may not exist so there's no
  210. // check for failure.
  211. g_InputFile = fopen(InputFile, "r");
  212. g_IoInitialized = TRUE;
  213. }
  214. void
  215. CreateConsole(void)
  216. {
  217. if (g_ConInitialized)
  218. {
  219. return;
  220. }
  221. // Set this early to prevent an init call from Exit in
  222. // case an Exit call is made inside this routine.
  223. g_ConInitialized = TRUE;
  224. #ifdef INHERIT_CONSOLE
  225. g_ConInput = GetStdHandle(STD_INPUT_HANDLE);
  226. g_ConOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  227. #else
  228. SECURITY_ATTRIBUTES Security;
  229. if (!AllocConsole())
  230. {
  231. ErrorExit("AllocConsole failed, %d\n", GetLastError());
  232. }
  233. ZeroMemory(&Security, sizeof(Security));
  234. Security.nLength = sizeof(Security);
  235. Security.bInheritHandle = TRUE;
  236. g_ConInput = CreateFile( "CONIN$",
  237. GENERIC_READ,
  238. FILE_SHARE_READ | FILE_SHARE_WRITE,
  239. &Security,
  240. OPEN_EXISTING,
  241. 0,
  242. NULL
  243. );
  244. if (g_ConInput == INVALID_HANDLE_VALUE)
  245. {
  246. ErrorExit("Create CONIN$ failed, %d\n", GetLastError());
  247. }
  248. g_ConOutput = CreateFile( "CONOUT$",
  249. GENERIC_WRITE | GENERIC_READ,
  250. FILE_SHARE_READ | FILE_SHARE_WRITE,
  251. &Security,
  252. OPEN_EXISTING,
  253. 0,
  254. NULL
  255. );
  256. if (g_ConOutput == INVALID_HANDLE_VALUE)
  257. {
  258. ErrorExit("Create CONOUT$ failed, %d\n", GetLastError());
  259. }
  260. #endif
  261. g_PromptInput = g_ConInput;
  262. }
  263. void
  264. ReadPromptInputChars(PSTR Buffer, ULONG BufferSize)
  265. {
  266. ULONG Len;
  267. ULONG Read;
  268. // Reading from another source. Read character by
  269. // character until a line is read.
  270. Len = 0;
  271. while (Len < BufferSize)
  272. {
  273. if (!ReadFile(g_PromptInput, &Buffer[Len], sizeof(Buffer[0]),
  274. &Read, NULL) ||
  275. Read != sizeof(Buffer[0]))
  276. {
  277. OutputDebugString("Unable to read input\n");
  278. ExitDebugger(E_FAIL);
  279. }
  280. if (Buffer[Len] == '\n')
  281. {
  282. InterlockedDecrement(&g_Lines);
  283. break;
  284. }
  285. // Ignore carriage returns.
  286. if (Buffer[Len] != '\r')
  287. {
  288. // Prevent buffer overflow.
  289. if (Len == BufferSize - 1)
  290. {
  291. break;
  292. }
  293. Len++;
  294. }
  295. }
  296. Buffer[Len] = '\0';
  297. }
  298. BOOL
  299. CheckForControlCommands(PDEBUG_CLIENT Client, PDEBUG_CONTROL Control,
  300. char Char)
  301. {
  302. HRESULT Hr;
  303. ULONG OutMask;
  304. PCHAR DebugAction;
  305. ULONG EngOptions;
  306. switch(Char)
  307. {
  308. case CONTROL_B:
  309. case CONTROL_X:
  310. if (Client)
  311. {
  312. // Tell server about disconnect or
  313. // force servers to get cleaned up.
  314. Client->EndSession(g_RemoteClient ?
  315. DEBUG_END_DISCONNECT : DEBUG_END_REENTRANT);
  316. }
  317. ExitProcess(S_OK);
  318. case CONTROL_F:
  319. //
  320. // Force a breakin like Ctrl-C would do.
  321. // The advantage is this will work when kd is being debugged.
  322. //
  323. Control->SetInterrupt(DEBUG_INTERRUPT_ACTIVE);
  324. return TRUE;
  325. case CONTROL_P:
  326. // Launch cdb on this debugger.
  327. char PidStr[32];
  328. sprintf(PidStr, "\"cdb -p %d\"", GetCurrentProcessId());
  329. _spawnlp(_P_NOWAIT,
  330. "cmd.exe", "/c", "start",
  331. "remote", "/s", PidStr, "cdb_pipe",
  332. NULL);
  333. return TRUE;
  334. case CONTROL_V:
  335. Client->GetOtherOutputMask(g_DbgClient, &OutMask);
  336. OutMask ^= DEBUG_OUTPUT_VERBOSE;
  337. Client->SetOtherOutputMask(g_DbgClient, OutMask);
  338. Control->SetLogMask(OutMask);
  339. ConOut("Verbose mode %s.\n",
  340. (OutMask & DEBUG_OUTPUT_VERBOSE) ? "ON" : "OFF");
  341. return TRUE;
  342. case CONTROL_W:
  343. Hr = Control->OutputVersionInformation(DEBUG_OUTCTL_AMBIENT);
  344. if (Hr == HRESULT_FROM_WIN32(ERROR_BUSY))
  345. {
  346. ConOut("Engine is busy, try again\n");
  347. }
  348. else if (Hr != S_OK)
  349. {
  350. ConOut("Unable to show version information, 0x%X\n", Hr);
  351. }
  352. return TRUE;
  353. #ifdef KERNEL
  354. case CONTROL_A:
  355. Client->SetKernelConnectionOptions("cycle_speed");
  356. return TRUE;
  357. case CONTROL_D:
  358. Client->GetOtherOutputMask(g_DbgClient, &OutMask);
  359. OutMask ^= DEBUG_IOUTPUT_KD_PROTOCOL;
  360. Client->SetOtherOutputMask(g_DbgClient, OutMask);
  361. Control->SetLogMask(OutMask);
  362. return TRUE;
  363. case CONTROL_K:
  364. //
  365. // Toggle between the following possibilities-
  366. //
  367. // (0) no breakin
  368. // (1) -b style (same as Control-C up the wire)
  369. // (2) -d style (stop on first dll load).
  370. //
  371. // NB -b and -d could both be on the command line
  372. // but become mutually exclusive via this method.
  373. // (Maybe should be a single enum type).
  374. //
  375. Control->GetEngineOptions(&EngOptions);
  376. if (EngOptions & DEBUG_ENGOPT_INITIAL_BREAK)
  377. {
  378. //
  379. // Was type 1, go to type 2.
  380. //
  381. EngOptions |= DEBUG_ENGOPT_INITIAL_MODULE_BREAK;
  382. EngOptions &= ~DEBUG_ENGOPT_INITIAL_BREAK;
  383. DebugAction = "breakin on first symbol load";
  384. }
  385. else if (EngOptions & DEBUG_ENGOPT_INITIAL_MODULE_BREAK)
  386. {
  387. //
  388. // Was type 2, go to type 0.
  389. //
  390. EngOptions &= ~DEBUG_ENGOPT_INITIAL_MODULE_BREAK;
  391. DebugAction = "NOT breakin";
  392. }
  393. else
  394. {
  395. //
  396. // Was type 0, go to type 1.
  397. //
  398. EngOptions |= DEBUG_ENGOPT_INITIAL_BREAK;
  399. DebugAction = "request initial breakpoint";
  400. }
  401. Control->SetEngineOptions(EngOptions);
  402. ConOut("Will %s at next boot.\n", DebugAction);
  403. return TRUE;
  404. case CONTROL_R:
  405. Client->SetKernelConnectionOptions("resync");
  406. return TRUE;
  407. #endif // #ifdef KERNEL
  408. }
  409. return FALSE;
  410. }
  411. BOOL
  412. ConIn(PSTR Buffer, ULONG BufferSize, BOOL Wait)
  413. {
  414. if (g_InitialCommand != NULL)
  415. {
  416. ConOut("%s: Reading initial command '%s'\n",
  417. g_DebuggerName, g_InitialCommand);
  418. CopyString(Buffer, g_InitialCommand, BufferSize);
  419. g_InitialCommand = NULL;
  420. return TRUE;
  421. }
  422. while (g_InputFile && g_InputFile != stdin)
  423. {
  424. if (fgets(Buffer, BufferSize, g_InputFile))
  425. {
  426. ULONG Len = strlen(Buffer);
  427. ConOut("%s", Buffer);
  428. if (Len > 0 && Buffer[Len - 1] == '\n')
  429. {
  430. Buffer[Len - 1] = 0;
  431. }
  432. else
  433. {
  434. ConOut("\n");
  435. }
  436. return TRUE;
  437. }
  438. else
  439. {
  440. fclose(g_InputFile);
  441. if (g_NextOldInputFile > 0)
  442. {
  443. g_InputFile = g_OldInputFiles[--g_NextOldInputFile];
  444. }
  445. else
  446. {
  447. g_InputFile = stdin;
  448. }
  449. }
  450. }
  451. if (g_InputFile == NULL)
  452. {
  453. g_InputFile = stdin;
  454. }
  455. switch(g_IoMode)
  456. {
  457. case IO_NONE:
  458. return FALSE;
  459. case IO_DEBUG:
  460. case IO_DEBUG_DEFER:
  461. if (!Wait)
  462. {
  463. return FALSE;
  464. }
  465. g_NtDllCalls.DbgPrompt("", Buffer,
  466. min(BufferSize, MAX_DBG_PROMPT_COMMAND));
  467. break;
  468. case IO_CONSOLE:
  469. ULONG Len;
  470. if (g_PromptInput == g_ConInput)
  471. {
  472. if (!Wait)
  473. {
  474. return FALSE;
  475. }
  476. // Reading from the console so we can assume we'll
  477. // read a line.
  478. for (;;)
  479. {
  480. if (!ReadFile(g_PromptInput, Buffer, BufferSize, &Len, NULL))
  481. {
  482. OutputDebugString("Unable to read input\n");
  483. ExitDebugger(E_FAIL);
  484. }
  485. // At a minimum a read should have CRLF. If it
  486. // doesn't assume that something weird happened
  487. // and ignore the read.
  488. if (Len >= 2)
  489. {
  490. break;
  491. }
  492. Sleep(50);
  493. }
  494. // Remove CR LF.
  495. Len -= 2;
  496. Buffer[Len] = '\0';
  497. // Edit out any special characters.
  498. for (ULONG i = 0; i < Len; i++)
  499. {
  500. if (CheckForControlCommands(g_DbgClient, g_DbgControl,
  501. Buffer[i]))
  502. {
  503. Buffer[i] = ' ';
  504. }
  505. }
  506. }
  507. else
  508. {
  509. #ifndef KERNEL
  510. if (g_Lines == 0)
  511. {
  512. // Allow the input thread to read the console.
  513. SetEvent(g_AllowInput);
  514. }
  515. #endif
  516. while (g_Lines == 0)
  517. {
  518. if (!Wait)
  519. {
  520. return FALSE;
  521. }
  522. // Wait for the input thread to notify us that
  523. // a line of input is available. While we're waiting,
  524. // let the engine process callbacks provoked by
  525. // other clients.
  526. HRESULT Hr = g_DbgClient->DispatchCallbacks(INFINITE);
  527. if (Hr != S_OK)
  528. {
  529. OutputDebugString("Unable to dispatch callbacks\n");
  530. ExitDebugger(Hr);
  531. }
  532. // Some other client may have started execution in
  533. // which case we want to stop waiting for input.
  534. if (g_ExecStatus != DEBUG_STATUS_BREAK)
  535. {
  536. #ifndef KERNEL
  537. // XXX drewb - Need a way to turn input off.
  538. #endif
  539. return FALSE;
  540. }
  541. }
  542. ReadPromptInputChars(Buffer, BufferSize);
  543. }
  544. break;
  545. }
  546. return TRUE;
  547. }
  548. #define KD_OUT_LIMIT 510
  549. void
  550. ConOutStr(PCSTR Str)
  551. {
  552. int Len;
  553. switch(g_IoMode)
  554. {
  555. case IO_NONE:
  556. // Throw it away.
  557. break;
  558. case IO_DEBUG:
  559. case IO_DEBUG_DEFER:
  560. //
  561. // Send the output to the kernel debugger but note that we
  562. // want any control C processing to be done locally rather
  563. // than in the kernel.
  564. //
  565. // The kernel silently truncates DbgPrints longer than
  566. // 512 characters so use multiple calls if necessary.
  567. //
  568. Len = strlen(Str);
  569. if (Len > KD_OUT_LIMIT)
  570. {
  571. while (Len > 0)
  572. {
  573. if (g_NtDllCalls.DbgPrint("%.*s", KD_OUT_LIMIT,
  574. Str) == STATUS_BREAKPOINT &&
  575. g_DbgControl != NULL)
  576. {
  577. g_DbgControl->SetInterrupt(DEBUG_INTERRUPT_PASSIVE);
  578. }
  579. Len -= KD_OUT_LIMIT;
  580. Str += KD_OUT_LIMIT;
  581. }
  582. }
  583. else
  584. {
  585. if (g_NtDllCalls.DbgPrint("%s", Str) == STATUS_BREAKPOINT &&
  586. g_DbgControl != NULL)
  587. {
  588. g_DbgControl->SetInterrupt(DEBUG_INTERRUPT_PASSIVE);
  589. }
  590. }
  591. break;
  592. case IO_CONSOLE:
  593. if (g_ConOutput != NULL)
  594. {
  595. ULONG Written;
  596. WriteFile(g_ConOutput, Str, strlen(Str), &Written, NULL);
  597. }
  598. else
  599. {
  600. OutputDebugString(Str);
  601. }
  602. break;
  603. }
  604. }
  605. void
  606. ConOut(PCSTR Format, ...)
  607. {
  608. va_list Args;
  609. // If no attempt has been made to create a console
  610. // go ahead and try now.
  611. if (g_IoMode == IO_CONSOLE && !g_ConInitialized)
  612. {
  613. CreateConsole();
  614. }
  615. va_start(Args, Format);
  616. _vsnprintf(g_Buffer, DIMA(g_Buffer), Format, Args);
  617. g_Buffer[DIMA(g_Buffer) - 1] = 0;
  618. va_end(Args);
  619. ConOutStr(g_Buffer);
  620. }
  621. void
  622. ConClear(void)
  623. {
  624. if (g_IoMode != IO_CONSOLE)
  625. {
  626. return;
  627. }
  628. // If no attempt has been made to create a console
  629. // go ahead and try now.
  630. if (g_IoMode == IO_CONSOLE && !g_ConInitialized)
  631. {
  632. CreateConsole();
  633. }
  634. HANDLE Console;
  635. CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenInfo;
  636. DWORD Done;
  637. DWORD Chars;
  638. Console = GetStdHandle(STD_OUTPUT_HANDLE);
  639. if (!GetConsoleScreenBufferInfo(Console, &ConsoleScreenInfo))
  640. {
  641. return;
  642. }
  643. ConsoleScreenInfo.dwCursorPosition.X = 0;
  644. ConsoleScreenInfo.dwCursorPosition.Y = 0;
  645. Chars = ConsoleScreenInfo.dwSize.Y * ConsoleScreenInfo.dwSize.X;
  646. FillConsoleOutputCharacterA(Console, ' ', Chars,
  647. ConsoleScreenInfo.dwCursorPosition,
  648. &Done);
  649. FillConsoleOutputAttribute(Console, ConsoleScreenInfo.wAttributes,
  650. Chars, ConsoleScreenInfo.dwCursorPosition,
  651. &Done);
  652. SetConsoleCursorPosition(Console, ConsoleScreenInfo.dwCursorPosition);
  653. }
  654. void
  655. ExitDebugger(ULONG Code)
  656. {
  657. if (g_DbgClient != NULL)
  658. {
  659. if (g_RemoteClient)
  660. {
  661. // Disconnect from server.
  662. g_DbgClient->EndSession(DEBUG_END_DISCONNECT);
  663. }
  664. else
  665. {
  666. g_DbgClient->EndSession(DEBUG_END_PASSIVE);
  667. // Force servers to get cleaned up.
  668. g_DbgClient->EndSession(DEBUG_END_REENTRANT);
  669. }
  670. }
  671. ExitProcess(Code);
  672. }
  673. void
  674. ErrorExit(PCSTR Format, ...)
  675. {
  676. if (Format != NULL)
  677. {
  678. DWORD Len;
  679. va_list Args;
  680. // If no attempt has been made to create a console
  681. // go ahead and try now.
  682. if (g_IoRequested == IO_CONSOLE && !g_ConInitialized)
  683. {
  684. CreateConsole();
  685. }
  686. va_start(Args, Format);
  687. Len = _vsnprintf(g_Buffer, DIMA(g_Buffer), Format, Args);
  688. va_end(Args);
  689. g_Buffer[DIMA(g_Buffer) - 1] = 0;
  690. if ((int)Len < 0 || Len == DIMA(g_Buffer))
  691. {
  692. Len = DIMA(g_Buffer) - 1;
  693. }
  694. if (g_ConOutput != NULL)
  695. {
  696. WriteFile(g_ConOutput, g_Buffer, Len, &Len, NULL);
  697. }
  698. else
  699. {
  700. OutputDebugString(g_Buffer);
  701. }
  702. }
  703. #ifndef INHERIT_CONSOLE
  704. if (g_IoRequested == IO_CONSOLE)
  705. {
  706. ConOut("%s: exiting - press enter ---", g_DebuggerName);
  707. g_InitialCommand = NULL;
  708. g_InputFile = NULL;
  709. ConIn(g_Buffer, sizeof(g_Buffer), TRUE);
  710. }
  711. #endif
  712. ExitDebugger(E_FAIL);
  713. }
  714. DWORD WINAPI
  715. InputThreadLoop(PVOID Param)
  716. {
  717. DWORD Read;
  718. BOOL Status;
  719. UCHAR Char;
  720. BOOL NewLine = TRUE;
  721. BOOL SpecialChar = FALSE;
  722. HANDLE ConIn = g_ConInput;
  723. HRESULT Hr;
  724. BOOL ShowInputError = TRUE;
  725. BOOL PipeInput;
  726. // Create interfaces usable on this thread.
  727. if ((Hr = g_DbgClient->CreateClient(&g_ConClient)) != S_OK ||
  728. (Hr = g_ConClient->QueryInterface(IID_IDebugControl,
  729. (void **)&g_ConControl)) != S_OK)
  730. {
  731. ConOut("%s: Unable to create input thread interfaces, 0x%X\n",
  732. g_DebuggerName, Hr);
  733. // Force servers to get cleaned up or disconnect from server.
  734. g_DbgClient->EndSession(g_RemoteClient ?
  735. DEBUG_END_DISCONNECT : DEBUG_END_REENTRANT);
  736. ExitProcess(E_FAIL);
  737. }
  738. PipeInput = GetFileType(ConIn) == FILE_TYPE_PIPE;
  739. //
  740. // Capture all typed input immediately.
  741. // Stuff the characters into an anonymous pipe, from which
  742. // ConIn will read them.
  743. //
  744. for (;;)
  745. {
  746. #ifndef KERNEL
  747. // The debugger should only read the console when the
  748. // debuggee isn't running to avoid eating up input
  749. // intended for the debuggee.
  750. if (!g_RemoteClient && NewLine)
  751. {
  752. if (WaitForSingleObject(g_AllowInput,
  753. INFINITE) != WAIT_OBJECT_0)
  754. {
  755. ConOut("%s: Failed to wait for input window, %d\n",
  756. GetLastError());
  757. }
  758. NewLine = FALSE;
  759. }
  760. #endif
  761. //
  762. // The CRT does GetFileType's on all standard I/O handles
  763. // when initializing. GetFileType counts as a synchronous
  764. // I/O so if the handle happens to be a pipe and the pipe
  765. // already has a sync I/O on it the GetFileType will block
  766. // until the first I/O is satisfied.
  767. //
  768. // When this separate I/O thread is running it's normally
  769. // blocked in a ReadFile, causing any GetFileType call
  770. // on the handle to also block until there's some input.
  771. // In order to avoid this we detect that the input is
  772. // a pipe and use PeekNamedPipe to delay the ReadFile
  773. // until there's some input available.
  774. //
  775. if (PipeInput)
  776. {
  777. for (;;)
  778. {
  779. ULONG Avail;
  780. if (PeekNamedPipe(ConIn, NULL, 0, NULL, &Avail, NULL) &&
  781. Avail > 0)
  782. {
  783. break;
  784. }
  785. Sleep(10);
  786. }
  787. }
  788. Status = ReadFile(ConIn, &Char, sizeof(Char), &Read, NULL);
  789. if (!Status || Read != sizeof(Char))
  790. {
  791. if (ShowInputError &&
  792. GetLastError() != ERROR_OPERATION_ABORTED &&
  793. GetLastError() != ERROR_IO_PENDING)
  794. {
  795. ConOut("%s: Could not read from console, %d\n",
  796. g_DebuggerName, GetLastError());
  797. ShowInputError = FALSE;
  798. }
  799. // The most common cause of a console read failure
  800. // is killing remote with @K. Give things some
  801. // time to kill this process.
  802. // If this is a remote server it's possible that
  803. // the debugger was run without a valid console
  804. // and is just being accessed via remoting.
  805. // Sleep longer in that case since errors will
  806. // probably always occur.
  807. Sleep(!g_RemoteClient && g_RemoteOptions != NULL ?
  808. 1000 : 50);
  809. continue;
  810. }
  811. // We successfully got some input so if it
  812. // fails later we should show a fresh error.
  813. ShowInputError = TRUE;
  814. if (CheckForControlCommands(g_ConClient, g_ConControl, Char))
  815. {
  816. SpecialChar = TRUE;
  817. continue;
  818. }
  819. if (SpecialChar && Char == '\r')
  820. {
  821. // If we get a CR immediately after a special
  822. // char turn it into a space so that it doesn't cause
  823. // a command repeat.
  824. Char = ' ';
  825. }
  826. SpecialChar = FALSE;
  827. ULONG Len;
  828. Status = WriteFile(g_PipeWrite, &Char, sizeof(Char), &Len,
  829. &g_PipeWriteOverlapped);
  830. if (!Status && GetLastError() != ERROR_IO_PENDING)
  831. {
  832. ConOut("%s: Could not write to pipe, %d\n",
  833. g_DebuggerName, GetLastError());
  834. }
  835. else if (Char == '\n')
  836. {
  837. EnterCriticalSection(&g_InputLock);
  838. InterlockedIncrement(&g_Lines);
  839. // If input is needed send it directly
  840. // to the engine.
  841. if (g_InputStarted)
  842. {
  843. ReadPromptInputChars(g_Buffer, sizeof(g_Buffer));
  844. g_ConControl->ReturnInput(g_Buffer);
  845. g_InputStarted = FALSE;
  846. }
  847. else
  848. {
  849. // Wake up the engine thread when a line of
  850. // input is present.
  851. g_ConClient->ExitDispatch(g_DbgClient);
  852. }
  853. LeaveCriticalSection(&g_InputLock);
  854. NewLine = TRUE;
  855. }
  856. }
  857. return 0;
  858. }
  859. void
  860. CreateInputThread(void)
  861. {
  862. HANDLE Thread;
  863. DWORD ThreadId;
  864. CHAR PipeName[256];
  865. if (g_PipeWrite != NULL)
  866. {
  867. // Input thread already exists.
  868. return;
  869. }
  870. #ifndef KERNEL
  871. g_AllowInput = CreateEvent(NULL, FALSE, FALSE, NULL);
  872. if (g_AllowInput == NULL)
  873. {
  874. ErrorExit("Unable to create input event, %d\n", GetLastError());
  875. }
  876. #endif
  877. _snprintf(PipeName,
  878. sizeof(PipeName),
  879. "\\\\.\\pipe\\Dbg%d",
  880. GetCurrentProcessId());
  881. PipeName[sizeof(PipeName) - 1] = 0;
  882. g_PipeWrite = CreateNamedPipe(PipeName,
  883. PIPE_ACCESS_DUPLEX |
  884. FILE_FLAG_OVERLAPPED,
  885. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
  886. PIPE_WAIT,
  887. 2,
  888. 2000,
  889. 2000,
  890. NMPWAIT_WAIT_FOREVER,
  891. NULL);
  892. if (g_PipeWrite == INVALID_HANDLE_VALUE)
  893. {
  894. ErrorExit("Failed to create input pipe, %d\n",
  895. GetLastError());
  896. }
  897. g_PromptInput = CreateFile(PipeName,
  898. GENERIC_READ,
  899. FILE_SHARE_READ,
  900. NULL,
  901. OPEN_EXISTING,
  902. FILE_ATTRIBUTE_NORMAL,
  903. NULL);
  904. if (g_PromptInput == INVALID_HANDLE_VALUE)
  905. {
  906. ErrorExit("Failed to create read pipe, %d\n",
  907. GetLastError());
  908. }
  909. Thread = CreateThread(NULL,
  910. 16000, // THREAD_STACK_SIZE
  911. InputThreadLoop,
  912. NULL,
  913. THREAD_SET_INFORMATION,
  914. &ThreadId);
  915. if (Thread == NULL)
  916. {
  917. ErrorExit("Failed to create input thread, %d\n",
  918. GetLastError());
  919. }
  920. else
  921. {
  922. if (!SetThreadPriority(Thread, THREAD_PRIORITY_ABOVE_NORMAL))
  923. {
  924. ErrorExit("Failed to raise the input thread priority, %d\n",
  925. GetLastError());
  926. }
  927. }
  928. CloseHandle(Thread);
  929. // Wait for thread initialization. Callbacks are
  930. // already registered so we need to dispatch them
  931. // while waiting.
  932. while (g_ConControl == NULL)
  933. {
  934. g_DbgClient->DispatchCallbacks(50);
  935. }
  936. }