extended parseThat to use new addressSpace abstraction
[dyninst.git] / parseThat / src / parseThat.C
1 #include <iostream>
2 #include <string>
3 #include <cctype>
4 #include <regex.h>
5 #include <errno.h>
6 #include <unistd.h>
7 #include <sys/time.h>
8 #include <sys/resource.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>           // Needed for stat() call in parseArgs().
11 using namespace std;
12
13 #include "ipc.h"
14 #include "utils.h"
15 #include "config.h"
16 #include "dyninstCore.h"
17 #include "record.h"
18 #include "reglist.h"
19
20 void userError();
21 void parseArgs(int argc, char **argv);
22 void usage(const char *);
23
24 int main(int argc, char **argv)
25 {
26     int bannerLen;
27     parseArgs(argc, argv);
28
29     while (getNextTarget()) {
30         int pipefd[2];
31
32
33         if (config.no_fork || !config.use_process) {
34             return launch_mutator();
35         }
36         
37
38         if (pipe(pipefd) != 0) {
39             dlog(ERR, "Error on pipe(): %s\n", strerror(errno));
40             exit(-2);
41         }
42
43         config.grandchildren.clear();
44         config.state = NORMAL;
45
46         dlog(INFO, "[ Processing %s ] %n", config.target, &bannerLen);
47         while (++bannerLen < 80) dlog(INFO, "=");
48         dlog(INFO, "\n");
49         fflush(config.outfd);
50
51         config.pid = fork();
52         if (config.pid > 0) {
53             /**************************************************************
54              * Parent Case
55              */
56             close(pipefd[1]); // Close (historically) write side of pipe.
57
58             // Register target in history records.
59             if (config.record_enabled) {
60                 if (!record_create(&config.curr_rec, config.target, config.argc, config.argv))
61                     dlog(WARN, "Error creating history record.  No history will be recorded for %s\n", config.target);
62
63                 else if (!record_search(&config.curr_rec))
64                     record_update(&config.curr_rec);
65             }
66
67             // Convert raw socket to stream based FILE *.
68             errno = 0;
69             FILE *infd = fdopen(pipefd[0], "r");
70             if (infd == NULL) {
71                 dlog(ERR, "Error on fdopen() in child: %s\n", strerror(errno));
72                 dlog(ERR, "*** Child exiting.\n");
73                 exit(-2);
74             }
75
76             // Only parent should have signal handlers modified.
77             setSigHandlers();
78
79             launch_monitor(infd);
80
81             // Reset signal handers so next child won't be affected.
82             resetSigHandlers();
83
84             fprintf(config.outfd, "[ Done processing %s ] %n", config.target, &bannerLen);
85             while (++bannerLen < 80) fprintf(config.outfd, "-");
86             fprintf(config.outfd, "\n");
87
88             // Clean up any known processes we created.
89             cleanupProcess();
90
91             fclose(infd);
92
93         } else if (config.pid == 0) {
94             /**************************************************************
95              * Child Case
96              */
97
98             // Register to catch SIGINT
99             setSigHandlers();
100
101             // Start new process group.  Makes forced process shutdown easier.
102             setpgid(0, 0);
103
104             close(pipefd[0]); // Close (historically) read side of pipe.
105
106             // Leave stdout open for mutatee, but if an output file was specified by user,
107             // don't keep multiple descriptors open for it.
108             if (config.outfd != stdout) fclose(config.outfd);
109
110             // Convert raw socket to stream based FILE *.
111             errno = 0;
112             config.outfd = fdopen(pipefd[1], "w");
113             if (config.outfd == NULL) {
114                 fprintf(stderr, "Error on fdopen() in mutator: %s\n", strerror(errno));
115                 fprintf(stderr, "*** Mutator exiting.\n");
116                 exit(-2);
117             }
118
119             return( launch_mutator() );
120
121         } else {
122             /* Fork Error Case */
123             dlog(ERR, "Error on fork(): %s\n", strerror(errno));
124             exit(-2);
125         }
126     }
127     dlog(INFO, "Analysis complete.\n");
128     cleanupFinal();
129
130     return 0;
131 }
132
133 void parseArgs(int argc, char **argv)
134 {
135     int tempInt;
136     bool needShift;
137     char *arg;
138
139     if (argc < 2) {
140         fprintf(stderr, "Too few arguments.\n");
141         userError();
142     }
143
144     configInit();
145
146     int i = 0;
147     while (++i < argc && *argv[i] == '-') {
148         const char *ptr = argv[i];
149         while (*(++ptr)) {
150             switch (*ptr) {
151             case 'a':
152                 config.include_libs = true;
153                 break;
154
155             case 'c':
156                 if (++i < argc) {
157                     config.config_file = argv[i];
158                     config.runMode = BATCH_FILE;
159
160                 } else {
161                     fprintf(stderr, "-c flag requires an argument.\n");
162                     userError();
163                 }
164                 break;
165
166             case 'h':
167                 config.record_enabled = 1;
168                 break;
169
170             case 'i':
171                 if (isdigit(*(ptr + 1))) {
172                     config.inst_level = (InstLevel)strtol(++ptr, &arg, 0);
173                     ptr = arg - 1;
174
175                 } else if (++i < argc) {
176                     config.inst_level = (InstLevel)atoi(argv[i]);
177
178                 } else {
179                     fprintf(stderr, "-i flag requires an argument.\n");
180                     userError();
181                 }
182
183                 if (config.inst_level == 0 && errno == EINVAL) {
184                     fprintf(stderr, "Invalid argument to -i flag: '%s'\n", argv[i]);
185                     userError();
186                 }
187
188                 if (config.inst_level < 0 || config.inst_level >= INST_MAX) {
189                     fprintf(stderr, "Invalid argument to -i flag.  Valid range is 0 through %d\n", INST_MAX - 1);
190                     userError();
191                 }
192                 break;
193
194             case 'm':
195                 config.use_merge_tramp = true;
196                 break;
197
198             case 'o':
199                 if (++i < argc) {
200                     config.output_file = argv[i];
201                     config.outfd = NULL;
202
203                 } else {
204                     fprintf(stderr, "-o flag requires an argument.\n");
205                     userError();
206                 }
207                 break;
208
209             case 'p':
210                 if (isdigit(*(ptr + 1))) {
211                     config.parse_level = (ParseLevel)strtol(++ptr, &arg, 0);
212                     ptr = arg - 1;
213
214                 } else if (++i < argc) {
215                     config.parse_level = (ParseLevel)atoi(argv[i]);
216
217                 } else {
218                     fprintf(stderr, "-p flag requires an argument.\n");
219                     userError();
220                 }
221
222                 if (config.parse_level == 0 && errno == EINVAL) {
223                     fprintf(stderr, "Invalid argument to -p flag: '%s'\n", argv[i]);
224                     userError();
225                 }
226
227                 if (config.parse_level < 0 || config.parse_level >= PARSE_MAX) {
228                     fprintf(stderr, "Invalid argument to -p flag.  Valid range is 0 through %d\n", PARSE_MAX - 1);
229                     userError();
230                 }
231                 break;
232
233             case 'P':
234                 if (isdigit(*(ptr + 1))) {
235                     config.attach_pid = strtol(++ptr, &arg, 0);
236                     ptr = arg - 1;
237
238                 } else if (++i < argc) {
239                     config.attach_pid = atoi(argv[i]);
240
241                 } else {
242                     fprintf(stderr, "-P flag requires an argument.\n");
243                     userError();
244                 }
245
246                 if (config.attach_pid == 0) {
247                     fprintf(stderr, "Invalid argument to -P flag.\n");
248                     userError();
249                 }
250
251                 config.use_attach = true;
252                 break;
253
254             case 'r':
255                 config.recursive = true;
256                 break;
257
258             case 's':
259                 config.summary = true;
260                 break;
261
262             case 'S':
263                 config.no_fork = true;
264                 break;
265
266             case 't':
267                 errno = 0;
268                 if (isdigit(*(ptr + 1))) {
269                     config.time_limit = strtol(++ptr, &arg, 0);
270                     ptr = arg - 1;
271
272                 } else if (++i < argc) {
273                     config.time_limit = atoi(argv[i]);
274
275                 } else {
276                     fprintf(stderr, "-t flag requires an argument.\n");
277                     userError();
278                 }
279
280                 if (config.time_limit == 0 && errno == EINVAL) {
281                     fprintf(stderr, "Invalid argument to -t flag: '%s'\n", argv[i]);
282                     userError();
283                 }
284                 break;
285
286             case 'T':
287                 tempInt = 0;
288                 if (isdigit(*(ptr + 1))) {
289                     tempInt = strtol(++ptr, &arg, 0);
290                     ptr = arg - 1;
291
292                 } else if (i+1 < argc && isdigit(*argv[i+1])) {
293                     tempInt = atoi(argv[++i]);
294                 }
295
296                 config.trace_count = (tempInt < 0 ? 0 : (unsigned int)tempInt);
297                 if (config.use_process)
298                   config.trace_inst = true;
299                 break;
300
301             case 'v':
302                 if (isdigit(*(ptr + 1))) {
303                     config.verbose = strtol(++ptr, &arg, 0);
304                     ptr = arg - 1;
305
306                 } else if (i+1 < argc && isdigit(*argv[i+1])) {
307                     config.verbose = atoi(argv[++i]);
308
309                 } else {
310                     ++config.verbose;
311                 }
312
313                 if (config.verbose < 0 || config.verbose >= VERBOSE_MAX) {
314                     fprintf(stderr, "Invalid -v flag.  Valid range is 0 through %d\n", VERBOSE_MAX - 1);
315                 }
316
317                 break;
318
319             case 'q':
320                 --config.verbose;
321
322                 if (config.verbose < 0 || config.verbose >= VERBOSE_MAX) {
323                     fprintf(stderr, "Invalid -v flag.  Valid range is 0 through %d\n", VERBOSE_MAX - 1);
324                 }
325                 break;
326
327             case '-':
328                 needShift = false;
329                 arg = strchr(ptr, '=');
330                 if (arg) *(arg++) = '\0';
331                 else if (i+1 < argc) {
332                     arg = argv[i+1];
333                     needShift = true;
334                 }
335
336                 if (strcmp(ptr, "-all") == 0 ||
337                     strcmp(ptr, "-include-libs") == 0) {
338                     config.include_libs = true;
339
340                 } else if (strcmp(ptr, "-pid") == 0) {
341                     if (!arg) {
342                         fprintf(stderr, "--pid requires an integer argument.\n");
343                         userError();
344
345                     } else if (isdigit(*arg)) {
346                         config.attach_pid = strtol(arg, &arg, 0);
347                     }
348
349                     if (config.attach_pid == 0) {
350                         fprintf(stderr, "Invalid argument to --pid flag.\n");
351                         userError();
352                     }
353                     config.use_attach = true;
354
355                     if (needShift) ++i;
356                     break;
357                     
358                 } else if (strcmp(ptr, "-help") == 0) {
359                     usage(argv[0]);
360                     exit(0);
361
362                 } else if (strcmp(ptr, "-merge-tramp") == 0) {
363                     config.use_merge_tramp = true;
364
365                 } else if (strcmp(ptr, "-only-func") == 0) {
366                     if (!arg) {
367                         fprintf(stderr, "--only-func requires a regular expression argument.\n");
368                         userError();
369                     }
370                     if (!config.func_rules.insert(arg, RULE_ONLY))
371                         userError();
372                     if (needShift) ++i;
373
374                 } else if (strcmp(ptr, "-only-mod") == 0) {
375                     if (!arg) {
376                         fprintf(stderr, "--only-mod requires a regular expression argument.\n");
377                         userError();
378                     }
379                     if (!config.mod_rules.insert(arg, RULE_ONLY))
380                         userError();
381                     if (needShift) ++i;
382
383                 } else if (strcmp(ptr, "-summary") == 0) {
384                     config.summary = true;
385
386                 } else if (strcmp(ptr, "-save-world") == 0) {
387                   // SPECIAL CASE.  User *MUST* use '--save-world=<filename>' form.
388                   // '--save-world <filename>' is ambiguous and cannot be parsed
389                   // reliably.
390                     if (!needShift) {
391                       if (arg) config.saved_mutatee = arg;
392                       config.use_save_world = true;
393                     }
394                 }  else if (strcmp(ptr, "-binary-edit") == 0) {
395                   config.use_process = false;
396                   config.trace_inst = false;
397                   if (!arg) {
398                     fprintf(stderr, "--binary-edit requires a path argument\n");
399                     userError();
400                   }
401                   else
402                     {
403                       strcpy(config.writeFilePath,arg);
404                       printf("Write File Path is %s\n", config.writeFilePath);
405                     }
406                 } else if (strcmp(ptr, "-skip-func") == 0) {
407                   if (!arg) {
408                     fprintf(stderr, "--skip-func requires a regular expression argument.\n");
409                         userError();
410                     }
411                     if (!config.func_rules.insert(arg, RULE_SKIP))
412                         userError();
413                     if (needShift) ++i;
414
415                 } else if (strcmp(ptr, "-skip-mod") == 0) {
416                     if (!arg) {
417                         fprintf(stderr, "--skip-mod requires a regular expression argument.\n");
418                         userError();
419                     }
420                     if (!config.mod_rules.insert(arg, RULE_SKIP))
421                         userError();
422                     if (needShift) ++i;
423
424                 } else if (strcmp(ptr, "-trace") == 0) {
425                     tempInt = 0;
426                     if (isdigit(*arg)) {
427                         tempInt = strtol(arg, &arg, 0);
428                         if (needShift) ++i;
429                     }
430
431                     config.trace_count = (tempInt < 0 ? 0 : (unsigned int)tempInt);
432                     if (config.use_process)
433                       config.trace_inst = true;
434
435                 } else if (strcmp(ptr, "-use-transactions") == 0) {
436                     if (!arg) {
437                         fprintf(stderr, "No argument supplied to --use-transactions.  Using per-function as default.\n");
438                         config.transMode = TRANS_FUNCTION;
439                     }
440
441                     for (unsigned j = 0; arg[j]; ++j) arg[j] = tolower(arg[j]);
442                     if (strcmp(arg, "func") == 0) config.transMode = TRANS_FUNCTION;
443                     else if (strcmp(arg, "mod") == 0)  config.transMode = TRANS_MODULE;
444                     else if (strcmp(arg, "proc") == 0) config.transMode = TRANS_PROCESS;
445                     else {
446                         fprintf(stderr, "Invalid argument supplied to --use-transactions.  Valid arguments are func, mod, or proc.\n");
447                         userError();
448                     }
449
450                 } else {
451                     fprintf(stderr, "Unknown parameter: %s\n", ptr);
452                     userError();
453                 }
454
455                 ptr += strlen(ptr) - 1;
456                 break;
457
458             default:
459                 fprintf(stderr, "Unknown parameter: -%c\n", *ptr);
460                 userError();
461             }
462         }
463     }
464
465     // Prepare child arguments
466     if (i < argc) {
467         strncpy(config.target, argv[i], sizeof(config.target));
468         config.argv = argv + i - 1;
469         config.argc = argc - i;
470
471         // Shift argv array down one to make room for NULL
472         while (i < argc) {
473             argv[i - 1] = argv[i];
474             ++i;
475         }
476         argv[argc - 1] = NULL;
477
478         if (strrchr(config.target, '/'))
479             config.argv[0] = strrchr(config.target, '/') + 1;
480
481     } else {
482         config.argc = 0;
483         argv[argc - 1] = NULL;
484         config.argv = argv + argc - 1;
485     }
486
487     // Argument integrity checks
488     if (config.target[0] == '\0') {
489         if (config.use_attach)
490             fprintf(stderr, "Attach mode requries an image file in addition to process id.\n");
491         else
492             fprintf(stderr, "No directory or program specified.\n");
493         userError();
494     }
495
496     // Determine run mode, if necessary.
497     if (config.runMode != BATCH_FILE) {
498         errno = 0;
499         struct stat file_stat;
500         if (stat(config.target, &file_stat) != 0) {
501             fprintf(stderr, "Could not stat %s: %s\n", config.target, strerror(errno));
502             userError();
503         }
504
505         if ((file_stat.st_mode & S_IFMT) == S_IFDIR) {
506             // User specified a directory.
507             config.runMode = BATCH_DIRECTORY;
508
509         } else if ((file_stat.st_mode & S_IFMT) == S_IFREG) {
510             // User specified a file.
511             config.runMode = SINGLE_BINARY;
512
513         } else {
514             fprintf(stderr, "%s is not a directory or regular file. 0x%x\n", config.target, (file_stat.st_mode & S_IFMT));
515             userError();
516         }
517     }
518
519     // Catch run mode inconsistencies.
520     if (config.use_attach && config.runMode != SINGLE_BINARY) {
521         fprintf(stderr, "Attach flag cannot be used with batch mode.\n");
522         userError();
523     }
524
525     if (config.use_save_world && config.runMode != SINGLE_BINARY) {
526         fprintf(stderr, "Save-the-world cannot be used with batch mode.\n");
527         userError();
528     }
529
530     // Open output file descriptor.
531     if (config.output_file) {
532         errno = 0;
533         config.outfd = fopen(config.output_file, "w");
534         if (config.outfd == NULL) {
535             fprintf(stderr, "Could not open %s for writing: %s\n", config.output_file, strerror(errno));
536             userError();
537         }
538     }
539
540     if (config.runMode == BATCH_FILE && config.target[0] != '\0') {
541         fprintf(stderr, "Warning: Batch file specified.  Ignoring command line argument %s.\n", config.target);
542     }
543
544     // Create history record directory, if needed.
545     if (config.record_enabled) {
546         if (config.record_dir[0] == '\0') {
547             fprintf(stderr, "*\n* Environment variable HOME not defined.  Disabling history records.\n*\n");
548             config.record_enabled = false;
549
550         } else {
551             errno = 0;
552             struct stat dir_stat;
553             if (stat(config.record_dir, &dir_stat) < 0) {
554                 if (errno && errno == ENOENT) {
555                     errno = 0;
556                     mkdir(config.record_dir, S_IRUSR | S_IWUSR | S_IXUSR);
557                     if (errno) {
558                         fprintf(stderr, "Could not create directory '%s': %s\n", config.record_dir, strerror(errno));
559                         userError();
560                     }
561                 } else {
562                     fprintf(stderr, "Could not stat %s: %s\n", config.record_dir, strerror(errno));
563                     userError();
564                 }
565
566             } else if (!S_ISDIR(dir_stat.st_mode)) {
567                 fprintf(stderr, "%s exists, but is not a directory.  History record disabled.\n", config.record_dir);
568                 config.record_enabled = 0;
569             }
570         }
571     }
572
573     // Create named pipe, if needed.
574     if (config.trace_inst) {
575         if (config.pipe_filename[0] == '\0') {
576             fprintf(stderr, "*\n* Environment variable HOME not defined.  Disabling instrumentation tracing.\n*\n");
577             config.trace_inst = false;
578
579         } else {
580             int retval = -1;
581             for (int j = 0; retval < 0; ++j) {
582                 char *tmp_pipename = sprintf_static("%s.%d", config.pipe_filename, j);
583
584                 errno = 0;
585                 retval = mkfifo(tmp_pipename, S_IRUSR | S_IWUSR | S_IXUSR);
586                 if (errno) {
587                     if (errno == EEXIST) continue;
588                     fprintf(stderr, "Could not create named pipe '%s': %s\n", tmp_pipename, strerror(errno));
589                     userError();
590
591                 }
592                 strncpy(config.pipe_filename, tmp_pipename, sizeof(config.pipe_filename));
593             }
594         }
595     }
596
597     // Enforce parse/instrumentation relationships
598     if (config.inst_level >= INST_BASIC_BLOCK && config.parse_level < PARSE_CFG)
599         config.parse_level = PARSE_CFG;
600
601     if (config.inst_level >= INST_FUNC_ENTRY && config.parse_level < PARSE_FUNC)
602         config.parse_level = PARSE_FUNC;
603
604     // Skip .so files unless --include-libs flag is specified.
605     if (!config.include_libs) {
606         config.mod_rules.insert("\\.so", RULE_SKIP, false);
607         config.mod_rules.insert("\\.a$", RULE_SKIP, false);
608     }
609
610     if (config.no_fork && config.runMode != SINGLE_BINARY) {
611         fprintf(stderr, "Single (No-Fork) only compatible with a single binary mutatee.\n");
612         userError();
613     }
614 }
615
616 void usage(const char *progname)
617 {
618     fprintf(stderr, "Usage: %s [options] <dir | prog> [prog_args]\n\n", progname);
619     fprintf(stderr, "Options:\n");
620     fprintf(stderr, "  -a, --all, --include-libs\n");
621     fprintf(stderr, "    Include shared libraries as targets for parsing and instrumentation.\n");
622     fprintf(stderr, "\n");
623     fprintf(stderr, "  -c <filename>\n");
624     fprintf(stderr, "    Specifies batch mode configuration file.\n");
625     fprintf(stderr, "\n");
626     fprintf(stderr, "  -h\n");
627     fprintf(stderr, "    Enables history record logging.  Log files will be placed in:\n");
628     fprintf(stderr, "      %s/%s\n", getenv("HOME"), HISTORY_RECORD_DIR_DEFAULT);
629     fprintf(stderr, "\n");
630     fprintf(stderr, "  --help\n");
631     fprintf(stderr, "    Print this message.\n");
632     fprintf(stderr, "\n");
633     fprintf(stderr, "  -i <int>\n");
634     fprintf(stderr, "    Instrumentation level.  Valid parameters range from 0 to %d, where:\n", INST_MAX - 1);
635     fprintf(stderr, "      0 = No instrumentation\n");
636     fprintf(stderr, "      1 = Function entry instrumentation\n");
637     fprintf(stderr, "      2 = Function exit instrumentation\n");
638     fprintf(stderr, "      3 = Basic block instrumentation\n");
639     fprintf(stderr, "      4 = Memory read instrumentation\n");
640     fprintf(stderr, "      5 = Memory write instrumentation\n");
641     fprintf(stderr, "\n");
642     fprintf(stderr, "  -m, --merge-tramp\n");
643     fprintf(stderr, "    Merge mini-tramps into base-tramps for more efficent instrumentation.\n");
644     fprintf(stderr, "\n");
645     fprintf(stderr, "  -o <filename>\n");
646     fprintf(stderr, "    Send all output from monitor to specified file.\n");
647     fprintf(stderr, "    NOTE: Mutator and mutatee output will not be sent to file.\n");
648     fprintf(stderr, "\n");
649     fprintf(stderr, "  -p <int>\n");
650     fprintf(stderr, "    Parse level.  Valid parameters range from 0 to %d, where:\n", PARSE_MAX - 1);
651     fprintf(stderr, "      0 = Parse for module data\n");
652     fprintf(stderr, "      1 = Parse for function data\n");
653     fprintf(stderr, "      2 = Parse for control flow graph data\n");
654     fprintf(stderr, "\n");
655     fprintf(stderr, "  -P <int>, --pid=<int>\n");
656     fprintf(stderr, "    Attach to specified PID, instead of launching mutatee via fork()/exec().\n");
657     fprintf(stderr, "\n");
658     fprintf(stderr, "  -r\n");
659     fprintf(stderr, "    Descend into subdirectories when processing directories.\n");
660     fprintf(stderr, "\n");
661     fprintf(stderr, "  -s, --summary\n");
662     fprintf(stderr, "    Print values of counters allocated for instrumentation on mutatee exit.\n");
663     fprintf(stderr, "\n");
664     fprintf(stderr, "  -S\n");
665     fprintf(stderr, "    Single-process mode.  Do not fork before launching mutatee.\n");
666     fprintf(stderr, "    Used mainly for internal %s debugging.\n", progname);
667     fprintf(stderr, "\n");
668     fprintf(stderr, "  -t <seconds>\n");
669     fprintf(stderr, "    Time limit before monitor forcibly kills mutator and mutatee.\n");
670     fprintf(stderr, "\n");
671     fprintf(stderr, "  -T [count], --trace[=count]\n");
672     fprintf(stderr, "    Have mutatee report progress at each function entry or exit.\n");
673     fprintf(stderr, "    If count > 0, only last [count] trace points will be reported.\n");
674     fprintf(stderr, "\n");
675     fprintf(stderr, "  -v [int]\n");
676     fprintf(stderr, "    Increase verbose level.  Each -v encountered will increment level.\n");
677     fprintf(stderr, "    You may also provide a parameter from 0 to %d.  DEFAULT = %d\n", VERBOSE_MAX - 1, (int)INFO);
678     fprintf(stderr, "\n");
679     fprintf(stderr, "  -q\n");
680     fprintf(stderr, "    Decrement verbose level.\n");
681     fprintf(stderr, "\n");
682     fprintf(stderr, "  --use-transactions=<string>\n");
683     fprintf(stderr, "    Enable instrumentation transactions.  Valid parameters are:\n");
684     fprintf(stderr, "      func = Insert instrumentation once per function.\n");
685     fprintf(stderr, "      mod  = Insert instrumentation once per module.\n");
686     fprintf(stderr, "      proc = Insert instrumentation once per process.\n");
687     fprintf(stderr, "\n");
688     fprintf(stderr, "  --only-mod=<regex>\n");
689     fprintf(stderr, "  --only-func=<regex>\n");
690     fprintf(stderr, "    Only parse/instrument modules or functions that match the\n");
691     fprintf(stderr, "    specified basic regular expression.\n");
692     fprintf(stderr, "\n");
693     fprintf(stderr, "  --save-world=<filename>\n");
694     fprintf(stderr, "    Save mutatee to specified filename after instrumentation process.\n");
695     fprintf(stderr, "\n");
696     fprintf(stderr, "  --skip-mod=<regex>\n");
697     fprintf(stderr, "  --skip-func=<regex>\n");
698     fprintf(stderr, "    Do not parse/instrument modules or functions that match the\n");
699     fprintf(stderr, "    specified basic regular expression.\n");
700     fprintf(stderr, "\n");
701 }
702
703 void userError()
704 {
705     fprintf(stderr, "Use --help for list of valid parameters.\n");
706     exit(-1);
707 }