1 /*
2  * Copyright (c) 2003 - 2010, Nils R. Weller
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  * Functions to execute cpp/NASM/ncc
28  */
29 #include "cc1_main.h"
30 #include "exectools.h"
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <ctype.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <signal.h>
38 #include <sys/stat.h>
39 #include <sys/wait.h>
40 #include "defs.h"
41 #include "analyze.h"
42 #include "error.h"
43 #include "lex.h"
44 #include "misc.h"
45 #include "functions.h"
46 #include "scope.h"
47 #include "backend.h"
48 #include "typemap.h"
49 #include "zalloc.h"
50 #include "debug.h"
51 #include "symlist.h"
52 #include "sysdeps.h"
53 #include "config.h"
54 #include "n_libc.h"
55 #include "fcatalog.h"
56 #include "standards.h"
57 
58 #if USE_ZONE_ALLOCATOR
59 /* Some includes for zalloc_init() */
60 #  include "control.h"
61 #  include "expr.h"
62 #  include "functions.h"
63 #  include "icode.h"
64 #  include "reg.h"
65 #  include "subexpr.h"
66 #endif
67 
68 
69 int	stackprotectflag;
70 int	ansiflag;
71 int	pedanticflag;
72 int	verboseflag;
73 int	stupidtraceflag;
74 int	gnuheadersflag = 1;
75 int	gflag;
76 int	Eflag;
77 int	Oflag = /*-1*/ 0; /* XXX set to 0 */
78 int	assembler; /* XXX unused by nwcc1, necessary for exectools linking */
79 int	abiflag;
80 int	archflag;
81 int	sysflag; /* 01/31/09: Specify system using -sys */
82 int	picflag;
83 int	timeflag;
84 char	*input_file;
85 char	*asmflag;
86 char	*asmname;
87 char	*gnuc_version;
88 char	*cpp;
89 
90 char	*custom_cpp_args;
91 
92 /*
93  * 12/25/08: For PPC - Full or minimal TOC
94  */
95 int	mintocflag;
96 int	fulltocflag;
97 
98 /*
99  * 03/02/09: -funsigned-char and -fsigned-char
100  */
101 int	funsignedchar_flag;
102 int	fsignedchar_flag;
103 /*
104  * 05/17/09: Added support for common variables
105  */
106 int	fnocommon_flag;
107 int	use_common_variables;
108 
109 /*
110  * 05/18/09: Added -notgnu
111  */
112 int	notgnu_flag;
113 int	color_flag;
114 
115 int	dump_macros_flag;
116 
117 int	write_fcat_flag;
118 int	save_bad_translation_unit_flag;
119 
120 
121 static char *
check_preprocessor(const char * path,const char * name,int * using_nwcpp)122 check_preprocessor(const char *path, const char *name, int *using_nwcpp) {
123 	if (strcmp(name, "nwcpp") == 0) {
124 		*using_nwcpp = 1;
125 	} else if (strcmp(name, "cpp") == 0) {
126 		; /* OK - cpp  (XXX: check system?) */
127 	} else if (strcmp(name, "gcc") == 0) {
128 		/* OK - gcc - append -E */
129 		char	*temp;
130 
131 		temp = n_xmalloc(strlen(path)
132 			+ sizeof " -E");
133 		sprintf(temp, "%s -E", path);
134 		path = temp;
135 	} else {
136 		(void) fprintf(stderr, "Unrecognized "
137 			"preprocessor `%s' - must be "
138 			"gcc, cpp or nwcpp\n",
139 			name);
140 		return NULL;
141 	}
142 	return (char *)path;
143 }
144 
145 #define REM_EXIT(n1, n2) do { \
146 	if (is_tmpfile) { \
147 		if (!save_bad_translation_unit_flag) { \
148 			(void) remove(n1); \
149 		} \
150 	} \
151 	(void) remove(n2); \
152 	return EXIT_FAILURE; \
153 } while (0)
154 
155 static char *
do_cpp(char * file,char ** args,int cppind)156 do_cpp(char *file, char **args, int cppind) {
157 	/* XXX FILENAME_MAX is broken on HP-UX */
158 	static char	output_path[FILENAME_MAX + 1];
159 	char		buf[FILENAME_MAX + 1];
160 	char		tmpbuf[128] = "/var/tmp/cpp";
161 	char		*arch;
162 	char		*progname;
163 	char		*progflag = "-E";
164 	char		*p;
165 	char		*gnooh = NULL;
166 	char		*gnooh2 = NULL;
167 	int		using_nwcpp = 0;
168 	int		i;
169 	int		host_sys;
170 	FILE		*fd;
171 	FILE		*fd2;
172 
173 	host_sys = sysdep_get_host_system();
174 
175 	if (sysdep_get_host_system() == OS_MIRBSD) {
176 		progname = "mgcc";
177 	} else {
178 		progname = "gcc";
179 	}
180 
181 	if (cpp == NULL) {
182 		cpp = getenv("NWCC_CPP");
183 		if (cpp == NULL) {
184 			/*
185 			 * No user preference; We use gcc -E if available,
186 			 * otherwise cpp, otherwise nwcpp. gcc comes
187 			 * before cpp because e.g. GNU cpp on OpenBSD seems
188 			 * very broken. Also, if we're on a different Unix
189 			 * system, its cpp may not be compatible with nwcc.
190 			 * nwcpp last because it's likely to be the most
191 			 * buggy of all at this point :-(
192 			 */
193 			if (find_cmd(progname, NULL, 0) != 0) {
194 				if (find_cmd("cpp", NULL, 0) == 0) {
195 					progname = "cpp";
196 					progflag = "";
197 				} else {
198 					progname = INSTALLDIR "/nwcc/bin/nwcpp";
199 					progflag = "";
200 					using_nwcpp = 1;
201 				}
202 			} else {
203 				; /* progname is already set to gcc -E */
204 			}
205 		}
206 	}
207 	if (cpp != NULL) {
208 		/*
209 		 * A preprocessor was selected using NWCC_CPP or
210 		 * -cpp. If it begins with a slash, we take it for
211 		 * an absolute path, otherwise it is presumably a
212 		 * binary located in one of the $PATH directories
213 		 */
214 		progflag = "";
215 		if (cpp[0] == '/') {
216 			struct stat	sbuf;
217 
218 			if (stat(cpp, &sbuf) == -1) {
219 				(void) fprintf(stderr, "Fatal error: "
220 					"Preprocessor `%s' "
221 					"not accessible\n", cpp);
222 				return NULL;
223 			}
224 			progname = cpp;
225 			p = strrchr(cpp, '/');
226 			progname = check_preprocessor(cpp, p+1, &using_nwcpp);
227 			if (progname == NULL) {
228 				return NULL;
229 			}
230 		} else {
231 			if (find_cmd(cpp, NULL, 0) == 0) {
232 				progname = check_preprocessor(cpp, cpp, &using_nwcpp);
233 				if (progname == NULL) {
234 					return NULL;
235 				}
236 			} else {
237 				if (strcmp(cpp, "nwcpp") == 0) {
238 					progname = INSTALLDIR "/nwcc/bin/nwcpp";
239 					using_nwcpp = 1;
240 				} else {
241 					(void) fprintf(stderr, "Fatal error: "
242 						"Cannot find preprocessor "
243 						"`%s' in $PATH\n", cpp);
244 					return NULL;
245 				}
246 			}
247 		}
248 	}
249 
250 	/*
251 	 * 03/02/09: Pass -funsigned-char/-fsigned-char so that it can pass
252 	 * proper macro definitions to libc's limits.h (for CHAR_MAX/MIN)
253 	 */
254 	if (cross_get_char_signedness() == TOK_KEY_UNSIGNED) {
255 		args[cppind++] = "-funsigned-char";
256 	} else {
257 		args[cppind++] = "-fsigned-char";
258 	}
259 
260 	if (using_nwcpp) {
261 		/*
262 		 * If we're cross-compiling, we have to pass on the
263 		 * architecture and ABI to nwcpp
264 		 */
265 		if (archflag != 0) {
266 			args[cppind++] = arch_to_option(archflag);
267 		}
268 		if (abiflag != 0) {
269 			args[cppind++] = abi_to_option(abiflag);
270 		}
271 	} else {
272 		int	host_arch;
273 		int	host_abi;
274 		int	host_sys;
275 
276 		get_host_arch(&host_arch, &host_abi, &host_sys);
277 		/*
278 		 * 11/10/08: This passes flags depending on the host
279 		 * architecture; This is wrong in that we may be
280 		 * generating for a different target (e.g. we're on
281 		 * 64bit PPC but generate for 64bit SPARC - In that
282 		 * case the code below will assume a 32bit PPC ABI.
283 		 * And it's correct in that a typical preprocessor
284 		 * will only recognize the host architecture, so
285 		 * picking wrong flags is better than nothing.
286 		 *
287 		 * XXX We should at least pick the most suitable
288 		 * flags, e.g. 64bit SPARC ABI yields 64bit PPC host
289 		 * flags
290 		 */
291 		if (host_arch == ARCH_MIPS) {
292 			if (abiflag == ABI_MIPS_N64) {
293 				args[cppind++] = "-mabi=64";
294 			}
295 		} else if (host_arch == ARCH_POWER) {
296 			if (abiflag == ABI_POWER64) {
297 				if (host_sys == OS_AIX) {
298 					args[cppind++] = "-maix64";
299 				} else {
300 					args[cppind++] = "-m64";
301 				}
302 			} else {
303 				if (host_sys != OS_AIX) {
304 					args[cppind++] = "-m32";
305 				}
306 			}
307 		}
308 	}
309 
310 	if (custom_cpp_args != NULL) {
311 		char	*p;
312 		char	*start;
313 
314 		for (p = start = custom_cpp_args; *p != 0; ++p) {
315 			if (*p == ',' || p[1] == 0) {
316 				if (*p == ',') {
317 					*p = 0;
318 				}
319 				/* XXX Check overflow!!!!!! */
320 				args[cppind++] = start;
321 				start = p+1;
322 			}
323 		}
324 	}
325 
326 	args[cppind] = NULL;
327 
328 	tunit_name = n_xmalloc(strlen(file) + 1);
329 	for (p = file, i = 0; *p != 0; ++p) {
330 		if (isalnum((unsigned char)*p) || *p == '_') {
331 			tunit_name[i++] = *p;
332 		}
333 	}
334 	tunit_name[i] = 0;
335 
336 	if ((p = strrchr(tunit_name, '.')) != NULL) {
337 		*p = 0;
338 	}
339 
340 	input_file = n_xstrdup(file);
341 	if (Eflag) {
342 		fd = stdout;
343 	} else if (save_bad_translation_unit_flag) {
344 		sprintf(output_path, "%s.i", input_file);
345 		fd = fopen(output_path, "w");
346 		if (fd == NULL) {
347 			perror(output_path);
348 			return NULL;
349 		}
350 	} else {
351 		fd = get_tmp_file(tmpbuf, output_path, "cpp");
352 		if (fd == NULL) {
353 			return NULL;
354 		}
355 	}
356 
357 	arch = "";
358 
359 	if (gnuheadersflag && stdflag != ISTD_C89 && !notgnu_flag) {
360 		if (host_sys == OS_LINUX) {
361 #ifdef GNUBYDEFAULT
362 			/*
363 			 * 07/01/07: Because the major()/minor() macros on my
364 			 * old SuSE system do not work with a GNU C version of
365 			 * less than 2, now is probably the time we have to
366 			 * bump it up. This will probably open a can of worms,
367 			 * but has to be done some time
368 			 */
369 
370 			/*
371 			 * 07/22/07: That goddamn GNU make tests for version
372 			 * 2.5... and if that's not present, it #defines
373 			 * __attribute__ to expand to an empty body. That
374 			 * breaks stuff like wait() which uses a transparent_
375 			 * union attribute. So let's set the rest on fire as
376 			 * well by bumping straight to 3
377 			 */
378 #if 0
379 		gnooh = " -U__GNUC__ -D__GNUC__=3 "; /* was 1 , then 2 !!! */
380 #endif
381 			gnooh = "-U__GNUC__"; /* was 1 , then 2 !!! */
382 			gnooh2 = "-D__GNUC__=3 "; /* was 1 , then 2 !!! */
383 #else
384 			gnooh = " -D__GNUC__=3 "; /* was 1, then 2 !!! */
385 			gnooh2 = "";
386 #endif
387 			if (using_nwcpp) {
388 				gnooh = gnooh2 = ""; /* XXX */
389 			}
390 			fd2 = exec_cmd(0, progname, "%s %s %s%s%s%[] %s",
391 				progflag,
392 				"-D__NWCC__=1",
393 				arch, gnooh, gnooh2, args, file);
394 		} else {
395 			fd2 = exec_cmd(0, progname, "%s %s %s %[] %s",
396 				progflag,
397 				"-D__NWCC__=1",
398 				arch, args, file);
399 		}
400 	} else {
401 		if (host_sys == OS_FREEBSD
402 			|| host_sys == OS_DRAGONFLYBSD
403 			|| host_sys == OS_OPENBSD
404 			|| host_sys == OS_MIRBSD) {
405 			/*
406 			 * The FreeBSD headers are worthless without __GNUC__, so
407 			 * let's invoke cpp with default settings (enables __GNUC__)
408 			 */
409 			fd2 = exec_cmd(0, progname, "%s %s %s %s %s %[] %s",
410 				progflag,
411 				ansiflag? "-D__aligned\\(x\\)=": "",
412 				"-D__NWCC__=1",
413 				(notgnu_flag || ansiflag)? "-U__GNUC__": "",
414 				arch, args, file);
415 		} else {
416 			fd2 = exec_cmd(0, progname, "%s %s %s %s %[] %s",
417 				progflag,
418 				"-D__NWCC__=1",
419 				arch,
420 				"-U__GNUC__",
421 				args, file);
422 		}
423 	}
424 
425 	if (fd2 == NULL) {
426 		perror("popen");
427 		fclose(fd);
428 		remove(output_path);
429 		return NULL;
430 	}
431 
432 	while (fgets(buf, sizeof buf, fd2)) {
433 		fputs(buf, fd);
434 	}
435 
436 	{
437 		int	rc;
438 		int	bad = 0;
439 
440 		wait(&rc);
441 		if (!WIFEXITED(rc)) {
442 			(void) fprintf(stderr, "*** cpp crashed\n");
443 			bad = 1;
444 		} else if (WEXITSTATUS(rc) != 0) {
445 			(void) fprintf(stderr, "*** cpp returned nonzero exit status.\n");
446 			bad = 1;
447 		}
448 		fclose(fd2);
449 		if (bad) {
450 			fclose(fd);
451 			if (!save_bad_translation_unit_flag) {
452 				remove(output_path);
453 			}
454 			return NULL;
455 		}
456 	}
457 
458 	fclose(fd);
459 	return output_path;
460 }
461 
462 
463 static char *garbage;
464 
465 static void
remove_garbage(void)466 remove_garbage(void) {
467 	if (errors) {
468 		remove(garbage);
469 	}
470 }
471 
472 static int	timing_cpp;
473 
474 static int
do_ncc(char * cppfile,char * nccfile,int is_tmpfile)475 do_ncc(char *cppfile, char *nccfile, int is_tmpfile) {
476 	static int		inits_done;
477 	int			fildes;
478 	FILE			*input;
479 	FILE			*fd;
480 	char			*p;
481 	static struct timeval	tv;
482 	static int		timing_init;
483 	static int		timing_lex;
484 	static int		timing_analysis;
485 	static int		timing_gen;
486 	struct stat		sbuf;
487 
488 	if (timeflag) {
489 		/* Time initialization stuff */
490 		start_timer(&tv);
491 	}
492 	/* Generate in CWD */
493 	if ((p = strrchr(nccfile, '/')) != NULL) {
494 		nccfile = p+1;
495 	}
496 
497 	garbage = nccfile;
498 	atexit(remove_garbage);
499 	if (inits_done == 0) {
500 		init_keylookup();
501 		init_oplookup();
502 		inits_done = 1;
503 	}
504 	toklist = NULL;
505 	funclist = NULL;
506 
507 	if (!write_fcat_flag) {
508 		input = fopen(cppfile, "r");
509 		if (input == NULL) {
510 			perror(cppfile);
511 			return EXIT_FAILURE;
512 		}
513 	}
514 
515 	if (dump_macros_flag) {
516 		char	buf[1024];
517 
518 		while (fgets(buf, sizeof buf, input) != NULL) {
519 			printf("%s", buf);
520 		}
521 		return 0;
522 	}
523 
524 	if (write_fcat_flag) {
525 		fd = NULL;
526 	} else {
527 		(void) unlink(nccfile); /* trash stale .asm file */
528 
529 		if ((fildes = open(nccfile, O_CREAT | O_EXCL | O_RDWR, S_IRWXU))
530 			== -1) {
531 			perror(nccfile);
532 			if (is_tmpfile) remove(cppfile);
533 			return EXIT_FAILURE;
534 		}
535 		if ((fd = fdopen(fildes, "r+")) == NULL) {
536 			perror(nccfile);
537 			REM_EXIT(cppfile, nccfile);
538 			return EXIT_FAILURE;
539 		}
540 	}
541 
542 	/*
543 	 * It is important to initialize the backend before doing
544 	 * lexical analysis because architecture and ABI information
545 	 * are needed
546 	 */
547 	if (init_backend(fd, &global_scope) != 0) {
548 			REM_EXIT(cppfile, nccfile);
549 		}
550 
551 	#if USE_ZONE_ALLOCATOR
552 		zalloc_create();
553 		zalloc_init(Z_CONTROL, sizeof(struct control), 1, 0);
554 		/*
555 		 * 10/20/09: Disable label memory reclaimation for now. This is
556 		 * needed since the switch label changes were made, or else the
557 		 * ctrl->labels (ctrl_to_icode() for TOK_KEY_SWITCH) list will
558 		 * end up containing a member that links to itself.
559 		 */
560 		zalloc_init(Z_LABEL, sizeof(struct label), 1, 1);
561 		zalloc_init(Z_EXPR, sizeof(struct expr), 1, 0);  /* XXX doesn't work */
562 		zalloc_init(Z_INITIALIZER, sizeof(struct initializer), 1, 1);
563 		zalloc_init(Z_STATEMENT, sizeof(struct statement), 1, 1);
564 		zalloc_init(Z_FUNCTION, sizeof(struct function), 1, 1);
565 		zalloc_init(Z_ICODE_INSTR, sizeof(struct icode_instr), 1, 0);
566 		zalloc_init(Z_ICODE_LIST, sizeof(struct icode_list), 1, 0);
567 		zalloc_init(Z_VREG, sizeof(struct vreg), 1, 0);
568 	zalloc_init(Z_STACK_BLOCK, sizeof(struct stack_block), 1, 0);
569 	zalloc_init(Z_S_EXPR, sizeof(struct s_expr), 1, 0);
570 	zalloc_init(Z_FCALL_DATA, sizeof(struct fcall_data), 1, 0);
571 /*	zalloc_init(Z_IDENTIFIER, sizeof(struct control), 1);*/
572 #if FAST_SYMBOL_LOOKUP
573 	zalloc_init(Z_FASTSYMHASH, sizeof(struct fast_sym_hash_entry), 1, 0);
574 #endif
575 
576 	zalloc_init(Z_CEXPR_BUF, 16, 1, 1); /* XXX */
577 
578 #endif
579 
580 
581 	if (write_fcat_flag) {
582 		/*
583 		 * 07/27/09: Parse function catalog and write index file.
584 		 * We do this here because there are various parser
585 		 * initializations which shouldn't be missed
586 		 */
587 		if (is_tmpfile) (void) remove(cppfile);
588 		(void) remove(nccfile);
589 
590 		return fcat_write_index_file("fcatalog.idx", "fcatalog");
591 	}
592 
593 	if (stat(INSTALLDIR "/nwcc/lib/fcatalog.idx", &sbuf) == 0) {
594 		(void) fcat_open_index_file(INSTALLDIR "/nwcc/lib/fcatalog.idx");
595 	} else {
596 		(void) fcat_open_index_file("fcatalog.idx");
597 	}
598 
599 	if (timeflag) {
600 		timing_init = stop_timer(&tv);
601 		start_timer(&tv);
602 	}
603 
604 	if (lex(input) != 0) {
605 		REM_EXIT(cppfile, nccfile);
606 	}
607 
608 	if (timeflag) {
609 		timing_lex = stop_timer(&tv);
610 		start_timer(&tv);
611 	}
612 
613 
614 #if XLATE_IMMEDIATELY
615 	/* Prepare .asm file for code generation */
616 	backend->gen_prepare_output();
617 #endif
618 
619 	/* Now compile all code */
620 	if (analyze(NULL) != 0) {
621 		REM_EXIT(cppfile, nccfile);
622 	}
623 
624 #if XLATE_IMMEDIATELY
625 	if (!errors) {
626 		/* Finish code generation */
627 		backend->gen_finish_output();
628 	}
629 #endif
630 
631 	if (timeflag) {
632 		timing_analysis = stop_timer(&tv);
633 		start_timer(&tv);
634 	}
635 
636 #if ! XLATE_IMMEDIATELY
637 	/*
638 	 * All code has been parsed and translated to icode, and can now
639 	 * be written as a whole .asm file in one step
640 	 */
641 	if (errors || backend->generate_program() != 0) {
642 		;
643 	}
644 #endif
645 
646 	if (timeflag) {
647 		timing_gen = stop_timer(&tv);
648 	}
649 
650 	/* destroy_toklist(&toklist); */
651 	fclose(input);
652 	if (is_tmpfile) {
653 		if (!save_bad_translation_unit_flag) {
654 			remove(cppfile);
655 		}
656 	}
657 
658 	if (color_flag) {
659 		reset_text_color();
660 	}
661 
662 	(void) fprintf(stderr, "%s - %u error(s), %u warning(s)\n",
663 		cppfile, (unsigned)errors, (unsigned)warnings);
664 
665 	if (timeflag) {
666 		int	timing_total = timing_cpp + timing_init + timing_lex +
667 				timing_analysis + timing_gen;
668 
669 #define RESULT(x) x / 1000000.0, (float)x / timing_total * 100
670 		(void) fprintf(stderr, "=== Timing of nwcc1 ===\n");
671 		(void) fprintf(stderr, "   Preprocessing:   %f sec  "
672 			"(%f%% of total)\n", RESULT(timing_cpp));
673 		(void) fprintf(stderr, "   Initialization:  %f sec  "
674 			"(%f%% of total)\n", RESULT(timing_init));
675 		(void) fprintf(stderr, "   Lexing:          %f sec  "
676 			"(%f%% of total)\n", RESULT(timing_lex));
677 		(void) fprintf(stderr, "   Parsing+icode:   %f sec  "
678 			"(%f%% of total)\n", RESULT(timing_analysis));
679 		(void) fprintf(stderr, "   Emission:        %f sec  "
680 			"(%f%% of total)\n", RESULT(timing_gen));
681 	}
682 
683 	if (errors) {
684 		remove(nccfile);
685 		return EXIT_FAILURE;
686 	}
687 	return 0;
688 }
689 
690 
691 static void
segv_handler(int s)692 segv_handler(int s) {
693 	char	*p;
694 	(void) s;
695 	p = "Segmentation fault\n";
696 	write(1, p, strlen(p));
697 	exit(EXIT_FAILURE); /* Dangerous, but necessary for debugging */
698 }
699 
700 static void
usage(void)701 usage(void) {
702 	/* XXX add useful stuff here */
703 	puts("You invoked nwcc1 incorrectly. Please refer to the README file");
704 	puts("for supported command line arguments");
705 	exit(EXIT_FAILURE);
706 }
707 
708 
709 
710 int
main(int argc,char * argv[])711 main(int argc, char *argv[]) {
712 	int			ch;
713 	char			*p;
714 	char			*nccfile = NULL;
715 	char			*tmp;
716 	char			*target_str = NULL;
717 	char			*abi_str = NULL;
718 	char			*sys_str = NULL;
719 	char			*cpp_args[128];
720 	int			cppind = 0;
721 	int			is_tmpfile = 0;
722 	int			nostdincflag = 0;
723 	static struct timeval	tv;
724 	struct ga_option	options[] = {
725 		{ 'D', NULL, 1 },
726 		{ 'U', NULL, 1 },
727 		{ 'I', NULL, 1 },
728 		{ 'E', NULL, 0 },
729 		{ 'g', NULL, 0 },
730 		{ 0, "stackprotect", 0 },
731 		{ 0, "nostdinc", 0 },
732 		{ 0, "arch", 1 },
733 		{ 0, "gnuc", 1 },
734 		{ 0, "cpp", 1 },
735 #ifdef __sun
736 		{ 0, "xarch", 1 },
737 #endif
738 		{ 0, "mabi", 1 },
739 		{ 0, "abi", 1 },
740 		{ 0, "sys", 1 },
741 		{ 0, "pedantic", 0 },
742 		{ 0, "verbose", 0 },
743 		{ 0, "stupidtrace", 0 },
744 		{ 0, "std", 1 },
745 		{ 0, "asm", 1 },
746 		{ 0, "fpic", 0 },
747 		{ 0, "fPIC", 0 },
748 		{ 0, "ansi", 0 },
749 		{ 0, "time", 0 },
750 		{ 0, "dM", 0 },
751 		{ 0, "mminimal-toc", 0 },
752 		{ 0, "mfull-toc", 0 },
753 		{ 0, "funsigned-char", 0 },
754 		{ 0, "fsigned-char", 0 },
755 		{ 0, "fno-common", 0 },
756 		{ 0, "notgnu", 0 },
757 		{ 0, "gnu", 0 },
758 		{ 0, "color", 0 },
759 		{ 0, "Wp", 1 },
760 		{ 0, "O-1", 0 },
761 		{ 0, "O0", 0 },
762 		{ 0, "O1", 0 },
763 		{ 0, "O2", 0 },
764 		{ 0, "O3", 0 },
765 		{ 0, "write-fcat", 0 },
766 		{ 0, "save-bad-translation-unit", 0 }
767 	};
768 	int			nopts = N_OPTIONS(options);
769 	int			idx;
770 
771 	(void) segv_handler;
772 #if 0
773 	(void) signal(SIGSEGV, segv_handler);
774 	get_host_arch(&archflag, &abiflag);
775 #endif
776 	if (argc <= 1) {
777 		usage();
778 	}
779 
780 	while ((ch = nw_get_arg(argc-1, argv+1, options, nopts, &idx)) != -1) {
781 		switch (ch) {
782 		case 'D':
783 		case 'U':
784 		case 'I':
785 			if (cppind == 126) {
786 				(void) fprintf(stderr, "Too many stderr "
787 					     "arguments\n");
788 				return EXIT_FAILURE;
789 			}
790 
791 			/* OpenBSD's cpp chokes on -D arg, needs -Darg ... */
792 			cpp_args[cppind] = n_xmalloc(strlen(n_optarg) + 3);
793 			sprintf(cpp_args[cppind++], "-%c%s", ch, n_optarg);
794 			break;
795 		case 'g':
796 			gflag = 1;
797 			/* XXX */gflag = 0;
798 			break;
799 		case 'E':
800 			Eflag = 1;
801 			break;
802 		case '!':
803 			if (nccfile != NULL) {
804 				(void) fprintf(stderr, "Error: More than one "
805 					      "input file specified\n");
806 				usage();
807 			}
808 			nccfile = n_xmalloc(strlen(n_optarg) + 16);
809 			strcpy(nccfile, n_optarg);
810 			break;
811 		case '?':
812 			if (idx) {
813 				if (options[idx].name[0] == 'O'
814 					&& (options[idx].name[1] == '-'
815 					|| isdigit((unsigned char)options[idx].
816 						name[1]))) {
817 					if (strcmp(options[idx].name, "O-1")
818 						== 0) {
819 						Oflag = -1;
820 					} else if (options[idx].name[1] == '0') {
821 						Oflag = 0;
822 					} else {
823 						; /* ignore for now */
824 					}
825 				} else if (strcmp(options[idx].name, "stackprotect")
826 					== 0) {
827 					stackprotectflag = 1;
828 				} else if (strcmp(options[idx].name, "ansi")
829 					== 0) {
830 					/*ansiflag = standard = C89;*/
831 					stdflag = option_to_std("c89");
832 					ansiflag = 1;
833 				} else if (strcmp(options[idx].name, "pedantic")
834 					== 0) {
835 					pedanticflag = 1;
836 				} else if (strcmp(options[idx].name, "verbose")
837 					== 0) {
838 					verboseflag = 1;
839 				} else if (strcmp(options[idx].name, "stupidtrace")
840 					== 0) {
841 					stupidtraceflag = 1;
842 				} else if (strcmp(options[idx].name, "nostdinc")
843 					== 0) {
844 					cpp_args[cppind++] = "-nostdinc";
845 					nostdincflag = 1;
846 				} else if (strcmp(options[idx].name, "asm")
847 					== 0) {
848 					asmflag = n_xstrdup(n_optarg);
849 					if ((asmname = strrchr(asmflag, '/')) != NULL) {
850 						++asmname;
851 					} else {
852 						asmname = asmflag;
853 					}
854 				} else if (strcmp(options[idx].name, "std")
855 					== 0) {
856 					stdflag = option_to_std(n_optarg);
857 				} else if (strcmp(options[idx].name, "dM")
858 					== 0) {
859 					cpp_args[cppind++] = n_xstrdup("-dM");
860 					dump_macros_flag = 1;
861 				} else if (strcmp(options[idx].name, "arch")
862 					== 0) {
863 					if (target_str != NULL) {
864 						(void) fprintf(stderr, "-arch "
865 						"used more than once\n");
866 						exit(EXIT_FAILURE);
867 					}
868 					target_str = n_xstrdup(n_optarg);
869 				} else if (strcmp(options[idx].name, "gnuc")
870 					== 0) {
871 					if (gnuc_version != NULL) {
872 						(void) fprintf(stderr, "-gnuc "
873 						"used more than once\n");
874 						exit(EXIT_FAILURE);
875 					}
876 					gnuc_version = n_xstrdup(n_optarg);
877 				} else if (strcmp(options[idx].name, "cpp")
878 					== 0) {
879 					if (cpp != NULL) {
880 						(void) fprintf(stderr, "-cpp "
881 						"used more than once\n");
882 						exit(EXIT_FAILURE);
883 					}
884 					cpp = n_xstrdup(n_optarg);
885 				} else if (strcmp(options[idx].name, "xarch")
886 					== 0) {
887 					/* SunCC compatibility */
888 					;
889 				} else if (strcmp(options[idx].name, "mfull-toc")
890 					== 0) {
891 					fulltocflag = 1;
892 				} else if (strcmp(options[idx].name, "mminimal-toc")
893 					== 0) {
894 					mintocflag = 1;
895 				} else if (strcmp(options[idx].name, "mabi")
896 					== 0
897 					|| strcmp(options[idx].name, "abi")
898 					== 0) {
899 					if (abi_str != NULL) {
900 						(void) fprintf(stderr, "-%s "
901 						"used more than once\n",
902 						options[idx].name);
903 						exit(EXIT_FAILURE);
904 					}
905 					abi_str = n_xstrdup(n_optarg);
906 #if 0
907 					abiflag = ascii_abi_to_value(
908 						n_optarg, archflag);
909 #endif
910 				} else if (strcmp(options[idx].name, "sys") == 0) {
911 					if (sys_str != NULL) {
912 						(void) fprintf(stderr, "-sys "
913 							"used more than once");
914 						exit(EXIT_FAILURE);
915 					}
916 					sys_str = n_xstrdup(n_optarg);
917 				} else if (strcmp(options[idx].name, "fpic")
918 					== 0
919 					|| strcmp(options[idx].name, "fPIC")
920 					== 0) {
921 					picflag = 1;
922 				} else if (strcmp(options[idx].name, "fsigned-char")
923 					== 0) {
924 					fsignedchar_flag = 1;
925 				} else if (strcmp(options[idx].name, "funsigned-char")
926 					== 0) {
927 					funsignedchar_flag = 1;
928 				} else if (strcmp(options[idx].name, "fno-common")
929 					== 0) {
930 					fnocommon_flag = 1;
931 				} else if (strcmp(options[idx].name, "notgnu") == 0) {
932 					notgnu_flag = 1;
933 				} else if (strcmp(options[idx].name, "gnu") == 0) {
934 					notgnu_flag = 0;
935 				} else if (strcmp(options[idx].name, "color") == 0) {
936 					color_flag = 1;
937 				} else if (strcmp(options[idx].name, "time")
938 					== 0) {
939 					timeflag = 1;
940 				} else if (strcmp(options[idx].name, "Wp") == 0) {
941 					custom_cpp_args = n_xstrdup(n_optarg);
942 				} else if (strcmp(options[idx].name, "write-fcat") == 0) {
943 					write_fcat_flag = 1;
944 				} else if (strcmp(options[idx].name, "save-bad-translation-unit") == 0) {
945 					save_bad_translation_unit_flag = 1;
946 				} else {
947 					usage();
948 				}
949 			} else {
950 				usage();
951 			}
952 			break;
953 		default:
954 			return EXIT_FAILURE;
955 		}
956 	}
957 
958 
959 	if (nccfile == NULL) {
960 		/* XXX use stdin */
961 		(void) fprintf(stderr, "No input file specified.\n");
962 		return EXIT_FAILURE;
963 	}
964 
965 	if (stdflag == ISTD_NONE) {
966 		stdflag = set_default_std();
967 	}
968 
969 	if (gnuc_version == NULL) {
970 		gnuc_version = "2";
971 	}
972 
973 	set_target_arch_and_abi_and_sys(&archflag, &abiflag, &sysflag, target_str, abi_str, sys_str);
974 
975 	if (!nostdincflag) {
976 		if (archflag == ARCH_SPARC && sysdep_get_host_system() == OS_SOLARIS) {
977 			cpp_args[cppind++] = "-nostdinc";
978 			cpp_args[cppind++] = "-I/usr/include";
979 		}
980 	}
981 
982 	{
983 		/*
984 		 * 05/13/09: Added this.
985 		 * XXX Should we ever handle non-GNU preprocessors? (ucpp
986 		 * may be nice to have)
987 		 */
988 		static char	stdbuf[16];
989 		sprintf(stdbuf, "-std=%s", get_selected_std_name());
990 		cpp_args[cppind++] = stdbuf;
991 	}
992 
993 	if (abiflag == ABI_POWER64) {
994 #if 0
995 		cpp_args[cppind++] = "-D__64BIT__=1";
996 		cpp_args[cppind++] = "-U__LONG_MAX__";
997 #endif
998 		/*
999 		 *  XXX -maix64 doesn't work with GNU cpp on non-AIX
1000 		 * platforms...
1001 		 */
1002 		if (sysdep_get_host_system() == OS_AIX) {
1003 			cpp_args[cppind++] = "-maix64";
1004 		}
1005 #if 0
1006 		if (sizeof(long) != 8) {
1007 			(void) fprintf(stderr, "ERROR: This compiler was not "
1008 				"built with 64bit support\n");
1009 			exit(EXIT_FAILURE);
1010 		}
1011 #endif
1012 	} else if (abiflag == ABI_POWER32) {
1013 #if 0
1014 		if (sizeof(long) == 8) {
1015 			/* Built for 64bit */
1016 			abiflag = ABI_POWER64;
1017 		}
1018 #endif
1019 	} else if (abiflag == ABI_MIPS_N64) {
1020 		if (sysdep_get_host_system() == OS_IRIX) {
1021 			cpp_args[cppind++] = "-mabi=n64";
1022 		} else if (sysdep_get_host_system() == OS_LINUX) {
1023 			cpp_args[cppind++] = "-mabi=64";
1024 		}
1025 	} else if (abiflag == ABI_SPARC64) {
1026 		if (sysdep_get_host_arch() == ARCH_SPARC) {
1027 			cpp_args[cppind++] = "-m64";
1028 		}
1029 	}
1030 
1031 	if (sysflag == OS_OSX) {
1032 		if (archflag == ARCH_AMD64) {
1033 			cpp_args[cppind++] = "-m64";
1034 		} else {
1035 			cpp_args[cppind++] = "-m32";
1036 		}
1037 	}
1038 
1039 	cpp_args[cppind] = NULL;
1040 
1041 	/*
1042 	 * 03/02/09: Before calling cross_initialize_type_map(), determine
1043 	 * the plain ``char'' signedness! This must be done beforehand to
1044 	 * ensure that the map is initialized with proper signedness
1045 	 */
1046 	{
1047 		/*
1048 		 * XXX This is done in do_cpp() too - combine!!!
1049 		 */
1050 		int	host_arch;
1051 		int	host_abi;
1052 		int	host_sys;
1053 
1054 		get_host_arch(&host_arch, &host_abi, &host_sys);
1055 		cross_set_char_signedness(funsignedchar_flag, fsignedchar_flag,
1056 				host_arch, archflag);
1057 	}
1058 
1059 	cross_initialize_type_map(archflag, abiflag, sysflag);
1060 
1061 	if (archflag == ARCH_MIPS && get_target_endianness() == ENDIAN_LITTLE) {
1062 		cross_get_target_arch_properties()->endianness = ENDIAN_LITTLE;
1063 	}
1064 
1065 	/*
1066 	 * 05/17/09: Use a more descriptive name (without negation)
1067 	 */
1068 	use_common_variables = !fnocommon_flag;
1069 #if 0
1070 optind = 0;
1071 argv[0] = "new.c";
1072 #endif
1073 	if ((p = strrchr(nccfile, '.')) == NULL
1074 		|| (strcmp(++p, "c") != 0
1075 		&& strcmp(p, "i") != 0)) {
1076 		fprintf(stderr, "%s: Invalid input file name\n", nccfile);
1077 		return EXIT_FAILURE;
1078 	}
1079 
1080 	if (timeflag) {
1081 		start_timer(&tv);
1082 	}
1083 
1084 	if (strcmp(p, "i") == 0) {
1085 		/* Already preprocessed */
1086 		tmp = n_xstrdup(nccfile);
1087 	} else {
1088 		is_tmpfile = 1;
1089 		if ((tmp = do_cpp(nccfile, cpp_args, cppind)) == NULL) {
1090 			return EXIT_FAILURE;
1091 		}
1092 	}
1093 
1094 	if (timeflag) {
1095 		timing_cpp = stop_timer(&tv);
1096 	}
1097 
1098 	if (Eflag) {
1099 		/* Done! */
1100 		return 0;
1101 	}
1102 	strcpy(p, "asm");
1103 
1104 	if (mintocflag) {
1105 		mintocflag = 2;
1106 	}
1107 
1108 	if (sysflag == OS_OSX) {
1109 		picflag = 1;
1110 	}
1111 
1112 	return do_ncc(tmp, nccfile, is_tmpfile);
1113 }
1114 
1115