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