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