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