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