rts: mark 'setProgName' as static
[ghc.git] / rts / RtsFlags.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The AQUA Project, Glasgow University, 1994-1997
4 * (c) The GHC Team, 1998-2006
5 *
6 * Functions for parsing the argument list.
7 *
8 * ---------------------------------------------------------------------------*/
9
10 #include "PosixSource.h"
11 #include "Rts.h"
12
13 #include "RtsUtils.h"
14 #include "Profiling.h"
15 #include "RtsFlags.h"
16 #include "sm/OSMem.h"
17 #include "hooks/Hooks.h"
18
19 #ifdef HAVE_CTYPE_H
20 #include <ctype.h>
21 #endif
22
23 #include <string.h>
24
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32
33 // Flag Structure
34 RTS_FLAGS RtsFlags;
35
36 /*
37 * Split argument lists
38 */
39 int prog_argc = 0; /* an "int" so as to match normal "argc" */
40 char **prog_argv = NULL;
41 int full_prog_argc = 0; /* an "int" so as to match normal "argc" */
42 char **full_prog_argv = NULL;
43 char *prog_name = NULL; /* 'basename' of prog_argv[0] */
44 int rts_argc = 0; /* ditto */
45 char **rts_argv = NULL;
46 int rts_argv_size = 0;
47 #if defined(mingw32_HOST_OS)
48 // On Windows, we want to use GetCommandLineW rather than argc/argv,
49 // but we need to mutate the command line arguments for withProgName and
50 // friends. The System.Environment module achieves that using this bit of
51 // shared state:
52 int win32_prog_argc = 0;
53 wchar_t **win32_prog_argv = NULL;
54 #endif
55
56 // The global rtsConfig, set from the RtsConfig supplied by the call
57 // to hs_init_ghc().
58 RtsConfig rtsConfig;
59
60 const RtsConfig defaultRtsConfig = {
61 .rts_opts_enabled = RtsOptsSafeOnly,
62 .rts_opts_suggestions = rtsTrue,
63 .rts_opts = NULL,
64 .rts_hs_main = rtsFalse,
65 .keep_cafs = rtsFalse,
66 .defaultsHook = FlagDefaultsHook,
67 .onExitHook = OnExitHook,
68 .stackOverflowHook = StackOverflowHook,
69 .outOfHeapHook = OutOfHeapHook,
70 .mallocFailHook = MallocFailHook,
71 .gcDoneHook = NULL
72 };
73
74 /*
75 * constants, used later
76 */
77 #define RTS 1
78 #define PGM 0
79
80 /* -----------------------------------------------------------------------------
81 Static function decls
82 -------------------------------------------------------------------------- */
83
84 static void procRtsOpts (int rts_argc0, RtsOptsEnabledEnum enabled);
85
86 static void normaliseRtsOpts (void);
87
88 static void initStatsFile (FILE *f);
89
90 static int openStatsFile (
91 char *filename, const char *FILENAME_FMT, FILE **file_ret);
92
93 static StgWord64 decodeSize (
94 const char *flag, nat offset, StgWord64 min, StgWord64 max);
95
96 static void bad_option (const char *s);
97
98 #ifdef DEBUG
99 static void read_debug_flags(const char *arg);
100 #endif
101
102 #ifdef PROFILING
103 static rtsBool read_heap_profiling_flag(const char *arg);
104 #endif
105
106 #ifdef TRACING
107 static void read_trace_flags(const char *arg);
108 #endif
109
110 static void errorUsage (void) GNU_ATTRIBUTE(__noreturn__);
111
112 static char * copyArg (char *arg);
113 static char ** copyArgv (int argc, char *argv[]);
114 static void freeArgv (int argc, char *argv[]);
115 static void setProgName (char *argv[]);
116
117 static void errorRtsOptsDisabled (const char *s);
118
119 /* -----------------------------------------------------------------------------
120 * Command-line option parsing routines.
121 * ---------------------------------------------------------------------------*/
122
123 void initRtsFlagsDefaults(void)
124 {
125 StgWord64 maxStkSize = 8 * getPhysicalMemorySize() / 10;
126 // if getPhysicalMemorySize fails just move along with an 8MB limit
127 if (maxStkSize == 0)
128 maxStkSize = 8 * 1024 * 1024;
129
130 RtsFlags.GcFlags.statsFile = NULL;
131 RtsFlags.GcFlags.giveStats = NO_GC_STATS;
132
133 RtsFlags.GcFlags.maxStkSize = maxStkSize / sizeof(W_);
134 RtsFlags.GcFlags.initialStkSize = 1024 / sizeof(W_);
135 RtsFlags.GcFlags.stkChunkSize = (32 * 1024) / sizeof(W_);
136 RtsFlags.GcFlags.stkChunkBufferSize = (1 * 1024) / sizeof(W_);
137
138 RtsFlags.GcFlags.minAllocAreaSize = (512 * 1024) / BLOCK_SIZE;
139 RtsFlags.GcFlags.nurseryChunkSize = 0;
140 RtsFlags.GcFlags.minOldGenSize = (1024 * 1024) / BLOCK_SIZE;
141 RtsFlags.GcFlags.maxHeapSize = 0; /* off by default */
142 RtsFlags.GcFlags.heapSizeSuggestion = 0; /* none */
143 RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsFalse;
144 RtsFlags.GcFlags.pcFreeHeap = 3; /* 3% */
145 RtsFlags.GcFlags.oldGenFactor = 2;
146 RtsFlags.GcFlags.generations = 2;
147 RtsFlags.GcFlags.squeezeUpdFrames = rtsTrue;
148 RtsFlags.GcFlags.compact = rtsFalse;
149 RtsFlags.GcFlags.compactThreshold = 30.0;
150 RtsFlags.GcFlags.sweep = rtsFalse;
151 RtsFlags.GcFlags.idleGCDelayTime = USToTime(300000); // 300ms
152 #ifdef THREADED_RTS
153 RtsFlags.GcFlags.doIdleGC = rtsTrue;
154 #else
155 RtsFlags.GcFlags.doIdleGC = rtsFalse;
156 #endif
157
158 #if osf3_HOST_OS
159 /* ToDo: Perhaps by adjusting this value we can make linking without
160 * -static work (i.e., not generate a core-dumping executable)? */
161 # if SIZEOF_VOID_P == 8
162 RtsFlags.GcFlags.heapBase = 0x180000000L;
163 # else
164 # error I have no idea where to begin the heap on a non-64-bit osf3 machine.
165 # endif
166 #else
167 RtsFlags.GcFlags.heapBase = 0; /* means don't care */
168 #endif
169 RtsFlags.GcFlags.allocLimitGrace = (100*1024) / BLOCK_SIZE;
170
171 #ifdef DEBUG
172 RtsFlags.DebugFlags.scheduler = rtsFalse;
173 RtsFlags.DebugFlags.interpreter = rtsFalse;
174 RtsFlags.DebugFlags.weak = rtsFalse;
175 RtsFlags.DebugFlags.gccafs = rtsFalse;
176 RtsFlags.DebugFlags.gc = rtsFalse;
177 RtsFlags.DebugFlags.block_alloc = rtsFalse;
178 RtsFlags.DebugFlags.sanity = rtsFalse;
179 RtsFlags.DebugFlags.stable = rtsFalse;
180 RtsFlags.DebugFlags.stm = rtsFalse;
181 RtsFlags.DebugFlags.prof = rtsFalse;
182 RtsFlags.DebugFlags.apply = rtsFalse;
183 RtsFlags.DebugFlags.linker = rtsFalse;
184 RtsFlags.DebugFlags.squeeze = rtsFalse;
185 RtsFlags.DebugFlags.hpc = rtsFalse;
186 RtsFlags.DebugFlags.sparks = rtsFalse;
187 #endif
188
189 #if defined(PROFILING)
190 RtsFlags.CcFlags.doCostCentres = 0;
191 #endif /* PROFILING */
192
193 RtsFlags.ProfFlags.doHeapProfile = rtsFalse;
194 RtsFlags.ProfFlags. heapProfileInterval = USToTime(100000); // 100ms
195
196 #ifdef PROFILING
197 RtsFlags.ProfFlags.includeTSOs = rtsFalse;
198 RtsFlags.ProfFlags.showCCSOnException = rtsFalse;
199 RtsFlags.ProfFlags.maxRetainerSetSize = 8;
200 RtsFlags.ProfFlags.ccsLength = 25;
201 RtsFlags.ProfFlags.modSelector = NULL;
202 RtsFlags.ProfFlags.descrSelector = NULL;
203 RtsFlags.ProfFlags.typeSelector = NULL;
204 RtsFlags.ProfFlags.ccSelector = NULL;
205 RtsFlags.ProfFlags.ccsSelector = NULL;
206 RtsFlags.ProfFlags.retainerSelector = NULL;
207 RtsFlags.ProfFlags.bioSelector = NULL;
208 #endif
209
210 #ifdef TRACING
211 RtsFlags.TraceFlags.tracing = TRACE_NONE;
212 RtsFlags.TraceFlags.timestamp = rtsFalse;
213 RtsFlags.TraceFlags.scheduler = rtsFalse;
214 RtsFlags.TraceFlags.gc = rtsFalse;
215 RtsFlags.TraceFlags.sparks_sampled= rtsFalse;
216 RtsFlags.TraceFlags.sparks_full = rtsFalse;
217 RtsFlags.TraceFlags.user = rtsFalse;
218 #endif
219
220 #ifdef PROFILING
221 // When profiling we want a lot more ticks
222 RtsFlags.MiscFlags.tickInterval = USToTime(1000); // 1ms
223 #else
224 RtsFlags.MiscFlags.tickInterval = DEFAULT_TICK_INTERVAL;
225 #endif
226 RtsFlags.ConcFlags.ctxtSwitchTime = USToTime(20000); // 20ms
227
228 RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
229 RtsFlags.MiscFlags.machineReadable = rtsFalse;
230 RtsFlags.MiscFlags.linkerMemBase = 0;
231
232 #ifdef THREADED_RTS
233 RtsFlags.ParFlags.nNodes = 1;
234 RtsFlags.ParFlags.migrate = rtsTrue;
235 RtsFlags.ParFlags.parGcEnabled = 1;
236 RtsFlags.ParFlags.parGcGen = 0;
237 RtsFlags.ParFlags.parGcLoadBalancingEnabled = rtsTrue;
238 RtsFlags.ParFlags.parGcLoadBalancingGen = 1;
239 RtsFlags.ParFlags.parGcNoSyncWithIdle = 0;
240 RtsFlags.ParFlags.setAffinity = 0;
241 #endif
242
243 #if defined(THREADED_RTS)
244 RtsFlags.ParFlags.maxLocalSparks = 4096;
245 #endif /* THREADED_RTS */
246
247 #ifdef TICKY_TICKY
248 RtsFlags.TickyFlags.showTickyStats = rtsFalse;
249 RtsFlags.TickyFlags.tickyFile = NULL;
250 #endif
251 }
252
253 static const char *
254 usage_text[] = {
255 "",
256 "Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
257 "",
258 " +RTS Indicates run time system options follow",
259 " -RTS Indicates program arguments follow",
260 " --RTS Indicates that ALL subsequent arguments will be given to the",
261 " program (including any of these RTS flags)",
262 "",
263 "The following run time system options are available:",
264 "",
265 " -? Prints this message and exits; the program is not executed",
266 " --info Print information about the RTS used by this program",
267 "",
268 " -K<size> Sets the maximum stack size (default: 80% of the heap)",
269 " Egs: -K32k -K512k -K8M",
270 " -ki<size> Sets the initial thread stack size (default 1k) Egs: -ki4k -ki2m",
271 " -kc<size> Sets the stack chunk size (default 32k)",
272 " -kb<size> Sets the stack chunk buffer size (default 1k)",
273 "",
274 " -A<size> Sets the minimum allocation area size (default 512k) Egs: -A1m -A10k",
275 " -n<size> Allocation area chunk size (0 = disabled, default: 0)",
276 " -O<size> Sets the minimum size of the old generation (default 1M)",
277 " -M<size> Sets the maximum heap size (default unlimited) Egs: -M256k -M1G",
278 " -H<size> Sets the minimum heap size (default 0M) Egs: -H24m -H1G",
279 " -m<n> Minimum % of heap which must be available (default 3%)",
280 " -G<n> Number of generations (default: 2)",
281 " -c<n> Use in-place compaction instead of copying in the oldest generation",
282 " when live data is at least <n>% of the maximum heap size set with",
283 " -M (default: 30%)",
284 " -c Use in-place compaction for all oldest generation collections",
285 " (the default is to use copying)",
286 " -w Use mark-region for the oldest generation (experimental)",
287 #if defined(THREADED_RTS)
288 " -I<sec> Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
289 #endif
290 "",
291 " -T Collect GC statistics (useful for in-program statistics access)",
292 " -t[<file>] One-line GC statistics (if <file> omitted, uses stderr)",
293 " -s[<file>] Summary GC statistics (if <file> omitted, uses stderr)",
294 " -S[<file>] Detailed GC statistics (if <file> omitted, uses stderr)",
295 "",
296 "",
297 " -Z Don't squeeze out update frames on stack overflow",
298 " -B Sound the bell at the start of each garbage collection",
299 #if defined(PROFILING)
300 "",
301 " -p Time/allocation profile (output file <program>.prof)",
302 " -P More detailed Time/Allocation profile",
303 " -Pa Give information about *all* cost centres",
304 "",
305 " -h<break-down> Heap residency profile (hp2ps) (output file <program>.hp)",
306 " break-down: c = cost centre stack (default)",
307 " m = module",
308 " d = closure description",
309 " y = type description",
310 " r = retainer",
311 " b = biography (LAG,DRAG,VOID,USE)",
312 " A subset of closures may be selected thusly:",
313 " -hc<cc>,... specific cost centre(s) (top of stack only)",
314 " -hC<cc>,... specific cost centre(s) (anywhere in stack)",
315 " -hm<mod>... all cost centres from the specified modules(s)",
316 " -hd<des>,... closures with specified closure descriptions",
317 " -hy<typ>... closures with specified type descriptions",
318 " -hr<cc>... closures with specified retainers",
319 " -hb<bio>... closures with specified biographies (lag,drag,void,use)",
320 "",
321 " -R<size> Set the maximum retainer set size (default: 8)",
322 "",
323 " -L<chars> Maximum length of a cost-centre stack in a heap profile",
324 " (default: 25)",
325 "",
326 " -xt Include threads (TSOs) in a heap profile",
327 "",
328 " -xc Show current cost centre stack on raising an exception",
329 #endif /* PROFILING */
330
331 #ifdef TRACING
332 "",
333 " -l[flags] Log events in binary format to the file <program>.eventlog",
334 # ifdef DEBUG
335 " -v[flags] Log events to stderr",
336 # endif
337 " where [flags] can contain:",
338 " s scheduler events",
339 " g GC and heap events",
340 " p par spark events (sampled)",
341 " f par spark events (full detail)",
342 " u user events (emitted from Haskell code)",
343 " a all event classes above",
344 # ifdef DEBUG
345 " t add time stamps (only useful with -v)",
346 # endif
347 " -x disable an event class, for any flag above",
348 " the initial enabled event classes are 'sgpu'",
349 #endif
350
351 #if !defined(PROFILING)
352 "",
353 " -h Heap residency profile (output file <program>.hp)",
354 #endif
355 " -i<sec> Time between heap profile samples (seconds, default: 0.1)",
356 "",
357 #if defined(TICKY_TICKY)
358 " -r<file> Produce ticky-ticky statistics (with -rstderr for stderr)",
359 "",
360 #endif
361 " -C<secs> Context-switch interval in seconds.",
362 " 0 or no argument means switch as often as possible.",
363 " Default: 0.02 sec.",
364 " -V<secs> Master tick interval in seconds (0 == disable timer).",
365 " This sets the resolution for -C and the heap profile timer -i,",
366 " and is the frequence of time profile samples.",
367 #ifdef PROFILING
368 " Default: 0.001 sec.",
369 #else
370 " Default: 0.01 sec.",
371 #endif
372 "",
373 #if defined(DEBUG)
374 " -Ds DEBUG: scheduler",
375 " -Di DEBUG: interpreter",
376 " -Dw DEBUG: weak",
377 " -DG DEBUG: gccafs",
378 " -Dg DEBUG: gc",
379 " -Db DEBUG: block",
380 " -DS DEBUG: sanity",
381 " -Dt DEBUG: stable",
382 " -Dp DEBUG: prof",
383 " -Da DEBUG: apply",
384 " -Dl DEBUG: linker",
385 " -Dm DEBUG: stm",
386 " -Dz DEBUG: stack squeezing",
387 " -Dc DEBUG: program coverage",
388 " -Dr DEBUG: sparks",
389 "",
390 " NOTE: DEBUG events are sent to stderr by default; add -l to create a",
391 " binary event log file instead.",
392 "",
393 #endif /* DEBUG */
394 #if defined(THREADED_RTS) && !defined(NOSMP)
395 " -N[<n>] Use <n> processors (default: 1, -N alone determines",
396 " the number of processors to use automatically)",
397 " -maxN[<n>] Use up to <n> processors automatically",
398 " -qg[<n>] Use parallel GC only for generations >= <n>",
399 " (default: 0, -qg alone turns off parallel GC)",
400 " -qb[<n>] Use load-balancing in the parallel GC only for generations >= <n>",
401 " (default: 1, -qb alone turns off load-balancing)",
402 " -qa Use the OS to set thread affinity (experimental)",
403 " -qm Don't automatically migrate threads between CPUs",
404 " -qi<n> If a processor has been idle for the last <n> GCs, do not",
405 " wake it up for a non-load-balancing parallel GC.",
406 " (0 disables, default: 0)",
407 #endif
408 " --install-signal-handlers=<yes|no>",
409 " Install signal handlers (default: yes)",
410 #if defined(THREADED_RTS)
411 " -e<n> Maximum number of outstanding local sparks (default: 4096)",
412 #endif
413 #if defined(x86_64_HOST_ARCH)
414 " -xm Base address to mmap memory in the GHCi linker",
415 " (hex; must be <80000000)",
416 #endif
417 " -xq The allocation limit given to a thread after it receives",
418 " an AllocationLimitExceeded exception. (default: 100k)",
419 "",
420 "RTS options may also be specified using the GHCRTS environment variable.",
421 "",
422 "Other RTS options may be available for programs compiled a different way.",
423 "The GHC User's Guide has full details.",
424 "",
425 0
426 };
427
428 STATIC_INLINE rtsBool strequal(const char *a, const char * b)
429 {
430 return(strcmp(a, b) == 0);
431 }
432
433 // We can't predict up front how much space we'll need for rts_argv,
434 // because it involves parsing ghc_rts_opts and GHCRTS, so we
435 // expand it on demand.
436 static void appendRtsArg (char *arg)
437 {
438 if (rts_argc == rts_argv_size) {
439 rts_argv_size *= 2;
440 rts_argv = stgReallocBytes(rts_argv, rts_argv_size * sizeof (char *),
441 "RtsFlags.c:appendRtsArg");
442 }
443 rts_argv[rts_argc++] = arg;
444 }
445
446 static void splitRtsFlags(const char *s)
447 {
448 const char *c1, *c2;
449 char *t;
450
451 c1 = s;
452 do {
453 while (isspace(*c1)) { c1++; };
454 c2 = c1;
455 while (!isspace(*c2) && *c2 != '\0') { c2++; };
456
457 if (c1 == c2) { break; }
458
459 t = stgMallocBytes(c2-c1+1, "RtsFlags.c:splitRtsFlags()");
460 strncpy(t, c1, c2-c1);
461 t[c2-c1] = '\0';
462 appendRtsArg(t);
463
464 c1 = c2;
465 } while (*c1 != '\0');
466 }
467
468 static void errorRtsOptsDisabled(const char *s)
469 {
470 char *advice;
471 if (rtsConfig.rts_hs_main) {
472 advice = "Link with -rtsopts to enable them.";
473 } else {
474 advice = "Use hs_init_with_rtsopts() to enable them.";
475 }
476 errorBelch(s, advice);
477 }
478
479 /* -----------------------------------------------------------------------------
480 Parse the command line arguments, collecting options for the RTS.
481
482 On return:
483 - argv[] is *modified*, any RTS options have been stripped out
484 - *argc contains the new count of arguments in argv[]
485
486 - rts_argv[] (global) contains a copy of the collected RTS args
487 - rts_argc (global) contains the count of args in rts_argv
488
489 - prog_argv[] (global) contains a copy of the non-RTS args (== argv)
490 - prog_argc (global) contains the count of args in prog_argv
491
492 - prog_name (global) contains the basename of prog_argv[0]
493
494 - rtsConfig (global) contains the supplied RtsConfig
495
496 -------------------------------------------------------------------------- */
497
498 void setupRtsFlags (int *argc, char *argv[], RtsConfig rts_config)
499 {
500 nat mode;
501 nat total_arg;
502 nat arg, rts_argc0;
503
504 rtsConfig = rts_config;
505
506 setProgName (argv);
507 total_arg = *argc;
508 arg = 1;
509
510 if (*argc > 1) { *argc = 1; };
511 rts_argc = 0;
512
513 rts_argv_size = total_arg + 1;
514 rts_argv = stgMallocBytes(rts_argv_size * sizeof (char *), "setupRtsFlags");
515
516 rts_argc0 = rts_argc;
517
518 // process arguments from the -with-rtsopts compile-time flag first
519 // (arguments from the GHCRTS environment variable and the command
520 // line override these).
521 {
522 if (rtsConfig.rts_opts != NULL) {
523 splitRtsFlags(rtsConfig.rts_opts);
524 // opts from rts_opts are always enabled:
525 procRtsOpts(rts_argc0, RtsOptsAll);
526 rts_argc0 = rts_argc;
527 }
528 }
529
530 // process arguments from the GHCRTS environment variable next
531 // (arguments from the command line override these).
532 {
533 char *ghc_rts = getenv("GHCRTS");
534
535 if (ghc_rts != NULL) {
536 if (rtsConfig.rts_opts_enabled == RtsOptsNone) {
537 errorRtsOptsDisabled(
538 "Warning: Ignoring GHCRTS variable as RTS options are disabled.\n %s");
539 // We don't actually exit, just warn
540 } else {
541 splitRtsFlags(ghc_rts);
542 procRtsOpts(rts_argc0, rtsConfig.rts_opts_enabled);
543 rts_argc0 = rts_argc;
544 }
545 }
546 }
547
548 // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
549 // argv[0] must be PGM argument -- leave in argv
550
551 for (mode = PGM; arg < total_arg; arg++) {
552 // The '--RTS' argument disables all future +RTS ... -RTS processing.
553 if (strequal("--RTS", argv[arg])) {
554 arg++;
555 break;
556 }
557 // The '--' argument is passed through to the program, but
558 // disables all further +RTS ... -RTS processing.
559 else if (strequal("--", argv[arg])) {
560 break;
561 }
562 else if (strequal("+RTS", argv[arg])) {
563 mode = RTS;
564 }
565 else if (strequal("-RTS", argv[arg])) {
566 mode = PGM;
567 }
568 else if (mode == RTS) {
569 appendRtsArg(copyArg(argv[arg]));
570 }
571 else {
572 argv[(*argc)++] = argv[arg];
573 }
574 }
575 // process remaining program arguments
576 for (; arg < total_arg; arg++) {
577 argv[(*argc)++] = argv[arg];
578 }
579 argv[*argc] = (char *) 0;
580
581 procRtsOpts(rts_argc0, rtsConfig.rts_opts_enabled);
582
583 appendRtsArg((char *)0);
584 rts_argc--; // appendRtsArg will have bumped it for the NULL (#7227)
585
586 normaliseRtsOpts();
587
588 setProgArgv(*argc, argv);
589
590 if (RtsFlags.GcFlags.statsFile != NULL) {
591 initStatsFile (RtsFlags.GcFlags.statsFile);
592 }
593 if (RtsFlags.TickyFlags.tickyFile != NULL) {
594 initStatsFile (RtsFlags.GcFlags.statsFile);
595 }
596 }
597
598 /* -----------------------------------------------------------------------------
599 * procRtsOpts: Process rts_argv between rts_argc0 and rts_argc.
600 * -------------------------------------------------------------------------- */
601
602 #if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_TYPES_H) && !defined(mingw32_HOST_OS)
603 static void checkSuid(RtsOptsEnabledEnum enabled)
604 {
605 if (enabled == RtsOptsSafeOnly) {
606 /* This doesn't cover linux/posix capabilities like CAP_DAC_OVERRIDE,
607 we'd have to link with -lcap for that. */
608 if ((getuid() != geteuid()) || (getgid() != getegid())) {
609 errorRtsOptsDisabled(
610 "RTS options are disabled for setuid binaries. %s");
611 stg_exit(EXIT_FAILURE);
612 }
613 }
614 }
615 #else
616 static void checkSuid (RtsOptsEnabledEnum enabled STG_UNUSED)
617 {
618 }
619 #endif
620
621 static void checkUnsafe(RtsOptsEnabledEnum enabled)
622 {
623 if (enabled == RtsOptsSafeOnly) {
624 errorRtsOptsDisabled("Most RTS options are disabled. %s");
625 stg_exit(EXIT_FAILURE);
626 }
627 }
628
629 static void procRtsOpts (int rts_argc0,
630 RtsOptsEnabledEnum rtsOptsEnabled)
631 {
632 rtsBool error = rtsFalse;
633 int arg;
634 int unchecked_arg_start;
635
636 if (!(rts_argc0 < rts_argc)) return;
637
638 if (rtsOptsEnabled == RtsOptsNone) {
639 errorRtsOptsDisabled("RTS options are disabled. %s");
640 stg_exit(EXIT_FAILURE);
641 }
642
643 checkSuid(rtsOptsEnabled);
644
645 // Process RTS (rts_argv) part: mainly to determine statsfile
646 for (arg = rts_argc0; arg < rts_argc; arg++) {
647
648 /* We handle RtsOptsSafeOnly mode by declaring each option as
649 either OPTION_SAFE or OPTION_UNSAFE. To make sure we cover
650 every branch we use an option_checked flag which is reset
651 at the start each iteration and checked at the end. */
652 rtsBool option_checked = rtsFalse;
653
654 // See Note [OPTION_SAFE vs OPTION_UNSAFE].
655 #define OPTION_SAFE option_checked = rtsTrue;
656 #define OPTION_UNSAFE checkUnsafe(rtsOptsEnabled); option_checked = rtsTrue;
657
658 if (rts_argv[arg][0] != '-') {
659 fflush(stdout);
660 errorBelch("unexpected RTS argument: %s", rts_argv[arg]);
661 error = rtsTrue;
662
663 } else {
664 /* 0 is dash, 1 is first letter */
665 /* see Trac #9839 */
666 unchecked_arg_start = 1;
667 switch(rts_argv[arg][1]) {
668
669 /* process: general args, then PROFILING-only ones, then
670 CONCURRENT-only, TICKY-only (same order as defined in
671 RtsFlags.lh); within those groups, mostly in
672 case-insensitive alphabetical order. Final group is
673 x*, which allows for more options.
674 */
675
676 #ifdef TICKY_TICKY
677 # define TICKY_BUILD_ONLY(x) x
678 #else
679 # define TICKY_BUILD_ONLY(x) \
680 errorBelch("the flag %s requires the program to be built with -ticky", \
681 rts_argv[arg]); \
682 error = rtsTrue;
683 #endif
684
685 #ifdef PROFILING
686 # define PROFILING_BUILD_ONLY(x) x
687 #else
688 # define PROFILING_BUILD_ONLY(x) \
689 errorBelch("the flag %s requires the program to be built with -prof", \
690 rts_argv[arg]); \
691 error = rtsTrue;
692 #endif
693
694 #ifdef TRACING
695 # define TRACING_BUILD_ONLY(x) x
696 #else
697 # define TRACING_BUILD_ONLY(x) \
698 errorBelch("the flag %s requires the program to be built with -eventlog or -debug", \
699 rts_argv[arg]); \
700 error = rtsTrue;
701 #endif
702
703 #ifdef THREADED_RTS
704 # define THREADED_BUILD_ONLY(x) x
705 #else
706 # define THREADED_BUILD_ONLY(x) \
707 errorBelch("the flag %s requires the program to be built with -threaded", \
708 rts_argv[arg]); \
709 error = rtsTrue;
710 #endif
711
712 #ifdef DEBUG
713 # define DEBUG_BUILD_ONLY(x) x
714 #else
715 # define DEBUG_BUILD_ONLY(x) \
716 errorBelch("the flag %s requires the program to be built with -debug", \
717 rts_argv[arg]); \
718 error = rtsTrue;
719 #endif
720
721 /* =========== GENERAL ========================== */
722 case '?':
723 OPTION_SAFE;
724 error = rtsTrue;
725 break;
726
727 /* This isn't going to allow us to keep related options
728 together as we add more --* flags. We really need a
729 proper options parser. */
730 case '-':
731 if (strequal("install-signal-handlers=yes",
732 &rts_argv[arg][2])) {
733 OPTION_UNSAFE;
734 RtsFlags.MiscFlags.install_signal_handlers = rtsTrue;
735 }
736 else if (strequal("install-signal-handlers=no",
737 &rts_argv[arg][2])) {
738 OPTION_UNSAFE;
739 RtsFlags.MiscFlags.install_signal_handlers = rtsFalse;
740 }
741 else if (strequal("machine-readable",
742 &rts_argv[arg][2])) {
743 OPTION_UNSAFE;
744 RtsFlags.MiscFlags.machineReadable = rtsTrue;
745 }
746 else if (strequal("info",
747 &rts_argv[arg][2])) {
748 OPTION_SAFE;
749 printRtsInfo();
750 stg_exit(0);
751 }
752 else {
753 OPTION_SAFE;
754 errorBelch("unknown RTS option: %s",rts_argv[arg]);
755 error = rtsTrue;
756 }
757 break;
758 case 'A':
759 OPTION_UNSAFE;
760 // minimum two blocks in the nursery, so that we have one to
761 // grab for allocate().
762 RtsFlags.GcFlags.minAllocAreaSize
763 = decodeSize(rts_argv[arg], 2, 2*BLOCK_SIZE, HS_INT_MAX)
764 / BLOCK_SIZE;
765 break;
766 case 'n':
767 OPTION_UNSAFE;
768 RtsFlags.GcFlags.nurseryChunkSize
769 = decodeSize(rts_argv[arg], 2, 2*BLOCK_SIZE, HS_INT_MAX)
770 / BLOCK_SIZE;
771 break;
772
773 case 'B':
774 OPTION_UNSAFE;
775 RtsFlags.GcFlags.ringBell = rtsTrue;
776 unchecked_arg_start++;
777 goto check_rest;
778
779 case 'c':
780 OPTION_UNSAFE;
781 if (rts_argv[arg][2] != '\0') {
782 RtsFlags.GcFlags.compactThreshold =
783 atof(rts_argv[arg]+2);
784 } else {
785 RtsFlags.GcFlags.compact = rtsTrue;
786 }
787 break;
788
789 case 'w':
790 OPTION_UNSAFE;
791 RtsFlags.GcFlags.sweep = rtsTrue;
792 unchecked_arg_start++;
793 goto check_rest;
794
795 case 'F':
796 OPTION_UNSAFE;
797 RtsFlags.GcFlags.oldGenFactor = atof(rts_argv[arg]+2);
798
799 if (RtsFlags.GcFlags.oldGenFactor < 0)
800 bad_option( rts_argv[arg] );
801 break;
802
803 case 'D':
804 OPTION_SAFE;
805 DEBUG_BUILD_ONLY(read_debug_flags(rts_argv[arg]);)
806 break;
807
808 case 'K':
809 OPTION_UNSAFE;
810 RtsFlags.GcFlags.maxStkSize =
811 decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX)
812 / sizeof(W_);
813 break;
814
815 case 'k':
816 OPTION_UNSAFE;
817 switch(rts_argv[arg][2]) {
818 case 'c':
819 RtsFlags.GcFlags.stkChunkSize =
820 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
821 / sizeof(W_);
822 break;
823 case 'b':
824 RtsFlags.GcFlags.stkChunkBufferSize =
825 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
826 / sizeof(W_);
827 break;
828 case 'i':
829 RtsFlags.GcFlags.initialStkSize =
830 decodeSize(rts_argv[arg], 3, sizeof(W_), HS_WORD_MAX)
831 / sizeof(W_);
832 break;
833 default:
834 RtsFlags.GcFlags.initialStkSize =
835 decodeSize(rts_argv[arg], 2, sizeof(W_), HS_WORD_MAX)
836 / sizeof(W_);
837 break;
838 }
839 break;
840
841 case 'M':
842 OPTION_UNSAFE;
843 RtsFlags.GcFlags.maxHeapSize =
844 decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX)
845 / BLOCK_SIZE;
846 /* user give size in *bytes* but "maxHeapSize" is in
847 * *blocks* */
848 break;
849
850 case 'm':
851 /* Case for maxN feature request ticket #10728, it's a little
852 odd being so far from the N case. */
853 #if !defined(NOSMP)
854 if (strncmp("maxN", &rts_argv[arg][1], 4) == 0) {
855 OPTION_SAFE;
856 THREADED_BUILD_ONLY(
857 int nNodes;
858 int proc = (int)getNumberOfProcessors();
859
860 nNodes = strtol(rts_argv[arg]+5, (char **) NULL, 10);
861 if (nNodes > proc) { nNodes = proc; }
862
863 if (nNodes <= 0) {
864 errorBelch("bad value for -maxN");
865 error = rtsTrue;
866 }
867 #if defined(PROFILING)
868 RtsFlags.ParFlags.nNodes = 1;
869 #else
870 RtsFlags.ParFlags.nNodes = (nat)nNodes;
871 #endif
872 ) break;
873 } else {
874 #endif
875 OPTION_UNSAFE;
876 RtsFlags.GcFlags.pcFreeHeap = atof(rts_argv[arg]+2);
877
878 /* -m was allowing bad flags to go unreported */
879 if (RtsFlags.GcFlags.pcFreeHeap == 0.0 &&
880 rts_argv[arg][2] != '0')
881 bad_option( rts_argv[arg] );
882
883 if (RtsFlags.GcFlags.pcFreeHeap < 0 ||
884 RtsFlags.GcFlags.pcFreeHeap > 100)
885 bad_option( rts_argv[arg] );
886 break;
887 #if !defined(NOSMP)
888 }
889 #endif
890 case 'G':
891 OPTION_UNSAFE;
892 RtsFlags.GcFlags.generations =
893 decodeSize(rts_argv[arg], 2, 1, HS_INT_MAX);
894 break;
895
896 case 'H':
897 OPTION_UNSAFE;
898 if (rts_argv[arg][2] == '\0') {
899 RtsFlags.GcFlags.heapSizeSuggestionAuto = rtsTrue;
900 } else {
901 RtsFlags.GcFlags.heapSizeSuggestion =
902 (nat)(decodeSize(rts_argv[arg], 2, BLOCK_SIZE, HS_WORD_MAX) / BLOCK_SIZE);
903 }
904 break;
905
906 case 'O':
907 OPTION_UNSAFE;
908 RtsFlags.GcFlags.minOldGenSize =
909 (nat)(decodeSize(rts_argv[arg], 2, BLOCK_SIZE,
910 HS_WORD_MAX)
911 / BLOCK_SIZE);
912 break;
913
914 case 'I': /* idle GC delay */
915 OPTION_UNSAFE;
916 if (rts_argv[arg][2] == '\0') {
917 /* use default */
918 } else {
919 Time t = fsecondsToTime(atof(rts_argv[arg]+2));
920 if (t == 0) {
921 RtsFlags.GcFlags.doIdleGC = rtsFalse;
922 } else {
923 RtsFlags.GcFlags.doIdleGC = rtsTrue;
924 RtsFlags.GcFlags.idleGCDelayTime = t;
925 }
926 }
927 break;
928
929 case 'T':
930 OPTION_SAFE;
931 RtsFlags.GcFlags.giveStats = COLLECT_GC_STATS;
932 unchecked_arg_start++;
933 goto check_rest; /* Don't initialize statistics file. */
934
935 case 'S':
936 OPTION_SAFE; /* but see below */
937 RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
938 goto stats;
939
940 case 's':
941 OPTION_SAFE; /* but see below */
942 RtsFlags.GcFlags.giveStats = SUMMARY_GC_STATS;
943 goto stats;
944
945 case 't':
946 OPTION_SAFE; /* but see below */
947 RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;
948 goto stats;
949
950 stats:
951 {
952 int r;
953 if (rts_argv[arg][2] != '\0') {
954 OPTION_UNSAFE;
955 }
956 r = openStatsFile(rts_argv[arg]+2, NULL,
957 &RtsFlags.GcFlags.statsFile);
958 if (r == -1) { error = rtsTrue; }
959 }
960 break;
961
962 case 'Z':
963 OPTION_UNSAFE;
964 RtsFlags.GcFlags.squeezeUpdFrames = rtsFalse;
965 unchecked_arg_start++;
966 goto check_rest;
967
968 /* =========== PROFILING ========================== */
969
970 case 'P': /* detailed cost centre profiling (time/alloc) */
971 case 'p': /* cost centre profiling (time/alloc) */
972 OPTION_SAFE;
973 PROFILING_BUILD_ONLY(
974 switch (rts_argv[arg][2]) {
975 case 'a':
976 RtsFlags.CcFlags.doCostCentres = COST_CENTRES_ALL;
977 if (rts_argv[arg][3] != '\0') {
978 errorBelch("flag -Pa given an argument"
979 " when none was expected: %s"
980 ,rts_argv[arg]);
981 error = rtsTrue;
982 }
983 break;
984 case '\0':
985 if (rts_argv[arg][1] == 'P') {
986 RtsFlags.CcFlags.doCostCentres =
987 COST_CENTRES_VERBOSE;
988 } else {
989 RtsFlags.CcFlags.doCostCentres =
990 COST_CENTRES_SUMMARY;
991 }
992 break;
993 default:
994 unchecked_arg_start++;
995 goto check_rest;
996 }
997 ) break;
998
999 case 'R':
1000 OPTION_SAFE;
1001 PROFILING_BUILD_ONLY(
1002 RtsFlags.ProfFlags.maxRetainerSetSize =
1003 atof(rts_argv[arg]+2);
1004 ) break;
1005 case 'L':
1006 OPTION_SAFE;
1007 PROFILING_BUILD_ONLY(
1008 RtsFlags.ProfFlags.ccsLength = atof(rts_argv[arg]+2);
1009 if(RtsFlags.ProfFlags.ccsLength <= 0) {
1010 bad_option(rts_argv[arg]);
1011 }
1012 ) break;
1013 case 'h': /* serial heap profile */
1014 #if !defined(PROFILING)
1015 switch (rts_argv[arg][2]) {
1016 case '\0':
1017 case 'T':
1018 OPTION_UNSAFE;
1019 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CLOSURE_TYPE;
1020 break;
1021 default:
1022 OPTION_SAFE;
1023 PROFILING_BUILD_ONLY();
1024 }
1025 #else
1026 OPTION_SAFE;
1027 PROFILING_BUILD_ONLY(
1028 error = read_heap_profiling_flag(rts_argv[arg]);
1029 );
1030 #endif /* PROFILING */
1031 break;
1032
1033 case 'i': /* heap sample interval */
1034 OPTION_UNSAFE;
1035 if (rts_argv[arg][2] == '\0') {
1036 /* use default */
1037 } else {
1038 RtsFlags.ProfFlags.heapProfileInterval =
1039 fsecondsToTime(atof(rts_argv[arg]+2));
1040 }
1041 break;
1042
1043 /* =========== CONCURRENT ========================= */
1044 case 'C': /* context switch interval */
1045 OPTION_UNSAFE;
1046 if (rts_argv[arg][2] == '\0')
1047 RtsFlags.ConcFlags.ctxtSwitchTime = 0;
1048 else {
1049 RtsFlags.ConcFlags.ctxtSwitchTime =
1050 fsecondsToTime(atof(rts_argv[arg]+2));
1051 }
1052 break;
1053
1054 case 'V': /* master tick interval */
1055 OPTION_UNSAFE;
1056 if (rts_argv[arg][2] == '\0') {
1057 // turns off ticks completely
1058 RtsFlags.MiscFlags.tickInterval = 0;
1059 } else {
1060 RtsFlags.MiscFlags.tickInterval =
1061 fsecondsToTime(atof(rts_argv[arg]+2));
1062 }
1063 break;
1064
1065 #if !defined(NOSMP)
1066 case 'N':
1067 OPTION_SAFE;
1068 THREADED_BUILD_ONLY(
1069 if (rts_argv[arg][2] == '\0') {
1070 #if defined(PROFILING)
1071 RtsFlags.ParFlags.nNodes = 1;
1072 #else
1073 RtsFlags.ParFlags.nNodes = getNumberOfProcessors();
1074 #endif
1075 } else {
1076 int nNodes;
1077 OPTION_SAFE; /* but see extra checks below... */
1078
1079 nNodes = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1080
1081 if (nNodes <= 0) {
1082 errorBelch("bad value for -N");
1083 error = rtsTrue;
1084 }
1085 if (rtsOptsEnabled == RtsOptsSafeOnly &&
1086 nNodes > (int)getNumberOfProcessors()) {
1087 errorRtsOptsDisabled("Using large values for -N is not allowed by default. %s");
1088 stg_exit(EXIT_FAILURE);
1089 }
1090 RtsFlags.ParFlags.nNodes = (nat)nNodes;
1091 }
1092 ) break;
1093
1094 case 'g':
1095 OPTION_UNSAFE;
1096 THREADED_BUILD_ONLY(
1097 switch (rts_argv[arg][2]) {
1098 case '1':
1099 // backwards compat only
1100 RtsFlags.ParFlags.parGcEnabled = rtsFalse;
1101 break;
1102 default:
1103 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1104 error = rtsTrue;
1105 break;
1106 }
1107 ) break;
1108
1109 case 'q':
1110 OPTION_UNSAFE;
1111 THREADED_BUILD_ONLY(
1112 switch (rts_argv[arg][2]) {
1113 case '\0':
1114 errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1115 error = rtsTrue;
1116 break;
1117 case 'g':
1118 if (rts_argv[arg][3] == '\0') {
1119 RtsFlags.ParFlags.parGcEnabled = rtsFalse;
1120 } else {
1121 RtsFlags.ParFlags.parGcEnabled = rtsTrue;
1122 RtsFlags.ParFlags.parGcGen
1123 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1124 }
1125 break;
1126 case 'b':
1127 if (rts_argv[arg][3] == '\0') {
1128 RtsFlags.ParFlags.parGcLoadBalancingEnabled =
1129 rtsFalse;
1130 }
1131 else {
1132 RtsFlags.ParFlags.parGcLoadBalancingEnabled =
1133 rtsTrue;
1134 RtsFlags.ParFlags.parGcLoadBalancingGen
1135 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1136 }
1137 break;
1138 case 'i':
1139 RtsFlags.ParFlags.parGcNoSyncWithIdle
1140 = strtol(rts_argv[arg]+3, (char **) NULL, 10);
1141 break;
1142 case 'a':
1143 RtsFlags.ParFlags.setAffinity = rtsTrue;
1144 break;
1145 case 'm':
1146 RtsFlags.ParFlags.migrate = rtsFalse;
1147 break;
1148 case 'w':
1149 // -qw was removed; accepted for backwards compat
1150 break;
1151 default:
1152 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1153 error = rtsTrue;
1154 break;
1155 }
1156 ) break;
1157 #endif
1158 /* =========== PARALLEL =========================== */
1159 case 'e':
1160 OPTION_UNSAFE;
1161 THREADED_BUILD_ONLY(
1162 if (rts_argv[arg][2] != '\0') {
1163 RtsFlags.ParFlags.maxLocalSparks
1164 = strtol(rts_argv[arg]+2, (char **) NULL, 10);
1165 if (RtsFlags.ParFlags.maxLocalSparks <= 0) {
1166 errorBelch("bad value for -e");
1167 error = rtsTrue;
1168 }
1169 }
1170 ) break;
1171
1172 /* =========== TICKY ============================== */
1173
1174 case 'r': /* Basic profiling stats */
1175 OPTION_SAFE;
1176 TICKY_BUILD_ONLY(
1177
1178 RtsFlags.TickyFlags.showTickyStats = rtsTrue;
1179
1180 {
1181 int r;
1182 if (rts_argv[arg][2] != '\0') {
1183 OPTION_UNSAFE;
1184 }
1185 r = openStatsFile(rts_argv[arg]+2,
1186 TICKY_FILENAME_FMT,
1187 &RtsFlags.TickyFlags.tickyFile);
1188 if (r == -1) { error = rtsTrue; }
1189 }
1190 ) break;
1191
1192 /* =========== TRACING ---------=================== */
1193
1194 case 'l':
1195 OPTION_SAFE;
1196 TRACING_BUILD_ONLY(
1197 RtsFlags.TraceFlags.tracing = TRACE_EVENTLOG;
1198 read_trace_flags(&rts_argv[arg][2]);
1199 );
1200 break;
1201
1202 case 'v':
1203 OPTION_SAFE;
1204 DEBUG_BUILD_ONLY(
1205 RtsFlags.TraceFlags.tracing = TRACE_STDERR;
1206 read_trace_flags(&rts_argv[arg][2]);
1207 );
1208 break;
1209
1210 /* =========== EXTENDED OPTIONS =================== */
1211
1212 case 'x': /* Extend the argument space */
1213 unchecked_arg_start++;
1214 switch(rts_argv[arg][2]) {
1215 case '\0':
1216 OPTION_SAFE;
1217 errorBelch("incomplete RTS option: %s",rts_argv[arg]);
1218 error = rtsTrue;
1219 break;
1220
1221 case 'b': /* heapBase in hex; undocumented */
1222 OPTION_UNSAFE;
1223 if (rts_argv[arg][3] != '\0') {
1224 RtsFlags.GcFlags.heapBase
1225 = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1226 } else {
1227 errorBelch("-xb: requires argument");
1228 error = rtsTrue;
1229 }
1230 break;
1231
1232 #if defined(x86_64_HOST_ARCH)
1233 case 'm': /* linkerMemBase */
1234 OPTION_UNSAFE;
1235 if (rts_argv[arg][3] != '\0') {
1236 RtsFlags.MiscFlags.linkerMemBase
1237 = strtol(rts_argv[arg]+3, (char **) NULL, 16);
1238 if (RtsFlags.MiscFlags.linkerMemBase > 0x80000000) {
1239 errorBelch("-xm: value must be <80000000");
1240 error = rtsTrue;
1241 }
1242 } else {
1243 RtsFlags.MiscFlags.linkerMemBase = 0;
1244 }
1245 break;
1246 #endif
1247
1248 case 'c': /* Debugging tool: show current cost centre on
1249 an exception */
1250 OPTION_SAFE;
1251 PROFILING_BUILD_ONLY(
1252 RtsFlags.ProfFlags.showCCSOnException = rtsTrue;
1253 );
1254 unchecked_arg_start++;
1255 goto check_rest;
1256
1257 case 't': /* Include memory used by TSOs in a heap profile */
1258 OPTION_SAFE;
1259 PROFILING_BUILD_ONLY(
1260 RtsFlags.ProfFlags.includeTSOs = rtsTrue;
1261 );
1262 unchecked_arg_start++;
1263 goto check_rest;
1264
1265 /*
1266 * The option prefix '-xx' is reserved for future
1267 * extension. KSW 1999-11.
1268 */
1269
1270 case 'q':
1271 OPTION_UNSAFE;
1272 RtsFlags.GcFlags.allocLimitGrace
1273 = decodeSize(rts_argv[arg], 3, BLOCK_SIZE, HS_INT_MAX)
1274 / BLOCK_SIZE;
1275 break;
1276
1277 default:
1278 OPTION_SAFE;
1279 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1280 error = rtsTrue;
1281 break;
1282 }
1283 break; /* defensive programming */
1284
1285 /* check the rest to be sure there is nothing afterwards.*/
1286 /* see Trac #9839 */
1287 check_rest:
1288 {
1289 /* start checking from the first unchecked position,
1290 * not from index 2*/
1291 /* see Trac #9839 */
1292 if (rts_argv[arg][unchecked_arg_start] != '\0') {
1293 errorBelch("flag -%c given an argument"
1294 " when none was expected: %s",
1295 rts_argv[arg][1],rts_argv[arg]);
1296 error = rtsTrue;
1297 }
1298 break;
1299 }
1300
1301 /* =========== OH DEAR ============================ */
1302 default:
1303 OPTION_SAFE;
1304 errorBelch("unknown RTS option: %s",rts_argv[arg]);
1305 error = rtsTrue;
1306 break;
1307 }
1308
1309 if (!option_checked) {
1310 /* Naughty! Someone didn't use OPTION_UNSAFE / OPTION_SAFE for
1311 an option above */
1312 errorBelch("Internal error in the RTS options parser");
1313 stg_exit(EXIT_FAILURE);
1314 }
1315 }
1316 }
1317
1318 if (error) errorUsage();
1319 }
1320
1321 /* -----------------------------------------------------------------------------
1322 * normaliseRtsOpts: Set some derived values, and make sure things are
1323 * within sensible ranges.
1324 * -------------------------------------------------------------------------- */
1325
1326 static void normaliseRtsOpts (void)
1327 {
1328 if (RtsFlags.MiscFlags.tickInterval < 0) {
1329 RtsFlags.MiscFlags.tickInterval = DEFAULT_TICK_INTERVAL;
1330 }
1331
1332 // If the master timer is disabled, turn off the other timers.
1333 if (RtsFlags.MiscFlags.tickInterval == 0) {
1334 RtsFlags.ConcFlags.ctxtSwitchTime = 0;
1335 RtsFlags.GcFlags.idleGCDelayTime = 0;
1336 RtsFlags.ProfFlags.heapProfileInterval = 0;
1337 }
1338
1339 // Determine what tick interval we should use for the RTS timer
1340 // by taking the shortest of the various intervals that we need to
1341 // monitor.
1342 if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1343 RtsFlags.MiscFlags.tickInterval =
1344 stg_min(RtsFlags.ConcFlags.ctxtSwitchTime,
1345 RtsFlags.MiscFlags.tickInterval);
1346 }
1347
1348 if (RtsFlags.GcFlags.idleGCDelayTime > 0) {
1349 RtsFlags.MiscFlags.tickInterval =
1350 stg_min(RtsFlags.GcFlags.idleGCDelayTime,
1351 RtsFlags.MiscFlags.tickInterval);
1352 }
1353
1354 if (RtsFlags.ProfFlags.heapProfileInterval > 0) {
1355 RtsFlags.MiscFlags.tickInterval =
1356 stg_min(RtsFlags.ProfFlags.heapProfileInterval,
1357 RtsFlags.MiscFlags.tickInterval);
1358 }
1359
1360 if (RtsFlags.ConcFlags.ctxtSwitchTime > 0) {
1361 RtsFlags.ConcFlags.ctxtSwitchTicks =
1362 RtsFlags.ConcFlags.ctxtSwitchTime /
1363 RtsFlags.MiscFlags.tickInterval;
1364 } else {
1365 RtsFlags.ConcFlags.ctxtSwitchTicks = 0;
1366 }
1367
1368 if (RtsFlags.ProfFlags.heapProfileInterval > 0) {
1369 RtsFlags.ProfFlags.heapProfileIntervalTicks =
1370 RtsFlags.ProfFlags.heapProfileInterval /
1371 RtsFlags.MiscFlags.tickInterval;
1372 } else {
1373 RtsFlags.ProfFlags.heapProfileIntervalTicks = 0;
1374 }
1375
1376 if (RtsFlags.GcFlags.stkChunkBufferSize >
1377 RtsFlags.GcFlags.stkChunkSize / 2) {
1378 errorBelch("stack chunk buffer size (-kb) must be less than 50%%\n"
1379 "of the stack chunk size (-kc)");
1380 errorUsage();
1381 }
1382 }
1383
1384 static void errorUsage (void)
1385 {
1386 const char **p;
1387
1388 fflush(stdout);
1389 for (p = usage_text; *p; p++)
1390 errorBelch("%s", *p);
1391 stg_exit(EXIT_FAILURE);
1392 }
1393
1394 static void
1395 stats_fprintf(FILE *f, char *s, ...)
1396 {
1397 va_list ap;
1398 va_start(ap,s);
1399 if (f == NULL) {
1400 vdebugBelch(s, ap);
1401 } else {
1402 vfprintf(f, s, ap);
1403 }
1404 va_end(ap);
1405 }
1406
1407 /* -----------------------------------------------------------------------------
1408 * openStatsFile: open a file in which to put some runtime stats
1409 * -------------------------------------------------------------------------- */
1410
1411 static int // return -1 on error
1412 openStatsFile (char *filename, // filename, or NULL
1413 const char *filename_fmt, // if filename == NULL, use
1414 // this fmt with sprintf to
1415 // generate the filename. %s
1416 // expands to the program name.
1417 FILE **file_ret) // return the FILE*
1418 {
1419 FILE *f = NULL;
1420
1421 if (strequal(filename, "stderr")
1422 || (filename_fmt == NULL && *filename == '\0')) {
1423 f = NULL; /* NULL means use debugBelch */
1424 } else {
1425 if (*filename != '\0') { /* stats file specified */
1426 f = fopen(filename,"w");
1427 } else {
1428 /* default <program>.<ext> */
1429 char stats_filename[STATS_FILENAME_MAXLEN];
1430 sprintf(stats_filename, filename_fmt, prog_name);
1431 f = fopen(stats_filename,"w");
1432 }
1433 if (f == NULL) {
1434 errorBelch("Can't open stats file %s\n", filename);
1435 return -1;
1436 }
1437 }
1438 *file_ret = f;
1439
1440 return 0;
1441 }
1442
1443 /* -----------------------------------------------------------------------------
1444 * initStatsFile: write a line to the file containing the program name
1445 * and the arguments it was invoked with.
1446 -------------------------------------------------------------------------- */
1447
1448 static void initStatsFile (FILE *f)
1449 {
1450 /* Write prog_argv and rts_argv into start of stats file */
1451 int count;
1452 for (count = 0; count < prog_argc; count++) {
1453 stats_fprintf(f, "%s ", prog_argv[count]);
1454 }
1455 stats_fprintf(f, "+RTS ");
1456 for (count = 0; count < rts_argc; count++)
1457 stats_fprintf(f, "%s ", rts_argv[count]);
1458 stats_fprintf(f, "\n");
1459 }
1460
1461 /* -----------------------------------------------------------------------------
1462 * decodeSize: parse a string containing a size, like 300K or 1.2M
1463 -------------------------------------------------------------------------- */
1464
1465 static StgWord64
1466 decodeSize(const char *flag, nat offset, StgWord64 min, StgWord64 max)
1467 {
1468 char c;
1469 const char *s;
1470 StgDouble m;
1471 StgWord64 val;
1472
1473 s = flag + offset;
1474
1475 if (!*s)
1476 {
1477 m = 0;
1478 }
1479 else
1480 {
1481 m = atof(s);
1482 c = s[strlen(s)-1];
1483
1484 if (c == 'g' || c == 'G')
1485 m *= 1024*1024*1024;
1486 else if (c == 'm' || c == 'M')
1487 m *= 1024*1024;
1488 else if (c == 'k' || c == 'K')
1489 m *= 1024;
1490 else if (c == 'w' || c == 'W')
1491 m *= sizeof(W_);
1492 }
1493
1494 val = (StgWord64)m;
1495
1496 if (m < 0 || val < min || val > max) {
1497 // printf doesn't like 64-bit format specs on Windows
1498 // apparently, so fall back to unsigned long.
1499 errorBelch("error in RTS option %s: size outside allowed range (%" FMT_Word " - %" FMT_Word ")", flag, (W_)min, (W_)max);
1500 stg_exit(EXIT_FAILURE);
1501 }
1502
1503 return val;
1504 }
1505
1506 #ifdef DEBUG
1507 static void read_debug_flags(const char* arg)
1508 {
1509 // Already parsed "-D"
1510 const char *c;
1511 for (c = arg + 2; *c != '\0'; c++) {
1512 switch (*c) {
1513 case 's':
1514 RtsFlags.DebugFlags.scheduler = rtsTrue;
1515 break;
1516 case 'i':
1517 RtsFlags.DebugFlags.interpreter = rtsTrue;
1518 break;
1519 case 'w':
1520 RtsFlags.DebugFlags.weak = rtsTrue;
1521 break;
1522 case 'G':
1523 RtsFlags.DebugFlags.gccafs = rtsTrue;
1524 break;
1525 case 'g':
1526 RtsFlags.DebugFlags.gc = rtsTrue;
1527 break;
1528 case 'b':
1529 RtsFlags.DebugFlags.block_alloc = rtsTrue;
1530 break;
1531 case 'S':
1532 RtsFlags.DebugFlags.sanity = rtsTrue;
1533 break;
1534 case 't':
1535 RtsFlags.DebugFlags.stable = rtsTrue;
1536 break;
1537 case 'p':
1538 RtsFlags.DebugFlags.prof = rtsTrue;
1539 break;
1540 case 'l':
1541 RtsFlags.DebugFlags.linker = rtsTrue;
1542 break;
1543 case 'a':
1544 RtsFlags.DebugFlags.apply = rtsTrue;
1545 break;
1546 case 'm':
1547 RtsFlags.DebugFlags.stm = rtsTrue;
1548 break;
1549 case 'z':
1550 RtsFlags.DebugFlags.squeeze = rtsTrue;
1551 break;
1552 case 'c':
1553 RtsFlags.DebugFlags.hpc = rtsTrue;
1554 break;
1555 case 'r':
1556 RtsFlags.DebugFlags.sparks = rtsTrue;
1557 break;
1558 default:
1559 bad_option( arg );
1560 }
1561 }
1562 // -Dx also turns on -v. Use -l to direct trace
1563 // events to the .eventlog file instead.
1564 RtsFlags.TraceFlags.tracing = TRACE_STDERR;
1565 }
1566 #endif
1567
1568 #ifdef PROFILING
1569 // Parse a "-h" flag, returning whether the parse resulted in an error.
1570 static rtsBool read_heap_profiling_flag(const char *arg_in)
1571 {
1572 // Already parsed "-h"
1573
1574 // For historical reasons the parser here mutates the arguments.
1575 // However, for sanity we want to guarantee const-correctness and parsing
1576 // really ought to be an immutable operation. To avoid rewriting the parser
1577 // we just operate on a temporary copy of the argument.
1578 char *arg = strdup(arg_in);
1579 rtsBool error = rtsFalse;
1580 switch (arg[2]) {
1581 case '\0':
1582 case 'C':
1583 case 'c':
1584 case 'M':
1585 case 'm':
1586 case 'D':
1587 case 'd':
1588 case 'Y':
1589 case 'y':
1590 case 'R':
1591 case 'r':
1592 case 'B':
1593 case 'b':
1594 if (arg[2] != '\0' && arg[3] != '\0') {
1595 {
1596 char *left = strchr(arg, '{');
1597 char *right = strrchr(arg, '}');
1598
1599 // curly braces are optional, for
1600 // backwards compat.
1601 if (left)
1602 left = left+1;
1603 else
1604 left = arg + 3;
1605
1606 if (!right)
1607 right = arg + strlen(arg);
1608
1609 *right = '\0';
1610
1611 switch (arg[2]) {
1612 case 'c': // cost centre label select
1613 RtsFlags.ProfFlags.ccSelector = left;
1614 break;
1615 case 'C':
1616 RtsFlags.ProfFlags.ccsSelector = left;
1617 break;
1618 case 'M':
1619 case 'm': // cost centre module select
1620 RtsFlags.ProfFlags.modSelector = left;
1621 break;
1622 case 'D':
1623 case 'd': // closure descr select
1624 RtsFlags.ProfFlags.descrSelector = left;
1625 break;
1626 case 'Y':
1627 case 'y': // closure type select
1628 RtsFlags.ProfFlags.typeSelector = left;
1629 break;
1630 case 'R':
1631 case 'r': // retainer select
1632 RtsFlags.ProfFlags.retainerSelector = left;
1633 break;
1634 case 'B':
1635 case 'b': // biography select
1636 RtsFlags.ProfFlags.bioSelector = left;
1637 break;
1638 }
1639 }
1640 break;
1641 }
1642
1643 if (RtsFlags.ProfFlags.doHeapProfile != 0) {
1644 errorBelch("multiple heap profile options");
1645 error = rtsTrue;
1646 break;
1647 }
1648
1649 switch (arg[2]) {
1650 case '\0':
1651 case 'C':
1652 case 'c':
1653 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
1654 break;
1655 case 'M':
1656 case 'm':
1657 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
1658 break;
1659 case 'D':
1660 case 'd':
1661 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
1662 break;
1663 case 'Y':
1664 case 'y':
1665 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
1666 break;
1667 case 'R':
1668 case 'r':
1669 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
1670 break;
1671 case 'B':
1672 case 'b':
1673 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
1674 break;
1675 }
1676 break;
1677
1678 default:
1679 errorBelch("invalid heap profile option: %s", arg);
1680 error = rtsTrue;
1681 }
1682
1683 free(arg);
1684 return error;
1685 }
1686 #endif
1687
1688 #if defined(TRACING)
1689 static void read_trace_flags(const char *arg)
1690 {
1691 const char *c;
1692 rtsBool enabled = rtsTrue;
1693 /* Syntax for tracing flags currently looks like:
1694 *
1695 * -l To turn on eventlog tracing with default trace classes
1696 * -lx Turn on class 'x' (for some class listed below)
1697 * -l-x Turn off class 'x'
1698 * -la Turn on all classes
1699 * -l-a Turn off all classes
1700 *
1701 * This lets users say things like:
1702 * -la-p "all but sparks"
1703 * -l-ap "only sparks"
1704 */
1705
1706 /* Start by turning on the default tracing flags.
1707 *
1708 * Currently this is all the trace classes, except full-detail sparks.
1709 * Similarly, in future we might default to slightly less verbose
1710 * scheduler or GC tracing.
1711 */
1712 RtsFlags.TraceFlags.scheduler = rtsTrue;
1713 RtsFlags.TraceFlags.gc = rtsTrue;
1714 RtsFlags.TraceFlags.sparks_sampled = rtsTrue;
1715 RtsFlags.TraceFlags.user = rtsTrue;
1716
1717 for (c = arg; *c != '\0'; c++) {
1718 switch(*c) {
1719 case '\0':
1720 break;
1721 case '-':
1722 enabled = rtsFalse;
1723 break;
1724 case 'a':
1725 RtsFlags.TraceFlags.scheduler = enabled;
1726 RtsFlags.TraceFlags.gc = enabled;
1727 RtsFlags.TraceFlags.sparks_sampled = enabled;
1728 RtsFlags.TraceFlags.sparks_full = enabled;
1729 RtsFlags.TraceFlags.user = enabled;
1730 enabled = rtsTrue;
1731 break;
1732
1733 case 's':
1734 RtsFlags.TraceFlags.scheduler = enabled;
1735 enabled = rtsTrue;
1736 break;
1737 case 'p':
1738 RtsFlags.TraceFlags.sparks_sampled = enabled;
1739 enabled = rtsTrue;
1740 break;
1741 case 'f':
1742 RtsFlags.TraceFlags.sparks_full = enabled;
1743 enabled = rtsTrue;
1744 break;
1745 case 't':
1746 RtsFlags.TraceFlags.timestamp = enabled;
1747 enabled = rtsTrue;
1748 break;
1749 case 'g':
1750 RtsFlags.TraceFlags.gc = enabled;
1751 enabled = rtsTrue;
1752 break;
1753 case 'u':
1754 RtsFlags.TraceFlags.user = enabled;
1755 enabled = rtsTrue;
1756 break;
1757 default:
1758 errorBelch("unknown trace option: %c",*c);
1759 break;
1760 }
1761 }
1762 }
1763 #endif
1764
1765 static void GNU_ATTRIBUTE(__noreturn__)
1766 bad_option(const char *s)
1767 {
1768 errorBelch("bad RTS option: %s", s);
1769 stg_exit(EXIT_FAILURE);
1770 }
1771
1772 /* ----------------------------------------------------------------------------
1773 Copying and freeing argc/argv
1774 ------------------------------------------------------------------------- */
1775
1776 static char * copyArg(char *arg)
1777 {
1778 char *new_arg = stgMallocBytes(strlen(arg) + 1, "copyArg");
1779 strcpy(new_arg, arg);
1780 return new_arg;
1781 }
1782
1783 static char ** copyArgv(int argc, char *argv[])
1784 {
1785 int i;
1786 char **new_argv;
1787
1788 new_argv = stgCallocBytes(argc + 1, sizeof (char *), "copyArgv 1");
1789 for (i = 0; i < argc; i++) {
1790 new_argv[i] = copyArg(argv[i]);
1791 }
1792 new_argv[argc] = NULL;
1793 return new_argv;
1794 }
1795
1796 static void freeArgv(int argc, char *argv[])
1797 {
1798 int i;
1799 if (argv != NULL) {
1800 for (i = 0; i < argc; i++) {
1801 stgFree(argv[i]);
1802 }
1803 stgFree(argv);
1804 }
1805 }
1806
1807 /* -----------------------------------------------------------------------------
1808 Getting/Setting the program's arguments.
1809
1810 These are used by System.Environment, and parts of the RTS.
1811 -------------------------------------------------------------------------- */
1812
1813 void
1814 setProgName(char *argv[])
1815 {
1816 char *last_slash;
1817
1818 if (argv[0] == NULL) { // #7037
1819 prog_name = "";
1820 return;
1821 }
1822
1823 /* Remove directory from argv[0] -- default files in current directory */
1824 #if !defined(mingw32_HOST_OS)
1825 if ( (last_slash = (char *) strrchr(argv[0], '/')) != NULL ) {
1826 prog_name = last_slash+1;
1827 } else {
1828 prog_name = argv[0];
1829 }
1830 #else
1831 last_slash = argv[0] + (strlen(argv[0]) - 1);
1832 while ( last_slash > argv[0] ) {
1833 if ( *last_slash == '/' || *last_slash == '\\' ) {
1834 prog_name = last_slash+1;
1835 return;
1836 }
1837 last_slash--;
1838 }
1839 prog_name = argv[0];
1840 #endif
1841 }
1842
1843 void
1844 getProgArgv(int *argc, char **argv[])
1845 {
1846 if (argc) { *argc = prog_argc; }
1847 if (argv) { *argv = prog_argv; }
1848 }
1849
1850 void
1851 setProgArgv(int argc, char *argv[])
1852 {
1853 prog_argc = argc;
1854 prog_argv = copyArgv(argc,argv);
1855 setProgName(prog_argv);
1856 }
1857
1858 static void
1859 freeProgArgv(void)
1860 {
1861 freeArgv(prog_argc,prog_argv);
1862 prog_argc = 0;
1863 prog_argv = NULL;
1864 }
1865
1866 /* ----------------------------------------------------------------------------
1867 The full argv - a copy of the original program's argc/argv
1868 ------------------------------------------------------------------------- */
1869
1870 void
1871 setFullProgArgv(int argc, char *argv[])
1872 {
1873 full_prog_argc = argc;
1874 full_prog_argv = copyArgv(argc,argv);
1875 }
1876
1877 /* These functions record and recall the full arguments, including the
1878 +RTS ... -RTS options. The reason for adding them was so that the
1879 ghc-inplace program can pass /all/ the arguments on to the real ghc. */
1880 void
1881 getFullProgArgv(int *argc, char **argv[])
1882 {
1883 if (argc) { *argc = full_prog_argc; }
1884 if (argv) { *argv = full_prog_argv; }
1885 }
1886
1887 void
1888 freeFullProgArgv (void)
1889 {
1890 freeArgv(full_prog_argc, full_prog_argv);
1891 full_prog_argc = 0;
1892 full_prog_argv = NULL;
1893 }
1894
1895 /* ----------------------------------------------------------------------------
1896 The Win32 argv
1897 ------------------------------------------------------------------------- */
1898
1899 #if defined(mingw32_HOST_OS)
1900 void freeWin32ProgArgv (void);
1901
1902 void
1903 freeWin32ProgArgv (void)
1904 {
1905 int i;
1906
1907 if (win32_prog_argv != NULL) {
1908 for (i = 0; i < win32_prog_argc; i++) {
1909 stgFree(win32_prog_argv[i]);
1910 }
1911 stgFree(win32_prog_argv);
1912 }
1913
1914 win32_prog_argc = 0;
1915 win32_prog_argv = NULL;
1916 }
1917
1918 void
1919 getWin32ProgArgv(int *argc, wchar_t **argv[])
1920 {
1921 *argc = win32_prog_argc;
1922 *argv = win32_prog_argv;
1923 }
1924
1925 void
1926 setWin32ProgArgv(int argc, wchar_t *argv[])
1927 {
1928 int i;
1929
1930 freeWin32ProgArgv();
1931
1932 win32_prog_argc = argc;
1933 if (argv == NULL) {
1934 win32_prog_argv = NULL;
1935 return;
1936 }
1937
1938 win32_prog_argv = stgCallocBytes(argc + 1, sizeof (wchar_t *),
1939 "setWin32ProgArgv 1");
1940 for (i = 0; i < argc; i++) {
1941 win32_prog_argv[i] = stgMallocBytes((wcslen(argv[i]) + 1) * sizeof(wchar_t),
1942 "setWin32ProgArgv 2");
1943 wcscpy(win32_prog_argv[i], argv[i]);
1944 }
1945 win32_prog_argv[argc] = NULL;
1946 }
1947 #endif
1948
1949 /* ----------------------------------------------------------------------------
1950 The RTS argv
1951 ------------------------------------------------------------------------- */
1952
1953 static void
1954 freeRtsArgv(void)
1955 {
1956 freeArgv(rts_argc,rts_argv);
1957 rts_argc = 0;
1958 rts_argv = NULL;
1959 rts_argv_size = 0;
1960 }
1961
1962 /* ----------------------------------------------------------------------------
1963 All argvs
1964 ------------------------------------------------------------------------- */
1965
1966 void freeRtsArgs(void)
1967 {
1968 #if defined(mingw32_HOST_OS)
1969 freeWin32ProgArgv();
1970 #endif
1971 freeFullProgArgv();
1972 freeProgArgv();
1973 freeRtsArgv();
1974 }
1975
1976
1977 /*
1978 Note [OPTION_SAFE vs OPTION_UNSAFE]
1979
1980 Ticket #3910 originally pointed out that the RTS options are a potential
1981 security problem. For example the -t -s or -S flags can be used to
1982 overwrite files. This would be bad in the context of CGI scripts or
1983 setuid binaries. So we introduced a system where +RTS processing is more
1984 or less disabled unless you pass the -rtsopts flag at link time.
1985
1986 This scheme is safe enough but it also really annoyes users. They have
1987 to use -rtsopts in many circumstances: with -threaded to use -N, with
1988 -eventlog to use -l, with -prof to use any of the profiling flags. Many
1989 users just set -rtsopts globally or in project .cabal files. Apart from
1990 annoying users it reduces security because it means that deployed
1991 binaries will have all RTS options enabled rather than just profiling
1992 ones.
1993
1994 So now, we relax the set of RTS options that are available in the
1995 default -rtsopts=some case. For "deployment" ways like vanilla and
1996 -threaded we remain quite conservative. Only --info -? --help are
1997 allowed for vanilla. For -threaded, -N and -N<x> are allowed with a
1998 check that x <= num cpus.
1999
2000 For "developer" ways like -debug, -eventlog, -prof, we allow all the
2001 options that are special to that way. Some of these allow writing files,
2002 but the file written is not directly under the control of the attacker.
2003 For the setuid case (where the attacker would have control over binary
2004 name, current dir, local symlinks etc) we check if the process is
2005 running setuid/setgid and refuse all RTS option processing. Users would
2006 need to use -rtsopts=all in this case.
2007
2008 We are making the assumption that developers will not deploy binaries
2009 built in the -debug, -eventlog, -prof ways. And even if they do, the
2010 damage should be limited to DOS, information disclosure and writing
2011 files like <progname>.eventlog, not arbitrary files.
2012 */