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.

959 lines
24 KiB

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