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