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