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