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