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