rts: Fix ASSERTs with space before opening paren
[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 sprintf(stats_filename, filename_fmt, prog_name);
1640 f = fopen(stats_filename,"w");
1641 }
1642 if (f == NULL) {
1643 errorBelch("Can't open stats file %s\n", filename);
1644 return -1;
1645 }
1646 }
1647 *file_ret = f;
1648
1649 return 0;
1650 }
1651
1652 /* -----------------------------------------------------------------------------
1653 * initStatsFile: write a line to the file containing the program name
1654 * and the arguments it was invoked with.
1655 -------------------------------------------------------------------------- */
1656
1657 static void initStatsFile (FILE *f)
1658 {
1659 /* Write prog_argv and rts_argv into start of stats file */
1660 int count;
1661 for (count = 0; count < prog_argc; count++) {
1662 stats_fprintf(f, "%s ", prog_argv[count]);
1663 }
1664 stats_fprintf(f, "+RTS ");
1665 for (count = 0; count < rts_argc; count++)
1666 stats_fprintf(f, "%s ", rts_argv[count]);
1667 stats_fprintf(f, "\n");
1668 }
1669
1670 /* -----------------------------------------------------------------------------
1671 * decodeSize: parse a string containing a size, like 300K or 1.2M
1672 -------------------------------------------------------------------------- */
1673
1674 static StgWord64
1675 decodeSize(const char *flag, uint32_t offset, StgWord64 min, StgWord64 max)
1676 {
1677 char c;
1678 const char *s;
1679 StgDouble m;
1680 StgWord64 val;
1681
1682 s = flag + offset;
1683
1684 if (!*s)
1685 {
1686 m = 0;
1687 }
1688 else
1689 {
1690 m = atof(s);
1691 c = s[strlen(s)-1];
1692
1693 if (c == 'g' || c == 'G')
1694 m *= 1024*1024*1024;
1695 else if (c == 'm' || c == 'M')
1696 m *= 1024*1024;
1697 else if (c == 'k' || c == 'K')
1698 m *= 1024;
1699 else if (c == 'w' || c == 'W')
1700 m *= sizeof(W_);
1701 }
1702
1703 val = (StgWord64)m;
1704
1705 if (m < 0 || val < min || val > max) {
1706 // printf doesn't like 64-bit format specs on Windows
1707 // apparently, so fall back to unsigned long.
1708 errorBelch("error in RTS option %s: size outside allowed range (%" FMT_Word " - %" FMT_Word ")", flag, (W_)min, (W_)max);
1709 stg_exit(EXIT_FAILURE);
1710 }
1711
1712 return val;
1713 }
1714
1715 #if defined(DEBUG)
1716 static void read_debug_flags(const char* arg)
1717 {
1718 // Already parsed "-D"
1719 const char *c;
1720 for (c = arg + 2; *c != '\0'; c++) {
1721 switch (*c) {
1722 case 's':
1723 RtsFlags.DebugFlags.scheduler = true;
1724 break;
1725 case 'i':
1726 RtsFlags.DebugFlags.interpreter = true;
1727 break;
1728 case 'w':
1729 RtsFlags.DebugFlags.weak = true;
1730 break;
1731 case 'G':
1732 RtsFlags.DebugFlags.gccafs = true;
1733 break;
1734 case 'g':
1735 RtsFlags.DebugFlags.gc = true;
1736 break;
1737 case 'b':
1738 RtsFlags.DebugFlags.block_alloc = true;
1739 break;
1740 case 'S':
1741 RtsFlags.DebugFlags.sanity = true;
1742 break;
1743 case 't':
1744 RtsFlags.DebugFlags.stable = true;
1745 break;
1746 case 'p':
1747 RtsFlags.DebugFlags.prof = true;
1748 break;
1749 case 'l':
1750 RtsFlags.DebugFlags.linker = true;
1751 break;
1752 case 'a':
1753 RtsFlags.DebugFlags.apply = true;
1754 break;
1755 case 'm':
1756 RtsFlags.DebugFlags.stm = true;
1757 break;
1758 case 'z':
1759 RtsFlags.DebugFlags.squeeze = true;
1760 break;
1761 case 'c':
1762 RtsFlags.DebugFlags.hpc = true;
1763 break;
1764 case 'r':
1765 RtsFlags.DebugFlags.sparks = true;
1766 break;
1767 case 'C':
1768 RtsFlags.DebugFlags.compact = true;
1769 break;
1770 default:
1771 bad_option( arg );
1772 }
1773 }
1774 // -Dx also turns on -v. Use -l to direct trace
1775 // events to the .eventlog file instead.
1776 RtsFlags.TraceFlags.tracing = TRACE_STDERR;
1777 }
1778 #endif
1779
1780 #if defined(PROFILING)
1781 // Parse a "-h" flag, returning whether the parse resulted in an error.
1782 static bool read_heap_profiling_flag(const char *arg)
1783 {
1784 // Already parsed "-h"
1785
1786 bool error = false;
1787 switch (arg[2]) {
1788 case '\0':
1789 case 'C':
1790 case 'c':
1791 case 'M':
1792 case 'm':
1793 case 'D':
1794 case 'd':
1795 case 'Y':
1796 case 'y':
1797 case 'R':
1798 case 'r':
1799 case 'B':
1800 case 'b':
1801 if (arg[2] != '\0' && arg[3] != '\0') {
1802 {
1803 const char *left = strchr(arg, '{');
1804 const char *right = strrchr(arg, '}');
1805
1806 // curly braces are optional, for
1807 // backwards compat.
1808 if (left)
1809 left = left+1;
1810 else
1811 left = arg + 3;
1812
1813 if (!right)
1814 right = arg + strlen(arg);
1815
1816 char *selector = stgStrndup(left, right - left + 1);
1817
1818 switch (arg[2]) {
1819 case 'c': // cost centre label select
1820 RtsFlags.ProfFlags.ccSelector = selector;
1821 break;
1822 case 'C':
1823 RtsFlags.ProfFlags.ccsSelector = selector;
1824 break;
1825 case 'M':
1826 case 'm': // cost centre module select
1827 RtsFlags.ProfFlags.modSelector = selector;
1828 break;
1829 case 'D':
1830 case 'd': // closure descr select
1831 RtsFlags.ProfFlags.descrSelector = selector;
1832 break;
1833 case 'Y':
1834 case 'y': // closure type select
1835 RtsFlags.ProfFlags.typeSelector = selector;
1836 break;
1837 case 'R':
1838 case 'r': // retainer select
1839 RtsFlags.ProfFlags.retainerSelector = selector;
1840 break;
1841 case 'B':
1842 case 'b': // biography select
1843 RtsFlags.ProfFlags.bioSelector = selector;
1844 break;
1845 default:
1846 free(selector);
1847 }
1848 }
1849 break;
1850 }
1851
1852 if (RtsFlags.ProfFlags.doHeapProfile != 0) {
1853 errorBelch("multiple heap profile options");
1854 error = true;
1855 break;
1856 }
1857
1858 switch (arg[2]) {
1859 case '\0':
1860 case 'C':
1861 case 'c':
1862 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_CCS;
1863 break;
1864 case 'M':
1865 case 'm':
1866 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_MOD;
1867 break;
1868 case 'D':
1869 case 'd':
1870 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_DESCR;
1871 break;
1872 case 'Y':
1873 case 'y':
1874 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_TYPE;
1875 break;
1876 case 'R':
1877 case 'r':
1878 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_RETAINER;
1879 break;
1880 case 'B':
1881 case 'b':
1882 RtsFlags.ProfFlags.doHeapProfile = HEAP_BY_LDV;
1883 break;
1884 }
1885 break;
1886
1887 default:
1888 errorBelch("invalid heap profile option: %s", arg);
1889 error = true;
1890 }
1891
1892 return error;
1893 }
1894 #endif
1895
1896 #if defined(TRACING)
1897 static void read_trace_flags(const char *arg)
1898 {
1899 const char *c;
1900 bool enabled = true;
1901 /* Syntax for tracing flags currently looks like:
1902 *
1903 * -l To turn on eventlog tracing with default trace classes
1904 * -lx Turn on class 'x' (for some class listed below)
1905 * -l-x Turn off class 'x'
1906 * -la Turn on all classes
1907 * -l-a Turn off all classes
1908 *
1909 * This lets users say things like:
1910 * -la-p "all but sparks"
1911 * -l-ap "only sparks"
1912 */
1913
1914 /* Start by turning on the default tracing flags.
1915 *
1916 * Currently this is all the trace classes, except full-detail sparks.
1917 * Similarly, in future we might default to slightly less verbose
1918 * scheduler or GC tracing.
1919 */
1920 RtsFlags.TraceFlags.scheduler = true;
1921 RtsFlags.TraceFlags.gc = true;
1922 RtsFlags.TraceFlags.sparks_sampled = true;
1923 RtsFlags.TraceFlags.user = true;
1924
1925 for (c = arg; *c != '\0'; c++) {
1926 switch(*c) {
1927 case '\0':
1928 break;
1929 case '-':
1930 enabled = false;
1931 break;
1932 case 'a':
1933 RtsFlags.TraceFlags.scheduler = enabled;
1934 RtsFlags.TraceFlags.gc = enabled;
1935 RtsFlags.TraceFlags.sparks_sampled = enabled;
1936 RtsFlags.TraceFlags.sparks_full = enabled;
1937 RtsFlags.TraceFlags.user = enabled;
1938 enabled = true;
1939 break;
1940
1941 case 's':
1942 RtsFlags.TraceFlags.scheduler = enabled;
1943 enabled = true;
1944 break;
1945 case 'p':
1946 RtsFlags.TraceFlags.sparks_sampled = enabled;
1947 enabled = true;
1948 break;
1949 case 'f':
1950 RtsFlags.TraceFlags.sparks_full = enabled;
1951 enabled = true;
1952 break;
1953 case 't':
1954 RtsFlags.TraceFlags.timestamp = enabled;
1955 enabled = true;
1956 break;
1957 case 'g':
1958 RtsFlags.TraceFlags.gc = enabled;
1959 enabled = true;
1960 break;
1961 case 'u':
1962 RtsFlags.TraceFlags.user = enabled;
1963 enabled = true;
1964 break;
1965 default:
1966 errorBelch("unknown trace option: %c",*c);
1967 break;
1968 }
1969 }
1970 }
1971 #endif
1972
1973 static void GNU_ATTRIBUTE(__noreturn__)
1974 bad_option(const char *s)
1975 {
1976 errorBelch("bad RTS option: %s", s);
1977 stg_exit(EXIT_FAILURE);
1978 }
1979
1980 /* ----------------------------------------------------------------------------
1981 Copying and freeing argc/argv
1982 ------------------------------------------------------------------------- */
1983
1984 static char * copyArg(char *arg)
1985 {
1986 char *new_arg = stgMallocBytes(strlen(arg) + 1, "copyArg");
1987 strcpy(new_arg, arg);
1988 return new_arg;
1989 }
1990
1991 static char ** copyArgv(int argc, char *argv[])
1992 {
1993 int i;
1994 char **new_argv;
1995
1996 new_argv = stgCallocBytes(argc + 1, sizeof (char *), "copyArgv 1");
1997 for (i = 0; i < argc; i++) {
1998 new_argv[i] = copyArg(argv[i]);
1999 }
2000 new_argv[argc] = NULL;
2001 return new_argv;
2002 }
2003
2004 static void freeArgv(int argc, char *argv[])
2005 {
2006 int i;
2007 if (argv != NULL) {
2008 for (i = 0; i < argc; i++) {
2009 stgFree(argv[i]);
2010 }
2011 stgFree(argv);
2012 }
2013 }
2014
2015 /* -----------------------------------------------------------------------------
2016 Getting/Setting the program's arguments.
2017
2018 These are used by System.Environment, and parts of the RTS.
2019 -------------------------------------------------------------------------- */
2020
2021 void
2022 setProgName(char *argv[])
2023 {
2024 char *last_slash;
2025
2026 if (argv[0] == NULL) { // #7037
2027 prog_name = "";
2028 return;
2029 }
2030
2031 /* Remove directory from argv[0] -- default files in current directory */
2032 #if !defined(mingw32_HOST_OS)
2033 if ( (last_slash = (char *) strrchr(argv[0], '/')) != NULL ) {
2034 prog_name = last_slash+1;
2035 } else {
2036 prog_name = argv[0];
2037 }
2038 #else
2039 last_slash = argv[0] + (strlen(argv[0]) - 1);
2040 while ( last_slash > argv[0] ) {
2041 if ( *last_slash == '/' || *last_slash == '\\' ) {
2042 prog_name = last_slash+1;
2043 return;
2044 }
2045 last_slash--;
2046 }
2047 prog_name = argv[0];
2048 #endif
2049 }
2050
2051 void
2052 getProgArgv(int *argc, char **argv[])
2053 {
2054 if (argc) { *argc = prog_argc; }
2055 if (argv) { *argv = prog_argv; }
2056 }
2057
2058 void
2059 setProgArgv(int argc, char *argv[])
2060 {
2061 freeArgv(prog_argc,prog_argv);
2062 prog_argc = argc;
2063 prog_argv = copyArgv(argc,argv);
2064 setProgName(prog_argv);
2065 }
2066
2067 static void
2068 freeProgArgv(void)
2069 {
2070 freeArgv(prog_argc,prog_argv);
2071 prog_argc = 0;
2072 prog_argv = NULL;
2073 }
2074
2075 /* ----------------------------------------------------------------------------
2076 The full argv - a copy of the original program's argc/argv
2077 ------------------------------------------------------------------------- */
2078
2079 void
2080 setFullProgArgv(int argc, char *argv[])
2081 {
2082 full_prog_argc = argc;
2083 full_prog_argv = copyArgv(argc,argv);
2084 }
2085
2086 /* These functions record and recall the full arguments, including the
2087 +RTS ... -RTS options. The reason for adding them was so that the
2088 ghc-inplace program can pass /all/ the arguments on to the real ghc. */
2089 void
2090 getFullProgArgv(int *argc, char **argv[])
2091 {
2092 if (argc) { *argc = full_prog_argc; }
2093 if (argv) { *argv = full_prog_argv; }
2094 }
2095
2096 void
2097 freeFullProgArgv (void)
2098 {
2099 freeArgv(full_prog_argc, full_prog_argv);
2100 full_prog_argc = 0;
2101 full_prog_argv = NULL;
2102 }
2103
2104 /* ----------------------------------------------------------------------------
2105 The Win32 argv
2106 ------------------------------------------------------------------------- */
2107
2108 #if defined(mingw32_HOST_OS)
2109 void freeWin32ProgArgv (void);
2110
2111 void
2112 freeWin32ProgArgv (void)
2113 {
2114 if(win32_utf8_argv == NULL) {
2115 return;
2116 }
2117 else
2118 {
2119 freeArgv(win32_full_utf8_argc, win32_full_utf8_argv);
2120 stgFree(win32_utf8_argv);
2121 }
2122
2123
2124 }
2125
2126 #endif
2127
2128 /* ----------------------------------------------------------------------------
2129 The RTS argv
2130 ------------------------------------------------------------------------- */
2131
2132 static void
2133 freeRtsArgv(void)
2134 {
2135 freeArgv(rts_argc,rts_argv);
2136 rts_argc = 0;
2137 rts_argv = NULL;
2138 rts_argv_size = 0;
2139 }
2140
2141 /* ----------------------------------------------------------------------------
2142 All argvs
2143 ------------------------------------------------------------------------- */
2144
2145 void freeRtsArgs(void)
2146 {
2147 #if defined(mingw32_HOST_OS)
2148 freeWin32ProgArgv();
2149 #endif
2150 freeFullProgArgv();
2151 freeProgArgv();
2152 freeRtsArgv();
2153 }
2154
2155
2156 /*
2157 Note [OPTION_SAFE vs OPTION_UNSAFE]
2158
2159 Ticket #3910 originally pointed out that the RTS options are a potential
2160 security problem. For example the -t -s or -S flags can be used to
2161 overwrite files. This would be bad in the context of CGI scripts or
2162 setuid binaries. So we introduced a system where +RTS processing is more
2163 or less disabled unless you pass the -rtsopts flag at link time.
2164
2165 This scheme is safe enough but it also really annoyes users. They have
2166 to use -rtsopts in many circumstances: with -threaded to use -N, with
2167 -eventlog to use -l, with -prof to use any of the profiling flags. Many
2168 users just set -rtsopts globally or in project .cabal files. Apart from
2169 annoying users it reduces security because it means that deployed
2170 binaries will have all RTS options enabled rather than just profiling
2171 ones.
2172
2173 So now, we relax the set of RTS options that are available in the
2174 default -rtsopts=some case. For "deployment" ways like vanilla and
2175 -threaded we remain quite conservative. Only --info -? --help are
2176 allowed for vanilla. For -threaded, -N and -N<x> are allowed with a
2177 check that x <= num cpus.
2178
2179 For "developer" ways like -debug, -eventlog, -prof, we allow all the
2180 options that are special to that way. Some of these allow writing files,
2181 but the file written is not directly under the control of the attacker.
2182 For the setuid case (where the attacker would have control over binary
2183 name, current dir, local symlinks etc) we check if the process is
2184 running setuid/setgid and refuse all RTS option processing. Users would
2185 need to use -rtsopts=all in this case.
2186
2187 We are making the assumption that developers will not deploy binaries
2188 built in the -debug, -eventlog, -prof ways. And even if they do, the
2189 damage should be limited to DOS, information disclosure and writing
2190 files like <progname>.eventlog, not arbitrary files.
2191 */