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