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