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