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