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