1 /* $Id: gdb2.cpp 42968 2009-08-30 15:35:14Z sginsberg $
3 * gdb2 - gdb output splitter
5 * Copyright (C) 2000,2001 Nedko Arnaoudov <nedkohome@atia.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
25 #define GDB_INITIAL_COMMAND "gdb.exe"
26 #define PARAMS_SEPARATOR " "
27 #define PARAMS_SEPARATOR_LEN strlen(PARAMS_SEPARATOR);
29 void DisplayError(const char *pszAPI
);
30 void ReadAndHandleOutput(HANDLE hPipeRead
);
31 void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut
,
34 char *pchCommandLine
);
36 DWORD WINAPI
GetAndSendInputThread(LPVOID lpvThreadParam
);
37 HANDLE hChildProcess
= NULL
;
38 HANDLE hStdIn
= NULL
; // Handle to parents std input.
39 BOOL bRunThread
= TRUE
;
41 int main(int argc
, char* argv
[])
43 HANDLE hOutputReadTmp
,hOutputRead
,hOutputWrite
;
44 HANDLE hInputWriteTmp
,hInputRead
,hInputWrite
;
48 SECURITY_ATTRIBUTES sa
;
50 // Set up the security attributes struct.
51 sa
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
52 sa
.lpSecurityDescriptor
= NULL
;
53 sa
.bInheritHandle
= TRUE
;
56 // Create the child output pipe.
57 if (!CreatePipe(&hOutputReadTmp
,&hOutputWrite
,&sa
,0))
58 DisplayError("CreatePipe");
61 // Create a duplicate of the output write handle for the std error
62 // write handle. This is necessary in case the child application
63 // closes one of its std output handles.
64 if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite
,
65 GetCurrentProcess(),&hErrorWrite
,0,
66 TRUE
,DUPLICATE_SAME_ACCESS
))
67 DisplayError("DuplicateHandle");
70 // Create the child input pipe.
71 if (!CreatePipe(&hInputRead
,&hInputWriteTmp
,&sa
,0))
72 DisplayError("CreatePipe");
75 // Create new output read handle and the input write handles. Set
76 // the Properties to FALSE. Otherwise, the child inherits the
77 // properties and, as a result, non-closeable handles to the pipes
79 if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp
,
81 &hOutputRead
, // Address of new handle.
82 0,FALSE
, // Make it uninheritable.
83 DUPLICATE_SAME_ACCESS
))
84 DisplayError("DupliateHandle");
86 if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp
,
88 &hInputWrite
, // Address of new handle.
89 0,FALSE
, // Make it uninheritable.
90 DUPLICATE_SAME_ACCESS
))
91 DisplayError("DupliateHandle");
94 // Close inheritable copies of the handles you do not want to be
96 if (!CloseHandle(hOutputReadTmp
)) DisplayError("CloseHandle");
97 if (!CloseHandle(hInputWriteTmp
)) DisplayError("CloseHandle");
100 // Get std input handle so you can close it and force the ReadFile to
101 // fail when you want the input thread to exit.
102 if ( (hStdIn
= GetStdHandle(STD_INPUT_HANDLE
)) ==
103 INVALID_HANDLE_VALUE
)
104 DisplayError("GetStdHandle");
106 SetConsoleTitle("gdb control console");
108 size_t size
= strlen(GDB_INITIAL_COMMAND
)+PARAMS_SEPARATOR_LEN
;
110 // get parameters length
111 for (int i
= 1 ; i
< argc
; i
++)
112 size
+= strlen(argv
[i
])+PARAMS_SEPARATOR_LEN
;
114 size
++; // terminating null
116 char *pszCommandLine
= new char [size
];
119 printf("out of memory.\n");
123 strcpy(pszCommandLine
,GDB_INITIAL_COMMAND
);
124 for (int i
= 1 ; i
< argc
; i
++)
126 strcat(pszCommandLine
,PARAMS_SEPARATOR
);
127 strcat(pszCommandLine
,argv
[i
]);
130 PrepAndLaunchRedirectedChild(hOutputWrite
,hInputRead
,hErrorWrite
,pszCommandLine
);
133 // Close pipe handles (do not continue to modify the parent).
134 // You need to make sure that no handles to the write end of the
135 // output pipe are maintained in this process or else the pipe will
136 // not close when the child process exits and the ReadFile will hang.
137 if (!CloseHandle(hOutputWrite
)) DisplayError("CloseHandle");
138 if (!CloseHandle(hInputRead
)) DisplayError("CloseHandle");
139 if (!CloseHandle(hErrorWrite
)) DisplayError("CloseHandle");
142 // Launch the thread that gets the input and sends it to the child.
143 hThread
= CreateThread(NULL
,0,GetAndSendInputThread
,
144 (LPVOID
)hInputWrite
,0,&ThreadId
);
145 if (hThread
== NULL
) DisplayError("CreateThread");
148 // Read the child's output.
149 ReadAndHandleOutput(hOutputRead
);
150 // Redirection is complete
153 // Force the read on the input to return by closing the stdin handle.
154 if (!CloseHandle(hStdIn
)) DisplayError("CloseHandle");
157 // Tell the thread to exit and wait for thread to die.
160 if (WaitForSingleObject(hThread
,INFINITE
) == WAIT_FAILED
)
161 DisplayError("WaitForSingleObject");
163 if (!CloseHandle(hOutputRead
)) DisplayError("CloseHandle");
164 if (!CloseHandle(hInputWrite
)) DisplayError("CloseHandle");
169 ///////////////////////////////////////////////////////////////////////
170 // PrepAndLaunchRedirectedChild
171 // Sets up STARTUPINFO structure, and launches redirected child.
172 ///////////////////////////////////////////////////////////////////////
173 void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut
,
176 char *pchCommandLine
)
178 PROCESS_INFORMATION pi
;
180 static CHAR Title
[] = "debugged program console";
182 // Set up the start up info struct.
183 ZeroMemory(&si
,sizeof(STARTUPINFO
));
184 si
.cb
= sizeof(STARTUPINFO
);
185 si
.dwFlags
= STARTF_USESTDHANDLES
;
186 si
.hStdOutput
= hChildStdOut
;
187 si
.hStdInput
= hChildStdIn
;
188 si
.hStdError
= hChildStdErr
;
190 // Use this if you want to hide the child:
191 // si.wShowWindow = SW_HIDE;
192 // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
193 // use the wShowWindow flags.
196 // Launch the process that you want to redirect (in this case,
197 // Child.exe). Make sure Child.exe is in the same directory as
198 // redirect.c launch redirect from a command line to prevent location
200 if (!CreateProcess(NULL
,pchCommandLine
,NULL
,NULL
,TRUE
,
201 CREATE_NEW_CONSOLE
,NULL
,NULL
,&si
,&pi
))
202 DisplayError("CreateProcess");
205 // Set global child process handle to cause threads to exit.
206 hChildProcess
= pi
.hProcess
;
209 // Close any unnecessary handles.
210 if (!CloseHandle(pi
.hThread
)) DisplayError("CloseHandle");
213 ///////////////////////////////////////////////////////////////////////
214 // ReadAndHandleOutput
215 // Monitors handle for input. Exits when child exits or pipe breaks.
216 ///////////////////////////////////////////////////////////////////////
217 void ReadAndHandleOutput(HANDLE hPipeRead
)
225 if (!ReadFile(hPipeRead
,lpBuffer
,sizeof(lpBuffer
),
226 &nBytesRead
,NULL
) || !nBytesRead
)
228 if (GetLastError() == ERROR_BROKEN_PIPE
)
229 break; // pipe done - normal exit path.
231 DisplayError("ReadFile"); // Something bad happened.
234 // Display the character read on the screen.
235 if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE
),lpBuffer
,
236 nBytesRead
,&nCharsWritten
,NULL
))
237 DisplayError("WriteConsole");
242 ///////////////////////////////////////////////////////////////////////
243 // GetAndSendInputThread
244 // Thread procedure that monitors the console for input and sends input
245 // to the child process through the input pipe.
246 // This thread ends when the child application exits.
247 ///////////////////////////////////////////////////////////////////////
248 DWORD WINAPI
GetAndSendInputThread(LPVOID lpvThreadParam
)
251 DWORD nBytesRead
,nBytesWrote
;
252 HANDLE hPipeWrite
= (HANDLE
)lpvThreadParam
;
254 // Get input from our console and send it to child through the pipe.
257 if(!ReadConsole(hStdIn
,read_buff
,1,&nBytesRead
,NULL
))
258 DisplayError("ReadConsole");
260 read_buff
[nBytesRead
] = '\0'; // Follow input with a NULL.
262 if (!WriteFile(hPipeWrite
,read_buff
,nBytesRead
,&nBytesWrote
,NULL
))
264 if (GetLastError() == ERROR_NO_DATA
)
265 break; // Pipe was closed (normal exit path).
267 DisplayError("WriteFile");
274 ///////////////////////////////////////////////////////////////////////
276 // Displays the error number and corresponding message.
277 ///////////////////////////////////////////////////////////////////////
278 void DisplayError(const char *pszAPI
)
280 LPVOID lpvMessageBuffer
;
281 CHAR szPrintBuffer
[512];
285 FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_FROM_SYSTEM
,
286 NULL
, GetLastError(),
287 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
288 (LPTSTR
)&lpvMessageBuffer
, 0, NULL
);
290 wsprintf(szPrintBuffer
,
291 "ERROR: API = %s.\n error code = %d.\n message = %s.\n",
292 pszAPI
, GetLastError(), (char *)lpvMessageBuffer
);
294 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE
),szPrintBuffer
,
295 lstrlen(szPrintBuffer
),&nCharsWritten
,NULL
);
297 LocalFree(lpvMessageBuffer
);
298 ExitProcess(GetLastError());