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