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