rts: Don't use strndup
[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 char *selector = stgStrndup(left, right - left + 1);
1601
1602 switch (arg[2]) {
1603 case 'c': // cost centre label select
1604 RtsFlags.ProfFlags.ccSelector = selector;
1605 break;
1606 case 'C':
1607 RtsFlags.ProfFlags.ccsSelector = selector;
1608 break;
1609 case 'M':
1610 case 'm': // cost centre module select
1611 RtsFlags.ProfFlags.modSelector = selector;
1612 break;
1613 case 'D':
1614 case 'd': // closure descr select
1615 RtsFlags.ProfFlags.descrSelector = selector;
1616 break;
1617 case 'Y':
1618 case 'y': // closure type select
1619 RtsFlags.ProfFlags.typeSelector = selector;
1620 break;
1621 case 'R':
1622 case 'r': // retainer select
1623 RtsFlags.ProfFlags.retainerSelector = selector;
1624 break;
1625 case 'B':
1626 case 'b': // biography select
1627 RtsFlags.ProfFlags.bioSelector = selector;
1628 break;
1629 default:
1630 free(selector);
1631 }
1632 }
1633 break;
1634 }
1635
1636 if (RtsFlags.ProfFlags.doHeapProfile != 0) {
1637 errorBelch("multiple heap profile options");
1638 error = rtsTrue;
1639 break;
1640 }
1641
1642 switch (arg[2]) {
1643 case '\0':
1644 case 'C':
1645 case 'c':
1646 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
1647 break;
1648 case 'M':
1649 case 'm':
1650 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
1651 break;
1652 case 'D':
1653 case 'd':
1654 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
1655 break;
1656 case 'Y':
1657 case 'y':
1658 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
1659 break;
1660 case 'R':
1661 case 'r':
1662 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
1663 break;
1664 case 'B':
1665 case 'b':
1666 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
1667 break;
1668 }
1669 break;
1670
1671 default:
1672 errorBelch("invalid heap profile option: %s", arg);
1673 error = rtsTrue;
1674 }
1675
1676 free(arg);
1677 return error;
1678 }
1679 #endif
1680
1681 #if defined(TRACING)
1682 static void read_trace_flags(const char *arg)
1683 {
1684 const char *c;
1685 rtsBool enabled = rtsTrue;
1686 /* Syntax for tracing flags currently looks like:
1687 *
1688 * -l To turn on eventlog tracing with default trace classes
1689 * -lx Turn on class 'x' (for some class listed below)
1690 * -l-x Turn off class 'x'
1691 * -la Turn on all classes
1692 * -l-a Turn off all classes
1693 *
1694 * This lets users say things like:
1695 * -la-p "all but sparks"
1696 * -l-ap "only sparks"
1697 */
1698
1699 /* Start by turning on the default tracing flags.
1700 *
1701 * Currently this is all the trace classes, except full-detail sparks.
1702 * Similarly, in future we might default to slightly less verbose
1703 * scheduler or GC tracing.
1704 */
1705 RtsFlags.TraceFlags.scheduler = rtsTrue;
1706 RtsFlags.TraceFlags.gc = rtsTrue;
1707 RtsFlags.TraceFlags.sparks_sampled = rtsTrue;
1708 RtsFlags.TraceFlags.user = rtsTrue;
1709
1710 for (c = arg; *c != '\0'; c++) {
1711 switch(*c) {
1712 case '\0':
1713 break;
1714 case '-':
1715 enabled = rtsFalse;
1716 break;
1717 case 'a':
1718 RtsFlags.TraceFlags.scheduler = enabled;
1719 RtsFlags.TraceFlags.gc = enabled;
1720 RtsFlags.TraceFlags.sparks_sampled = enabled;
1721 RtsFlags.TraceFlags.sparks_full = enabled;
1722 RtsFlags.TraceFlags.user = enabled;
1723 enabled = rtsTrue;
1724 break;
1725
1726 case 's':
1727 RtsFlags.TraceFlags.scheduler = enabled;
1728 enabled = rtsTrue;
1729 break;
1730 case 'p':
1731 RtsFlags.TraceFlags.sparks_sampled = enabled;
1732 enabled = rtsTrue;
1733 break;
1734 case 'f':
1735 RtsFlags.TraceFlags.sparks_full = enabled;
1736 enabled = rtsTrue;
1737 break;
1738 case 't':
1739 RtsFlags.TraceFlags.timestamp = enabled;
1740 enabled = rtsTrue;
1741 break;
1742 case 'g':
1743 RtsFlags.TraceFlags.gc = enabled;
1744 enabled = rtsTrue;
1745 break;
1746 case 'u':
1747 RtsFlags.TraceFlags.user = enabled;
1748 enabled = rtsTrue;
1749 break;
1750 default:
1751 errorBelch("unknown trace option: %c",*c);
1752 break;
1753 }
1754 }
1755 }
1756 #endif
1757
1758 static void GNU_ATTRIBUTE(__noreturn__)
1759 bad_option(const char *s)
1760 {
1761 errorBelch("bad RTS option: %s", s);
1762 stg_exit(EXIT_FAILURE);
1763 }
1764
1765 /* ----------------------------------------------------------------------------
1766 Copying and freeing argc/argv
1767 ------------------------------------------------------------------------- */
1768
1769 static char * copyArg(char *arg)
1770 {
1771 char *new_arg = stgMallocBytes(strlen(arg) + 1, "copyArg");
1772 strcpy(new_arg, arg);
1773 return new_arg;
1774 }
1775
1776 static char ** copyArgv(int argc, char *argv[])
1777 {
1778 int i;
1779 char **new_argv;
1780
1781 new_argv = stgCallocBytes(argc + 1, sizeof (char *), "copyArgv 1");
1782 for (i = 0; i < argc; i++) {
1783 new_argv[i] = copyArg(argv[i]);
1784 }
1785 new_argv[argc] = NULL;
1786 return new_argv;
1787 }
1788
1789 static void freeArgv(int argc, char *argv[])
1790 {
1791 int i;
1792 if (argv != NULL) {
1793 for (i = 0; i < argc; i++) {
1794 stgFree(argv[i]);
1795 }
1796 stgFree(argv);
1797 }
1798 }
1799
1800 /* -----------------------------------------------------------------------------
1801 Getting/Setting the program's arguments.
1802
1803 These are used by System.Environment, and parts of the RTS.
1804 -------------------------------------------------------------------------- */
1805
1806 void
1807 setProgName(char *argv[])
1808 {
1809 char *last_slash;
1810
1811 if (argv[0] == NULL) { // #7037
1812 prog_name = "";
1813 return;
1814 }
1815
1816 /* Remove directory from argv[0] -- default files in current directory */
1817 #if !defined(mingw32_HOST_OS)
1818 if ( (last_slash = (char *) strrchr(argv[0], '/')) != NULL ) {
1819 prog_name = last_slash+1;
1820 } else {
1821 prog_name = argv[0];
1822 }
1823 #else
1824 last_slash = argv[0] + (strlen(argv[0]) - 1);
1825 while ( last_slash > argv[0] ) {
1826 if ( *last_slash == '/' || *last_slash == '\\' ) {
1827 prog_name = last_slash+1;
1828 return;
1829 }
1830 last_slash--;
1831 }
1832 prog_name = argv[0];
1833 #endif
1834 }
1835
1836 void
1837 getProgArgv(int *argc, char **argv[])
1838 {
1839 if (argc) { *argc = prog_argc; }
1840 if (argv) { *argv = prog_argv; }
1841 }
1842
1843 void
1844 setProgArgv(int argc, char *argv[])
1845 {
1846 prog_argc = argc;
1847 prog_argv = copyArgv(argc,argv);
1848 setProgName(prog_argv);
1849 }
1850
1851 static void
1852 freeProgArgv(void)
1853 {
1854 freeArgv(prog_argc,prog_argv);
1855 prog_argc = 0;
1856 prog_argv = NULL;
1857 }
1858
1859 /* ----------------------------------------------------------------------------
1860 The full argv - a copy of the original program's argc/argv
1861 ------------------------------------------------------------------------- */
1862
1863 void
1864 setFullProgArgv(int argc, char *argv[])
1865 {
1866 full_prog_argc = argc;
1867 full_prog_argv = copyArgv(argc,argv);
1868 }
1869
1870 /* These functions record and recall the full arguments, including the
1871 +RTS ... -RTS options. The reason for adding them was so that the
1872 ghc-inplace program can pass /all/ the arguments on to the real ghc. */
1873 void
1874 getFullProgArgv(int *argc, char **argv[])
1875 {
1876 if (argc) { *argc = full_prog_argc; }
1877 if (argv) { *argv = full_prog_argv; }
1878 }
1879
1880 void
1881 freeFullProgArgv (void)
1882 {
1883 freeArgv(full_prog_argc, full_prog_argv);
1884 full_prog_argc = 0;
1885 full_prog_argv = NULL;
1886 }
1887
1888 /* ----------------------------------------------------------------------------
1889 The Win32 argv
1890 ------------------------------------------------------------------------- */
1891
1892 #if defined(mingw32_HOST_OS)
1893 void freeWin32ProgArgv (void);
1894
1895 void
1896 freeWin32ProgArgv (void)
1897 {
1898 int i;
1899
1900 if (win32_prog_argv != NULL) {
1901 for (i = 0; i < win32_prog_argc; i++) {
1902 stgFree(win32_prog_argv[i]);
1903 }
1904 stgFree(win32_prog_argv);
1905 }
1906
1907 win32_prog_argc = 0;
1908 win32_prog_argv = NULL;
1909 }
1910
1911 void
1912 getWin32ProgArgv(int *argc, wchar_t **argv[])
1913 {
1914 *argc = win32_prog_argc;
1915 *argv = win32_prog_argv;
1916 }
1917
1918 void
1919 setWin32ProgArgv(int argc, wchar_t *argv[])
1920 {
1921 int i;
1922
1923 freeWin32ProgArgv();
1924
1925 win32_prog_argc = argc;
1926 if (argv == NULL) {
1927 win32_prog_argv = NULL;
1928 return;
1929 }
1930
1931 win32_prog_argv = stgCallocBytes(argc + 1, sizeof (wchar_t *),
1932 "setWin32ProgArgv 1");
1933 for (i = 0; i < argc; i++) {
1934 win32_prog_argv[i] = stgMallocBytes((wcslen(argv[i]) + 1) * sizeof(wchar_t),
1935 "setWin32ProgArgv 2");
1936 wcscpy(win32_prog_argv[i], argv[i]);
1937 }
1938 win32_prog_argv[argc] = NULL;
1939 }
1940 #endif
1941
1942 /* ----------------------------------------------------------------------------
1943 The RTS argv
1944 ------------------------------------------------------------------------- */
1945
1946 static void
1947 freeRtsArgv(void)
1948 {
1949 freeArgv(rts_argc,rts_argv);
1950 rts_argc = 0;
1951 rts_argv = NULL;
1952 rts_argv_size = 0;
1953 }
1954
1955 /* ----------------------------------------------------------------------------
1956 All argvs
1957 ------------------------------------------------------------------------- */
1958
1959 void freeRtsArgs(void)
1960 {
1961 #if defined(mingw32_HOST_OS)
1962 freeWin32ProgArgv();
1963 #endif
1964 freeFullProgArgv();
1965 freeProgArgv();
1966 freeRtsArgv();
1967 }
1968
1969
1970 /*
1971 Note [OPTION_SAFE vs OPTION_UNSAFE]
1972
1973 Ticket #3910 originally pointed out that the RTS options are a potential
1974 security problem. For example the -t -s or -S flags can be used to
1975 overwrite files. This would be bad in the context of CGI scripts or
1976 setuid binaries. So we introduced a system where +RTS processing is more
1977 or less disabled unless you pass the -rtsopts flag at link time.
1978
1979 This scheme is safe enough but it also really annoyes users. They have
1980 to use -rtsopts in many circumstances: with -threaded to use -N, with
1981 -eventlog to use -l, with -prof to use any of the profiling flags. Many
1982 users just set -rtsopts globally or in project .cabal files. Apart from
1983 annoying users it reduces security because it means that deployed
1984 binaries will have all RTS options enabled rather than just profiling
1985 ones.
1986
1987 So now, we relax the set of RTS options that are available in the
1988 default -rtsopts=some case. For "deployment" ways like vanilla and
1989 -threaded we remain quite conservative. Only --info -? --help are
1990 allowed for vanilla. For -threaded, -N and -N<x> are allowed with a
1991 check that x <= num cpus.
1992
1993 For "developer" ways like -debug, -eventlog, -prof, we allow all the
1994 options that are special to that way. Some of these allow writing files,
1995 but the file written is not directly under the control of the attacker.
1996 For the setuid case (where the attacker would have control over binary
1997 name, current dir, local symlinks etc) we check if the process is
1998 running setuid/setgid and refuse all RTS option processing. Users would
1999 need to use -rtsopts=all in this case.
2000
2001 We are making the assumption that developers will not deploy binaries
2002 built in the -debug, -eventlog, -prof ways. And even if they do, the
2003 damage should be limited to DOS, information disclosure and writing
2004 files like <progname>.eventlog, not arbitrary files.
2005 */