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