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