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