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