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