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