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