1 /***************************************************************************
2 ** The BSD 3-Clause License. http://www.opensource.org/licenses/BSD-3-Clause
3 **
4 ** This file is part of 'mingw-builds' project.
5 ** Copyright (c) 2011,2012,2013 by niXman (i dotty nixman doggy gmail dotty com)
6 ** All rights reserved.
7 **
8 ** Project: mingw-builds ( http://sourceforge.net/projects/mingwbuilds/ )
9 **
10 ** Redistribution and use in source and binary forms, with or without
11 ** modification, are permitted provided that the following conditions are met:
12 ** - Redistributions of source code must retain the above copyright
13 **     notice, this list of conditions and the following disclaimer.
14 ** - Redistributions in binary form must reproduce the above copyright
15 **     notice, this list of conditions and the following disclaimer in
16 **     the documentation and/or other materials provided with the distribution.
17 ** - Neither the name of the 'mingw-builds' nor the names of its contributors may
18 **     be used to endorse or promote products derived from this software
19 **     without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 ** A PARTICULAR PURPOSE ARE DISCLAIMED.
25 ** IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
26 ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
31 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 **
33 ***************************************************************************/
34 
35 #include <windows.h>
36 
37 #include <stdio.h>
38 #include <strings.h>
39 
40 #ifdef _DEBUG
41  #define dbg_printf(...) printf(__VA_ARGS__)
42 #else
43  #define dbg_printf(...) do {} while(0)
44 #endif
45 
46 // When built for the Android NDK, values are
47 // passed in on the GCC commandline, and when
48 // built for mingw-builds, these defaults are
49 // used.
50 #ifndef GDB_TO_PYTHON_REL_DIR
51  #define GDB_TO_PYTHON_REL_DIR "..\\opt\\bin"
52 #endif
53 
54 #ifndef GDB_EXECUTABLE_ORIG_FILENAME
55  #define GDB_EXECUTABLE_ORIG_FILENAME "gdborig.exe"
56 #endif
57 
58 #ifndef PYTHONHOME_REL_DIR
59  #define PYTHONHOME_REL_DIR "..\\opt"
60 #endif
61 
62 #define DIE_IF_FALSE(var) \
63 	do { \
64 		if ( !(var) ) { \
65 			fprintf(stderr, "%s(%d)[%d]: expression \"%s\" fail. terminate.\n" \
66 				,__FILE__ \
67 				,__LINE__ \
68 				,GetLastError() \
69 				,#var \
70 			); \
71 			exit(1); \
72 		} \
73 	} while (0)
74 
main(int argc,char ** argv)75 int main(int argc, char** argv) {
76 	enum {
77 		 envbufsize = 1024*32
78 		,exebufsize = 1024
79 		,cmdbufsize = envbufsize
80 	};
81 
82 	char *envbuf, *sep, *resbuf, *cmdbuf;
83 	DWORD len, exitCode;
84 	STARTUPINFO si;
85 	PROCESS_INFORMATION pi;
86 
87 	DIE_IF_FALSE(
88 		(envbuf = (char *)malloc(envbufsize))
89 	);
90 	DIE_IF_FALSE(
91 		(cmdbuf = (char *)malloc(cmdbufsize))
92 	);
93 	*cmdbuf = 0;
94 
95 	DIE_IF_FALSE(
96 		GetEnvironmentVariable("PATH", envbuf, envbufsize)
97 	);
98 	dbg_printf("env: %s\n", envbuf);
99 
100 	DIE_IF_FALSE(
101 		GetModuleFileName(0, cmdbuf, exebufsize)
102 	);
103 	dbg_printf("curdir: %s\n", cmdbuf);
104 
105 	DIE_IF_FALSE(
106 		(sep = strrchr(cmdbuf, '\\'))
107 	);
108 	*(sep+1) = 0;
109 	strcat(cmdbuf, GDB_TO_PYTHON_REL_DIR);
110 	dbg_printf("sep: %s\n", cmdbuf);
111 
112 	len = strlen(envbuf)+strlen(cmdbuf)
113 		+1  /* for envronment separator */
114 		+1; /* for zero-terminator */
115 
116 	DIE_IF_FALSE(
117 		(resbuf = (char *)malloc(len))
118 	);
119 
120 	DIE_IF_FALSE(
121 		(snprintf(resbuf, len, "%s;%s", cmdbuf, envbuf) > 0)
122 	);
123 	dbg_printf("PATH: %s\n", resbuf);
124 
125 	DIE_IF_FALSE(
126 		SetEnvironmentVariable("PATH", resbuf)
127 	);
128 
129 	*(sep+1) = 0;
130 	strcat(cmdbuf, PYTHONHOME_REL_DIR);
131 	dbg_printf("PYTHONHOME: %s\n", cmdbuf);
132 	DIE_IF_FALSE(
133 		SetEnvironmentVariable("PYTHONHOME", cmdbuf)
134 	);
135 
136 	*(sep+1) = 0;
137 	strcat(cmdbuf, GDB_EXECUTABLE_ORIG_FILENAME" ");
138 
139 	if ( argc > 1 ) {
140 		for ( ++argv; *argv; ++argv ) {
141 			len = strlen(cmdbuf);
142 			snprintf(cmdbuf+len, cmdbufsize-len, "%s ", *argv);
143 		}
144 	}
145 	dbg_printf("cmd: %s\n", cmdbuf);
146 
147 	HANDLE ghJob = CreateJobObject(NULL, "Gdb-Wrapper\0"/*NULL*/);
148 	if ( ghJob == NULL ) {
149         fprintf(stderr, "Could not create job object\n");
150 	}
151 	else{
152 		JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
153 		// Configure all child processes associated with the job to terminate when the last handle to the job is closed
154 		jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
155 		if ( SetInformationJobObject(ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)) == 0 ) {
156             fprintf(stderr, "Could not SetInformationJobObject\n");
157 		}
158 	}
159 
160 	memset(&si, 0, sizeof(si));
161 	si.cb = sizeof(si);
162 	si.dwFlags |= STARTF_USESTDHANDLES;
163 	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
164 	si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
165 	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
166 
167 	memset(&pi, 0, sizeof(pi));
168 
169 	DIE_IF_FALSE(
170 		CreateProcess(
171 			0			// exe name
172 			,cmdbuf		// command line
173 			,0			// process security attributes
174 			,0			// primary thread security attributes
175 			,TRUE		// handles are inherited
176 			,0			// creation flags
177 			,0			// use parent's environment
178 			,0			// use parent's current directory
179 			,&si		// STARTUPINFO pointer
180 			,&pi		// receives PROCESS_INFORMATION
181 		)
182 	);
183 
184 	if ( ghJob != NULL )
185 		if ( AssignProcessToJobObject(ghJob, pi.hProcess) == 0 ) {
186             fprintf(stderr, "Could not AssignProcessToObject\n");
187 		}
188 
189 	// Do not handle Ctrl-C in the wrapper
190 	SetConsoleCtrlHandler(NULL, TRUE);
191 
192 	WaitForSingleObject(pi.hProcess, INFINITE);
193 
194 	DIE_IF_FALSE(
195 		GetExitCodeProcess(pi.hProcess, &exitCode)
196 	);
197 
198 	if ( ghJob != NULL )
199 		CloseHandle(ghJob);
200 	CloseHandle( pi.hProcess );
201 	CloseHandle( pi.hThread );
202 
203 	free(envbuf);
204 	free(resbuf);
205 	free(cmdbuf);
206 
207 	dbg_printf("exiting with exitCode %d", exitCode);
208 
209 	return exitCode;
210 }
211