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