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