• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: MIT
2 /*
3  * 'sparse' library helper routines.
4  *
5  * Copyright (C) 2003 Transmeta Corp.
6  *               2003-2004 Linus Torvalds
7  *               2017-2020 Luc Van Oostenryck
8  */
9 
10 #include "options.h"
11 #include "lib.h"
12 #include "machine.h"
13 #include "target.h"
14 #include <ctype.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 
20 #ifndef __GNUC__
21 # define __GNUC__ 2
22 # define __GNUC_MINOR__ 95
23 # define __GNUC_PATCHLEVEL__ 0
24 #endif
25 
26 enum flag_type {
27 	FLAG_OFF,
28 	FLAG_ON,
29 	FLAG_FORCE_OFF
30 };
31 
32 int die_if_error = 0;
33 int do_output = 1;
34 int gcc_major = __GNUC__;
35 int gcc_minor = __GNUC_MINOR__;
36 int gcc_patchlevel = __GNUC_PATCHLEVEL__;
37 int has_error = 0;
38 int optimize_level;
39 int optimize_size;
40 int preprocess_only;
41 int preprocessing;
42 int verbose;
43 
44 #define CMDLINE_INCLUDE 20
45 int cmdline_include_nr = 0;
46 char *cmdline_include[CMDLINE_INCLUDE];
47 
48 const char *base_filename;
49 const char *diag_prefix = "";
50 const char *gcc_base_dir = GCC_BASE;
51 const char *multiarch_dir = MULTIARCH_TRIPLET;
52 const char *outfile = NULL;
53 
54 enum standard standard = STANDARD_GNU89;
55 
56 int arch_big_endian = ARCH_BIG_ENDIAN;
57 int arch_cmodel = CMODEL_UNKNOWN;
58 int arch_fp_abi = FP_ABI_NATIVE;
59 int arch_m64 = ARCH_M64_DEFAULT;
60 int arch_msize_long = 0;
61 int arch_os = OS_NATIVE;
62 
63 int dbg_compound = 0;
64 int dbg_dead = 0;
65 int dbg_domtree = 0;
66 int dbg_entry = 0;
67 int dbg_ir = 0;
68 int dbg_postorder = 0;
69 
70 int dump_macro_defs = 0;
71 int dump_macros_only = 0;
72 
73 unsigned long fdump_ir;
74 int fhosted = 1;
75 unsigned int fmax_errors = 100;
76 unsigned int fmax_warnings = 100;
77 int fmem_report = 0;
78 unsigned long long fmemcpy_max_count = 100000;
79 unsigned long fpasses = ~0UL;
80 int fpic = 0;
81 int fpie = 0;
82 int fshort_wchar = 0;
83 int funsigned_bitfields = 0;
84 int funsigned_char = 0;
85 
86 int Waddress = 0;
87 int Waddress_space = 1;
88 int Wbitwise = 1;
89 int Wbitwise_pointer = 0;
90 int Wcast_from_as = 0;
91 int Wcast_to_as = 0;
92 int Wcast_truncate = 1;
93 int Wconstant_suffix = 0;
94 int Wconstexpr_not_const = 0;
95 int Wcontext = 1;
96 int Wdecl = 1;
97 int Wdeclarationafterstatement = -1;
98 int Wdefault_bitfield_sign = 0;
99 int Wdesignated_init = 1;
100 int Wdo_while = 0;
101 int Wenum_mismatch = 1;
102 int Wexternal_function_has_definition = 1;
103 int Wflexible_array_array = 1;
104 int Wflexible_array_nested = 0;
105 int Wflexible_array_sizeof = 0;
106 int Wflexible_array_union = 0;
107 int Wimplicit_int = 1;
108 int Winit_cstring = 0;
109 int Wint_to_pointer_cast = 1;
110 int Wmemcpy_max_count = 1;
111 int Wnewline_eof = 1;
112 int Wnon_pointer_null = 1;
113 int Wold_initializer = 1;
114 int Wold_style_definition = 1;
115 int Wone_bit_signed_bitfield = 1;
116 int Woverride_init = 1;
117 int Woverride_init_all = 0;
118 int Woverride_init_whole_range = 0;
119 int Wparen_string = 0;
120 int Wpast_deep_designator = 0;
121 int Wpedantic = 0;
122 int Wpointer_arith = 0;
123 int Wpointer_to_int_cast = 1;
124 int Wptr_subtraction_blows = 0;
125 int Wreturn_void = 0;
126 int Wshadow = 0;
127 int Wshift_count_negative = 1;
128 int Wshift_count_overflow = 1;
129 int Wsizeof_bool = 0;
130 int Wsparse_error = FLAG_FORCE_OFF;
131 int Wstrict_prototypes = 1;
132 int Wtautological_compare = 0;
133 int Wtransparent_union = 0;
134 int Wtypesign = 0;
135 int Wundef = 0;
136 int Wuninitialized = 1;
137 int Wunion_cast = 0;
138 int Wuniversal_initializer = 0;
139 int Wunknown_attribute = 0;
140 int Wvla = 1;
141 
142 ////////////////////////////////////////////////////////////////////////////////
143 // Helpers for option parsing
144 
match_option(const char * arg,const char * prefix)145 static const char *match_option(const char *arg, const char *prefix)
146 {
147 	unsigned int n = strlen(prefix);
148 	if (strncmp(arg, prefix, n) == 0)
149 		return arg + n;
150 	return NULL;
151 }
152 
153 
154 struct val_map {
155 	const char *name;
156 	int val;
157 };
158 
handle_subopt_val(const char * opt,const char * arg,const struct val_map * map,int * flag)159 static int handle_subopt_val(const char *opt, const char *arg, const struct val_map *map, int *flag)
160 {
161 	const char *name;
162 
163 	if (*arg++ != '=')
164 		die("missing argument for option '%s'", opt);
165 	for (;(name = map->name); map++) {
166 		if (strcmp(name, arg) == 0 || strcmp(name, "*") == 0) {
167 			*flag = map->val;
168 			return 1;
169 		}
170 		if (strcmp(name, "?") == 0)
171 			die("invalid argument '%s' in option '%s'", arg, opt);
172 	}
173 	return 0;
174 }
175 
176 
177 struct mask_map {
178 	const char *name;
179 	unsigned long mask;
180 };
181 
apply_mask(unsigned long * val,const char * str,unsigned len,const struct mask_map * map,int neg)182 static int apply_mask(unsigned long *val, const char *str, unsigned len, const struct mask_map *map, int neg)
183 {
184 	const char *name;
185 
186 	for (;(name = map->name); map++) {
187 		if (!strncmp(name, str, len) && !name[len]) {
188 			if (neg == 0)
189 				*val |= map->mask;
190 			else
191 				*val &= ~map->mask;
192 			return 0;
193 		}
194 	}
195 	return 1;
196 }
197 
handle_suboption_mask(const char * arg,const char * opt,const struct mask_map * map,unsigned long * flag)198 static int handle_suboption_mask(const char *arg, const char *opt, const struct mask_map *map, unsigned long *flag)
199 {
200 	if (*opt == '\0') {
201 		apply_mask(flag, "", 0, map, 0);
202 		return 1;
203 	}
204 	if (*opt++ != '=')
205 		return 0;
206 	while (1) {
207 		unsigned int len = strcspn(opt, ",+");
208 		int neg = 0;
209 		if (len == 0)
210 			goto end;
211 		if (!strncmp(opt, "no-", 3)) {
212 			opt += 3;
213 			len -= 3;
214 			neg = 1;
215 		}
216 		if (apply_mask(flag, opt, len, map, neg))
217 			die("error: wrong option '%.*s' for \'%s\'", len, opt, arg);
218 
219 end:
220 		opt += len;
221 		if (*opt++ == '\0')
222 			break;
223 	}
224 	return 1;
225 }
226 
227 
228 #define OPT_INVERSE	1
229 #define OPT_VAL		2
230 struct flag {
231 	const char *name;
232 	int *flag;
233 	int (*fun)(const char *arg, const char *opt, const struct flag *, int options);
234 	unsigned long mask;
235 	int val;
236 };
237 
handle_switches(const char * ori,const char * opt,const struct flag * flags)238 static int handle_switches(const char *ori, const char *opt, const struct flag *flags)
239 {
240 	const char *arg = opt;
241 	int val = 1;
242 
243 	// Prefixe "no-" mean to turn flag off.
244 	if (strncmp(arg, "no-", 3) == 0) {
245 		arg += 3;
246 		val = 0;
247 	}
248 
249 	for (; flags->name; flags++) {
250 		const char *opt = match_option(arg, flags->name);
251 		int rc;
252 
253 		if (!opt)
254 			continue;
255 
256 		if (flags->fun) {
257 			int options = 0;
258 			if (!val)
259 				options |= OPT_INVERSE;
260 			if ((rc = flags->fun(ori, opt, flags, options)))
261 				return rc;
262 		}
263 
264 		// boolean flag
265 		if (opt[0] == '\0' && flags->flag) {
266 			if (flags->mask & OPT_VAL)
267 				val = flags->val;
268 			if (flags->mask & OPT_INVERSE)
269 				val = !val;
270 			*flags->flag = val;
271 			return 1;
272 		}
273 	}
274 
275 	// not handled
276 	return 0;
277 }
278 
handle_onoff_switch(char * arg,char ** next,const struct flag flags[])279 static char **handle_onoff_switch(char *arg, char **next, const struct flag flags[])
280 {
281 	int flag = FLAG_ON;
282 	char *p = arg + 1;
283 	unsigned i;
284 
285 	// Prefixes "no" and "no-" mean to turn warning off.
286 	if (p[0] == 'n' && p[1] == 'o') {
287 		p += 2;
288 		if (p[0] == '-')
289 			p++;
290 		flag = FLAG_FORCE_OFF;
291 	}
292 
293 	for (i = 0; flags[i].name; i++) {
294 		if (!strcmp(p,flags[i].name)) {
295 			*flags[i].flag = flag;
296 			return next;
297 		}
298 	}
299 
300 	// Unknown.
301 	return NULL;
302 }
303 
handle_onoff_switch_finalize(const struct flag flags[])304 static void handle_onoff_switch_finalize(const struct flag flags[])
305 {
306 	unsigned i;
307 
308 	for (i = 0; flags[i].name; i++) {
309 		if (*flags[i].flag == FLAG_FORCE_OFF)
310 			*flags[i].flag = FLAG_OFF;
311 	}
312 }
313 
handle_switch_setval(const char * arg,const char * opt,const struct flag * flag,int options)314 static int handle_switch_setval(const char *arg, const char *opt, const struct flag *flag, int options)
315 {
316 	*(flag->flag) = flag->mask;
317 	return 1;
318 }
319 
320 
321 #define	OPTNUM_ZERO_IS_INF		1
322 #define	OPTNUM_UNLIMITED		2
323 
324 #define OPT_NUMERIC(NAME, TYPE, FUNCTION)	\
325 static int opt_##NAME(const char *arg, const char *opt, TYPE *ptr, int flag)	\
326 {									\
327 	char *end;							\
328 	TYPE val;							\
329 									\
330 	val = FUNCTION(opt, &end, 0);					\
331 	if (*end != '\0' || end == opt) {				\
332 		if ((flag & OPTNUM_UNLIMITED) && !strcmp(opt, "unlimited"))	\
333 			val = ~val;					\
334 		else							\
335 			die("error: wrong argument to \'%s\'", arg);	\
336 	}								\
337 	if ((flag & OPTNUM_ZERO_IS_INF) && val == 0)			\
338 		val = ~val;						\
339 	*ptr = val;							\
340 	return 1;							\
341 }
342 
OPT_NUMERIC(ullong,unsigned long long,strtoull)343 OPT_NUMERIC(ullong, unsigned long long, strtoull)
344 OPT_NUMERIC(uint, unsigned int, strtoul)
345 
346 ////////////////////////////////////////////////////////////////////////////////
347 // Option parsing
348 
349 static char **handle_switch_a(char *arg, char **next)
350 {
351 	if (!strcmp(arg, "ansi"))
352 		standard = STANDARD_C89;
353 
354 	return next;
355 }
356 
handle_switch_D(char * arg,char ** next)357 static char **handle_switch_D(char *arg, char **next)
358 {
359 	const char *name = arg + 1;
360 	const char *value = "1";
361 
362 	if (!*name) {
363 		arg = *++next;
364 		if (!arg)
365 			die("argument to `-D' is missing");
366 		name = arg;
367 	}
368 
369 	for (;;arg++) {
370 		char c;
371 		c = *arg;
372 		if (!c)
373 			break;
374 		if (c == '=') {
375 			*arg = '\0';
376 			value = arg + 1;
377 			break;
378 		}
379 	}
380 	add_pre_buffer("#define %s %s\n", name, value);
381 	return next;
382 }
383 
handle_switch_d(char * arg,char ** next)384 static char **handle_switch_d(char *arg, char **next)
385 {
386 	char *arg_char = arg + 1;
387 
388 	/*
389 	 * -d<CHARS>, where <CHARS> is a sequence of characters, not preceded
390 	 * by a space. If you specify characters whose behaviour conflicts,
391 	 * the result is undefined.
392 	 */
393 	while (*arg_char) {
394 		switch (*arg_char) {
395 		case 'M': /* dump just the macro definitions */
396 			dump_macros_only = 1;
397 			dump_macro_defs = 0;
398 			break;
399 		case 'D': /* like 'M', but also output pre-processed text */
400 			dump_macro_defs = 1;
401 			dump_macros_only = 0;
402 			break;
403 		case 'N': /* like 'D', but only output macro names not bodies */
404 			break;
405 		case 'I': /* like 'D', but also output #include directives */
406 			break;
407 		case 'U': /* like 'D', but only output expanded macros */
408 			break;
409 		}
410 		arg_char++;
411 	}
412 	return next;
413 }
414 
handle_switch_E(char * arg,char ** next)415 static char **handle_switch_E(char *arg, char **next)
416 {
417 	if (arg[1] == '\0')
418 		preprocess_only = 1;
419 	return next;
420 }
421 
handle_ftabstop(const char * arg,const char * opt,const struct flag * flag,int options)422 static int handle_ftabstop(const char *arg, const char *opt, const struct flag *flag, int options)
423 {
424 	unsigned long val;
425 	char *end;
426 
427 	if (*opt == '\0')
428 		die("error: missing argument to \"%s\"", arg);
429 
430 	/* we silently ignore silly values */
431 	val = strtoul(opt, &end, 10);
432 	if (*end == '\0' && 1 <= val && val <= 100)
433 		tabstop = val;
434 
435 	return 1;
436 }
437 
handle_fpasses(const char * arg,const char * opt,const struct flag * flag,int options)438 static int handle_fpasses(const char *arg, const char *opt, const struct flag *flag, int options)
439 {
440 	unsigned long mask;
441 
442 	mask = flag->mask;
443 	if (*opt == '\0') {
444 		if (options & OPT_INVERSE)
445 			fpasses &= ~mask;
446 		else
447 			fpasses |=  mask;
448 		return 1;
449 	}
450 	if (options & OPT_INVERSE)
451 		return 0;
452 	if (!strcmp(opt, "-enable")) {
453 		fpasses |= mask;
454 		return 1;
455 	}
456 	if (!strcmp(opt, "-disable")) {
457 		fpasses &= ~mask;
458 		return 1;
459 	}
460 	if (!strcmp(opt, "=last")) {
461 		// clear everything above
462 		mask |= mask - 1;
463 		fpasses &= mask;
464 		return 1;
465 	}
466 	return 0;
467 }
468 
handle_fdiagnostic_prefix(const char * arg,const char * opt,const struct flag * flag,int options)469 static int handle_fdiagnostic_prefix(const char *arg, const char *opt, const struct flag *flag, int options)
470 {
471 	switch (*opt) {
472 	case '\0':
473 		diag_prefix = "sparse: ";
474 		return 1;
475 	case '=':
476 		diag_prefix = xasprintf("%s: ", opt+1);
477 		return 1;
478 	default:
479 		return 0;
480 	}
481 }
482 
handle_fdump_ir(const char * arg,const char * opt,const struct flag * flag,int options)483 static int handle_fdump_ir(const char *arg, const char *opt, const struct flag *flag, int options)
484 {
485 	static const struct mask_map dump_ir_options[] = {
486 		{ "",			PASS_LINEARIZE },
487 		{ "linearize",		PASS_LINEARIZE },
488 		{ "mem2reg",		PASS_MEM2REG },
489 		{ "final",		PASS_FINAL },
490 		{ },
491 	};
492 
493 	return handle_suboption_mask(arg, opt, dump_ir_options, &fdump_ir);
494 }
495 
handle_fmemcpy_max_count(const char * arg,const char * opt,const struct flag * flag,int options)496 static int handle_fmemcpy_max_count(const char *arg, const char *opt, const struct flag *flag, int options)
497 {
498 	opt_ullong(arg, opt, &fmemcpy_max_count, OPTNUM_ZERO_IS_INF|OPTNUM_UNLIMITED);
499 	return 1;
500 }
501 
handle_fmax_errors(const char * arg,const char * opt,const struct flag * flag,int options)502 static int handle_fmax_errors(const char *arg, const char *opt, const struct flag *flag, int options)
503 {
504 	opt_uint(arg, opt, &fmax_errors, OPTNUM_UNLIMITED);
505 	return 1;
506 }
507 
handle_fmax_warnings(const char * arg,const char * opt,const struct flag * flag,int options)508 static int handle_fmax_warnings(const char *arg, const char *opt, const struct flag *flag, int options)
509 {
510 	opt_uint(arg, opt, &fmax_warnings, OPTNUM_UNLIMITED);
511 	return 1;
512 }
513 
514 static struct flag fflags[] = {
515 	{ "diagnostic-prefix",	NULL,	handle_fdiagnostic_prefix },
516 	{ "dump-ir",		NULL,	handle_fdump_ir },
517 	{ "freestanding",	&fhosted, NULL, OPT_INVERSE },
518 	{ "hosted",		&fhosted },
519 	{ "linearize",		NULL,	handle_fpasses,	PASS_LINEARIZE },
520 	{ "max-errors=",	NULL,	handle_fmax_errors },
521 	{ "max-warnings=",	NULL,	handle_fmax_warnings },
522 	{ "mem-report",		&fmem_report },
523 	{ "memcpy-max-count=",	NULL,	handle_fmemcpy_max_count },
524 	{ "tabstop=",		NULL,	handle_ftabstop },
525 	{ "mem2reg",		NULL,	handle_fpasses,	PASS_MEM2REG },
526 	{ "optim",		NULL,	handle_fpasses,	PASS_OPTIM },
527 	{ "pic",		&fpic,	handle_switch_setval, 1 },
528 	{ "PIC",		&fpic,	handle_switch_setval, 2 },
529 	{ "pie",		&fpie,	handle_switch_setval, 1 },
530 	{ "PIE",		&fpie,	handle_switch_setval, 2 },
531 	{ "signed-bitfields",	&funsigned_bitfields, NULL, OPT_INVERSE },
532 	{ "unsigned-bitfields",	&funsigned_bitfields, NULL, },
533 	{ "signed-char",	&funsigned_char, NULL,	OPT_INVERSE },
534 	{ "short-wchar",	&fshort_wchar },
535 	{ "unsigned-char",	&funsigned_char, NULL, },
536 	{ },
537 };
538 
handle_switch_f(char * arg,char ** next)539 static char **handle_switch_f(char *arg, char **next)
540 {
541 	if (handle_switches(arg-1, arg+1, fflags))
542 		return next;
543 
544 	return next;
545 }
546 
handle_switch_G(char * arg,char ** next)547 static char **handle_switch_G(char *arg, char **next)
548 {
549 	if (!strcmp(arg, "G") && *next)
550 		return next + 1; // "-G 0"
551 	else
552 		return next;     // "-G0" or (bogus) terminal "-G"
553 }
554 
handle_base_dir(char * arg,char ** next)555 static char **handle_base_dir(char *arg, char **next)
556 {
557 	gcc_base_dir = *++next;
558 	if (!gcc_base_dir)
559 		die("missing argument for -gcc-base-dir option");
560 	return next;
561 }
562 
handle_switch_g(char * arg,char ** next)563 static char **handle_switch_g(char *arg, char **next)
564 {
565 	if (!strcmp(arg, "gcc-base-dir"))
566 		return handle_base_dir(arg, next);
567 
568 	return next;
569 }
570 
handle_switch_I(char * arg,char ** next)571 static char **handle_switch_I(char *arg, char **next)
572 {
573 	char *path = arg+1;
574 
575 	switch (arg[1]) {
576 	case '-':
577 		add_pre_buffer("#split_include\n");
578 		break;
579 
580 	case '\0':	/* Plain "-I" */
581 		path = *++next;
582 		if (!path)
583 			die("missing argument for -I option");
584 		/* Fall through */
585 	default:
586 		add_pre_buffer("#add_include \"%s/\"\n", path);
587 	}
588 	return next;
589 }
590 
add_cmdline_include(char * filename)591 static void add_cmdline_include(char *filename)
592 {
593 	if (cmdline_include_nr >= CMDLINE_INCLUDE)
594 		die("too many include files for %s\n", filename);
595 	cmdline_include[cmdline_include_nr++] = filename;
596 }
597 
handle_switch_i(char * arg,char ** next)598 static char **handle_switch_i(char *arg, char **next)
599 {
600 	if (*next && !strcmp(arg, "include"))
601 		add_cmdline_include(*++next);
602 	else if (*next && !strcmp(arg, "imacros"))
603 		add_cmdline_include(*++next);
604 	else if (*next && !strcmp(arg, "isystem")) {
605 		char *path = *++next;
606 		if (!path)
607 			die("missing argument for -isystem option");
608 		add_pre_buffer("#add_isystem \"%s/\"\n", path);
609 	} else if (*next && !strcmp(arg, "idirafter")) {
610 		char *path = *++next;
611 		if (!path)
612 			die("missing argument for -idirafter option");
613 		add_pre_buffer("#add_dirafter \"%s/\"\n", path);
614 	}
615 	return next;
616 }
617 
handle_switch_M(char * arg,char ** next)618 static char **handle_switch_M(char *arg, char **next)
619 {
620 	if (!strcmp(arg, "MF") || !strcmp(arg,"MQ") || !strcmp(arg,"MT")) {
621 		if (!*next)
622 			die("missing argument for -%s option", arg);
623 		return next + 1;
624 	}
625 	return next;
626 }
627 
handle_march(const char * opt,const char * arg,const struct flag * flag,int options)628 static int handle_march(const char *opt, const char *arg, const struct flag *flag, int options)
629 {
630 	if (arch_target->parse_march)
631 		arch_target->parse_march(arg);
632 	return 1;
633 }
634 
handle_mcmodel(const char * opt,const char * arg,const struct flag * flag,int options)635 static int handle_mcmodel(const char *opt, const char *arg, const struct flag *flag, int options)
636 {
637 	static const struct val_map cmodels[] = {
638 		{ "kernel",	CMODEL_KERNEL },
639 		{ "large",	CMODEL_LARGE },
640 		{ "medany",	CMODEL_MEDANY },
641 		{ "medium",	CMODEL_MEDIUM },
642 		{ "medlow",	CMODEL_MEDLOW },
643 		{ "small",	CMODEL_SMALL },
644 		{ "tiny",	CMODEL_TINY },
645 		{ },
646 	};
647 	return handle_subopt_val(opt, arg, cmodels, flag->flag);
648 }
649 
handle_mfloat_abi(const char * opt,const char * arg,const struct flag * flag,int options)650 static int handle_mfloat_abi(const char *opt, const char *arg, const struct flag *flag, int options) {
651 	static const struct val_map fp_abis[] = {
652 		{ "hard",		FP_ABI_HARD },
653 		{ "soft",		FP_ABI_SOFT },
654 		{ "softfp",		FP_ABI_HYBRID },
655 		{ "?" },
656 	};
657 	return handle_subopt_val(opt, arg, fp_abis, flag->flag);
658 }
659 
handle_multiarch_dir(char * arg,char ** next)660 static char **handle_multiarch_dir(char *arg, char **next)
661 {
662 	multiarch_dir = *++next;
663 	if (!multiarch_dir)
664 		die("missing argument for -multiarch-dir option");
665 	return next;
666 }
667 
668 static const struct flag mflags[] = {
669 	{ "64", &arch_m64, NULL, OPT_VAL, ARCH_LP64 },
670 	{ "32", &arch_m64, NULL, OPT_VAL, ARCH_LP32 },
671 	{ "31", &arch_m64, NULL, OPT_VAL, ARCH_LP32 },
672 	{ "16", &arch_m64, NULL, OPT_VAL, ARCH_LP32 },
673 	{ "x32",&arch_m64, NULL, OPT_VAL, ARCH_X32 },
674 	{ "size-llp64", &arch_m64, NULL, OPT_VAL, ARCH_LLP64 },
675 	{ "size-long", &arch_msize_long },
676 	{ "arch=", NULL, handle_march },
677 	{ "big-endian", &arch_big_endian, NULL },
678 	{ "little-endian", &arch_big_endian, NULL, OPT_INVERSE },
679 	{ "cmodel", &arch_cmodel, handle_mcmodel },
680 	{ "float-abi", &arch_fp_abi, handle_mfloat_abi },
681 	{ "hard-float", &arch_fp_abi, NULL, OPT_VAL, FP_ABI_HARD },
682 	{ "soft-float", &arch_fp_abi, NULL, OPT_VAL, FP_ABI_SOFT },
683 	{ }
684 };
685 
handle_switch_m(char * arg,char ** next)686 static char **handle_switch_m(char *arg, char **next)
687 {
688 	if (!strcmp(arg, "multiarch-dir")) {
689 		return handle_multiarch_dir(arg, next);
690 	} else {
691 		handle_switches(arg-1, arg+1, mflags);
692 	}
693 
694 	return next;
695 }
696 
handle_nostdinc(char * arg,char ** next)697 static char **handle_nostdinc(char *arg, char **next)
698 {
699 	add_pre_buffer("#nostdinc\n");
700 	return next;
701 }
702 
handle_switch_n(char * arg,char ** next)703 static char **handle_switch_n(char *arg, char **next)
704 {
705 	if (!strcmp(arg, "nostdinc"))
706 		return handle_nostdinc(arg, next);
707 
708 	return next;
709 }
710 
handle_switch_O(char * arg,char ** next)711 static char **handle_switch_O(char *arg, char **next)
712 {
713 	int level = 1;
714 	if (arg[1] >= '0' && arg[1] <= '9')
715 		level = arg[1] - '0';
716 	optimize_level = level;
717 	optimize_size = arg[1] == 's';
718 	return next;
719 }
720 
handle_switch_o(char * arg,char ** next)721 static char **handle_switch_o(char *arg, char **next)
722 {
723 	if (!strcmp(arg, "o")) {	// "-o foo"
724 		if (!*++next)
725 			die("argument to '-o' is missing");
726 		outfile = *next;
727 	}
728 	// else "-ofoo"
729 
730 	return next;
731 }
732 
733 static const struct flag pflags[] = {
734 	{ "pedantic", &Wpedantic, NULL, OPT_VAL, FLAG_ON },
735 	{ }
736 };
737 
handle_switch_p(char * arg,char ** next)738 static char **handle_switch_p(char *arg, char **next)
739 {
740 	handle_switches(arg-1, arg, pflags);
741 	return next;
742 }
743 
handle_switch_s(const char * arg,char ** next)744 static char **handle_switch_s(const char *arg, char **next)
745 {
746 	if ((arg = match_option(arg, "std="))) {
747 		if (!strcmp(arg, "c89") ||
748 		    !strcmp(arg, "iso9899:1990"))
749 			standard = STANDARD_C89;
750 
751 		else if (!strcmp(arg, "iso9899:199409"))
752 			standard = STANDARD_C94;
753 
754 		else if (!strcmp(arg, "c99") ||
755 			 !strcmp(arg, "c9x") ||
756 			 !strcmp(arg, "iso9899:1999") ||
757 			 !strcmp(arg, "iso9899:199x"))
758 			standard = STANDARD_C99;
759 
760 		else if (!strcmp(arg, "gnu89"))
761 			standard = STANDARD_GNU89;
762 
763 		else if (!strcmp(arg, "gnu99") || !strcmp(arg, "gnu9x"))
764 			standard = STANDARD_GNU99;
765 
766 		else if (!strcmp(arg, "c11") ||
767 			 !strcmp(arg, "c1x") ||
768 			 !strcmp(arg, "iso9899:2011"))
769 			standard = STANDARD_C11;
770 
771 		else if (!strcmp(arg, "gnu11"))
772 			standard = STANDARD_GNU11;
773 
774 		else if (!strcmp(arg, "c17") ||
775 			 !strcmp(arg, "c18") ||
776 			 !strcmp(arg, "iso9899:2017") ||
777 			 !strcmp(arg, "iso9899:2018"))
778 			standard = STANDARD_C17;
779 		else if (!strcmp(arg, "gnu17") ||
780 			 !strcmp(arg, "gnu18"))
781 			standard = STANDARD_GNU17;
782 
783 		else
784 			die("Unsupported C dialect");
785 	}
786 
787 	return next;
788 }
789 
handle_switch_U(char * arg,char ** next)790 static char **handle_switch_U(char *arg, char **next)
791 {
792 	const char *name = arg + 1;
793 
794 	if (*name == '\0') {
795 		name = *++next;
796 		if (!name)
797 			die("argument to `-U' is missing");
798 	}
799 	add_pre_buffer("#undef %s\n", name);
800 	return next;
801 }
802 
803 static struct flag debugs[] = {
804 	{ "compound", &dbg_compound},
805 	{ "dead", &dbg_dead},
806 	{ "domtree", &dbg_domtree},
807 	{ "entry", &dbg_entry},
808 	{ "ir", &dbg_ir},
809 	{ "postorder", &dbg_postorder},
810 	{ }
811 };
812 
handle_switch_v(char * arg,char ** next)813 static char **handle_switch_v(char *arg, char **next)
814 {
815 	char ** ret = handle_onoff_switch(arg, next, debugs);
816 	if (ret)
817 		return ret;
818 
819 	// Unknown.
820 	do {
821 		verbose++;
822 	} while (*++arg == 'v');
823 	return next;
824 }
825 
handle_switch_v_finalize(void)826 static void handle_switch_v_finalize(void)
827 {
828 	handle_onoff_switch_finalize(debugs);
829 }
830 
831 static const struct flag warnings[] = {
832 	{ "address", &Waddress },
833 	{ "address-space", &Waddress_space },
834 	{ "bitwise", &Wbitwise },
835 	{ "bitwise-pointer", &Wbitwise_pointer},
836 	{ "cast-from-as", &Wcast_from_as },
837 	{ "cast-to-as", &Wcast_to_as },
838 	{ "cast-truncate", &Wcast_truncate },
839 	{ "constant-suffix", &Wconstant_suffix },
840 	{ "constexpr-not-const", &Wconstexpr_not_const},
841 	{ "context", &Wcontext },
842 	{ "decl", &Wdecl },
843 	{ "declaration-after-statement", &Wdeclarationafterstatement },
844 	{ "default-bitfield-sign", &Wdefault_bitfield_sign },
845 	{ "designated-init", &Wdesignated_init },
846 	{ "do-while", &Wdo_while },
847 	{ "enum-mismatch", &Wenum_mismatch },
848 	{ "external-function-has-definition", &Wexternal_function_has_definition },
849 	{ "flexible-array-array", &Wflexible_array_array },
850 	{ "flexible-array-nested", &Wflexible_array_nested },
851 	{ "flexible-array-sizeof", &Wflexible_array_sizeof },
852 	{ "flexible-array-union", &Wflexible_array_union },
853 	{ "implicit-int", &Wimplicit_int },
854 	{ "init-cstring", &Winit_cstring },
855 	{ "int-to-pointer-cast", &Wint_to_pointer_cast },
856 	{ "memcpy-max-count", &Wmemcpy_max_count },
857 	{ "non-pointer-null", &Wnon_pointer_null },
858 	{ "newline-eof", &Wnewline_eof },
859 	{ "old-initializer", &Wold_initializer },
860 	{ "old-style-definition", &Wold_style_definition },
861 	{ "one-bit-signed-bitfield", &Wone_bit_signed_bitfield },
862 	{ "override-init", &Woverride_init },
863 	{ "override-init-all", &Woverride_init_all },
864 	{ "paren-string", &Wparen_string },
865 	{ "past-deep-designator", &Wpast_deep_designator },
866 	{ "pedantic", &Wpedantic },
867 	{ "pointer-to-int-cast", &Wpointer_to_int_cast },
868 	{ "ptr-subtraction-blows", &Wptr_subtraction_blows },
869 	{ "return-void", &Wreturn_void },
870 	{ "shadow", &Wshadow },
871 	{ "shift-count-negative", &Wshift_count_negative },
872 	{ "shift-count-overflow", &Wshift_count_overflow },
873 	{ "sizeof-bool", &Wsizeof_bool },
874 	{ "strict-prototypes", &Wstrict_prototypes },
875 	{ "pointer-arith", &Wpointer_arith },
876 	{ "sparse-error", &Wsparse_error },
877 	{ "tautological-compare", &Wtautological_compare },
878 	{ "transparent-union", &Wtransparent_union },
879 	{ "typesign", &Wtypesign },
880 	{ "undef", &Wundef },
881 	{ "uninitialized", &Wuninitialized },
882 	{ "union-cast", &Wunion_cast },
883 	{ "universal-initializer", &Wuniversal_initializer },
884 	{ "unknown-attribute", &Wunknown_attribute },
885 	{ "vla", &Wvla },
886 	{ }
887 };
888 
handle_switch_W(char * arg,char ** next)889 static char **handle_switch_W(char *arg, char **next)
890 {
891 	char ** ret = handle_onoff_switch(arg, next, warnings);
892 	if (ret)
893 		return ret;
894 
895 	if (!strcmp(arg, "Wsparse-all")) {
896 		int i;
897 		for (i = 0; warnings[i].name; i++) {
898 			if (*warnings[i].flag != FLAG_FORCE_OFF)
899 				*warnings[i].flag = FLAG_ON;
900 		}
901 	}
902 
903 	// Unknown.
904 	return next;
905 }
906 
handle_switch_W_finalize(void)907 static void handle_switch_W_finalize(void)
908 {
909 	handle_onoff_switch_finalize(warnings);
910 
911 	/* default Wdeclarationafterstatement based on the C dialect */
912 	if (-1 == Wdeclarationafterstatement) {
913 		switch (standard) {
914 			case STANDARD_C89:
915 			case STANDARD_C94:
916 				Wdeclarationafterstatement = 1;
917 				break;
918 			default:
919 				Wdeclarationafterstatement = 0;
920 				break;
921 		}
922 	}
923 }
924 
handle_switch_x(char * arg,char ** next)925 static char **handle_switch_x(char *arg, char **next)
926 {
927 	if (!*++next)
928 		die("missing argument for -x option");
929 	return next;
930 }
931 
932 
handle_arch(char * arg,char ** next)933 static char **handle_arch(char *arg, char **next)
934 {
935 	enum machine mach;
936 
937 	if (*arg++ != '=')
938 		die("missing argument for --arch option");
939 
940 	mach = target_parse(arg);
941 	if (mach != MACH_UNKNOWN)
942 		target_config(mach);
943 
944 	return next;
945 }
946 
handle_param(char * arg,char ** next)947 static char **handle_param(char *arg, char **next)
948 {
949 	char *value = NULL;
950 
951 	/* For now just skip any '--param=*' or '--param *' */
952 	if (*arg == '\0') {
953 		value = *++next;
954 	} else if (isspace((unsigned char)*arg) || *arg == '=') {
955 		value = ++arg;
956 	}
957 
958 	if (!value)
959 		die("missing argument for --param option");
960 
961 	return next;
962 }
963 
handle_os(char * arg,char ** next)964 static char **handle_os(char *arg, char **next)
965 {
966 	if (*arg++ != '=')
967 		die("missing argument for --os option");
968 
969 	target_os(arg);
970 
971 	return next;
972 }
973 
handle_version(char * arg,char ** next)974 static char **handle_version(char *arg, char **next)
975 {
976 	printf("%s\n", sparse_version);
977 	exit(0);
978 }
979 
980 struct switches {
981 	const char *name;
982 	char **(*fn)(char *, char **);
983 	unsigned int prefix:1;
984 };
985 
handle_long_options(char * arg,char ** next)986 static char **handle_long_options(char *arg, char **next)
987 {
988 	static struct switches cmd[] = {
989 		{ "arch", handle_arch, 1 },
990 		{ "os",   handle_os, 1 },
991 		{ "param", handle_param, 1 },
992 		{ "version", handle_version },
993 		{ NULL, NULL }
994 	};
995 	struct switches *s = cmd;
996 
997 	while (s->name) {
998 		int optlen = strlen(s->name);
999 		if (!strncmp(s->name, arg, optlen + !s->prefix))
1000 			return s->fn(arg + optlen, next);
1001 		s++;
1002 	}
1003 	return next;
1004 }
1005 
handle_switch(char * arg,char ** next)1006 char **handle_switch(char *arg, char **next)
1007 {
1008 	switch (*arg) {
1009 	case 'a': return handle_switch_a(arg, next);
1010 	case 'D': return handle_switch_D(arg, next);
1011 	case 'd': return handle_switch_d(arg, next);
1012 	case 'E': return handle_switch_E(arg, next);
1013 	case 'f': return handle_switch_f(arg, next);
1014 	case 'g': return handle_switch_g(arg, next);
1015 	case 'G': return handle_switch_G(arg, next);
1016 	case 'I': return handle_switch_I(arg, next);
1017 	case 'i': return handle_switch_i(arg, next);
1018 	case 'M': return handle_switch_M(arg, next);
1019 	case 'm': return handle_switch_m(arg, next);
1020 	case 'n': return handle_switch_n(arg, next);
1021 	case 'o': return handle_switch_o(arg, next);
1022 	case 'O': return handle_switch_O(arg, next);
1023 	case 'p': return handle_switch_p(arg, next);
1024 	case 's': return handle_switch_s(arg, next);
1025 	case 'U': return handle_switch_U(arg, next);
1026 	case 'v': return handle_switch_v(arg, next);
1027 	case 'W': return handle_switch_W(arg, next);
1028 	case 'x': return handle_switch_x(arg, next);
1029 	case '-': return handle_long_options(arg + 1, next);
1030 	default:
1031 		break;
1032 	}
1033 
1034 	/*
1035 	 * Ignore unknown command line options:
1036 	 * they're probably gcc switches
1037 	 */
1038 	return next;
1039 }
1040 
handle_switch_finalize(void)1041 void handle_switch_finalize(void)
1042 {
1043 	handle_switch_v_finalize();
1044 	handle_switch_W_finalize();
1045 }
1046