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