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