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