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