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