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