Home | History | Annotate | Download | only in gdb-stub
      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 
     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