Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299/* * gdb2 - gdb output splitter * * Copyright (C) 2000,2001 Nedko Arnaoudov <nedkohome@atia.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */
#include "ph.h"
#define GDB_INITIAL_COMMAND "gdb.exe"#define PARAMS_SEPARATOR " "#define PARAMS_SEPARATOR_LEN strlen(PARAMS_SEPARATOR);
void DisplayError(const char *pszAPI);void ReadAndHandleOutput(HANDLE hPipeRead);void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut, HANDLE hChildStdIn, HANDLE hChildStdErr, char *pchCommandLine);
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);HANDLE hChildProcess = NULL;HANDLE hStdIn = NULL; // Handle to parents std input.BOOL bRunThread = TRUE;
int main(int argc, char* argv[]){ HANDLE hOutputReadTmp,hOutputRead,hOutputWrite; HANDLE hInputWriteTmp,hInputRead,hInputWrite; HANDLE hErrorWrite; HANDLE hThread; DWORD ThreadId; SECURITY_ATTRIBUTES sa;
// Set up the security attributes struct. sa.nLength= sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE;
// Create the child output pipe. if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0)) DisplayError("CreatePipe");
// Create a duplicate of the output write handle for the std error // write handle. This is necessary in case the child application // closes one of its std output handles. if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite, GetCurrentProcess(),&hErrorWrite,0, TRUE,DUPLICATE_SAME_ACCESS)) DisplayError("DuplicateHandle");
// Create the child input pipe. if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0)) DisplayError("CreatePipe");
// Create new output read handle and the input write handles. Set // the Properties to FALSE. Otherwise, the child inherits the // properties and, as a result, non-closeable handles to the pipes // are created. if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp, GetCurrentProcess(), &hOutputRead, // Address of new handle. 0,FALSE, // Make it uninheritable. DUPLICATE_SAME_ACCESS)) DisplayError("DupliateHandle");
if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp, GetCurrentProcess(), &hInputWrite, // Address of new handle. 0,FALSE, // Make it uninheritable. DUPLICATE_SAME_ACCESS)) DisplayError("DupliateHandle");
// Close inheritable copies of the handles you do not want to be // inherited. if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle"); if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");
// Get std input handle so you can close it and force the ReadFile to // fail when you want the input thread to exit. if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE ) DisplayError("GetStdHandle");
SetConsoleTitle("gdb control console");
size_t size = strlen(GDB_INITIAL_COMMAND)+PARAMS_SEPARATOR_LEN;
// get parameters length for (int i = 1 ; i < argc ; i++) size += strlen(argv[i])+PARAMS_SEPARATOR_LEN;
size++; // terminating null
char *pszCommandLine = new char [size]; if (!pszCommandLine) { printf("out of memory.\n"); return -1; }
strcpy(pszCommandLine,GDB_INITIAL_COMMAND); for (int i = 1 ; i < argc ; i++) { strcat(pszCommandLine,PARAMS_SEPARATOR); strcat(pszCommandLine,argv[i]); }
PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite,pszCommandLine);
// Close pipe handles (do not continue to modify the parent). // You need to make sure that no handles to the write end of the // output pipe are maintained in this process or else the pipe will // not close when the child process exits and the ReadFile will hang. if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle"); if (!CloseHandle(hInputRead )) DisplayError("CloseHandle"); if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");
// Launch the thread that gets the input and sends it to the child. hThread = CreateThread(NULL,0,GetAndSendInputThread, (LPVOID)hInputWrite,0,&ThreadId); if (hThread == NULL) DisplayError("CreateThread");
// Read the child's output. ReadAndHandleOutput(hOutputRead); // Redirection is complete
// Force the read on the input to return by closing the stdin handle. if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");
// Tell the thread to exit and wait for thread to die. bRunThread = FALSE;
if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED) DisplayError("WaitForSingleObject");
if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle"); if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
return 0;}
///////////////////////////////////////////////////////////////////////// PrepAndLaunchRedirectedChild// Sets up STARTUPINFO structure, and launches redirected child.///////////////////////////////////////////////////////////////////////void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut, HANDLE hChildStdIn, HANDLE hChildStdErr, char *pchCommandLine){ PROCESS_INFORMATION pi; STARTUPINFO si; static CHAR Title[] = "debugged program console";
// Set up the start up info struct. ZeroMemory(&si,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdOutput = hChildStdOut; si.hStdInput = hChildStdIn; si.hStdError = hChildStdErr; si.lpTitle = Title; // Use this if you want to hide the child: // si.wShowWindow = SW_HIDE; // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to // use the wShowWindow flags.
// Launch the process that you want to redirect (in this case, // Child.exe). Make sure Child.exe is in the same directory as // redirect.c launch redirect from a command line to prevent location // confusion. if (!CreateProcess(NULL,pchCommandLine,NULL,NULL,TRUE, CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)) DisplayError("CreateProcess");
// Set global child process handle to cause threads to exit. hChildProcess = pi.hProcess;
// Close any unnecessary handles. if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");}
///////////////////////////////////////////////////////////////////////// ReadAndHandleOutput// Monitors handle for input. Exits when child exits or pipe breaks.///////////////////////////////////////////////////////////////////////void ReadAndHandleOutput(HANDLE hPipeRead){ CHAR lpBuffer[256]; DWORD nBytesRead; DWORD nCharsWritten;
while(TRUE) { if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer), &nBytesRead,NULL) || !nBytesRead) { if (GetLastError() == ERROR_BROKEN_PIPE) break; // pipe done - normal exit path. else DisplayError("ReadFile"); // Something bad happened. }
// Display the character read on the screen. if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer, nBytesRead,&nCharsWritten,NULL)) DisplayError("WriteConsole"); }}
///////////////////////////////////////////////////////////////////////// GetAndSendInputThread// Thread procedure that monitors the console for input and sends input// to the child process through the input pipe.// This thread ends when the child application exits.///////////////////////////////////////////////////////////////////////DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam){ CHAR read_buff[256]; DWORD nBytesRead,nBytesWrote; HANDLE hPipeWrite = (HANDLE)lpvThreadParam;
// Get input from our console and send it to child through the pipe. while (bRunThread) { if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL)) DisplayError("ReadConsole");
read_buff[nBytesRead] = '\0'; // Follow input with a NULL.
if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL)) { if (GetLastError() == ERROR_NO_DATA) break; // Pipe was closed (normal exit path). else DisplayError("WriteFile"); } }
return 1;}
///////////////////////////////////////////////////////////////////////// DisplayError// Displays the error number and corresponding message.///////////////////////////////////////////////////////////////////////void DisplayError(const char *pszAPI){ LPVOID lpvMessageBuffer; CHAR szPrintBuffer[512]; DWORD nCharsWritten;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpvMessageBuffer, 0, NULL);
wsprintf(szPrintBuffer, "ERROR: API = %s.\n error code = %d.\n message = %s.\n", pszAPI, GetLastError(), (char *)lpvMessageBuffer);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),szPrintBuffer, lstrlen(szPrintBuffer),&nCharsWritten,NULL);
LocalFree(lpvMessageBuffer); ExitProcess(GetLastError());}