1 /* -----------------------------------------------------------------------------
3 * (c) The AQUA Project, Glasgow University, 1994-1997
4 * (c) The GHC Team, 1998-2006
6 * Functions for parsing the argument list.
8 * ---------------------------------------------------------------------------*/
10 #include "PosixSource.h"
14 #include "Profiling.h"
17 #include "hooks/Hooks.h"
18 #include "Capability.h"
20 #if defined(HAVE_CTYPE_H)
26 #if defined(HAVE_UNISTD_H)
30 #if defined(HAVE_SYS_TYPES_H)
31 #include <sys/types.h>
40 * Split argument lists
42 int prog_argc
= 0; /* an "int" so as to match normal "argc" */
43 char **prog_argv
= NULL
;
44 int full_prog_argc
= 0; /* an "int" so as to match normal "argc" */
45 char **full_prog_argv
= NULL
;
46 char *prog_name
= NULL
; /* 'basename' of prog_argv[0] */
47 int rts_argc
= 0; /* ditto */
48 char **rts_argv
= NULL
;
49 int rts_argv_size
= 0;
50 #if defined(mingw32_HOST_OS)
51 // On Windows hs_main uses GetCommandLineW to get Unicode arguments and
52 // passes them along UTF8 encoded as argv. We store them here in order to
54 int win32_full_utf8_argc
= 0;
55 char** win32_utf8_argv
= NULL
;
58 // The global rtsConfig, set from the RtsConfig supplied by the call
62 const RtsConfig defaultRtsConfig
= {
63 .rts_opts_enabled
= RtsOptsSafeOnly
,
64 .rts_opts_suggestions
= true,
68 .eventlog_writer
= &FileEventLogWriter
,
69 .defaultsHook
= FlagDefaultsHook
,
70 .onExitHook
= OnExitHook
,
71 .stackOverflowHook
= StackOverflowHook
,
72 .outOfHeapHook
= OutOfHeapHook
,
73 .mallocFailHook
= MallocFailHook
,
75 .longGCSync
= LongGCSync
,
76 .longGCSyncEnd
= LongGCSyncEnd
80 * constants, used later
85 /* -----------------------------------------------------------------------------
87 -------------------------------------------------------------------------- */
89 static void procRtsOpts (int rts_argc0
, RtsOptsEnabledEnum enabled
);
91 static void normaliseRtsOpts (void);
93 static void initStatsFile (FILE *f
);
95 static int openStatsFile (
96 char *filename
, const char *FILENAME_FMT
, FILE **file_ret
);
98 static StgWord64
decodeSize (
99 const char *flag
, uint32_t offset
, StgWord64 min
, StgWord64 max
);
101 static void bad_option (const char *s
);
104 static void read_debug_flags(const char *arg
);
107 #if defined(PROFILING)
108 static bool read_heap_profiling_flag(const char *arg
);
112 static void read_trace_flags(const char *arg
);
115 static void errorUsage (void) GNU_ATTRIBUTE(__noreturn__
);
117 #if defined(mingw32_HOST_OS)
118 static char** win32_full_utf8_argv
;
120 static char * copyArg (char *arg
);
121 static char ** copyArgv (int argc
, char *argv
[]);
122 static void freeArgv (int argc
, char *argv
[]);
123 static void setProgName (char *argv
[]);
125 static void errorRtsOptsDisabled (const char *s
);
127 /* -----------------------------------------------------------------------------
128 * Command-line option parsing routines.
129 * ---------------------------------------------------------------------------*/
131 void initRtsFlagsDefaults(void)
133 StgWord64 maxStkSize
= 8 * getPhysicalMemorySize() / 10;
134 // if getPhysicalMemorySize fails just move along with an 8MB limit
136 maxStkSize
= 8 * 1024 * 1024;
138 RtsFlags
.GcFlags
.statsFile
= NULL
;
139 RtsFlags
.GcFlags
.giveStats
= NO_GC_STATS
;
141 RtsFlags
.GcFlags
.maxStkSize
= maxStkSize
/ sizeof(W_
);
142 RtsFlags
.GcFlags
.initialStkSize
= 1024 / sizeof(W_
);
143 RtsFlags
.GcFlags
.stkChunkSize
= (32 * 1024) / sizeof(W_
);
144 RtsFlags
.GcFlags
.stkChunkBufferSize
= (1 * 1024) / sizeof(W_
);
146 RtsFlags
.GcFlags
.minAllocAreaSize
= (1024 * 1024) / BLOCK_SIZE
;
147 RtsFlags
.GcFlags
.largeAllocLim
= 0; /* defaults to minAllocAreasize */
148 RtsFlags
.GcFlags
.nurseryChunkSize
= 0;
149 RtsFlags
.GcFlags
.minOldGenSize
= (1024 * 1024) / BLOCK_SIZE
;
150 RtsFlags
.GcFlags
.maxHeapSize
= 0; /* off by default */
151 RtsFlags
.GcFlags
.heapLimitGrace
= (1024 * 1024);
152 RtsFlags
.GcFlags
.heapSizeSuggestion
= 0; /* none */
153 RtsFlags
.GcFlags
.heapSizeSuggestionAuto
= false;
154 RtsFlags
.GcFlags
.pcFreeHeap
= 3; /* 3% */
155 RtsFlags
.GcFlags
.oldGenFactor
= 2;
156 RtsFlags
.GcFlags
.generations
= 2;
157 RtsFlags
.GcFlags
.squeezeUpdFrames
= true;
158 RtsFlags
.GcFlags
.compact
= false;
159 RtsFlags
.GcFlags
.compactThreshold
= 30.0;
160 RtsFlags
.GcFlags
.sweep
= false;
161 RtsFlags
.GcFlags
.idleGCDelayTime
= USToTime(300000); // 300ms
162 #if defined(THREADED_RTS)
163 RtsFlags
.GcFlags
.doIdleGC
= true;
165 RtsFlags
.GcFlags
.doIdleGC
= false;
167 RtsFlags
.GcFlags
.heapBase
= 0; /* means don't care */
168 RtsFlags
.GcFlags
.allocLimitGrace
= (100*1024) / BLOCK_SIZE
;
169 RtsFlags
.GcFlags
.numa
= false;
170 RtsFlags
.GcFlags
.numaMask
= 1;
171 RtsFlags
.GcFlags
.ringBell
= false;
172 RtsFlags
.GcFlags
.longGCSync
= 0; /* detection turned off */
174 RtsFlags
.DebugFlags
.scheduler
= false;
175 RtsFlags
.DebugFlags
.interpreter
= false;
176 RtsFlags
.DebugFlags
.weak
= false;
177 RtsFlags
.DebugFlags
.gccafs
= false;
178 RtsFlags
.DebugFlags
.gc
= false;
179 RtsFlags
.DebugFlags
.block_alloc
= false;
180 RtsFlags
.DebugFlags
.sanity
= false;
181 RtsFlags
.DebugFlags
.stable
= false;
182 RtsFlags
.DebugFlags
.stm
= false;
183 RtsFlags
.DebugFlags
.prof
= false;
184 RtsFlags
.DebugFlags
.apply
= false;
185 RtsFlags
.DebugFlags
.linker
= false;
186 RtsFlags
.DebugFlags
.squeeze
= false;
187 RtsFlags
.DebugFlags
.hpc
= false;
188 RtsFlags
.DebugFlags
.sparks
= false;
189 RtsFlags
.DebugFlags
.numa
= false;
190 RtsFlags
.DebugFlags
.compact
= false;
192 #if defined(PROFILING)
193 RtsFlags
.CcFlags
.doCostCentres
= COST_CENTRES_NONE
;
194 RtsFlags
.CcFlags
.outputFileNameStem
= NULL
;
195 #endif /* PROFILING */
197 RtsFlags
.ProfFlags
.doHeapProfile
= false;
198 RtsFlags
.ProfFlags
.heapProfileInterval
= USToTime(100000); // 100ms
200 #if defined(PROFILING)
201 RtsFlags
.ProfFlags
.includeTSOs
= false;
202 RtsFlags
.ProfFlags
.showCCSOnException
= false;
203 RtsFlags
.ProfFlags
.maxRetainerSetSize
= 8;
204 RtsFlags
.ProfFlags
.ccsLength
= 25;
205 RtsFlags
.ProfFlags
.modSelector
= NULL
;
206 RtsFlags
.ProfFlags
.descrSelector
= NULL
;
207 RtsFlags
.ProfFlags
.typeSelector
= NULL
;
208 RtsFlags
.ProfFlags
.ccSelector
= NULL
;
209 RtsFlags
.ProfFlags
.ccsSelector
= NULL
;
210 RtsFlags
.ProfFlags
.retainerSelector
= NULL
;
211 RtsFlags
.ProfFlags
.bioSelector
= NULL
;
215 RtsFlags
.TraceFlags
.tracing
= TRACE_NONE
;
216 RtsFlags
.TraceFlags
.timestamp
= false;
217 RtsFlags
.TraceFlags
.scheduler
= false;
218 RtsFlags
.TraceFlags
.gc
= false;
219 RtsFlags
.TraceFlags
.sparks_sampled
= false;
220 RtsFlags
.TraceFlags
.sparks_full
= false;
221 RtsFlags
.TraceFlags
.user
= false;
224 #if defined(PROFILING)
225 // When profiling we want a lot more ticks
226 RtsFlags
.MiscFlags
.tickInterval
= USToTime(1000); // 1ms
228 RtsFlags
.MiscFlags
.tickInterval
= DEFAULT_TICK_INTERVAL
;
230 RtsFlags
.ConcFlags
.ctxtSwitchTime
= USToTime(20000); // 20ms
232 RtsFlags
.MiscFlags
.install_signal_handlers
= true;
233 RtsFlags
.MiscFlags
.install_seh_handlers
= true;
234 RtsFlags
.MiscFlags
.generate_stack_trace
= true;
235 RtsFlags
.MiscFlags
.generate_dump_file
= false;
236 RtsFlags
.MiscFlags
.machineReadable
= false;
237 RtsFlags
.MiscFlags
.internalCounters
= false;
238 RtsFlags
.MiscFlags
.linkerMemBase
= 0;
240 #if defined(THREADED_RTS)
241 RtsFlags
.ParFlags
.nCapabilities
= 1;
242 RtsFlags
.ParFlags
.migrate
= true;
243 RtsFlags
.ParFlags
.parGcEnabled
= 1;
244 RtsFlags
.ParFlags
.parGcGen
= 0;
245 RtsFlags
.ParFlags
.parGcLoadBalancingEnabled
= true;
246 RtsFlags
.ParFlags
.parGcLoadBalancingGen
= ~0u; /* auto, based on -A */
247 RtsFlags
.ParFlags
.parGcNoSyncWithIdle
= 0;
248 RtsFlags
.ParFlags
.parGcThreads
= 0; /* defaults to -N */
249 RtsFlags
.ParFlags
.setAffinity
= 0;
252 #if defined(THREADED_RTS)
253 RtsFlags
.ParFlags
.maxLocalSparks
= 4096;
254 #endif /* THREADED_RTS */
256 #if defined(TICKY_TICKY)
257 RtsFlags
.TickyFlags
.showTickyStats
= false;
258 RtsFlags
.TickyFlags
.tickyFile
= NULL
;
265 "Usage: <prog> <args> [+RTS <rtsopts> | -RTS <args>] ... --RTS <args>",
267 " +RTS Indicates run time system options follow",
268 " -RTS Indicates program arguments follow",
269 " --RTS Indicates that ALL subsequent arguments will be given to the",
270 " program (including any of these RTS flags)",
272 "The following run time system options are available:",
274 " -? Prints this message and exits; the program is not executed",
275 " --info Print information about the RTS used by this program",
277 " -K<size> Sets the maximum stack size (default: 80% of the heap)",
278 " Egs: -K32k -K512k -K8M",
279 " -ki<size> Sets the initial thread stack size (default 1k) Egs: -ki4k -ki2m",
280 " -kc<size> Sets the stack chunk size (default 32k)",
281 " -kb<size> Sets the stack chunk buffer size (default 1k)",
283 " -A<size> Sets the minimum allocation area size (default 1m) Egs: -A20m -A10k",
284 " -AL<size> Sets the amount of large-object memory that can be allocated",
285 " before a GC is triggered (default: the value of -A)",
286 " -n<size> Allocation area chunk size (0 = disabled, default: 0)",
287 " -O<size> Sets the minimum size of the old generation (default 1M)",
288 " -M<size> Sets the maximum heap size (default unlimited) Egs: -M256k -M1G",
289 " -H<size> Sets the minimum heap size (default 0M) Egs: -H24m -H1G",
290 " -xb<addr> Sets the address from which a suitable start for the heap memory",
291 " will be searched from. This is useful if the default address",
292 " clashes with some third-party library.",
293 " -m<n> Minimum % of heap which must be available (default 3%)",
294 " -G<n> Number of generations (default: 2)",
295 " -c<n> Use in-place compaction instead of copying in the oldest generation",
296 " when live data is at least <n>% of the maximum heap size set with",
297 " -M (default: 30%)",
298 " -c Use in-place compaction for all oldest generation collections",
299 " (the default is to use copying)",
300 " -w Use mark-region for the oldest generation (experimental)",
301 #if defined(THREADED_RTS)
302 " -I<sec> Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
305 " -T Collect GC statistics (useful for in-program statistics access)",
306 " -t[<file>] One-line GC statistics (if <file> omitted, uses stderr)",
307 " -s[<file>] Summary GC statistics (if <file> omitted, uses stderr)",
308 " -S[<file>] Detailed GC statistics (if <file> omitted, uses stderr)",
311 " -Z Don't squeeze out update frames on stack overflow",
312 " -B Sound the bell at the start of each garbage collection",
313 #if defined(PROFILING)
315 " -p Time/allocation profile in tree format ",
316 " (output file <output prefix>.prof)",
317 " -po<file> Override profiling output file name prefix (program name by default)",
318 " -P More detailed Time/Allocation profile in tree format",
319 " -Pa Give information about *all* cost centres in tree format",
320 " -pj Output cost-center profile in JSON format",
322 " -h<break-down> Heap residency profile (hp2ps) (output file <program>.hp)",
323 " break-down: c = cost centre stack (default)",
325 " d = closure description",
326 " y = type description",
328 " b = biography (LAG,DRAG,VOID,USE)",
329 " A subset of closures may be selected thusly:",
330 " -hc<cc>,... specific cost centre(s) (top of stack only)",
331 " -hC<cc>,... specific cost centre(s) (anywhere in stack)",
332 " -hm<mod>... all cost centres from the specified modules(s)",
333 " -hd<des>,... closures with specified closure descriptions",
334 " -hy<typ>... closures with specified type descriptions",
335 " -hr<cc>... closures with specified retainers",
336 " -hb<bio>... closures with specified biographies (lag,drag,void,use)",
338 " -R<size> Set the maximum retainer set size (default: 8)",
340 " -L<chars> Maximum length of a cost-centre stack in a heap profile",
343 " -xt Include threads (TSOs) in a heap profile",
345 " -xc Show current cost centre stack on raising an exception",
346 #endif /* PROFILING */
350 " -l[flags] Log events in binary format to the file <program>.eventlog",
352 " -v[flags] Log events to stderr",
354 " where [flags] can contain:",
355 " s scheduler events",
356 " g GC and heap events",
357 " p par spark events (sampled)",
358 " f par spark events (full detail)",
359 " u user events (emitted from Haskell code)",
360 " a all event classes above",
362 " t add time stamps (only useful with -v)",
364 " -x disable an event class, for any flag above",
365 " the initial enabled event classes are 'sgpu'",
368 #if !defined(PROFILING)
370 " -h Heap residency profile (output file <program>.hp)",
372 " -i<sec> Time between heap profile samples (seconds, default: 0.1)",
374 #if defined(TICKY_TICKY)
375 " -r<file> Produce ticky-ticky statistics (with -rstderr for stderr)",
378 " -C<secs> Context-switch interval in seconds.",
379 " 0 or no argument means switch as often as possible.",
380 " Default: 0.02 sec.",
381 " -V<secs> Master tick interval in seconds (0 == disable timer).",
382 " This sets the resolution for -C and the heap profile timer -i,",
383 " and is the frequency of time profile samples.",
384 #if defined(PROFILING)
385 " Default: 0.001 sec.",
387 " Default: 0.01 sec.",
391 " -Ds DEBUG: scheduler",
392 " -Di DEBUG: interpreter",
394 " -DG DEBUG: gccafs",
397 " -DS DEBUG: sanity",
398 " -Dt DEBUG: stable",
401 " -Dl DEBUG: linker",
403 " -Dz DEBUG: stack squeezing",
404 " -Dc DEBUG: program coverage",
405 " -Dr DEBUG: sparks",
406 " -DC DEBUG: compact",
408 " NOTE: DEBUG events are sent to stderr by default; add -l to create a",
409 " binary event log file instead.",
412 #if defined(THREADED_RTS) && !defined(NOSMP)
413 " -N[<n>] Use <n> processors (default: 1, -N alone determines",
414 " the number of processors to use automatically)",
415 " -maxN[<n>] Use up to <n> processors automatically",
416 " -qg[<n>] Use parallel GC only for generations >= <n>",
417 " (default: 0, -qg alone turns off parallel GC)",
418 " -qb[<n>] Use load-balancing in the parallel GC only for generations >= <n>",
419 " (default: 1 for -A < 32M, 0 otherwise;"
420 " -qb alone turns off load-balancing)",
421 " -qn<n> Use <n> threads for parallel GC (defaults to value of -N)",
422 " -qa Use the OS to set thread affinity (experimental)",
423 " -qm Don't automatically migrate threads between CPUs",
424 " -qi<n> If a processor has been idle for the last <n> GCs, do not",
425 " wake it up for a non-load-balancing parallel GC.",
426 " (0 disables, default: 0)",
427 " --numa[=<node_mask>]",
428 " Use NUMA, nodes given by <node_mask> (default: off)",
430 " --debug-numa[=<num_nodes>]",
431 " Pretend NUMA: like --numa, but without the system calls.",
432 " Can be used on non-NUMA systems for debugging.",
436 " --install-signal-handlers=<yes|no>",
437 " Install signal handlers (default: yes)",
438 #if defined(mingw32_HOST_OS)
439 " --install-seh-handlers=<yes|no>",
440 " Install exception handlers (default: yes)",
441 " --generate-crash-dumps",
442 " Generate Windows crash dumps, requires exception handlers",
443 " to be installed. Implies --install-signal-handlers=yes.",
445 " --generate-stack-traces=<yes|no>",
446 " Generate a stack trace when your application encounters a",
447 " fatal error. When symbols are available an attempt will be",
448 " made to resolve addresses to names. (default: yes)",
450 #if defined(THREADED_RTS)
451 " -e<n> Maximum number of outstanding local sparks (default: 4096)",
453 #if defined(x86_64_HOST_ARCH)
454 " -xm Base address to mmap memory in the GHCi linker",
455 " (hex; must be <80000000)",
457 " -xq The allocation limit given to a thread after it receives",
458 " an AllocationLimitExceeded exception. (default: 100k)",
461 " The amount of allocation after the program receives a",
462 " HeapOverflow exception before the exception is thrown again, if",
463 " the program is still exceeding the heap limit.",
465 "RTS options may also be specified using the GHCRTS environment variable.",
467 "Other RTS options may be available for programs compiled a different way.",
468 "The GHC User's Guide has full details.",
474 Note [Windows Unicode Arguments]
475 ~~~~~~~~~~~~~~~~~~~~~~~~~~
476 On Windows argv is usually encoded in the current Codepage which might not
479 Instead of ignoring the arguments to hs_init we expect them to be utf-8
480 encoded when coming from a custom main function. In the regular hs_main we
481 get the unicode arguments from the windows API and pass them along utf8
484 This reduces special casing of arguments in later parts of the RTS and base
485 libraries to dealing with slash differences and using utf8 instead of the
486 current locale on Windows when decoding arguments.
490 #if defined(mingw32_HOST_OS)
491 //Allocate a buffer and return the string utf8 encoded.
492 char* lpcwstrToUTF8(const wchar_t* utf16_str
)
494 //Check the utf8 encoded size first
495 int res
= WideCharToMultiByte(CP_UTF8
, 0, utf16_str
, -1, NULL
, 0,
500 char* buffer
= (char*) stgMallocBytes((size_t)res
, "getUTF8Args 2");
501 res
= WideCharToMultiByte(CP_UTF8
, 0, utf16_str
, -1, buffer
, res
,
506 char** getUTF8Args(int* argc
)
508 LPCWSTR cmdLine
= GetCommandLineW();
509 LPWSTR
* argvw
= CommandLineToArgvW(cmdLine
, argc
);
511 // We create two argument arrays, one which is later permutated by the RTS
512 // instead of the main argv.
513 // The other one is used to free the allocted memory later.
514 char** argv
= (char**) stgMallocBytes(sizeof(char*) * (*argc
+ 1),
516 win32_full_utf8_argv
= (char**) stgMallocBytes(sizeof(char*) * (*argc
+ 1),
519 for (int i
= 0; i
< *argc
; i
++)
521 argv
[i
] = lpcwstrToUTF8(argvw
[i
]);
524 memcpy(win32_full_utf8_argv
, argv
, sizeof(char*) * (*argc
+ 1));
527 win32_utf8_argv
= argv
;
528 win32_full_utf8_argc
= *argc
;
533 STATIC_INLINE
bool strequal(const char *a
, const char * b
)
535 return(strcmp(a
, b
) == 0);
538 // We can't predict up front how much space we'll need for rts_argv,
539 // because it involves parsing ghc_rts_opts and GHCRTS, so we
540 // expand it on demand.
541 static void appendRtsArg (char *arg
)
543 if (rts_argc
== rts_argv_size
) {
545 rts_argv
= stgReallocBytes(rts_argv
, rts_argv_size
* sizeof (char *),
546 "RtsFlags.c:appendRtsArg");
548 rts_argv
[rts_argc
++] = arg
;
551 static void splitRtsFlags(const char *s
)
558 while (isspace(*c1
)) { c1
++; };
560 while (!isspace(*c2
) && *c2
!= '\0') { c2
++; };
562 if (c1
== c2
) { break; }
564 t
= stgMallocBytes(c2
-c1
+1, "RtsFlags.c:splitRtsFlags()");
565 strncpy(t
, c1
, c2
-c1
);
570 } while (*c1
!= '\0');
573 static void errorRtsOptsDisabled(const char *s
)
576 if (rtsConfig
.rts_hs_main
) {
577 advice
= "Link with -rtsopts to enable them.";
579 advice
= "Use hs_init_with_rtsopts() to enable them.";
581 errorBelch(s
, advice
);
584 /* -----------------------------------------------------------------------------
585 Parse the command line arguments, collecting options for the RTS.
588 - argv[] is *modified*, any RTS options have been stripped out
589 - *argc contains the new count of arguments in argv[]
591 - rts_argv[] (global) contains a copy of the collected RTS args
592 - rts_argc (global) contains the count of args in rts_argv
594 - prog_argv[] (global) contains a copy of the non-RTS args (== argv)
595 - prog_argc (global) contains the count of args in prog_argv
597 - prog_name (global) contains the basename of prog_argv[0]
599 - rtsConfig (global) contains the supplied RtsConfig
601 On Windows argv is assumed to be utf8 encoded for unicode compatibility.
602 See Note [Windows Unicode Arguments]
604 -------------------------------------------------------------------------- */
606 void setupRtsFlags (int *argc
, char *argv
[], RtsConfig rts_config
)
610 uint32_t arg
, rts_argc0
;
612 rtsConfig
= rts_config
;
618 if (*argc
> 1) { *argc
= 1; };
621 rts_argv_size
= total_arg
+ 1;
622 rts_argv
= stgMallocBytes(rts_argv_size
* sizeof (char *), "setupRtsFlags");
624 rts_argc0
= rts_argc
;
626 // process arguments from the -with-rtsopts compile-time flag first
627 // (arguments from the GHCRTS environment variable and the command
628 // line override these).
630 if (rtsConfig
.rts_opts
!= NULL
) {
631 splitRtsFlags(rtsConfig
.rts_opts
);
632 // opts from rts_opts are always enabled:
633 procRtsOpts(rts_argc0
, RtsOptsAll
);
634 rts_argc0
= rts_argc
;
638 // process arguments from the GHCRTS environment variable next
639 // (arguments from the command line override these).
640 // If we ignore all non-builtin rtsOpts we skip these.
641 if(rtsConfig
.rts_opts_enabled
!= RtsOptsIgnoreAll
)
643 char *ghc_rts
= getenv("GHCRTS");
645 if (ghc_rts
!= NULL
) {
646 if (rtsConfig
.rts_opts_enabled
== RtsOptsNone
) {
647 errorRtsOptsDisabled(
648 "Warning: Ignoring GHCRTS variable as RTS options are disabled.\n %s");
649 // We don't actually exit, just warn
651 splitRtsFlags(ghc_rts
);
652 procRtsOpts(rts_argc0
, rtsConfig
.rts_opts_enabled
);
653 rts_argc0
= rts_argc
;
659 // If we ignore all commandline rtsOpts we skip processing of argv by
660 // the RTS completely
661 if(!(rtsConfig
.rts_opts_enabled
== RtsOptsIgnoreAll
||
662 rtsConfig
.rts_opts_enabled
== RtsOptsIgnore
)
665 // Split arguments (argv) into PGM (argv) and RTS (rts_argv) parts
666 // argv[0] must be PGM argument -- leave in argv
668 for (mode
= PGM
; arg
< total_arg
; arg
++) {
669 // The '--RTS' argument disables all future
670 // +RTS ... -RTS processing.
671 if (strequal("--RTS", argv
[arg
])) {
675 // The '--' argument is passed through to the program, but
676 // disables all further +RTS ... -RTS processing.
677 else if (strequal("--", argv
[arg
])) {
680 else if (strequal("+RTS", argv
[arg
])) {
683 else if (strequal("-RTS", argv
[arg
])) {
686 else if (mode
== RTS
) {
687 appendRtsArg(copyArg(argv
[arg
]));
690 argv
[(*argc
)++] = argv
[arg
];
696 // process remaining program arguments
697 for (; arg
< total_arg
; arg
++) {
698 argv
[(*argc
)++] = argv
[arg
];
700 argv
[*argc
] = (char *) 0;
702 procRtsOpts(rts_argc0
, rtsConfig
.rts_opts_enabled
);
704 appendRtsArg((char *)0);
705 rts_argc
--; // appendRtsArg will have bumped it for the NULL (#7227)
709 setProgArgv(*argc
, argv
);
711 if (RtsFlags
.GcFlags
.statsFile
!= NULL
) {
712 initStatsFile (RtsFlags
.GcFlags
.statsFile
);
714 #if defined(TICKY_TICKY)
715 if (RtsFlags
.TickyFlags
.tickyFile
!= NULL
) {
716 initStatsFile (RtsFlags
.TickyFlags
.tickyFile
);
721 /* -----------------------------------------------------------------------------
722 * procRtsOpts: Process rts_argv between rts_argc0 and rts_argc.
723 * -------------------------------------------------------------------------- */
725 #if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_TYPES_H) && !defined(mingw32_HOST_OS)
726 static void checkSuid(RtsOptsEnabledEnum enabled
)
728 if (enabled
== RtsOptsSafeOnly
) {
729 /* This doesn't cover linux/posix capabilities like CAP_DAC_OVERRIDE,
730 we'd have to link with -lcap for that. */
731 if ((getuid() != geteuid()) || (getgid() != getegid())) {
732 errorRtsOptsDisabled(
733 "RTS options are disabled for setuid binaries. %s");
734 stg_exit(EXIT_FAILURE
);
739 static void checkSuid (RtsOptsEnabledEnum enabled STG_UNUSED
)
744 static void checkUnsafe(RtsOptsEnabledEnum enabled
)
746 if (enabled
== RtsOptsSafeOnly
) {
747 errorRtsOptsDisabled("Most RTS options are disabled. %s");
748 stg_exit(EXIT_FAILURE
);
752 static void procRtsOpts (int rts_argc0
,
753 RtsOptsEnabledEnum rtsOptsEnabled
)
757 int unchecked_arg_start
;
759 if (!(rts_argc0
< rts_argc
)) return;
761 if (rtsOptsEnabled
== RtsOptsNone
) {
762 errorRtsOptsDisabled("RTS options are disabled. %s");
763 stg_exit(EXIT_FAILURE
);
766 checkSuid(rtsOptsEnabled
);
768 // Process RTS (rts_argv) part: mainly to determine statsfile
769 for (arg
= rts_argc0
; arg
< rts_argc
; arg
++) {
771 /* We handle RtsOptsSafeOnly mode by declaring each option as
772 either OPTION_SAFE or OPTION_UNSAFE. To make sure we cover
773 every branch we use an option_checked flag which is reset
774 at the start each iteration and checked at the end. */
775 bool option_checked
= false;
777 // See Note [OPTION_SAFE vs OPTION_UNSAFE].
778 #define OPTION_SAFE option_checked = true;
779 #define OPTION_UNSAFE checkUnsafe(rtsOptsEnabled); option_checked = true;
781 if (rts_argv
[arg
][0] != '-') {
783 errorBelch("unexpected RTS argument: %s", rts_argv
[arg
]);
787 /* 0 is dash, 1 is first letter */
789 unchecked_arg_start
= 1;
790 switch(rts_argv
[arg
][1]) {
792 /* process: general args, then PROFILING-only ones, then
793 CONCURRENT-only, TICKY-only (same order as defined in
794 RtsFlags.lh); within those groups, mostly in
795 case-insensitive alphabetical order. Final group is
796 x*, which allows for more options.
799 #if defined(TICKY_TICKY)
800 # define TICKY_BUILD_ONLY(x) x
802 # define TICKY_BUILD_ONLY(x) \
803 errorBelch("the flag %s requires the program to be built with -ticky", \
808 #if defined(PROFILING)
809 # define PROFILING_BUILD_ONLY(x) x
811 # define PROFILING_BUILD_ONLY(x) \
812 errorBelch("the flag %s requires the program to be built with -prof", \
818 # define TRACING_BUILD_ONLY(x) x
820 # define TRACING_BUILD_ONLY(x) \
821 errorBelch("the flag %s requires the program to be built with -eventlog or -debug", \
826 #if defined(THREADED_RTS)
827 # define THREADED_BUILD_ONLY(x) x
829 # define THREADED_BUILD_ONLY(x) \
830 errorBelch("the flag %s requires the program to be built with -threaded", \
836 # define DEBUG_BUILD_ONLY(x) x
838 # define DEBUG_BUILD_ONLY(x) \
839 errorBelch("the flag %s requires the program to be built with -debug", \
844 /* =========== GENERAL ========================== */
850 /* This isn't going to allow us to keep related options
851 together as we add more --* flags. We really need a
852 proper options parser. */
854 if (strequal("install-signal-handlers=yes",
855 &rts_argv
[arg
][2])) {
857 RtsFlags
.MiscFlags
.install_signal_handlers
= true;
859 else if (strequal("install-signal-handlers=no",
860 &rts_argv
[arg
][2])) {
862 RtsFlags
.MiscFlags
.install_signal_handlers
= false;
864 else if (strequal("install-seh-handlers=yes",
865 &rts_argv
[arg
][2])) {
867 RtsFlags
.MiscFlags
.install_seh_handlers
= true;
869 else if (strequal("install-seh-handlers=no",
870 &rts_argv
[arg
][2])) {
872 RtsFlags
.MiscFlags
.install_seh_handlers
= false;
874 else if (strequal("generate-stack-traces=yes",
875 &rts_argv
[arg
][2])) {
877 RtsFlags
.MiscFlags
.generate_stack_trace
= true;
879 else if (strequal("generate-stack-traces=no",
880 &rts_argv
[arg
][2])) {
882 RtsFlags
.MiscFlags
.generate_stack_trace
= false;
884 else if (strequal("generate-crash-dumps",
885 &rts_argv
[arg
][2])) {
887 RtsFlags
.MiscFlags
.generate_dump_file
= true;
889 else if (strequal("machine-readable",
890 &rts_argv
[arg
][2])) {
892 RtsFlags
.MiscFlags
.machineReadable
= true;
894 else if (strequal("internal-counters",
895 &rts_argv
[arg
][2])) {
897 RtsFlags
.MiscFlags
.internalCounters
= true;
899 else if (strequal("info",
900 &rts_argv
[arg
][2])) {
905 #if defined(THREADED_RTS)
906 else if (!strncmp("numa", &rts_argv
[arg
][2], 4)) {
909 if (rts_argv
[arg
][6] == '=') {
910 mask
= (StgWord
)strtol(rts_argv
[arg
]+7,
915 if (!osNumaAvailable()) {
916 errorBelch("%s: OS reports NUMA is not available",
922 RtsFlags
.GcFlags
.numa
= true;
923 RtsFlags
.GcFlags
.numaMask
= mask
;
926 #if defined(DEBUG) && defined(THREADED_RTS)
927 else if (!strncmp("debug-numa", &rts_argv
[arg
][2], 10)) {
930 if (rts_argv
[arg
][12] == '=' &&
931 isdigit(rts_argv
[arg
][13])) {
932 nNodes
= (StgWord
)strtol(rts_argv
[arg
]+13,
935 errorBelch("%s: missing number of nodes",
940 if (nNodes
> MAX_NUMA_NODES
) {
941 errorBelch("%s: Too many NUMA nodes (max %d)",
942 rts_argv
[arg
], MAX_NUMA_NODES
);
945 RtsFlags
.GcFlags
.numa
= true;
946 RtsFlags
.DebugFlags
.numa
= true;
947 RtsFlags
.GcFlags
.numaMask
= (1<<nNodes
) - 1;
951 else if (!strncmp("long-gc-sync=", &rts_argv
[arg
][2], 13)) {
953 if (rts_argv
[arg
][2] == '\0') {
956 RtsFlags
.GcFlags
.longGCSync
=
957 fsecondsToTime(atof(rts_argv
[arg
]+16));
963 errorBelch("unknown RTS option: %s",rts_argv
[arg
]);
969 if (rts_argv
[arg
][2] == 'L') {
970 RtsFlags
.GcFlags
.largeAllocLim
971 = decodeSize(rts_argv
[arg
], 3, 2*BLOCK_SIZE
,
972 HS_INT_MAX
) / BLOCK_SIZE
;
974 // minimum two blocks in the nursery, so that we have one
975 // to grab for allocate().
976 RtsFlags
.GcFlags
.minAllocAreaSize
977 = decodeSize(rts_argv
[arg
], 2, 2*BLOCK_SIZE
,
978 HS_INT_MAX
) / BLOCK_SIZE
;
983 RtsFlags
.GcFlags
.nurseryChunkSize
984 = decodeSize(rts_argv
[arg
], 2, 2*BLOCK_SIZE
, HS_INT_MAX
)
990 RtsFlags
.GcFlags
.ringBell
= true;
991 unchecked_arg_start
++;
996 if (rts_argv
[arg
][2] != '\0') {
997 RtsFlags
.GcFlags
.compactThreshold
=
998 atof(rts_argv
[arg
]+2);
1000 RtsFlags
.GcFlags
.compact
= true;
1006 RtsFlags
.GcFlags
.sweep
= true;
1007 unchecked_arg_start
++;
1012 RtsFlags
.GcFlags
.oldGenFactor
= atof(rts_argv
[arg
]+2);
1014 if (RtsFlags
.GcFlags
.oldGenFactor
< 0)
1015 bad_option( rts_argv
[arg
] );
1020 DEBUG_BUILD_ONLY(read_debug_flags(rts_argv
[arg
]);)
1025 RtsFlags
.GcFlags
.maxStkSize
=
1026 decodeSize(rts_argv
[arg
], 2, 0, HS_WORD_MAX
)
1032 switch(rts_argv
[arg
][2]) {
1034 RtsFlags
.GcFlags
.stkChunkSize
=
1035 decodeSize(rts_argv
[arg
], 3, sizeof(W_
), HS_WORD_MAX
)
1039 RtsFlags
.GcFlags
.stkChunkBufferSize
=
1040 decodeSize(rts_argv
[arg
], 3, sizeof(W_
), HS_WORD_MAX
)
1044 RtsFlags
.GcFlags
.initialStkSize
=
1045 decodeSize(rts_argv
[arg
], 3, sizeof(W_
), HS_WORD_MAX
)
1049 RtsFlags
.GcFlags
.initialStkSize
=
1050 decodeSize(rts_argv
[arg
], 2, sizeof(W_
), HS_WORD_MAX
)
1058 if (0 == strncmp("grace=", rts_argv
[arg
] + 2, 6)) {
1059 RtsFlags
.GcFlags
.heapLimitGrace
=
1060 decodeSize(rts_argv
[arg
], 8, BLOCK_SIZE
, HS_WORD_MAX
);
1062 RtsFlags
.GcFlags
.maxHeapSize
=
1063 decodeSize(rts_argv
[arg
], 2, BLOCK_SIZE
, HS_WORD_MAX
)
1065 // user give size in *bytes* but "maxHeapSize" is in
1071 /* Case for maxN feature request ticket #10728, it's a little
1072 odd being so far from the N case. */
1074 if (strncmp("maxN", &rts_argv
[arg
][1], 4) == 0) {
1076 THREADED_BUILD_ONLY(
1078 int proc
= (int)getNumberOfProcessors();
1080 nCapabilities
= strtol(rts_argv
[arg
]+5, (char **) NULL
, 10);
1081 if (nCapabilities
> proc
) { nCapabilities
= proc
; }
1083 if (nCapabilities
<= 0) {
1084 errorBelch("bad value for -maxN");
1087 #if defined(PROFILING)
1088 RtsFlags
.ParFlags
.nCapabilities
= 1;
1090 RtsFlags
.ParFlags
.nCapabilities
= (uint32_t)nCapabilities
;
1096 RtsFlags
.GcFlags
.pcFreeHeap
= atof(rts_argv
[arg
]+2);
1098 /* -m was allowing bad flags to go unreported */
1099 if (RtsFlags
.GcFlags
.pcFreeHeap
== 0.0 &&
1100 rts_argv
[arg
][2] != '0')
1101 bad_option( rts_argv
[arg
] );
1103 if (RtsFlags
.GcFlags
.pcFreeHeap
< 0 ||
1104 RtsFlags
.GcFlags
.pcFreeHeap
> 100)
1105 bad_option( rts_argv
[arg
] );
1112 RtsFlags
.GcFlags
.generations
=
1113 decodeSize(rts_argv
[arg
], 2, 1, HS_INT_MAX
);
1118 if (rts_argv
[arg
][2] == '\0') {
1119 RtsFlags
.GcFlags
.heapSizeSuggestionAuto
= true;
1121 RtsFlags
.GcFlags
.heapSizeSuggestion
= (uint32_t)
1122 (decodeSize(rts_argv
[arg
], 2, BLOCK_SIZE
, HS_WORD_MAX
)
1129 RtsFlags
.GcFlags
.minOldGenSize
=
1130 (uint32_t)(decodeSize(rts_argv
[arg
], 2, BLOCK_SIZE
,
1135 case 'I': /* idle GC delay */
1137 if (rts_argv
[arg
][2] == '\0') {
1140 Time t
= fsecondsToTime(atof(rts_argv
[arg
]+2));
1142 RtsFlags
.GcFlags
.doIdleGC
= false;
1144 RtsFlags
.GcFlags
.doIdleGC
= true;
1145 RtsFlags
.GcFlags
.idleGCDelayTime
= t
;
1152 RtsFlags
.GcFlags
.giveStats
= COLLECT_GC_STATS
;
1153 unchecked_arg_start
++;
1154 goto check_rest
; /* Don't initialize statistics file. */
1157 OPTION_SAFE
; /* but see below */
1158 RtsFlags
.GcFlags
.giveStats
= VERBOSE_GC_STATS
;
1162 OPTION_SAFE
; /* but see below */
1163 RtsFlags
.GcFlags
.giveStats
= SUMMARY_GC_STATS
;
1167 OPTION_SAFE
; /* but see below */
1168 RtsFlags
.GcFlags
.giveStats
= ONELINE_GC_STATS
;
1174 if (rts_argv
[arg
][2] != '\0') {
1177 r
= openStatsFile(rts_argv
[arg
]+2, NULL
,
1178 &RtsFlags
.GcFlags
.statsFile
);
1179 if (r
== -1) { error
= true; }
1185 RtsFlags
.GcFlags
.squeezeUpdFrames
= false;
1186 unchecked_arg_start
++;
1189 /* =========== PROFILING ========================== */
1191 case 'P': /* detailed cost centre profiling (time/alloc) */
1192 case 'p': /* cost centre profiling (time/alloc) */
1194 PROFILING_BUILD_ONLY(
1195 switch (rts_argv
[arg
][2]) {
1197 RtsFlags
.CcFlags
.doCostCentres
= COST_CENTRES_ALL
;
1198 if (rts_argv
[arg
][3] != '\0') {
1199 errorBelch("flag -Pa given an argument"
1200 " when none was expected: %s"
1206 RtsFlags
.CcFlags
.doCostCentres
= COST_CENTRES_JSON
;
1209 if (rts_argv
[arg
][3] == '\0') {
1210 errorBelch("flag -po expects an argument");
1214 RtsFlags
.CcFlags
.outputFileNameStem
= rts_argv
[arg
]+3;
1217 if (rts_argv
[arg
][1] == 'P') {
1218 RtsFlags
.CcFlags
.doCostCentres
= COST_CENTRES_VERBOSE
;
1220 RtsFlags
.CcFlags
.doCostCentres
= COST_CENTRES_SUMMARY
;
1224 unchecked_arg_start
++;
1231 PROFILING_BUILD_ONLY(
1232 RtsFlags
.ProfFlags
.maxRetainerSetSize
=
1233 atof(rts_argv
[arg
]+2);
1237 PROFILING_BUILD_ONLY(
1238 RtsFlags
.ProfFlags
.ccsLength
= atof(rts_argv
[arg
]+2);
1239 if(RtsFlags
.ProfFlags
.ccsLength
<= 0) {
1240 bad_option(rts_argv
[arg
]);
1243 case 'h': /* serial heap profile */
1244 #if !defined(PROFILING)
1245 switch (rts_argv
[arg
][2]) {
1249 RtsFlags
.ProfFlags
.doHeapProfile
= HEAP_BY_CLOSURE_TYPE
;
1253 PROFILING_BUILD_ONLY();
1257 PROFILING_BUILD_ONLY(
1258 error
= read_heap_profiling_flag(rts_argv
[arg
]);
1260 #endif /* PROFILING */
1263 case 'i': /* heap sample interval */
1265 if (rts_argv
[arg
][2] == '\0') {
1268 RtsFlags
.ProfFlags
.heapProfileInterval
=
1269 fsecondsToTime(atof(rts_argv
[arg
]+2));
1273 /* =========== CONCURRENT ========================= */
1274 case 'C': /* context switch interval */
1276 if (rts_argv
[arg
][2] == '\0')
1277 RtsFlags
.ConcFlags
.ctxtSwitchTime
= 0;
1279 RtsFlags
.ConcFlags
.ctxtSwitchTime
=
1280 fsecondsToTime(atof(rts_argv
[arg
]+2));
1284 case 'V': /* master tick interval */
1286 if (rts_argv
[arg
][2] == '\0') {
1287 // turns off ticks completely
1288 RtsFlags
.MiscFlags
.tickInterval
= 0;
1290 RtsFlags
.MiscFlags
.tickInterval
=
1291 fsecondsToTime(atof(rts_argv
[arg
]+2));
1298 THREADED_BUILD_ONLY(
1299 if (rts_argv
[arg
][2] == '\0') {
1300 RtsFlags
.ParFlags
.nCapabilities
= getNumberOfProcessors();
1303 OPTION_SAFE
; /* but see extra checks below... */
1305 nCapabilities
= strtol(rts_argv
[arg
]+2, (char **) NULL
, 10);
1307 if (nCapabilities
<= 0) {
1308 errorBelch("bad value for -N");
1311 if (rtsOptsEnabled
== RtsOptsSafeOnly
&&
1312 nCapabilities
> (int)getNumberOfProcessors()) {
1313 errorRtsOptsDisabled("Using large values for -N is not allowed by default. %s");
1314 stg_exit(EXIT_FAILURE
);
1316 RtsFlags
.ParFlags
.nCapabilities
= (uint32_t)nCapabilities
;
1322 THREADED_BUILD_ONLY(
1323 switch (rts_argv
[arg
][2]) {
1325 // backwards compat only
1326 RtsFlags
.ParFlags
.parGcEnabled
= false;
1329 errorBelch("unknown RTS option: %s",rts_argv
[arg
]);
1337 THREADED_BUILD_ONLY(
1338 switch (rts_argv
[arg
][2]) {
1340 errorBelch("incomplete RTS option: %s",rts_argv
[arg
]);
1344 if (rts_argv
[arg
][3] == '\0') {
1345 RtsFlags
.ParFlags
.parGcEnabled
= false;
1347 RtsFlags
.ParFlags
.parGcEnabled
= true;
1348 RtsFlags
.ParFlags
.parGcGen
1349 = strtol(rts_argv
[arg
]+3, (char **) NULL
, 10);
1353 if (rts_argv
[arg
][3] == '\0') {
1354 RtsFlags
.ParFlags
.parGcLoadBalancingEnabled
=
1358 RtsFlags
.ParFlags
.parGcLoadBalancingEnabled
=
1360 RtsFlags
.ParFlags
.parGcLoadBalancingGen
1361 = strtol(rts_argv
[arg
]+3, (char **) NULL
, 10);
1365 RtsFlags
.ParFlags
.parGcNoSyncWithIdle
1366 = strtol(rts_argv
[arg
]+3, (char **) NULL
, 10);
1370 threads
= strtol(rts_argv
[arg
]+3, (char **) NULL
, 10);
1372 errorBelch("-qn must be 1 or greater");
1375 RtsFlags
.ParFlags
.parGcThreads
= threads
;
1380 RtsFlags
.ParFlags
.setAffinity
= true;
1383 RtsFlags
.ParFlags
.migrate
= false;
1386 // -qw was removed; accepted for backwards compat
1389 errorBelch("unknown RTS option: %s",rts_argv
[arg
]);
1395 /* =========== PARALLEL =========================== */
1398 THREADED_BUILD_ONLY(
1399 if (rts_argv
[arg
][2] != '\0') {
1400 RtsFlags
.ParFlags
.maxLocalSparks
1401 = strtol(rts_argv
[arg
]+2, (char **) NULL
, 10);
1402 if (RtsFlags
.ParFlags
.maxLocalSparks
<= 0) {
1403 errorBelch("bad value for -e");
1409 /* =========== TICKY ============================== */
1411 case 'r': /* Basic profiling stats */
1415 RtsFlags
.TickyFlags
.showTickyStats
= true;
1419 if (rts_argv
[arg
][2] != '\0') {
1422 r
= openStatsFile(rts_argv
[arg
]+2,
1424 &RtsFlags
.TickyFlags
.tickyFile
);
1425 if (r
== -1) { error
= true; }
1429 /* =========== TRACING ---------=================== */
1434 RtsFlags
.TraceFlags
.tracing
= TRACE_EVENTLOG
;
1435 read_trace_flags(&rts_argv
[arg
][2]);
1442 RtsFlags
.TraceFlags
.tracing
= TRACE_STDERR
;
1443 read_trace_flags(&rts_argv
[arg
][2]);
1447 /* =========== EXTENDED OPTIONS =================== */
1449 case 'x': /* Extend the argument space */
1450 unchecked_arg_start
++;
1451 switch(rts_argv
[arg
][2]) {
1454 errorBelch("incomplete RTS option: %s",rts_argv
[arg
]);
1458 case 'b': /* heapBase in hex; undocumented */
1460 if (rts_argv
[arg
][3] != '\0') {
1461 RtsFlags
.GcFlags
.heapBase
1462 = strToStgWord(rts_argv
[arg
]+3, (char **) NULL
, 0);
1464 errorBelch("-xb: requires argument");
1469 #if defined(x86_64_HOST_ARCH)
1470 case 'm': /* linkerMemBase */
1472 if (rts_argv
[arg
][3] != '\0') {
1473 RtsFlags
.MiscFlags
.linkerMemBase
1474 = strtol(rts_argv
[arg
]+3, (char **) NULL
, 16);
1475 if (RtsFlags
.MiscFlags
.linkerMemBase
> 0x80000000) {
1476 errorBelch("-xm: value must be <80000000");
1480 RtsFlags
.MiscFlags
.linkerMemBase
= 0;
1485 case 'c': /* Debugging tool: show current cost centre on
1488 PROFILING_BUILD_ONLY(
1489 RtsFlags
.ProfFlags
.showCCSOnException
= true;
1491 unchecked_arg_start
++;
1494 case 't': /* Include memory used by TSOs in a heap profile */
1496 PROFILING_BUILD_ONLY(
1497 RtsFlags
.ProfFlags
.includeTSOs
= true;
1499 unchecked_arg_start
++;
1503 * The option prefix '-xx' is reserved for future
1504 * extension. KSW 1999-11.
1509 RtsFlags
.GcFlags
.allocLimitGrace
1510 = decodeSize(rts_argv
[arg
], 3, BLOCK_SIZE
, HS_INT_MAX
)
1516 errorBelch("unknown RTS option: %s",rts_argv
[arg
]);
1520 break; /* defensive programming */
1522 /* check the rest to be sure there is nothing afterwards.*/
1523 /* see Trac #9839 */
1526 /* start checking from the first unchecked position,
1527 * not from index 2*/
1528 /* see Trac #9839 */
1529 if (rts_argv
[arg
][unchecked_arg_start
] != '\0') {
1530 errorBelch("flag -%c given an argument"
1531 " when none was expected: %s",
1532 rts_argv
[arg
][1],rts_argv
[arg
]);
1538 /* =========== OH DEAR ============================ */
1541 errorBelch("unknown RTS option: %s",rts_argv
[arg
]);
1546 if (!option_checked
) {
1547 /* Naughty! Someone didn't use OPTION_UNSAFE / OPTION_SAFE for
1549 errorBelch("Internal error in the RTS options parser");
1550 stg_exit(EXIT_FAILURE
);
1555 if (error
) errorUsage();
1558 /* -----------------------------------------------------------------------------
1559 * normaliseRtsOpts: Set some derived values, and make sure things are
1560 * within sensible ranges.
1561 * -------------------------------------------------------------------------- */
1563 static void normaliseRtsOpts (void)
1565 if (RtsFlags
.MiscFlags
.tickInterval
< 0) {
1566 RtsFlags
.MiscFlags
.tickInterval
= DEFAULT_TICK_INTERVAL
;
1569 // If the master timer is disabled, turn off the other timers.
1570 if (RtsFlags
.MiscFlags
.tickInterval
== 0) {
1571 RtsFlags
.ConcFlags
.ctxtSwitchTime
= 0;
1572 RtsFlags
.GcFlags
.idleGCDelayTime
= 0;
1573 RtsFlags
.ProfFlags
.heapProfileInterval
= 0;
1576 // Determine what tick interval we should use for the RTS timer
1577 // by taking the shortest of the various intervals that we need to
1579 if (RtsFlags
.ConcFlags
.ctxtSwitchTime
> 0) {
1580 RtsFlags
.MiscFlags
.tickInterval
=
1581 stg_min(RtsFlags
.ConcFlags
.ctxtSwitchTime
,
1582 RtsFlags
.MiscFlags
.tickInterval
);
1585 if (RtsFlags
.GcFlags
.idleGCDelayTime
> 0) {
1586 RtsFlags
.MiscFlags
.tickInterval
=
1587 stg_min(RtsFlags
.GcFlags
.idleGCDelayTime
,
1588 RtsFlags
.MiscFlags
.tickInterval
);
1591 if (RtsFlags
.ProfFlags
.heapProfileInterval
> 0) {
1592 RtsFlags
.MiscFlags
.tickInterval
=
1593 stg_min(RtsFlags
.ProfFlags
.heapProfileInterval
,
1594 RtsFlags
.MiscFlags
.tickInterval
);
1597 if (RtsFlags
.ConcFlags
.ctxtSwitchTime
> 0) {
1598 RtsFlags
.ConcFlags
.ctxtSwitchTicks
=
1599 RtsFlags
.ConcFlags
.ctxtSwitchTime
/
1600 RtsFlags
.MiscFlags
.tickInterval
;
1602 RtsFlags
.ConcFlags
.ctxtSwitchTicks
= 0;
1605 if (RtsFlags
.ProfFlags
.heapProfileInterval
> 0) {
1606 RtsFlags
.ProfFlags
.heapProfileIntervalTicks
=
1607 RtsFlags
.ProfFlags
.heapProfileInterval
/
1608 RtsFlags
.MiscFlags
.tickInterval
;
1610 RtsFlags
.ProfFlags
.heapProfileIntervalTicks
= 0;
1613 if (RtsFlags
.GcFlags
.stkChunkBufferSize
>
1614 RtsFlags
.GcFlags
.stkChunkSize
/ 2) {
1615 errorBelch("stack chunk buffer size (-kb) must be less than 50%%\n"
1616 "of the stack chunk size (-kc)");
1620 if (RtsFlags
.GcFlags
.maxHeapSize
!= 0 &&
1621 RtsFlags
.GcFlags
.heapSizeSuggestion
>
1622 RtsFlags
.GcFlags
.maxHeapSize
) {
1623 RtsFlags
.GcFlags
.maxHeapSize
= RtsFlags
.GcFlags
.heapSizeSuggestion
;
1626 if (RtsFlags
.GcFlags
.maxHeapSize
!= 0 &&
1627 RtsFlags
.GcFlags
.minAllocAreaSize
>
1628 RtsFlags
.GcFlags
.maxHeapSize
) {
1629 errorBelch("maximum heap size (-M) is smaller than minimum alloc area size (-A)");
1630 RtsFlags
.GcFlags
.minAllocAreaSize
= RtsFlags
.GcFlags
.maxHeapSize
;
1633 // If we have -A16m or larger, use -n4m.
1634 if (RtsFlags
.GcFlags
.minAllocAreaSize
>= (16*1024*1024) / BLOCK_SIZE
) {
1635 RtsFlags
.GcFlags
.nurseryChunkSize
= (4*1024*1024) / BLOCK_SIZE
;
1638 if (RtsFlags
.ParFlags
.parGcLoadBalancingGen
== ~0u) {
1639 StgWord alloc_area_bytes
1640 = RtsFlags
.GcFlags
.minAllocAreaSize
* BLOCK_SIZE
;
1642 // If allocation area is larger that CPU cache
1643 // we can finish scanning quicker doing work-stealing
1645 // 32M looks big enough not to fit into L2 cache
1646 // of popular modern CPUs.
1647 if (alloc_area_bytes
>= 32 * 1024 * 1024) {
1648 RtsFlags
.ParFlags
.parGcLoadBalancingGen
= 0;
1650 RtsFlags
.ParFlags
.parGcLoadBalancingGen
= 1;
1654 // We can't generate dumps without signal handlers
1655 if (RtsFlags
.MiscFlags
.generate_dump_file
) {
1656 RtsFlags
.MiscFlags
.install_seh_handlers
= true;
1660 static void errorUsage (void)
1665 for (p
= usage_text
; *p
; p
++)
1666 errorBelch("%s", *p
);
1667 stg_exit(EXIT_FAILURE
);
1671 stats_fprintf(FILE *f
, char *s
, ...)
1683 /* -----------------------------------------------------------------------------
1684 * openStatsFile: open a file in which to put some runtime stats
1685 * -------------------------------------------------------------------------- */
1687 static int // return -1 on error
1688 openStatsFile (char *filename
, // filename, or NULL
1689 const char *filename_fmt
, // if filename == NULL, use
1690 // this fmt with sprintf to
1691 // generate the filename. %s
1692 // expands to the program name.
1693 FILE **file_ret
) // return the FILE*
1697 if (strequal(filename
, "stderr")
1698 || (filename_fmt
== NULL
&& *filename
== '\0')) {
1699 f
= NULL
; /* NULL means use debugBelch */
1701 if (*filename
!= '\0') { /* stats file specified */
1702 f
= __rts_fopen (filename
,"w");
1704 if (filename_fmt
== NULL
) {
1705 errorBelch("Invalid stats filename format (NULL)\n");
1708 /* default <program>.<ext> */
1709 char stats_filename
[STATS_FILENAME_MAXLEN
];
1710 snprintf(stats_filename
, STATS_FILENAME_MAXLEN
, filename_fmt
,
1712 f
= __rts_fopen (stats_filename
,"w");
1715 errorBelch("Can't open stats file %s\n", filename
);
1724 /* -----------------------------------------------------------------------------
1725 * initStatsFile: write a line to the file containing the program name
1726 * and the arguments it was invoked with.
1727 -------------------------------------------------------------------------- */
1729 static void initStatsFile (FILE *f
)
1731 /* Write prog_argv and rts_argv into start of stats file */
1733 for (count
= 0; count
< prog_argc
; count
++) {
1734 stats_fprintf(f
, "%s ", prog_argv
[count
]);
1736 stats_fprintf(f
, "+RTS ");
1737 for (count
= 0; count
< rts_argc
; count
++)
1738 stats_fprintf(f
, "%s ", rts_argv
[count
]);
1739 stats_fprintf(f
, "\n");
1742 /* -----------------------------------------------------------------------------
1743 * decodeSize: parse a string containing a size, like 300K or 1.2M
1744 -------------------------------------------------------------------------- */
1747 decodeSize(const char *flag
, uint32_t offset
, StgWord64 min
, StgWord64 max
)
1765 if (c
== 'g' || c
== 'G')
1766 m
*= 1024*1024*1024;
1767 else if (c
== 'm' || c
== 'M')
1769 else if (c
== 'k' || c
== 'K')
1771 else if (c
== 'w' || c
== 'W')
1777 if (m
< 0 || val
< min
|| val
> max
) {
1778 // printf doesn't like 64-bit format specs on Windows
1779 // apparently, so fall back to unsigned long.
1780 errorBelch("error in RTS option %s: size outside allowed range (%" FMT_Word
" - %" FMT_Word
")", flag
, (W_
)min
, (W_
)max
);
1781 stg_exit(EXIT_FAILURE
);
1788 static void read_debug_flags(const char* arg
)
1790 // Already parsed "-D"
1792 for (c
= arg
+ 2; *c
!= '\0'; c
++) {
1795 RtsFlags
.DebugFlags
.scheduler
= true;
1798 RtsFlags
.DebugFlags
.interpreter
= true;
1801 RtsFlags
.DebugFlags
.weak
= true;
1804 RtsFlags
.DebugFlags
.gccafs
= true;
1807 RtsFlags
.DebugFlags
.gc
= true;
1810 RtsFlags
.DebugFlags
.block_alloc
= true;
1813 RtsFlags
.DebugFlags
.sanity
= true;
1816 RtsFlags
.DebugFlags
.stable
= true;
1819 RtsFlags
.DebugFlags
.prof
= true;
1822 RtsFlags
.DebugFlags
.linker
= true;
1825 RtsFlags
.DebugFlags
.apply
= true;
1828 RtsFlags
.DebugFlags
.stm
= true;
1831 RtsFlags
.DebugFlags
.squeeze
= true;
1834 RtsFlags
.DebugFlags
.hpc
= true;
1837 RtsFlags
.DebugFlags
.sparks
= true;
1840 RtsFlags
.DebugFlags
.compact
= true;
1846 // -Dx also turns on -v. Use -l to direct trace
1847 // events to the .eventlog file instead.
1848 RtsFlags
.TraceFlags
.tracing
= TRACE_STDERR
;
1852 #if defined(PROFILING)
1853 // Parse a "-h" flag, returning whether the parse resulted in an error.
1854 static bool read_heap_profiling_flag(const char *arg
)
1856 // Already parsed "-h"
1873 if (arg
[2] != '\0' && arg
[3] != '\0') {
1875 const char *left
= strchr(arg
, '{');
1876 const char *right
= strrchr(arg
, '}');
1878 // curly braces are optional, for
1879 // backwards compat.
1886 right
= arg
+ strlen(arg
);
1888 char *selector
= stgStrndup(left
, right
- left
+ 1);
1891 case 'c': // cost centre label select
1892 RtsFlags
.ProfFlags
.ccSelector
= selector
;
1895 RtsFlags
.ProfFlags
.ccsSelector
= selector
;
1898 case 'm': // cost centre module select
1899 RtsFlags
.ProfFlags
.modSelector
= selector
;
1902 case 'd': // closure descr select
1903 RtsFlags
.ProfFlags
.descrSelector
= selector
;
1906 case 'y': // closure type select
1907 RtsFlags
.ProfFlags
.typeSelector
= selector
;
1910 case 'r': // retainer select
1911 RtsFlags
.ProfFlags
.retainerSelector
= selector
;
1914 case 'b': // biography select
1915 RtsFlags
.ProfFlags
.bioSelector
= selector
;
1924 if (RtsFlags
.ProfFlags
.doHeapProfile
!= 0) {
1925 errorBelch("multiple heap profile options");
1934 RtsFlags
.ProfFlags
.doHeapProfile
= HEAP_BY_CCS
;
1938 RtsFlags
.ProfFlags
.doHeapProfile
= HEAP_BY_MOD
;
1942 RtsFlags
.ProfFlags
.doHeapProfile
= HEAP_BY_DESCR
;
1946 RtsFlags
.ProfFlags
.doHeapProfile
= HEAP_BY_TYPE
;
1950 RtsFlags
.ProfFlags
.doHeapProfile
= HEAP_BY_RETAINER
;
1954 RtsFlags
.ProfFlags
.doHeapProfile
= HEAP_BY_LDV
;
1960 errorBelch("invalid heap profile option: %s", arg
);
1968 #if defined(TRACING)
1969 static void read_trace_flags(const char *arg
)
1972 bool enabled
= true;
1973 /* Syntax for tracing flags currently looks like:
1975 * -l To turn on eventlog tracing with default trace classes
1976 * -lx Turn on class 'x' (for some class listed below)
1977 * -l-x Turn off class 'x'
1978 * -la Turn on all classes
1979 * -l-a Turn off all classes
1981 * This lets users say things like:
1982 * -la-p "all but sparks"
1983 * -l-ap "only sparks"
1986 /* Start by turning on the default tracing flags.
1988 * Currently this is all the trace classes, except full-detail sparks.
1989 * Similarly, in future we might default to slightly less verbose
1990 * scheduler or GC tracing.
1992 RtsFlags
.TraceFlags
.scheduler
= true;
1993 RtsFlags
.TraceFlags
.gc
= true;
1994 RtsFlags
.TraceFlags
.sparks_sampled
= true;
1995 RtsFlags
.TraceFlags
.user
= true;
1997 for (c
= arg
; *c
!= '\0'; c
++) {
2005 RtsFlags
.TraceFlags
.scheduler
= enabled
;
2006 RtsFlags
.TraceFlags
.gc
= enabled
;
2007 RtsFlags
.TraceFlags
.sparks_sampled
= enabled
;
2008 RtsFlags
.TraceFlags
.sparks_full
= enabled
;
2009 RtsFlags
.TraceFlags
.user
= enabled
;
2014 RtsFlags
.TraceFlags
.scheduler
= enabled
;
2018 RtsFlags
.TraceFlags
.sparks_sampled
= enabled
;
2022 RtsFlags
.TraceFlags
.sparks_full
= enabled
;
2026 RtsFlags
.TraceFlags
.timestamp
= enabled
;
2030 RtsFlags
.TraceFlags
.gc
= enabled
;
2034 RtsFlags
.TraceFlags
.user
= enabled
;
2038 errorBelch("unknown trace option: %c",*c
);
2045 static void GNU_ATTRIBUTE(__noreturn__
)
2046 bad_option(const char *s
)
2048 errorBelch("bad RTS option: %s", s
);
2049 stg_exit(EXIT_FAILURE
);
2052 /* ----------------------------------------------------------------------------
2053 Copying and freeing argc/argv
2054 ------------------------------------------------------------------------- */
2056 static char * copyArg(char *arg
)
2058 char *new_arg
= stgMallocBytes(strlen(arg
) + 1, "copyArg");
2059 strcpy(new_arg
, arg
);
2063 static char ** copyArgv(int argc
, char *argv
[])
2068 new_argv
= stgCallocBytes(argc
+ 1, sizeof (char *), "copyArgv 1");
2069 for (i
= 0; i
< argc
; i
++) {
2070 new_argv
[i
] = copyArg(argv
[i
]);
2072 new_argv
[argc
] = NULL
;
2076 static void freeArgv(int argc
, char *argv
[])
2080 for (i
= 0; i
< argc
; i
++) {
2087 /* -----------------------------------------------------------------------------
2088 Getting/Setting the program's arguments.
2090 These are used by System.Environment, and parts of the RTS.
2091 -------------------------------------------------------------------------- */
2094 setProgName(char *argv
[])
2098 if (argv
[0] == NULL
) { // #7037
2103 /* Remove directory from argv[0] -- default files in current directory */
2104 #if !defined(mingw32_HOST_OS)
2105 if ( (last_slash
= (char *) strrchr(argv
[0], '/')) != NULL
) {
2106 prog_name
= last_slash
+1;
2108 prog_name
= argv
[0];
2111 last_slash
= argv
[0] + (strlen(argv
[0]) - 1);
2112 while ( last_slash
> argv
[0] ) {
2113 if ( *last_slash
== '/' || *last_slash
== '\\' ) {
2114 prog_name
= last_slash
+1;
2119 prog_name
= argv
[0];
2124 getProgArgv(int *argc
, char **argv
[])
2126 if (argc
) { *argc
= prog_argc
; }
2127 if (argv
) { *argv
= prog_argv
; }
2131 setProgArgv(int argc
, char *argv
[])
2133 freeArgv(prog_argc
,prog_argv
);
2135 prog_argv
= copyArgv(argc
,argv
);
2136 setProgName(prog_argv
);
2142 freeArgv(prog_argc
,prog_argv
);
2147 /* ----------------------------------------------------------------------------
2148 The full argv - a copy of the original program's argc/argv
2149 ------------------------------------------------------------------------- */
2152 setFullProgArgv(int argc
, char *argv
[])
2154 full_prog_argc
= argc
;
2155 full_prog_argv
= copyArgv(argc
,argv
);
2158 /* These functions record and recall the full arguments, including the
2159 +RTS ... -RTS options. The reason for adding them was so that the
2160 ghc-inplace program can pass /all/ the arguments on to the real ghc. */
2162 getFullProgArgv(int *argc
, char **argv
[])
2164 if (argc
) { *argc
= full_prog_argc
; }
2165 if (argv
) { *argv
= full_prog_argv
; }
2169 freeFullProgArgv (void)
2171 freeArgv(full_prog_argc
, full_prog_argv
);
2173 full_prog_argv
= NULL
;
2176 /* ----------------------------------------------------------------------------
2178 ------------------------------------------------------------------------- */
2180 #if defined(mingw32_HOST_OS)
2181 void freeWin32ProgArgv (void);
2184 freeWin32ProgArgv (void)
2186 if(win32_utf8_argv
== NULL
) {
2191 freeArgv(win32_full_utf8_argc
, win32_full_utf8_argv
);
2192 stgFree(win32_utf8_argv
);
2200 /* ----------------------------------------------------------------------------
2202 ------------------------------------------------------------------------- */
2207 freeArgv(rts_argc
,rts_argv
);
2213 /* ----------------------------------------------------------------------------
2215 ------------------------------------------------------------------------- */
2217 void freeRtsArgs(void)
2219 #if defined(mingw32_HOST_OS)
2220 freeWin32ProgArgv();
2229 Note [OPTION_SAFE vs OPTION_UNSAFE]
2231 Ticket #3910 originally pointed out that the RTS options are a potential
2232 security problem. For example the -t -s or -S flags can be used to
2233 overwrite files. This would be bad in the context of CGI scripts or
2234 setuid binaries. So we introduced a system where +RTS processing is more
2235 or less disabled unless you pass the -rtsopts flag at link time.
2237 This scheme is safe enough but it also really annoyes users. They have
2238 to use -rtsopts in many circumstances: with -threaded to use -N, with
2239 -eventlog to use -l, with -prof to use any of the profiling flags. Many
2240 users just set -rtsopts globally or in project .cabal files. Apart from
2241 annoying users it reduces security because it means that deployed
2242 binaries will have all RTS options enabled rather than just profiling
2245 So now, we relax the set of RTS options that are available in the
2246 default -rtsopts=some case. For "deployment" ways like vanilla and
2247 -threaded we remain quite conservative. Only --info -? --help are
2248 allowed for vanilla. For -threaded, -N and -N<x> are allowed with a
2249 check that x <= num cpus.
2251 For "developer" ways like -debug, -eventlog, -prof, we allow all the
2252 options that are special to that way. Some of these allow writing files,
2253 but the file written is not directly under the control of the attacker.
2254 For the setuid case (where the attacker would have control over binary
2255 name, current dir, local symlinks etc) we check if the process is
2256 running setuid/setgid and refuse all RTS option processing. Users would
2257 need to use -rtsopts=all in this case.
2259 We are making the assumption that developers will not deploy binaries
2260 built in the -debug, -eventlog, -prof ways. And even if they do, the
2261 damage should be limited to DOS, information disclosure and writing
2262 files like <progname>.eventlog, not arbitrary files.