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