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