Make start address of `osReserveHeapMemory` tunable via command line -xb
[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.ParFlags.parGcLoadBalancingGen == ~0u) {
1458 StgWord alloc_area_bytes
1459 = RtsFlags.GcFlags.minAllocAreaSize * BLOCK_SIZE;
1460
1461 // If allocation area is larger that CPU cache
1462 // we can finish scanning quicker doing work-stealing
1463 // scan. Trac #9221
1464 // 32M looks big enough not to fit into L2 cache
1465 // of popular modern CPUs.
1466 if (alloc_area_bytes >= 32 * 1024 * 1024) {
1467 RtsFlags.ParFlags.parGcLoadBalancingGen = 0;
1468 } else {
1469 RtsFlags.ParFlags.parGcLoadBalancingGen = 1;
1470 }
1471 }
1472
1473 #ifdef THREADED_RTS
1474 if (RtsFlags.ParFlags.parGcThreads > RtsFlags.ParFlags.nCapabilities) {
1475 errorBelch("GC threads (-qn) must be between 1 and the value of -N");
1476 errorUsage();
1477 }
1478 #endif
1479 }
1480
1481 static void errorUsage (void)
1482 {
1483 const char **p;
1484
1485 fflush(stdout);
1486 for (p = usage_text; *p; p++)
1487 errorBelch("%s", *p);
1488 stg_exit(EXIT_FAILURE);
1489 }
1490
1491 static void
1492 stats_fprintf(FILE *f, char *s, ...)
1493 {
1494 va_list ap;
1495 va_start(ap,s);
1496 if (f == NULL) {
1497 vdebugBelch(s, ap);
1498 } else {
1499 vfprintf(f, s, ap);
1500 }
1501 va_end(ap);
1502 }
1503
1504 /* -----------------------------------------------------------------------------
1505 * openStatsFile: open a file in which to put some runtime stats
1506 * -------------------------------------------------------------------------- */
1507
1508 static int // return -1 on error
1509 openStatsFile (char *filename, // filename, or NULL
1510 const char *filename_fmt, // if filename == NULL, use
1511 // this fmt with sprintf to
1512 // generate the filename. %s
1513 // expands to the program name.
1514 FILE **file_ret) // return the FILE*
1515 {
1516 FILE *f = NULL;
1517
1518 if (strequal(filename, "stderr")
1519 || (filename_fmt == NULL && *filename == '\0')) {
1520 f = NULL; /* NULL means use debugBelch */
1521 } else {
1522 if (*filename != '\0') { /* stats file specified */
1523 f = fopen(filename,"w");
1524 } else {
1525 /* default <program>.<ext> */
1526 char stats_filename[STATS_FILENAME_MAXLEN];
1527 sprintf(stats_filename, filename_fmt, prog_name);
1528 f = fopen(stats_filename,"w");
1529 }
1530 if (f == NULL) {
1531 errorBelch("Can't open stats file %s\n", filename);
1532 return -1;
1533 }
1534 }
1535 *file_ret = f;
1536
1537 return 0;
1538 }
1539
1540 /* -----------------------------------------------------------------------------
1541 * initStatsFile: write a line to the file containing the program name
1542 * and the arguments it was invoked with.
1543 -------------------------------------------------------------------------- */
1544
1545 static void initStatsFile (FILE *f)
1546 {
1547 /* Write prog_argv and rts_argv into start of stats file */
1548 int count;
1549 for (count = 0; count < prog_argc; count++) {
1550 stats_fprintf(f, "%s ", prog_argv[count]);
1551 }
1552 stats_fprintf(f, "+RTS ");
1553 for (count = 0; count < rts_argc; count++)
1554 stats_fprintf(f, "%s ", rts_argv[count]);
1555 stats_fprintf(f, "\n");
1556 }
1557
1558 /* -----------------------------------------------------------------------------
1559 * decodeSize: parse a string containing a size, like 300K or 1.2M
1560 -------------------------------------------------------------------------- */
1561
1562 static StgWord64
1563 decodeSize(const char *flag, uint32_t offset, StgWord64 min, StgWord64 max)
1564 {
1565 char c;
1566 const char *s;
1567 StgDouble m;
1568 StgWord64 val;
1569
1570 s = flag + offset;
1571
1572 if (!*s)
1573 {
1574 m = 0;
1575 }
1576 else
1577 {
1578 m = atof(s);
1579 c = s[strlen(s)-1];
1580
1581 if (c == 'g' || c == 'G')
1582 m *= 1024*1024*1024;
1583 else if (c == 'm' || c == 'M')
1584 m *= 1024*1024;
1585 else if (c == 'k' || c == 'K')
1586 m *= 1024;
1587 else if (c == 'w' || c == 'W')
1588 m *= sizeof(W_);
1589 }
1590
1591 val = (StgWord64)m;
1592
1593 if (m < 0 || val < min || val > max) {
1594 // printf doesn't like 64-bit format specs on Windows
1595 // apparently, so fall back to unsigned long.
1596 errorBelch("error in RTS option %s: size outside allowed range (%" FMT_Word " - %" FMT_Word ")", flag, (W_)min, (W_)max);
1597 stg_exit(EXIT_FAILURE);
1598 }
1599
1600 return val;
1601 }
1602
1603 #ifdef DEBUG
1604 static void read_debug_flags(const char* arg)
1605 {
1606 // Already parsed "-D"
1607 const char *c;
1608 for (c = arg + 2; *c != '\0'; c++) {
1609 switch (*c) {
1610 case 's':
1611 RtsFlags.DebugFlags.scheduler = rtsTrue;
1612 break;
1613 case 'i':
1614 RtsFlags.DebugFlags.interpreter = rtsTrue;
1615 break;
1616 case 'w':
1617 RtsFlags.DebugFlags.weak = rtsTrue;
1618 break;
1619 case 'G':
1620 RtsFlags.DebugFlags.gccafs = rtsTrue;
1621 break;
1622 case 'g':
1623 RtsFlags.DebugFlags.gc = rtsTrue;
1624 break;
1625 case 'b':
1626 RtsFlags.DebugFlags.block_alloc = rtsTrue;
1627 break;
1628 case 'S':
1629 RtsFlags.DebugFlags.sanity = rtsTrue;
1630 break;
1631 case 't':
1632 RtsFlags.DebugFlags.stable = rtsTrue;
1633 break;
1634 case 'p':
1635 RtsFlags.DebugFlags.prof = rtsTrue;
1636 break;
1637 case 'l':
1638 RtsFlags.DebugFlags.linker = rtsTrue;
1639 break;
1640 case 'a':
1641 RtsFlags.DebugFlags.apply = rtsTrue;
1642 break;
1643 case 'm':
1644 RtsFlags.DebugFlags.stm = rtsTrue;
1645 break;
1646 case 'z':
1647 RtsFlags.DebugFlags.squeeze = rtsTrue;
1648 break;
1649 case 'c':
1650 RtsFlags.DebugFlags.hpc = rtsTrue;
1651 break;
1652 case 'r':
1653 RtsFlags.DebugFlags.sparks = rtsTrue;
1654 break;
1655 default:
1656 bad_option( arg );
1657 }
1658 }
1659 // -Dx also turns on -v. Use -l to direct trace
1660 // events to the .eventlog file instead.
1661 RtsFlags.TraceFlags.tracing = TRACE_STDERR;
1662 }
1663 #endif
1664
1665 #ifdef PROFILING
1666 // Parse a "-h" flag, returning whether the parse resulted in an error.
1667 static rtsBool read_heap_profiling_flag(const char *arg)
1668 {
1669 // Already parsed "-h"
1670
1671 rtsBool error = rtsFalse;
1672 switch (arg[2]) {
1673 case '\0':
1674 case 'C':
1675 case 'c':
1676 case 'M':
1677 case 'm':
1678 case 'D':
1679 case 'd':
1680 case 'Y':
1681 case 'y':
1682 case 'R':
1683 case 'r':
1684 case 'B':
1685 case 'b':
1686 if (arg[2] != '\0' && arg[3] != '\0') {
1687 {
1688 const char *left = strchr(arg, '{');
1689 const char *right = strrchr(arg, '}');
1690
1691 // curly braces are optional, for
1692 // backwards compat.
1693 if (left)
1694 left = left+1;
1695 else
1696 left = arg + 3;
1697
1698 if (!right)
1699 right = arg + strlen(arg);
1700
1701 char *selector = stgStrndup(left, right - left + 1);
1702
1703 switch (arg[2]) {
1704 case 'c': // cost centre label select
1705 RtsFlags.ProfFlags.ccSelector = selector;
1706 break;
1707 case 'C':
1708 RtsFlags.ProfFlags.ccsSelector = selector;
1709 break;
1710 case 'M':
1711 case 'm': // cost centre module select
1712 RtsFlags.ProfFlags.modSelector = selector;
1713 break;
1714 case 'D':
1715 case 'd': // closure descr select
1716 RtsFlags.ProfFlags.descrSelector = selector;
1717 break;
1718 case 'Y':
1719 case 'y': // closure type select
1720 RtsFlags.ProfFlags.typeSelector = selector;
1721 break;
1722 case 'R':
1723 case 'r': // retainer select
1724 RtsFlags.ProfFlags.retainerSelector = selector;
1725 break;
1726 case 'B':
1727 case 'b': // biography select
1728 RtsFlags.ProfFlags.bioSelector = selector;
1729 break;
1730 default:
1731 free(selector);
1732 }
1733 }
1734 break;
1735 }
1736
1737 if (RtsFlags.ProfFlags.doHeapProfile != 0) {
1738 errorBelch("multiple heap profile options");
1739 error = rtsTrue;
1740 break;
1741 }
1742
1743 switch (arg[2]) {
1744 case '\0':
1745 case 'C':
1746 case 'c':
1747 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
1748 break;
1749 case 'M':
1750 case 'm':
1751 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
1752 break;
1753 case 'D':
1754 case 'd':
1755 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
1756 break;
1757 case 'Y':
1758 case 'y':
1759 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
1760 break;
1761 case 'R':
1762 case 'r':
1763 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
1764 break;
1765 case 'B':
1766 case 'b':
1767 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
1768 break;
1769 }
1770 break;
1771
1772 default:
1773 errorBelch("invalid heap profile option: %s", arg);
1774 error = rtsTrue;
1775 }
1776
1777 return error;
1778 }
1779 #endif
1780
1781 #if defined(TRACING)
1782 static void read_trace_flags(const char *arg)
1783 {
1784 const char *c;
1785 rtsBool enabled = rtsTrue;
1786 /* Syntax for tracing flags currently looks like:
1787 *
1788 * -l To turn on eventlog tracing with default trace classes
1789 * -lx Turn on class 'x' (for some class listed below)
1790 * -l-x Turn off class 'x'
1791 * -la Turn on all classes
1792 * -l-a Turn off all classes
1793 *
1794 * This lets users say things like:
1795 * -la-p "all but sparks"
1796 * -l-ap "only sparks"
1797 */
1798
1799 /* Start by turning on the default tracing flags.
1800 *
1801 * Currently this is all the trace classes, except full-detail sparks.
1802 * Similarly, in future we might default to slightly less verbose
1803 * scheduler or GC tracing.
1804 */
1805 RtsFlags.TraceFlags.scheduler = rtsTrue;
1806 RtsFlags.TraceFlags.gc = rtsTrue;
1807 RtsFlags.TraceFlags.sparks_sampled = rtsTrue;
1808 RtsFlags.TraceFlags.user = rtsTrue;
1809
1810 for (c = arg; *c != '\0'; c++) {
1811 switch(*c) {
1812 case '\0':
1813 break;
1814 case '-':
1815 enabled = rtsFalse;
1816 break;
1817 case 'a':
1818 RtsFlags.TraceFlags.scheduler = enabled;
1819 RtsFlags.TraceFlags.gc = enabled;
1820 RtsFlags.TraceFlags.sparks_sampled = enabled;
1821 RtsFlags.TraceFlags.sparks_full = enabled;
1822 RtsFlags.TraceFlags.user = enabled;
1823 enabled = rtsTrue;
1824 break;
1825
1826 case 's':
1827 RtsFlags.TraceFlags.scheduler = enabled;
1828 enabled = rtsTrue;
1829 break;
1830 case 'p':
1831 RtsFlags.TraceFlags.sparks_sampled = enabled;
1832 enabled = rtsTrue;
1833 break;
1834 case 'f':
1835 RtsFlags.TraceFlags.sparks_full = enabled;
1836 enabled = rtsTrue;
1837 break;
1838 case 't':
1839 RtsFlags.TraceFlags.timestamp = enabled;
1840 enabled = rtsTrue;
1841 break;
1842 case 'g':
1843 RtsFlags.TraceFlags.gc = enabled;
1844 enabled = rtsTrue;
1845 break;
1846 case 'u':
1847 RtsFlags.TraceFlags.user = enabled;
1848 enabled = rtsTrue;
1849 break;
1850 default:
1851 errorBelch("unknown trace option: %c",*c);
1852 break;
1853 }
1854 }
1855 }
1856 #endif
1857
1858 static void GNU_ATTRIBUTE(__noreturn__)
1859 bad_option(const char *s)
1860 {
1861 errorBelch("bad RTS option: %s", s);
1862 stg_exit(EXIT_FAILURE);
1863 }
1864
1865 /* ----------------------------------------------------------------------------
1866 Copying and freeing argc/argv
1867 ------------------------------------------------------------------------- */
1868
1869 static char * copyArg(char *arg)
1870 {
1871 char *new_arg = stgMallocBytes(strlen(arg) + 1, "copyArg");
1872 strcpy(new_arg, arg);
1873 return new_arg;
1874 }
1875
1876 static char ** copyArgv(int argc, char *argv[])
1877 {
1878 int i;
1879 char **new_argv;
1880
1881 new_argv = stgCallocBytes(argc + 1, sizeof (char *), "copyArgv 1");
1882 for (i = 0; i < argc; i++) {
1883 new_argv[i] = copyArg(argv[i]);
1884 }
1885 new_argv[argc] = NULL;
1886 return new_argv;
1887 }
1888
1889 static void freeArgv(int argc, char *argv[])
1890 {
1891 int i;
1892 if (argv != NULL) {
1893 for (i = 0; i < argc; i++) {
1894 stgFree(argv[i]);
1895 }
1896 stgFree(argv);
1897 }
1898 }
1899
1900 /* -----------------------------------------------------------------------------
1901 Getting/Setting the program's arguments.
1902
1903 These are used by System.Environment, and parts of the RTS.
1904 -------------------------------------------------------------------------- */
1905
1906 void
1907 setProgName(char *argv[])
1908 {
1909 char *last_slash;
1910
1911 if (argv[0] == NULL) { // #7037
1912 prog_name = "";
1913 return;
1914 }
1915
1916 /* Remove directory from argv[0] -- default files in current directory */
1917 #if !defined(mingw32_HOST_OS)
1918 if ( (last_slash = (char *) strrchr(argv[0], '/')) != NULL ) {
1919 prog_name = last_slash+1;
1920 } else {
1921 prog_name = argv[0];
1922 }
1923 #else
1924 last_slash = argv[0] + (strlen(argv[0]) - 1);
1925 while ( last_slash > argv[0] ) {
1926 if ( *last_slash == '/' || *last_slash == '\\' ) {
1927 prog_name = last_slash+1;
1928 return;
1929 }
1930 last_slash--;
1931 }
1932 prog_name = argv[0];
1933 #endif
1934 }
1935
1936 void
1937 getProgArgv(int *argc, char **argv[])
1938 {
1939 if (argc) { *argc = prog_argc; }
1940 if (argv) { *argv = prog_argv; }
1941 }
1942
1943 void
1944 setProgArgv(int argc, char *argv[])
1945 {
1946 prog_argc = argc;
1947 prog_argv = copyArgv(argc,argv);
1948 setProgName(prog_argv);
1949 }
1950
1951 static void
1952 freeProgArgv(void)
1953 {
1954 freeArgv(prog_argc,prog_argv);
1955 prog_argc = 0;
1956 prog_argv = NULL;
1957 }
1958
1959 /* ----------------------------------------------------------------------------
1960 The full argv - a copy of the original program's argc/argv
1961 ------------------------------------------------------------------------- */
1962
1963 void
1964 setFullProgArgv(int argc, char *argv[])
1965 {
1966 full_prog_argc = argc;
1967 full_prog_argv = copyArgv(argc,argv);
1968 }
1969
1970 /* These functions record and recall the full arguments, including the
1971 +RTS ... -RTS options. The reason for adding them was so that the
1972 ghc-inplace program can pass /all/ the arguments on to the real ghc. */
1973 void
1974 getFullProgArgv(int *argc, char **argv[])
1975 {
1976 if (argc) { *argc = full_prog_argc; }
1977 if (argv) { *argv = full_prog_argv; }
1978 }
1979
1980 void
1981 freeFullProgArgv (void)
1982 {
1983 freeArgv(full_prog_argc, full_prog_argv);
1984 full_prog_argc = 0;
1985 full_prog_argv = NULL;
1986 }
1987
1988 /* ----------------------------------------------------------------------------
1989 The Win32 argv
1990 ------------------------------------------------------------------------- */
1991
1992 #if defined(mingw32_HOST_OS)
1993 void freeWin32ProgArgv (void);
1994
1995 void
1996 freeWin32ProgArgv (void)
1997 {
1998 int i;
1999
2000 if (win32_prog_argv != NULL) {
2001 for (i = 0; i < win32_prog_argc; i++) {
2002 stgFree(win32_prog_argv[i]);
2003 }
2004 stgFree(win32_prog_argv);
2005 }
2006
2007 win32_prog_argc = 0;
2008 win32_prog_argv = NULL;
2009 }
2010
2011 void
2012 getWin32ProgArgv(int *argc, wchar_t **argv[])
2013 {
2014 *argc = win32_prog_argc;
2015 *argv = win32_prog_argv;
2016 }
2017
2018 void
2019 setWin32ProgArgv(int argc, wchar_t *argv[])
2020 {
2021 int i;
2022
2023 freeWin32ProgArgv();
2024
2025 win32_prog_argc = argc;
2026 if (argv == NULL) {
2027 win32_prog_argv = NULL;
2028 return;
2029 }
2030
2031 win32_prog_argv = stgCallocBytes(argc + 1, sizeof (wchar_t *),
2032 "setWin32ProgArgv 1");
2033 for (i = 0; i < argc; i++) {
2034 win32_prog_argv[i] = stgMallocBytes((wcslen(argv[i]) + 1) * sizeof(wchar_t),
2035 "setWin32ProgArgv 2");
2036 wcscpy(win32_prog_argv[i], argv[i]);
2037 }
2038 win32_prog_argv[argc] = NULL;
2039 }
2040 #endif
2041
2042 /* ----------------------------------------------------------------------------
2043 The RTS argv
2044 ------------------------------------------------------------------------- */
2045
2046 static void
2047 freeRtsArgv(void)
2048 {
2049 freeArgv(rts_argc,rts_argv);
2050 rts_argc = 0;
2051 rts_argv = NULL;
2052 rts_argv_size = 0;
2053 }
2054
2055 /* ----------------------------------------------------------------------------
2056 All argvs
2057 ------------------------------------------------------------------------- */
2058
2059 void freeRtsArgs(void)
2060 {
2061 #if defined(mingw32_HOST_OS)
2062 freeWin32ProgArgv();
2063 #endif
2064 freeFullProgArgv();
2065 freeProgArgv();
2066 freeRtsArgv();
2067 }
2068
2069
2070 /*
2071 Note [OPTION_SAFE vs OPTION_UNSAFE]
2072
2073 Ticket #3910 originally pointed out that the RTS options are a potential
2074 security problem. For example the -t -s or -S flags can be used to
2075 overwrite files. This would be bad in the context of CGI scripts or
2076 setuid binaries. So we introduced a system where +RTS processing is more
2077 or less disabled unless you pass the -rtsopts flag at link time.
2078
2079 This scheme is safe enough but it also really annoyes users. They have
2080 to use -rtsopts in many circumstances: with -threaded to use -N, with
2081 -eventlog to use -l, with -prof to use any of the profiling flags. Many
2082 users just set -rtsopts globally or in project .cabal files. Apart from
2083 annoying users it reduces security because it means that deployed
2084 binaries will have all RTS options enabled rather than just profiling
2085 ones.
2086
2087 So now, we relax the set of RTS options that are available in the
2088 default -rtsopts=some case. For "deployment" ways like vanilla and
2089 -threaded we remain quite conservative. Only --info -? --help are
2090 allowed for vanilla. For -threaded, -N and -N<x> are allowed with a
2091 check that x <= num cpus.
2092
2093 For "developer" ways like -debug, -eventlog, -prof, we allow all the
2094 options that are special to that way. Some of these allow writing files,
2095 but the file written is not directly under the control of the attacker.
2096 For the setuid case (where the attacker would have control over binary
2097 name, current dir, local symlinks etc) we check if the process is
2098 running setuid/setgid and refuse all RTS option processing. Users would
2099 need to use -rtsopts=all in this case.
2100
2101 We are making the assumption that developers will not deploy binaries
2102 built in the -debug, -eventlog, -prof ways. And even if they do, the
2103 damage should be limited to DOS, information disclosure and writing
2104 files like <progname>.eventlog, not arbitrary files.
2105 */