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