1
0

ntcomm.c 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  1. /*++
  2. Copyright (c) 2012 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. ntcomm.c
  9. Abstract:
  10. This module implements the common win32 functionality for the debugger
  11. client between the GUI version and the command line version.
  12. Author:
  13. Evan Green 2-Jul-2012
  14. Environment:
  15. Debug Client (Win32)
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #define _WIN32_WINNT 0x0501
  21. #include <assert.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <stdio.h>
  25. #include <windows.h>
  26. #include <winsock.h>
  27. #ifndef PACKED
  28. #define PACKED __attribute__((__packed__))
  29. #endif
  30. #include <minoca/debug/spproto.h>
  31. #include <minoca/debug/dbgext.h>
  32. #include "dbgrprof.h"
  33. #include "console.h"
  34. #include "sock.h"
  35. //
  36. // ---------------------------------------------------------------- Definitions
  37. //
  38. //
  39. // Define the amount of time in milliseconds to wait before declaring failure
  40. // when opening a communications device. Qemu for instance needs a couple
  41. // seconds to open up its pipe servers, etc.
  42. //
  43. #define DEBUGGER_OPEN_TIMEOUT 10000
  44. //
  45. // Define the amount of time to wait in milliseconds between open attempts.
  46. //
  47. #define DEBUGGER_OPEN_RETRY_RATE 100
  48. //
  49. // ------------------------------------------------------ Data Type Definitions
  50. //
  51. typedef enum _CHANNEL_TYPE {
  52. CommChannelInvalid,
  53. CommChannelPipe,
  54. CommChannelSerial,
  55. CommChannelTcp,
  56. CommChannelExec
  57. } CHANNEL_TYPE, *PCHANNEL_TYPE;
  58. typedef struct _NT_THREAD_CREATION_CONTEXT {
  59. PDBGR_THREAD_ROUTINE ThreadRoutine;
  60. PVOID Parameter;
  61. } NT_THREAD_CREATION_CONTEXT, *PNT_THREAD_CREATION_CONTEXT;
  62. //
  63. // -------------------------------------------------------------------- Globals
  64. //
  65. HANDLE CommChannel = INVALID_HANDLE_VALUE;
  66. HANDLE CommChannelOut = INVALID_HANDLE_VALUE;
  67. CHANNEL_TYPE CommChannelType = CommChannelInvalid;
  68. //
  69. // ----------------------------------------------- Internal Function Prototypes
  70. //
  71. BOOL
  72. DbgrpCreateExecPipe (
  73. PSTR Command
  74. );
  75. DWORD
  76. WINAPI
  77. DbgrpOsThreadStart (
  78. LPVOID Parameter
  79. );
  80. VOID
  81. DbgrpPrintLastError (
  82. VOID
  83. );
  84. //
  85. // ------------------------------------------------------------------ Functions
  86. //
  87. INT
  88. DbgrOsCreateThread (
  89. PDBGR_THREAD_ROUTINE ThreadRoutine,
  90. PVOID Parameter
  91. )
  92. /*++
  93. Routine Description:
  94. This routine creates a new thread.
  95. Arguments:
  96. ThreadRoutine - Supplies a pointer to the routine to run in the new thread.
  97. The thread is destroyed when the supplied routine returns.
  98. Parameter - Supplies a pointer to a parameter to pass to the thread.
  99. Return Value:
  100. 0 on success.
  101. Returns an error code on failure.
  102. --*/
  103. {
  104. PNT_THREAD_CREATION_CONTEXT Context;
  105. INT Result;
  106. HANDLE Thread;
  107. Context = malloc(sizeof(NT_THREAD_CREATION_CONTEXT));
  108. if (Context == NULL) {
  109. Result = ENOMEM;
  110. goto OsCreateThreadEnd;
  111. }
  112. Context->ThreadRoutine = ThreadRoutine;
  113. Context->Parameter = Parameter;
  114. Thread = CreateThread(NULL, 0, DbgrpOsThreadStart, Context, 0, NULL);
  115. if (Thread == NULL) {
  116. Result = EINVAL;
  117. goto OsCreateThreadEnd;
  118. }
  119. Context = NULL;
  120. Result = 0;
  121. OsCreateThreadEnd:
  122. if (Context != NULL) {
  123. free(Context);
  124. }
  125. return Result;
  126. }
  127. int
  128. DbgrOsCreatePipe (
  129. int FileDescriptors[2]
  130. )
  131. /*++
  132. Routine Description:
  133. This routine creates an anonymous pipe.
  134. Arguments:
  135. FileDescriptors - Supplies a pointer where handles will be returned
  136. representing the read and write ends of the pipe.
  137. Return Value:
  138. 0 on success.
  139. -1 on failure. The errno variable will be set to indicate the error.
  140. --*/
  141. {
  142. return _pipe(FileDescriptors, 0, O_BINARY);
  143. }
  144. char *
  145. DbgrOsGetUserName (
  146. void
  147. )
  148. /*++
  149. Routine Description:
  150. This routine returns the user name of the current process.
  151. Arguments:
  152. None.
  153. Return Value:
  154. Returns a pointer to a string containing the user name if it can be found.
  155. The caller should not free or modify this memory, and it may be reused on
  156. subsequent calls.
  157. --*/
  158. {
  159. return getenv("USERNAME");
  160. }
  161. char *
  162. DbgrOsGetHostName (
  163. void
  164. )
  165. /*++
  166. Routine Description:
  167. This routine returns the host name of the current machine.
  168. Arguments:
  169. None.
  170. Return Value:
  171. Returns a pointer to a string containing the user name if it can be found.
  172. The caller is responsible for freeing this memory.
  173. --*/
  174. {
  175. char LocalHost[100];
  176. int Result;
  177. Result = gethostname(LocalHost, sizeof(LocalHost));
  178. if (Result != 0) {
  179. return NULL;
  180. }
  181. return strdup(LocalHost);
  182. }
  183. BOOL
  184. InitializeCommunications (
  185. PSTR Channel,
  186. ULONG Baudrate
  187. )
  188. /*++
  189. Routine Description:
  190. This routine initializes the communication medium the debugger uses to
  191. communicate with the target.
  192. Arguments:
  193. Channel - Supplies a description of the communication medium.
  194. Baudrate - Supplies the baudrate to use for serial based communications.
  195. Return Value:
  196. Returns TRUE on success, FALSE on failure.
  197. --*/
  198. {
  199. PSTR AfterScan;
  200. PSTR Colon;
  201. UCHAR EmptyBuffer[8];
  202. PSTR HostCopy;
  203. unsigned long Port;
  204. BOOL Result;
  205. DCB SerialParameters;
  206. int Socket;
  207. ULONG Timeout;
  208. COMMTIMEOUTS Timeouts;
  209. HostCopy = NULL;
  210. Result = FALSE;
  211. Socket = -1;
  212. //
  213. // Connect via TCP.
  214. //
  215. if (strncasecmp(Channel, "tcp:", 4) == 0) {
  216. if (DbgrSocketInitializeLibrary() != 0) {
  217. DbgOut("Failed to initialize socket library.\n");
  218. return FALSE;
  219. }
  220. HostCopy = strdup(Channel + 4);
  221. if (HostCopy == NULL) {
  222. goto InitializeCommunicationsEnd;
  223. }
  224. Colon = strrchr(HostCopy, ':');
  225. if (Colon == NULL) {
  226. DbgOut("Error: Port number expected in the form host:port.\n");
  227. goto InitializeCommunicationsEnd;
  228. }
  229. *Colon = '\0';
  230. Port = strtoul(Colon + 1, &AfterScan, 10);
  231. if ((*AfterScan != '\0') || (AfterScan == Colon + 1)) {
  232. DbgOut("Error: Invalid port '%s'.\n", Colon + 1);
  233. }
  234. Socket = DbgrSocketCreateStreamSocket();
  235. if (Socket < 0) {
  236. DbgOut("Failed to create socket.\n");
  237. goto InitializeCommunicationsEnd;
  238. }
  239. DbgOut("Connecting via TCP to %s on port %u...", HostCopy, Port);
  240. if (DbgrSocketConnect(Socket, HostCopy, Port) != 0) {
  241. DbgOut("Failed to connect: ");
  242. DbgrpPrintLastError();
  243. goto InitializeCommunicationsEnd;
  244. }
  245. DbgOut("Connected.\n");
  246. CommChannel = (HANDLE)Socket;
  247. CommChannelType = CommChannelTcp;
  248. Socket = -1;
  249. Result = TRUE;
  250. goto InitializeCommunicationsEnd;
  251. //
  252. // Execute another process and use its stdin/stdout as the kernel debug
  253. // channel.
  254. //
  255. } else if (strncasecmp(Channel, "exec:", 5) == 0) {
  256. Result = DbgrpCreateExecPipe(Channel + 5);
  257. goto InitializeCommunicationsEnd;
  258. }
  259. //
  260. // CreateFile can open both named pipes and COM ports. Named pipes usually
  261. // take the form "\\.\pipe\mypipe", and COM ports take the form "\\.\com1".
  262. // Open the resource for read/write access, no sharing, and with no other
  263. // remarkable properties.
  264. //
  265. Timeout = 0;
  266. while (Timeout <= DEBUGGER_OPEN_TIMEOUT) {
  267. CommChannel = CreateFile(Channel,
  268. GENERIC_READ | GENERIC_WRITE,
  269. 0,
  270. NULL,
  271. OPEN_EXISTING,
  272. 0,
  273. NULL);
  274. if (CommChannel != INVALID_HANDLE_VALUE) {
  275. break;
  276. }
  277. CommStall(DEBUGGER_OPEN_RETRY_RATE);
  278. Timeout += DEBUGGER_OPEN_RETRY_RATE;
  279. }
  280. if (CommChannel == INVALID_HANDLE_VALUE) {
  281. return FALSE;
  282. }
  283. //
  284. // If the channel was a serial port, set up the serial parameters.
  285. //
  286. if ((strncmp("COM", Channel, 3) == 0) ||
  287. (strncmp("com", Channel, 3) == 0) ||
  288. (strncmp("\\\\.\\COM", Channel, 7) == 0) ||
  289. (strncmp("\\\\.\\com", Channel, 7) == 0)) {
  290. memset(&SerialParameters, 0, sizeof(DCB));
  291. SerialParameters.DCBlength = sizeof(DCB);
  292. if (GetCommState(CommChannel, &SerialParameters) == FALSE) {
  293. goto InitializeCommunicationsEnd;
  294. }
  295. SerialParameters.BaudRate = Baudrate;
  296. SerialParameters.ByteSize = 8;
  297. SerialParameters.StopBits = ONESTOPBIT;
  298. SerialParameters.Parity = NOPARITY;
  299. SerialParameters.fOutX = FALSE;
  300. SerialParameters.fInX = FALSE;
  301. if (SetCommState(CommChannel, &SerialParameters) == FALSE) {
  302. goto InitializeCommunicationsEnd;
  303. }
  304. //
  305. // Set up a timeout to prevent blocking if there's no data available.
  306. //
  307. memset(&Timeouts, 0, sizeof(COMMTIMEOUTS));
  308. Timeouts.ReadIntervalTimeout = 50;
  309. Timeouts.ReadTotalTimeoutConstant = 1000;
  310. Timeouts.ReadTotalTimeoutMultiplier = 2;
  311. Timeouts.WriteTotalTimeoutConstant = 1000;
  312. Timeouts.WriteTotalTimeoutMultiplier = 10;
  313. if (SetCommTimeouts(CommChannel, &Timeouts) == FALSE) {
  314. DbgOut("Unable to set timeouts.\n");
  315. goto InitializeCommunicationsEnd;
  316. }
  317. CommChannelType = CommChannelSerial;
  318. } else {
  319. CommChannelType = CommChannelPipe;
  320. //
  321. // Send some data down the wire to "clear the pipes". Qemu on x86 is
  322. // the only known platform that needs this.
  323. //
  324. memset(EmptyBuffer, 0, sizeof(EmptyBuffer));
  325. CommSend(EmptyBuffer, sizeof(EmptyBuffer));
  326. }
  327. Result = TRUE;
  328. InitializeCommunicationsEnd:
  329. if (HostCopy != NULL) {
  330. free(HostCopy);
  331. }
  332. if (Socket >= 0) {
  333. DbgrSocketClose(Socket);
  334. Socket = -1;
  335. }
  336. if (Result == FALSE) {
  337. if (CommChannel != INVALID_HANDLE_VALUE) {
  338. CloseHandle(CommChannel);
  339. CommChannel = INVALID_HANDLE_VALUE;
  340. CommChannelType = CommChannelInvalid;
  341. }
  342. }
  343. return Result;
  344. }
  345. VOID
  346. DestroyCommunications (
  347. VOID
  348. )
  349. /*++
  350. Routine Description:
  351. This routine tears down the debug communication channel.
  352. Arguments:
  353. None.
  354. Return Value:
  355. None.
  356. --*/
  357. {
  358. if (CommChannelType == CommChannelTcp) {
  359. DbgrSocketClose((int)CommChannel);
  360. } else if (CommChannel != INVALID_HANDLE_VALUE) {
  361. CloseHandle(CommChannel);
  362. CommChannel = INVALID_HANDLE_VALUE;
  363. if (CommChannelOut != INVALID_HANDLE_VALUE) {
  364. CloseHandle(CommChannelOut);
  365. CommChannelOut = INVALID_HANDLE_VALUE;
  366. }
  367. CommChannelType = CommChannelInvalid;
  368. }
  369. return;
  370. }
  371. BOOL
  372. CommReceive (
  373. PVOID Buffer,
  374. ULONG BytesToRead
  375. )
  376. /*++
  377. Routine Description:
  378. This routine receives a number of bytes from the debugger/debuggee
  379. connection.
  380. Arguments:
  381. Buffer - Supplies a pointer to the buffer where the data should be returned.
  382. BytesToRead - Supplies the number of bytes that should be received into the
  383. buffer.
  384. Return Value:
  385. Returns TRUE on success, FALSE on failure.
  386. --*/
  387. {
  388. ULONG BytesRead;
  389. int BytesReceived;
  390. PVOID CurrentPosition;
  391. ULONG Result;
  392. ULONG TotalBytesReceived;
  393. CurrentPosition = Buffer;
  394. TotalBytesReceived = 0;
  395. while (TotalBytesReceived < BytesToRead) {
  396. if (CommChannelType == CommChannelTcp) {
  397. BytesReceived = DbgrSocketReceive((int)CommChannel,
  398. CurrentPosition,
  399. BytesToRead - TotalBytesReceived);
  400. if (BytesReceived == 0) {
  401. DbgOut("Socket closed\n");
  402. return FALSE;
  403. } else if (BytesReceived < 0) {
  404. DbgOut("Receive failure.\n");
  405. return FALSE;
  406. }
  407. BytesRead = BytesReceived;
  408. } else {
  409. Result = ReadFile(CommChannel,
  410. CurrentPosition,
  411. BytesToRead - TotalBytesReceived,
  412. &BytesRead,
  413. NULL);
  414. if (Result == FALSE) {
  415. return FALSE;
  416. }
  417. }
  418. TotalBytesReceived += BytesRead;
  419. CurrentPosition += BytesRead;
  420. }
  421. return TRUE;
  422. }
  423. BOOL
  424. CommSend (
  425. PVOID Buffer,
  426. ULONG BytesToSend
  427. )
  428. /*++
  429. Routine Description:
  430. This routine sends a number of bytes through the debugger/debuggee
  431. connection.
  432. Arguments:
  433. Buffer - Supplies a pointer to the buffer where the data to be sent resides.
  434. BytesToSend - Supplies the number of bytes that should be sent.
  435. Return Value:
  436. Returns TRUE on success, FALSE on failure.
  437. --*/
  438. {
  439. int BytesSent;
  440. ULONG BytesWritten;
  441. PVOID CurrentPosition;
  442. HANDLE Handle;
  443. ULONG Result;
  444. ULONG TotalBytesWritten;
  445. CurrentPosition = Buffer;
  446. TotalBytesWritten = 0;
  447. while (TotalBytesWritten < BytesToSend) {
  448. if (CommChannelType == CommChannelTcp) {
  449. BytesSent = DbgrSocketSend((int)CommChannel,
  450. CurrentPosition,
  451. BytesToSend - TotalBytesWritten);
  452. if (BytesSent <= 0) {
  453. DbgOut("Send failure.\n");
  454. return FALSE;
  455. }
  456. } else {
  457. Handle = CommChannel;
  458. if (CommChannelType == CommChannelExec) {
  459. Handle = CommChannelOut;
  460. }
  461. Result = WriteFile(Handle,
  462. CurrentPosition,
  463. BytesToSend - TotalBytesWritten,
  464. &BytesWritten,
  465. NULL);
  466. if (Result == FALSE) {
  467. return FALSE;
  468. }
  469. }
  470. TotalBytesWritten += BytesWritten;
  471. CurrentPosition += BytesWritten;
  472. }
  473. return TRUE;
  474. }
  475. BOOL
  476. CommReceiveBytesReady (
  477. VOID
  478. )
  479. /*++
  480. Routine Description:
  481. This routine determines whether or not bytes can be read from the
  482. debugger connection.
  483. Arguments:
  484. None.
  485. Return Value:
  486. TRUE if there are bytes ready to be read.
  487. FALSE if no bytes are ready at this time.
  488. --*/
  489. {
  490. DWORD BytesAvailable;
  491. char Peek[1024];
  492. int PeekSize;
  493. BOOL Result;
  494. COMSTAT SerialStatus;
  495. //
  496. // For both a named pipe and a serial port, determine how many bytes are
  497. // available to be received.
  498. //
  499. BytesAvailable = 0;
  500. switch (CommChannelType) {
  501. case CommChannelPipe:
  502. case CommChannelExec:
  503. Result = PeekNamedPipe(CommChannel,
  504. NULL,
  505. 0,
  506. NULL,
  507. &BytesAvailable,
  508. NULL);
  509. if (Result == FALSE) {
  510. BytesAvailable = 0;
  511. }
  512. break;
  513. case CommChannelSerial:
  514. Result = ClearCommError(CommChannel, NULL, &SerialStatus);
  515. if (Result != FALSE) {
  516. BytesAvailable = SerialStatus.cbInQue;
  517. }
  518. break;
  519. case CommChannelTcp:
  520. PeekSize = DbgrSocketPeek((int)CommChannel, Peek, sizeof(Peek));
  521. if (PeekSize > 0) {
  522. BytesAvailable = PeekSize;
  523. }
  524. break;
  525. default:
  526. assert(FALSE);
  527. break;
  528. }
  529. if (BytesAvailable != 0) {
  530. return TRUE;
  531. }
  532. return FALSE;
  533. }
  534. VOID
  535. CommStall (
  536. ULONG Milliseconds
  537. )
  538. /*++
  539. Routine Description:
  540. This routine pauses for the given amount of time.
  541. Arguments:
  542. Milliseconds - Supplies the amount of time, in milliseconds, to stall the
  543. current thread for.
  544. Return Value:
  545. None.
  546. --*/
  547. {
  548. Sleep(Milliseconds);
  549. return;
  550. }
  551. HANDLE
  552. CreateDebuggerLock (
  553. VOID
  554. )
  555. /*++
  556. Routine Description:
  557. This routine creates a debugger lock.
  558. Arguments:
  559. None.
  560. Return Value:
  561. Returns a handle to a debugger lock on success, or NULL on failure.
  562. --*/
  563. {
  564. HANDLE Mutex;
  565. Mutex = CreateMutex(NULL, FALSE, NULL);
  566. return (HANDLE)Mutex;
  567. }
  568. VOID
  569. AcquireDebuggerLock (
  570. HANDLE Lock
  571. )
  572. /*++
  573. Routine Description:
  574. This routine acquires a debugger lock. This routine does not return until
  575. the lock is required.
  576. Arguments:
  577. Lock - Supplies a handle to the lock that is to be acquired.
  578. Return Value:
  579. None.
  580. --*/
  581. {
  582. HANDLE Mutex;
  583. Mutex = (HANDLE)Lock;
  584. WaitForSingleObject(Mutex, INFINITE);
  585. return;
  586. }
  587. VOID
  588. ReleaseDebuggerLock (
  589. HANDLE Lock
  590. )
  591. /*++
  592. Routine Description:
  593. This routine releases a debugger lock.
  594. Arguments:
  595. Lock - Supplies a handle to the lock that is to be released.
  596. Return Value:
  597. None.
  598. --*/
  599. {
  600. HANDLE Mutex;
  601. Mutex = (HANDLE)Lock;
  602. ReleaseMutex(Mutex);
  603. return;
  604. }
  605. VOID
  606. DestroyDebuggerLock (
  607. HANDLE Lock
  608. )
  609. /*++
  610. Routine Description:
  611. This routine destroys a debugger lock.
  612. Arguments:
  613. Lock - Supplies a handle to the lock that is to be destroyed.
  614. Return Value:
  615. None.
  616. --*/
  617. {
  618. HANDLE Mutex;
  619. Mutex = (HANDLE)Lock;
  620. CloseHandle(Mutex);
  621. return;
  622. }
  623. //
  624. // --------------------------------------------------------- Internal Functions
  625. //
  626. BOOL
  627. DbgrpCreateExecPipe (
  628. PSTR Command
  629. )
  630. /*++
  631. Routine Description:
  632. This routine execs the given command and uses its stdin and stdout as the
  633. kernel debug channel.
  634. Arguments:
  635. Command - Supplies a pointer to a string of the command line.
  636. Return Value:
  637. Returns TRUE on success, FALSE on failure.
  638. --*/
  639. {
  640. DWORD Inherit;
  641. PROCESS_INFORMATION ProcessInformation;
  642. BOOL Result;
  643. HANDLE StandardIn[2];
  644. HANDLE StandardOut[2];
  645. STARTUPINFO StartupInfo;
  646. memset(&StartupInfo, 0, sizeof(STARTUPINFO));
  647. StartupInfo.cb = sizeof(STARTUPINFO);
  648. StartupInfo.dwFlags = STARTF_USESTDHANDLES;
  649. StandardIn[0] = INVALID_HANDLE_VALUE;
  650. StandardIn[1] = INVALID_HANDLE_VALUE;
  651. StandardOut[0] = INVALID_HANDLE_VALUE;
  652. StandardOut[1] = INVALID_HANDLE_VALUE;
  653. Result = FALSE;
  654. if ((!CreatePipe(&(StandardIn[0]), &(StandardIn[1]), NULL, 0)) ||
  655. (!CreatePipe(&(StandardOut[0]), &(StandardOut[1]), NULL, 0))) {
  656. goto CreateExecPipeEnd;
  657. }
  658. Inherit = HANDLE_FLAG_INHERIT;
  659. if ((!SetHandleInformation(StandardIn[0], Inherit, Inherit)) ||
  660. (!SetHandleInformation(StandardOut[1], Inherit, Inherit))) {
  661. goto CreateExecPipeEnd;
  662. }
  663. StartupInfo.hStdInput = StandardIn[0];
  664. StartupInfo.hStdOutput = StandardOut[1];
  665. StartupInfo.hStdError = StandardOut[1]; //GetStdHandle(STD_ERROR_HANDLE);
  666. DbgOut("Spawning '%s'\n", Command);
  667. Result = CreateProcess(NULL,
  668. Command,
  669. NULL,
  670. NULL,
  671. TRUE,
  672. CREATE_NEW_CONSOLE,
  673. NULL,
  674. NULL,
  675. &StartupInfo,
  676. &ProcessInformation);
  677. if (Result == FALSE) {
  678. DbgOut("Failed to exec process: %s: ", Command);
  679. DbgrpPrintLastError();
  680. goto CreateExecPipeEnd;
  681. }
  682. DbgOut("Created process %x.\n", ProcessInformation.dwProcessId);
  683. CloseHandle(ProcessInformation.hProcess);
  684. CloseHandle(ProcessInformation.hThread);
  685. CommChannel = StandardOut[0];
  686. StandardOut[0] = INVALID_HANDLE_VALUE;
  687. CommChannelOut = StandardIn[1];
  688. StandardIn[1] = INVALID_HANDLE_VALUE;
  689. CommChannelType = CommChannelExec;
  690. CreateExecPipeEnd:
  691. if (StandardIn[0] != INVALID_HANDLE_VALUE) {
  692. CloseHandle(StandardIn[0]);
  693. }
  694. if (StandardIn[1] != INVALID_HANDLE_VALUE) {
  695. CloseHandle(StandardIn[1]);
  696. }
  697. if (StandardOut[0] != INVALID_HANDLE_VALUE) {
  698. CloseHandle(StandardOut[0]);
  699. }
  700. if (StandardOut[1] != INVALID_HANDLE_VALUE) {
  701. CloseHandle(StandardOut[1]);
  702. }
  703. return Result;
  704. }
  705. DWORD
  706. WINAPI
  707. DbgrpOsThreadStart (
  708. LPVOID Parameter
  709. )
  710. /*++
  711. Routine Description:
  712. This routine implements a short wrapper for threads in Windows.
  713. Arguments:
  714. Parameter - Supplies a pointer to the thread creation context. This routine
  715. will free this parameter.
  716. Return Value:
  717. 0 always.
  718. --*/
  719. {
  720. PNT_THREAD_CREATION_CONTEXT Context;
  721. PDBGR_THREAD_ROUTINE Routine;
  722. PVOID RoutineParameter;
  723. Context = (PNT_THREAD_CREATION_CONTEXT)Parameter;
  724. Routine = Context->ThreadRoutine;
  725. RoutineParameter = Context->Parameter;
  726. free(Context);
  727. Routine(RoutineParameter);
  728. return 0;
  729. }
  730. VOID
  731. DbgrpPrintLastError (
  732. VOID
  733. )
  734. /*++
  735. Routine Description:
  736. This routine prints a description of GetLastError to standard error and
  737. also prints a newline.
  738. Arguments:
  739. None.
  740. Return Value:
  741. None.
  742. --*/
  743. {
  744. char *Message;
  745. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  746. NULL,
  747. GetLastError(),
  748. 0,
  749. (LPSTR)&Message,
  750. 0,
  751. NULL);
  752. DbgOut("%s", Message);
  753. LocalFree(Message);
  754. return;
  755. }