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
75int 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