about summary refs log tree commit diff homepage
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile21
-rw-r--r--tools/gen-random-bout/Makefile7
-rw-r--r--tools/gen-random-bout/gen-random-bout.cpp124
-rw-r--r--tools/kleaver/Makefile19
-rw-r--r--tools/kleaver/main.cpp120
-rw-r--r--tools/klee-bout-tool/Makefile46
-rwxr-xr-xtools/klee-bout-tool/klee-bout-tool106
-rw-r--r--tools/klee/Debug.cpp12
-rw-r--r--tools/klee/Makefile22
-rw-r--r--tools/klee/main.cpp1422
10 files changed, 1899 insertions, 0 deletions
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644
index 00000000..8c3501da
--- /dev/null
+++ b/tools/Makefile
@@ -0,0 +1,21 @@
+#===-- tools/Makefile --------------------------------------*- Makefile -*--===#
+#
+#                     The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+#
+# Relative path to the top of the source tree.
+#
+LEVEL=..
+
+#
+# List all of the subdirectories that we will compile.
+#
+PARALLEL_DIRS=klee kleaver klee-bout-tool gen-random-bout
+# FIXME: Move qplayer functionality into kleaver
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/gen-random-bout/Makefile b/tools/gen-random-bout/Makefile
new file mode 100644
index 00000000..97315af2
--- /dev/null
+++ b/tools/gen-random-bout/Makefile
@@ -0,0 +1,7 @@
+##===- tools/klee/Makefile ---------------*- Makefile -*-===##
+
+LEVEL=../..
+TOOLNAME = gen-random-bout
+USEDLIBS = kleeBasic.a
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/gen-random-bout/gen-random-bout.cpp b/tools/gen-random-bout/gen-random-bout.cpp
new file mode 100644
index 00000000..044c3d24
--- /dev/null
+++ b/tools/gen-random-bout/gen-random-bout.cpp
@@ -0,0 +1,124 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "klee/Internal/ADT/BOut.h"
+
+// --sym-args 0 1 10 --sym-args 0 2 2 --sym-files 1 8 --sym-stdout
+static int getint(char *i) {
+  if(!i) {
+    fprintf(stderr, "ran out of arguments!\n");
+    assert(i);
+  }
+  return atoi(i);
+}
+
+#define MAX 64
+static void push_obj(BOut *b, const char *name, unsigned non_zero_bytes, 
+                     unsigned total_bytes) {
+  BOutObject *o = &b->objects[b->numObjects++];
+  assert(b->numObjects < MAX);
+
+  o->name = strdup(name);
+  o->numBytes = total_bytes;
+  o->bytes = (unsigned char *)malloc(o->numBytes);
+
+  unsigned i;
+  for(i = 0; i < non_zero_bytes; i++)
+    o->bytes[i] = random();
+
+  for(i = non_zero_bytes; i < total_bytes; i++)
+    o->bytes[i] = 0;
+}
+
+
+static void push_range(BOut *b, const char *name, unsigned value) {
+  BOutObject *o = &b->objects[b->numObjects++];
+  assert(b->numObjects < MAX);
+
+  o->name = strdup(name);
+  o->numBytes = 4;
+  o->bytes = (unsigned char *)malloc(o->numBytes);
+
+  *(unsigned*)o->bytes = value;
+}
+
+int main(int argc, char *argv[]) {
+  unsigned i, narg;
+  unsigned sym_stdout = 0;
+
+  if (argc < 2) {
+    fprintf(stderr, "Usage: %s <random-seed> <argument-types>\n", argv[0]);
+    fprintf(stderr, "       If <random-seed> is 0, time(NULL)*getpid() is used as a seed\n");
+    fprintf(stderr, "       <argument-types> are the ones accepted by KLEE: --sym-args, --sym-files etc.\n");
+    fprintf(stderr, "   Ex: %s 100 --sym-args 0 2 2 --sym-files 1 8\n", argv[0]);
+    exit(1);
+  }
+
+  unsigned seed = atoi(argv[1]);
+  if (seed)
+    srandom(seed);
+  else srandom(time(NULL) * getpid());
+
+  BOut b;
+  b.numArgs = argc;
+  b.args = argv;
+  b.symArgvs = 0;
+  b.symArgvLen = 0;
+
+  b.numObjects = 0;
+  b.objects = (BOutObject *)malloc(MAX * sizeof *b.objects);
+
+  for(i = 2; i < (unsigned)argc; i++) {
+    if(strcmp(argv[i], "--sym-args") == 0) {
+      unsigned lb = getint(argv[++i]);
+      unsigned ub = getint(argv[++i]);
+      unsigned nbytes = getint(argv[++i]);
+
+      narg = random() % (ub - lb) + lb;
+      push_range(&b, "range", narg);
+
+      while(narg-- > 0) {
+        unsigned x = random() % (nbytes + 1);
+
+        // A little different than how klee does it but more natural
+        // for random.
+        static int total_args;
+        char arg[1024];
+
+        sprintf(arg, "arg%d", total_args++);
+        push_obj(&b, arg, x, nbytes+1);
+      }
+    } else if(strcmp(argv[i], "--sym-stdout") == 0) {
+      if(!sym_stdout) {
+        sym_stdout = 1;
+        push_obj(&b, "stdout", 1024, 1024);
+        push_obj(&b, "stdout-stat", sizeof(struct stat64), 
+                 sizeof(struct stat64));
+      }
+    } else if(strcmp(argv[i], "--sym-files") == 0) {
+      unsigned nfiles = getint(argv[++i]);
+      unsigned nbytes = getint(argv[++i]);
+
+      while(nfiles-- > 0) {
+        push_obj(&b, "file", nbytes, nbytes);
+        push_obj(&b, "file-stat", sizeof(struct stat64), sizeof(struct stat64));
+      }
+
+      push_obj(&b, "stdin", nbytes, nbytes);
+      push_obj(&b, "stdin-stat", sizeof(struct stat64), sizeof(struct stat64));
+    } else {
+      fprintf(stderr, "unexpected option <%s>\n", argv[i]);
+      assert(0);
+    }
+  }
+
+  if (!bOut_toFile(&b, "file.bout"))
+    assert(0);
+  return 0;
+}
diff --git a/tools/kleaver/Makefile b/tools/kleaver/Makefile
new file mode 100644
index 00000000..283b5bef
--- /dev/null
+++ b/tools/kleaver/Makefile
@@ -0,0 +1,19 @@
+#===-- tools/kleaver/Makefile ------------------------------*- Makefile -*--===#
+#
+#                     The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+TOOLNAME = kleaver
+# FIXME: Ideally we wouldn't have any LLVM dependencies here, which
+# means kicking out klee's Support.
+USEDLIBS = kleaverExpr.a kleaverSolver.a kleeSupport.a kleeBasic.a
+LINK_COMPONENTS = support
+
+include $(LEVEL)/Makefile.common
+
+LIBS += -lstp
diff --git a/tools/kleaver/main.cpp b/tools/kleaver/main.cpp
new file mode 100644
index 00000000..621776ee
--- /dev/null
+++ b/tools/kleaver/main.cpp
@@ -0,0 +1,120 @@
+#include "expr/Lexer.h"
+#include "expr/Parser.h"
+
+#include "klee/Expr.h"
+#include "klee/Solver.h"
+#include "klee/util/ExprPPrinter.h"
+#include "klee/util/ExprVisitor.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/System/Signals.h"
+
+#include <iomanip>
+#include <sstream>
+
+using namespace llvm;
+using namespace klee;
+using namespace klee::expr;
+
+namespace {
+  llvm::cl::opt<std::string>
+  InputFile(llvm::cl::desc("<input query log>"), llvm::cl::Positional,
+            llvm::cl::init("-"));
+
+  enum ToolActions {
+    PrintTokens,
+    PrintAST
+  };
+
+  static llvm::cl::opt<ToolActions> 
+  ToolAction(llvm::cl::desc("Tool actions:"),
+             llvm::cl::init(PrintTokens),
+             llvm::cl::values(
+             clEnumValN(PrintTokens, "print-tokens",
+                        "Print tokens from the input file."),
+             clEnumValN(PrintAST, "print-ast",
+                        "Print parsed AST nodes from the input file."),
+             clEnumValEnd));
+}
+
+static std::string escapedString(const char *start, unsigned length) {
+  std::stringstream s;
+  for (unsigned i=0; i<length; ++i) {
+    char c = start[i];
+    if (isprint(c)) {
+      s << c;
+    } else if (c == '\n') {
+      s << "\\n";
+    } else {
+      s << "\\x" << hexdigit(((unsigned char) c >> 4) & 0xF) << hexdigit((unsigned char) c & 0xF);
+    }
+  }
+  return s.str();
+}
+
+static void PrintInputTokens(const MemoryBuffer *MB) {
+  Lexer L(MB);
+  Token T;
+  do {
+    L.Lex(T);
+    llvm::cout << "(Token \"" << T.getKindName() << "\" "
+               << "\"" << escapedString(T.start, T.length) << "\" "
+               << T.length << " "
+               << T.line << " " << T.column << ")\n";
+  } while (T.kind != Token::EndOfFile);
+}
+
+static bool PrintInputAST(const char *Filename,
+                          const MemoryBuffer *MB) {
+  Parser *P = Parser::Create(Filename, MB);
+  P->SetMaxErrors(20);
+  while (Decl *D = P->ParseTopLevelDecl()) {
+    if (!P->GetNumErrors())
+      D->dump();
+    delete D;
+  }
+
+  bool success = true;
+  if (unsigned N = P->GetNumErrors()) {
+    llvm::cerr << Filename << ": parse failure: "
+               << N << " errors.\n";
+    success = false;
+  }
+  delete P;
+
+  return success;
+}
+
+int main(int argc, char **argv) {
+  bool success = true;
+
+  llvm::sys::PrintStackTraceOnErrorSignal();
+  llvm::cl::ParseCommandLineOptions(argc, argv);
+
+  std::string ErrorStr;
+  MemoryBuffer *MB = MemoryBuffer::getFileOrSTDIN(InputFile.c_str(), &ErrorStr);
+  if (!MB) {
+    llvm::cerr << argv[0] << ": ERROR: " << ErrorStr << "\n";
+    return 1;
+  }
+
+  switch (ToolAction) {
+  case PrintTokens:
+    PrintInputTokens(MB);
+    break;
+  case PrintAST:
+    success = PrintInputAST(InputFile=="-" ? "<stdin>" : InputFile.c_str(), MB);
+    break;
+  default:
+    llvm::cerr << argv[0] << ": ERROR: Unknown program action!\n";
+  }
+
+  delete MB;
+
+  llvm::llvm_shutdown();
+  return success ? 0 : 1;
+}
diff --git a/tools/klee-bout-tool/Makefile b/tools/klee-bout-tool/Makefile
new file mode 100644
index 00000000..28e80841
--- /dev/null
+++ b/tools/klee-bout-tool/Makefile
@@ -0,0 +1,46 @@
+#===-- tools/klee-bout-tool/Makefile -----------------------*- Makefile -*--===#
+#
+#                     The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL = ../..
+
+TOOLSCRIPTNAME := klee-bout-tool
+
+include $(LEVEL)/Makefile.common
+
+# FIXME: Move this stuff (to "build" a script) into Makefile.rules.
+
+ToolBuildPath := $(ToolDir)/$(TOOLSCRIPTNAME)
+
+all-local:: $(ToolBuildPath)
+
+$(ToolBuildPath): $(ToolDir)/.dir
+
+$(ToolBuildPath): $(TOOLSCRIPTNAME)
+	$(Echo) Copying $(BuildMode) script $(TOOLSCRIPTNAME)
+	$(Verb) $(CP) -f $(TOOLSCRIPTNAME) "$@"
+	$(Verb) chmod 0755 "$@"
+
+ifdef NO_INSTALL
+install-local::
+	$(Echo) Install circumvented with NO_INSTALL
+uninstall-local::
+	$(Echo) Uninstall circumvented with NO_INSTALL
+else
+DestTool = $(PROJ_bindir)/$(TOOLSCRIPTNAME)
+
+install-local:: $(DestTool)
+
+$(DestTool): $(ToolBuildPath) $(PROJ_bindir)
+	$(Echo) Installing $(BuildMode) $(DestTool)
+	$(Verb) $(ProgInstall) $(ToolBuildPath) $(DestTool)
+
+uninstall-local::
+	$(Echo) Uninstalling $(BuildMode) $(DestTool)
+	-$(Verb) $(RM) -f $(DestTool)
+endif
diff --git a/tools/klee-bout-tool/klee-bout-tool b/tools/klee-bout-tool/klee-bout-tool
new file mode 100755
index 00000000..19c9e893
--- /dev/null
+++ b/tools/klee-bout-tool/klee-bout-tool
@@ -0,0 +1,106 @@
+#!/usr/bin/python
+
+import os
+import struct
+import sys
+
+version_no=2
+
+class BOutError(Exception):
+    pass
+
+class BOut:
+    @staticmethod
+    def fromfile(path):
+        if not os.path.exists(path):
+            print "ERROR: file %s not found" % (path)
+            sys.exit(1)
+            
+        f = open(path,'rb')
+        hdr = f.read(5)
+        if len(hdr)!=5 or hdr!='BOUT\n':
+            raise BOutError,'unrecognized file'
+        version, = struct.unpack('>i', f.read(4))
+        if version > version_no:
+            raise BOutError,'unrecognized version'
+        numArgs, = struct.unpack('>i', f.read(4))
+        args = []
+        for i in range(numArgs):
+            size, = struct.unpack('>i', f.read(4))
+            args.append(f.read(size))
+            
+        if version >= 2:
+            symArgvs, = struct.unpack('>i', f.read(4))
+            symArgvLen, = struct.unpack('>i', f.read(4))
+        else:
+            symArgvs = 0
+            symArgvLen = 0
+
+        numObjects, = struct.unpack('>i', f.read(4))
+        objects = []
+        for i in range(numObjects):
+            size, = struct.unpack('>i', f.read(4))
+            name = f.read(size)
+            size, = struct.unpack('>i', f.read(4))
+            bytes = f.read(size)
+            objects.append( (name,bytes) )
+
+        # Create an instance
+        b = BOut(version, args, symArgvs, symArgvLen, objects)
+        # Augment with extra filename field
+        b.filename = path
+        return b
+    
+    def __init__(self, version, args, symArgvs, symArgvLen, objects):
+        self.version = version
+        self.symArgvs = symArgvs
+        self.symArgvLen = symArgvLen
+        self.args = args
+        self.objects = objects
+
+        # add a field that represents the name of the program used to
+        # generate this .bout file:
+        program_full_path = self.args[0]
+        program_name = os.path.basename(program_full_path)
+        # sometimes program names end in .bc, so strip them
+        if program_name.endswith('.bc'):
+          program_name = program_name[:-3]
+        self.programName = program_name
+        
+def trimZeros(str):
+    for i in range(len(str))[::-1]:
+        if str[i] != '\x00':
+            return str[:i+1]
+    return ''
+    
+def main(args):
+    from optparse import OptionParser
+    op = OptionParser("usage: %prog [options] files")
+    op.add_option('','--trim-zeros', dest='trimZeros', action='store_true', 
+                  default=False,
+                  help='trim trailing zeros')
+    
+    opts,args = op.parse_args()
+    if not args:
+        op.error("incorrect number of arguments")
+
+    for file in args:
+        b = BOut.fromfile(file)
+        pos = 0
+        print 'bout file  : %r' % file
+        print 'args       : %r' % b.args
+        print 'num objects: %r' % len(b.objects)
+        for i,(name,data) in enumerate(b.objects):
+            if opts.trimZeros:
+                str = trimZeros(data)
+            else:
+                str = data
+
+            print 'object %4d: name: %r' % (i, name)
+            print 'object %4d: size: %r' % (i, len(data))
+            print 'object %4d: data: %r' % (i, str)
+        if file != args[-1]:
+            print
+
+if __name__=='__main__':
+    main(sys.argv)
diff --git a/tools/klee/Debug.cpp b/tools/klee/Debug.cpp
new file mode 100644
index 00000000..d11a79a7
--- /dev/null
+++ b/tools/klee/Debug.cpp
@@ -0,0 +1,12 @@
+#include <klee/Expr.h>
+#include <iostream>
+
+void kdb_printExpr(klee::Expr *e) {
+  llvm::cerr << "expr: " << e << " -- ";
+  if (e) {
+    llvm::cerr << *e;
+  } else {
+    llvm::cerr << "(null)";
+  }
+  llvm::cerr << "\n";
+}
diff --git a/tools/klee/Makefile b/tools/klee/Makefile
new file mode 100644
index 00000000..b556175d
--- /dev/null
+++ b/tools/klee/Makefile
@@ -0,0 +1,22 @@
+#===-- tools/klee/Makefile ---------------------------------*- Makefile -*--===#
+#
+#                     The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+TOOLNAME = klee
+USEDLIBS = kleeCore.a kleeModule.a kleaverSolver.a kleaverExpr.a kleeSupport.a kleeBasic.a
+LINK_COMPONENTS = bitreader bitwriter ipo linker engine
+
+include $(LEVEL)/Makefile.common
+
+ifeq ($(ENABLE_STPLOG), 1)
+	LIBS += -lstplog
+endif
+
+LIBS += -lstp 
+#-ltcmalloc
diff --git a/tools/klee/main.cpp b/tools/klee/main.cpp
new file mode 100644
index 00000000..39b208ec
--- /dev/null
+++ b/tools/klee/main.cpp
@@ -0,0 +1,1422 @@
+/* -*- mode: c++; c-basic-offset: 2; -*- */
+
+// FIXME: This does not belong here.
+#include "../lib/Core/Common.h"
+
+#include "klee/ExecutionState.h"
+#include "klee/Expr.h"
+#include "klee/Interpreter.h"
+#include "klee/Statistics.h"
+#include "klee/Config/config.h"
+#include "klee/Internal/ADT/BOut.h"
+#include "klee/Internal/ADT/TreeStream.h"
+#include "klee/Internal/Support/ModuleUtil.h"
+#include "klee/Internal/System/Time.h"
+
+#include "llvm/Constants.h"
+#include "llvm/Module.h"
+#include "llvm/ModuleProvider.h"
+#include "llvm/Type.h"
+#include "llvm/InstrTypes.h"
+#include "llvm/Instruction.h"
+#include "llvm/Instructions.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Signals.h"
+#include <iostream>
+#include <fstream>
+#include <cerrno>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include <iostream>
+#include <iterator>
+#include <fstream>
+#include <sstream>
+
+using namespace llvm;
+using namespace klee;
+
+namespace {
+  cl::opt<std::string>
+  InputFile(cl::desc("<input bytecode>"), cl::Positional, cl::init("-"));
+
+  cl::opt<std::string>
+  RunInDir("run-in", cl::desc("Change to the given directory prior to executing"));
+
+  cl::opt<std::string>
+  Environ("environ", cl::desc("Parse environ from given file (in \"env\" format)"));
+
+  cl::list<std::string>
+  InputArgv(cl::ConsumeAfter, 
+            cl::desc("<program arguments>..."));
+
+  cl::opt<bool>
+  NoOutput("no-output", 
+           cl::desc("Don't generate test files"));
+    
+  cl::opt<bool>
+  WarnAllExternals("warn-all-externals", 
+                   cl::desc("Give initial warning for all externals."));
+    
+  cl::opt<bool>
+  WriteCVCs("write-cvcs", 
+            cl::desc("Write .cvc files for each test case"));
+
+  cl::opt<bool>
+  WritePCs("write-pcs", 
+            cl::desc("Write .pc files for each test case"));
+  
+  cl::opt<bool>
+  WriteCov("write-cov", 
+           cl::desc("Write coverage information for each test case"));
+  
+  cl::opt<bool>
+  WriteTestInfo("write-test-info", 
+                cl::desc("Write additional test case information"));
+  
+  cl::opt<bool>
+  WritePaths("write-paths", 
+                cl::desc("Write .path files for each test case"));
+    
+  cl::opt<bool>
+  WriteSymPaths("write-sym-paths", 
+                cl::desc("Write .sym.path files for each test case"));
+    
+  cl::opt<bool>
+  ExitOnError("exit-on-error", 
+              cl::desc("Exit if errors occur"));
+    
+
+  enum LibcType {
+    NoLibc, KleeLibc, UcLibc
+  };
+
+  cl::opt<LibcType>
+  Libc("libc", 
+       cl::desc("Choose libc version (none by default)."),
+       cl::values(clEnumValN(NoLibc, "none", "Don't link in a libc"),
+                  clEnumValN(KleeLibc, "klee", "Link in klee libc"),
+		  clEnumValN(UcLibc, "uclibc", "Link in uclibc (adapted for klee)"),
+		  clEnumValEnd),
+       cl::init(NoLibc));
+
+    
+  cl::opt<bool>
+  WithPOSIXRuntime("posix-runtime", 
+		cl::desc("Link with POSIX runtime"),
+		cl::init(false));
+    
+  cl::opt<bool>
+  OptimizeModule("optimize", 
+                 cl::desc("Optimize before execution"));
+
+  cl::opt<bool>
+  CheckDivZero("check-div-zero", 
+               cl::desc("Inject checks for division-by-zero"),
+               cl::init(true));
+    
+  cl::opt<std::string>
+  OutputDir("output-dir", 
+            cl::desc("Directory to write results in (defaults to klee-out-N)"),
+            cl::init(""));
+
+  // this is a fake entry, its automagically handled
+  cl::list<std::string>
+  ReadArgsFilesFake("read-args", 
+                    cl::desc("File to read arguments from (one arg per line)"));
+    
+  cl::opt<bool>
+  ReplayKeepSymbolic("replay-keep-symbolic", 
+                     cl::desc("Replay the test cases only by asserting"
+                              "the bytes, not necessarily making them concrete."));
+    
+  cl::list<std::string>
+  ReplayOutFile("replay-out",
+                cl::desc("Specify an out file to replay"),
+                cl::value_desc("out file"));
+
+  cl::list<std::string>
+  ReplayOutDir("replay-out-dir",
+	       cl::desc("Specify a directory to replay .out files from"),
+	       cl::value_desc("output directory"));
+
+  cl::opt<std::string>
+  ReplayPathFile("replay-path",
+                 cl::desc("Specify a path file to replay"),
+                 cl::value_desc("path file"));
+
+  cl::list<std::string>
+  SeedOutFile("seed-out");
+  
+  cl::list<std::string>
+  SeedOutDir("seed-out-dir");
+  
+  cl::opt<unsigned>
+  MakeConcreteSymbolic("make-concrete-symbolic",
+                       cl::desc("Rate at which to make concrete reads symbolic (0=off)"),
+                       cl::init(0));
+
+  cl::opt<bool>
+  InitEnv("init-env",
+	  cl::desc("Create custom environment.  Options that can be passed as arguments to the programs are: --sym-argv <max-len>  --sym-argvs <min-argvs> <max-argvs> <max-len> + file model options"));
+ 
+  cl::opt<unsigned>
+  StopAfterNTests("stop-after-n-tests",
+	     cl::desc("Stop execution after generating the given number of tests.  Extra tests corresponding to partially explored paths will also be dumped."),
+	     cl::init(0));
+
+  cl::opt<bool>
+  Watchdog("watchdog",
+           cl::desc("Use a watchdog process to enforce --max-time."),
+           cl::init(0));
+}
+
+extern bool WriteTraces;
+extern cl::opt<double> MaxTime;
+
+/***/
+
+class KleeHandler : public InterpreterHandler {
+private:
+  Interpreter *m_interpreter;
+  TreeStreamWriter *m_pathWriter, *m_symPathWriter;
+  std::ostream *m_infoFile;
+
+  char m_outputDirectory[1024];
+  unsigned m_testIndex;  // number of tests written so far
+  unsigned m_pathsExplored; // number of paths explored so far
+
+  // used for writing .bout files
+  int m_argc;
+  char **m_argv;
+
+public:
+  KleeHandler(int argc, char **argv);
+  ~KleeHandler();
+
+  std::ostream &getInfoStream() const { return *m_infoFile; }
+  unsigned getNumTestCases() { return m_testIndex; }
+  unsigned getNumPathsExplored() { return m_pathsExplored; }
+  void incPathsExplored() { m_pathsExplored++; }
+
+  void setInterpreter(Interpreter *i);
+
+  void processTestCase(const ExecutionState  &state,
+                       const char *errorMessage, 
+                       const char *errorSuffix);
+
+  std::string getOutputFilename(const std::string &filename);
+  std::ostream *openOutputFile(const std::string &filename);
+  std::string getTestFilename(const std::string &suffix, unsigned id);
+  std::ostream *openTestFile(const std::string &suffix, unsigned id);
+
+  // load a .out file
+  static void loadOutFile(std::string name, 
+                          std::vector<unsigned char> &buffer);
+
+  // load a .path file
+  static void loadPathFile(std::string name, 
+                           std::vector<bool> &buffer);
+
+  static void getOutFiles(std::string path,
+			  std::vector<std::string> &results);
+};
+
+KleeHandler::KleeHandler(int argc, char **argv) 
+  : m_interpreter(0),
+    m_pathWriter(0),
+    m_symPathWriter(0),
+    m_infoFile(0),
+    m_testIndex(0),
+    m_pathsExplored(0),
+    m_argc(argc),
+    m_argv(argv) {
+  std::string theDir;
+
+  if (OutputDir=="") {
+    llvm::sys::Path directory(InputFile);
+    std::string dirname = "";
+    directory.eraseComponent();
+    
+    if (directory.isEmpty())
+      directory.set(".");
+    
+    for (int i = 0; ; i++) {
+      char buf[256], tmp[64];
+      sprintf(tmp, "klee-out-%d", i);
+      dirname = tmp;
+      sprintf(buf, "%s/%s", directory.c_str(), tmp);
+      theDir = buf;
+      
+      if (DIR *dir = opendir(theDir.c_str())) {
+        closedir(dir);
+      } else {
+        break;
+      }
+    }    
+
+    llvm::cerr << "KLEE: output directory = \"" << dirname << "\"\n";
+
+    llvm::sys::Path klee_last(directory);
+    klee_last.appendComponent("klee-last");
+      
+    if ((unlink(klee_last.c_str()) < 0) && (errno != ENOENT)) {
+      perror("Cannot unlink klee-last");
+      assert(0 && "exiting.");
+    }
+    
+    if (symlink(dirname.c_str(), klee_last.c_str()) < 0) {
+      perror("Cannot make symlink");
+      assert(0 && "exiting.");
+    }
+  } else {
+    theDir = OutputDir;
+  }
+  
+  sys::Path p(theDir);
+  if (!p.isAbsolute()) {
+    sys::Path cwd = sys::Path::GetCurrentDirectory();
+    cwd.appendComponent(theDir);
+    p = cwd;
+  }
+  strcpy(m_outputDirectory, p.c_str());
+
+  if (mkdir(m_outputDirectory, 0775) < 0) {
+    llvm::cerr << "KLEE: ERROR: Unable to make output directory: \"" 
+               << m_outputDirectory 
+               << "\", refusing to overwrite.\n";
+    exit(1);
+  }
+
+  char fname[1024];
+  snprintf(fname, sizeof(fname), "%s/warnings.txt", m_outputDirectory);
+  klee_warning_file = fopen(fname, "w");
+  assert(klee_warning_file);
+
+  snprintf(fname, sizeof(fname), "%s/messages.txt", m_outputDirectory);
+  klee_message_file = fopen(fname, "w");
+  assert(klee_message_file);
+
+  m_infoFile = openOutputFile("info");
+}
+
+KleeHandler::~KleeHandler() {
+  if (m_pathWriter) delete m_pathWriter;
+  if (m_symPathWriter) delete m_symPathWriter;
+  delete m_infoFile;
+}
+
+void KleeHandler::setInterpreter(Interpreter *i) {
+  m_interpreter = i;
+
+  if (WritePaths) {
+    m_pathWriter = new TreeStreamWriter(getOutputFilename("paths.ts"));
+    assert(m_pathWriter->good());
+    m_interpreter->setPathWriter(m_pathWriter);
+  }
+
+  if (WriteSymPaths) {
+    m_symPathWriter = new TreeStreamWriter(getOutputFilename("symPaths.ts"));
+    assert(m_symPathWriter->good());
+    m_interpreter->setSymbolicPathWriter(m_symPathWriter);
+  }
+}
+
+std::string KleeHandler::getOutputFilename(const std::string &filename) {
+  char outfile[1024];
+  sprintf(outfile, "%s/%s", m_outputDirectory, filename.c_str());
+  return outfile;
+}
+
+std::ostream *KleeHandler::openOutputFile(const std::string &filename) {
+  std::ios::openmode io_mode = std::ios::out | std::ios::trunc 
+                             | std::ios::binary;
+  std::ostream *f;
+  std::string path = getOutputFilename(filename);
+  f = new std::ofstream(path.c_str(), io_mode);
+  if (!f) {
+    klee_warning("out of memory");
+  } else if (!f->good()) {
+    klee_warning("error opening: %s", filename.c_str());
+    delete f;
+    f = NULL;
+  }
+
+  return f;
+}
+
+std::string KleeHandler::getTestFilename(const std::string &suffix, unsigned id) {
+  char filename[1024];
+  sprintf(filename, "test%06d.%s", id, suffix.c_str());
+  return getOutputFilename(filename);
+}
+
+std::ostream *KleeHandler::openTestFile(const std::string &suffix, unsigned id) {
+  char filename[1024];
+  sprintf(filename, "test%06d.%s", id, suffix.c_str());
+  return openOutputFile(filename);
+}
+
+
+/* Outputs all files (.bout, .pc, .cov etc.) describing a test case */
+void KleeHandler::processTestCase(const ExecutionState &state,
+                                  const char *errorMessage, 
+                                  const char *errorSuffix) {
+  if (errorMessage && ExitOnError) {
+    llvm::cerr << "EXITING ON ERROR: " << errorMessage << "\n";
+    abort();
+  }
+
+  if (!NoOutput) {
+    std::vector< std::pair<std::string, std::vector<unsigned char> > > out;
+    bool success = m_interpreter->getSymbolicSolution(state, out);
+
+    if (!success)
+      klee_warning("unable to get symbolic solution, losing test case");
+
+    double start_time = util::getWallTime();
+
+    unsigned id = ++m_testIndex;
+
+    if (success) {
+      BOut b;      
+      b.numArgs = m_argc;
+      b.args = m_argv;
+      b.symArgvs = 0;
+      b.symArgvLen = 0;
+      b.numObjects = out.size();
+      b.objects = new BOutObject[b.numObjects];
+      assert(b.objects);
+      for (unsigned i=0; i<b.numObjects; i++) {
+        BOutObject *o = &b.objects[i];
+        o->name = const_cast<char*>(out[i].first.c_str());
+        o->numBytes = out[i].second.size();
+        o->bytes = new unsigned char[o->numBytes];
+        assert(o->bytes);
+        std::copy(out[i].second.begin(), out[i].second.end(), o->bytes);
+      }
+      
+      if (!bOut_toFile(&b, getTestFilename("bout", id).c_str())) {
+        klee_warning("unable to write output test case, losing it");
+      }
+      
+      for (unsigned i=0; i<b.numObjects; i++)
+        delete[] b.objects[i].bytes;
+      delete[] b.objects;
+    }
+
+    if (errorMessage) {
+      std::ostream *f = openTestFile(errorSuffix, id);
+      *f << errorMessage;
+      delete f;
+    }
+    
+    if (m_pathWriter) {
+      std::vector<unsigned char> concreteBranches;
+      m_pathWriter->readStream(m_interpreter->getPathStreamID(state),
+                               concreteBranches);
+      std::ostream *f = openTestFile("path", id);
+      std::copy(concreteBranches.begin(), concreteBranches.end(), 
+                std::ostream_iterator<unsigned char>(*f, "\n"));
+      delete f;
+    }
+   
+    if (errorMessage || WritePCs) {
+      std::string constraints;
+      m_interpreter->getConstraintLog(state, constraints);
+      std::ostream *f = openTestFile("pc", id);
+      *f << constraints;
+      delete f;
+    }
+
+    if (WriteCVCs) {
+      std::string constraints;
+      m_interpreter->getConstraintLog(state, constraints, true);
+      std::ostream *f = openTestFile("cvc", id);
+      *f << constraints;
+      delete f;
+    }
+    
+    if (m_symPathWriter) {
+      std::vector<unsigned char> symbolicBranches;
+      m_symPathWriter->readStream(m_interpreter->getSymbolicPathStreamID(state),
+                                  symbolicBranches);
+      std::ostream *f = openTestFile("sym.path", id);
+      std::copy(symbolicBranches.begin(), symbolicBranches.end(), 
+                std::ostream_iterator<unsigned char>(*f, "\n"));
+      delete f;
+    }
+
+    if (WriteCov) {
+      std::map<const std::string*, std::set<unsigned> > cov;
+      m_interpreter->getCoveredLines(state, cov);
+      std::ostream *f = openTestFile("cov", id);
+      for (std::map<const std::string*, std::set<unsigned> >::iterator
+             it = cov.begin(), ie = cov.end();
+           it != ie; ++it) {
+        for (std::set<unsigned>::iterator
+               it2 = it->second.begin(), ie = it->second.end();
+             it2 != ie; ++it2)
+          *f << *it->first << ":" << *it2 << "\n";
+      }
+      delete f;
+    }
+
+    if (WriteTraces) {
+      std::ostream *f = openTestFile("trace", id);
+      state.exeTraceMgr.printAllEvents(*f);
+      delete f;
+    }
+
+    if (m_testIndex == StopAfterNTests)
+      m_interpreter->setHaltExecution(true);
+
+    if (WriteTestInfo) {
+      double elapsed_time = util::getWallTime() - start_time;
+      std::ostream *f = openTestFile("info", id);
+      *f << "Time to generate test case: " 
+         << elapsed_time << "s\n";
+      delete f;
+    }
+  }
+}
+
+  // load a .path file
+void KleeHandler::loadPathFile(std::string name, 
+                                     std::vector<bool> &buffer) {
+  std::ifstream f(name.c_str(), std::ios::in | std::ios::binary);
+
+  if (!f.good())
+    assert(0 && "unable to open path file");
+
+  while (f.good()) {
+    unsigned value;
+    f >> value;
+    buffer.push_back(!!value);
+    f.get();
+  }
+}
+
+void KleeHandler::getOutFiles(std::string path,
+			      std::vector<std::string> &results) {
+  llvm::sys::Path p(path);
+  std::set<llvm::sys::Path> contents;
+  std::string error;
+  if (p.getDirectoryContents(contents, &error)) {
+    llvm::cerr << "ERROR: unable to read output directory: " << path << ": " << error << "\n";
+    exit(1);
+  }
+  for (std::set<llvm::sys::Path>::iterator it = contents.begin(),
+         ie = contents.end(); it != ie; ++it) {
+    std::string f = it->toString();
+    if (f.substr(f.size()-5,f.size()) == ".bout") {
+      results.push_back(f);
+    }
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// main Driver function
+//
+#if ENABLE_STPLOG == 1
+extern "C" void STPLOG_init(const char *);
+#endif
+
+static std::string strip(std::string &in) {
+  unsigned len = in.size();
+  unsigned lead = 0, trail = len;
+  while (lead<len && isspace(in[lead]))
+    ++lead;
+  while (trail>lead && isspace(in[trail-1]))
+    --trail;
+  return in.substr(lead, trail-lead);
+}
+
+static void readArgumentsFromFile(char *file, std::vector<std::string> &results) {
+  std::ifstream f(file);
+  assert(f.is_open() && "unable to open input for reading arguments");
+  while (!f.eof()) {
+    std::string line;
+    std::getline(f, line);
+    line = strip(line);
+    if (!line.empty())
+      results.push_back(line);
+  }
+  f.close();
+}
+
+static void parseArguments(int argc, char **argv) {
+  std::vector<std::string> arguments;
+
+  for (int i=1; i<argc; i++) {
+    if (!strcmp(argv[i],"--read-args") && i+1<argc) {
+      readArgumentsFromFile(argv[++i], arguments);
+    } else {
+      arguments.push_back(argv[i]);
+    }
+  }
+    
+  int numArgs = arguments.size() + 1;
+  const char **argArray = new const char*[numArgs+1];
+  argArray[0] = argv[0];
+  argArray[numArgs] = 0;
+  for (int i=1; i<numArgs; i++) {
+    argArray[i] = arguments[i-1].c_str();
+  }
+
+  cl::ParseCommandLineOptions(numArgs, (char**) argArray, " klee\n");
+  delete[] argArray;
+}
+
+
+
+static int initEnv(Module *mainModule) {
+
+  /*
+    nArgcP = alloc oldArgc->getType()
+    nArgvV = alloc oldArgv->getType()
+    store oldArgc nArgcP
+    store oldArgv nArgvP
+    klee_init_environment(nArgcP, nArgvP)
+    nArgc = load nArgcP
+    nArgv = load nArgvP
+    oldArgc->replaceAllUsesWith(nArgc)
+    oldArgv->replaceAllUsesWith(nArgv)
+  */
+
+  Function *mainFn = mainModule->getFunction("main");
+    
+  if (mainFn->arg_size() < 2) {
+    llvm::cerr << "Cannot handle ""-init-env"" when main() has less than two arguments.\n";
+    return -1;
+  }
+
+  Instruction* firstInst = mainFn->begin()->begin();
+
+  Value* oldArgc = mainFn->arg_begin();
+  Value* oldArgv = ++mainFn->arg_begin();
+  
+  AllocaInst* argcPtr = new AllocaInst(oldArgc->getType(), "argcPtr", firstInst);
+  AllocaInst* argvPtr = new AllocaInst(oldArgv->getType(), "argvPtr", firstInst);
+
+  /* Insert void klee_init_env(int* argc, char*** argv) */
+  std::vector<const Type*> params;
+  params.push_back(Type::Int32Ty);
+  params.push_back(Type::Int32Ty);
+  Function* initEnvFn = 
+    cast<Function>(mainModule->getOrInsertFunction("klee_init_env",
+                                                   Type::VoidTy,
+                                                   argcPtr->getType(),
+                                                   argvPtr->getType(),
+                                                   NULL));
+  assert(initEnvFn);    
+  std::vector<Value*> args;
+  args.push_back(argcPtr);
+  args.push_back(argvPtr);
+  Instruction* initEnvCall = CallInst::Create(initEnvFn, args.begin(), args.end(), 
+					      "", firstInst);
+  Value *argc = new LoadInst(argcPtr, "newArgc", firstInst);
+  Value *argv = new LoadInst(argvPtr, "newArgv", firstInst);
+  
+  oldArgc->replaceAllUsesWith(argc);
+  oldArgv->replaceAllUsesWith(argv);
+
+  new StoreInst(oldArgc, argcPtr, initEnvCall);
+  new StoreInst(oldArgv, argvPtr, initEnvCall);
+
+  return 0;
+}
+
+
+// This is a terrible hack until we get some real modelling of the
+// system. All we do is check the undefined symbols and m and warn about
+// any "unrecognized" externals and about any obviously unsafe ones.
+
+// Symbols we explicitly support
+static const char *modelledExternals[] = {
+  "_ZTVN10__cxxabiv117__class_type_infoE",
+  "_ZTVN10__cxxabiv120__si_class_type_infoE",
+  "_ZTVN10__cxxabiv121__vmi_class_type_infoE",
+
+  // special functions
+  "_assert", 
+  "__assert_fail", 
+  "__assert_rtn", 
+  "calloc", 
+  "_exit", 
+  "exit", 
+  "free", 
+  "abort", 
+  "klee_abort", 
+  "klee_assume", 
+  "klee_check_memory_access",
+  "klee_define_fixed_object",
+  "klee_get_errno", 
+  "klee_get_value",
+  "klee_get_obj_size", 
+  "klee_is_symbolic", 
+  "klee_make_symbolic_name", 
+  "klee_mark_global", 
+  "klee_malloc_n", 
+  "klee_merge", 
+  "klee_prefer_cex",
+  "klee_print_expr", 
+  "klee_print_range", 
+  "klee_report_error", 
+  "klee_revirt_objects", 
+  "klee_set_forking",
+  "klee_silent_exit", 
+  "klee_under_constrained", 
+  "klee_warning", 
+  "klee_warning_once", 
+  "klee_alias_function",
+  "llvm.dbg.stoppoint", 
+  "llvm.va_start", 
+  "llvm.va_end", 
+  "malloc", 
+  "realloc", 
+  "_ZdaPv", 
+  "_ZdlPv", 
+  "_Znaj", 
+  "_Znwj", 
+  "_Znam", 
+  "_Znwm", 
+};
+// Symbols we aren't going to warn about
+static const char *dontCareExternals[] = {
+#if 0
+  // stdio
+  "fprintf",
+  "fflush",
+  "fopen",
+  "fclose",
+  "fputs_unlocked",
+  "putchar_unlocked",
+  "vfprintf",
+  "fwrite",
+  "puts",
+  "printf",
+  "stdin",
+  "stdout",
+  "stderr",
+  "_stdio_term",
+  "__errno_location",
+  "fstat",
+#endif
+
+  // static information, pretty ok to return
+  "getegid",
+  "geteuid",
+  "getgid",
+  "getuid",
+  "getpid",
+  "gethostname",
+  "getpgrp",
+  "getppid",
+  "getpagesize",
+  "getpriority",
+  "getgroups",
+  "getdtablesize",
+  "getrlimit",
+  "getrlimit64",
+  "getcwd",
+  "getwd",
+  "gettimeofday",
+  "uname",
+
+  // fp stuff we just don't worry about yet
+  "frexp",  
+  "ldexp",
+  "__isnan",
+  "__signbit",
+};
+// Extra symbols we aren't going to warn about with klee-libc
+static const char *dontCareKlee[] = {
+  "__ctype_b_loc",
+  "__ctype_get_mb_cur_max",
+
+  // io system calls
+  "open",
+  "write",
+  "read",
+  "close",
+};
+// Extra symbols we aren't going to warn about with uclibc
+static const char *dontCareUclibc[] = {
+  "__dso_handle",
+
+  // Don't warn about these since we explicitly commented them out of
+  // uclibc.
+  "printf",
+  "vprintf"
+};
+// Symbols we consider unsafe
+static const char *unsafeExternals[] = {
+  "fork", // oh lord
+  "exec", // heaven help us
+  "error", // calls _exit
+  "raise", // yeah
+  "kill", // mmmhmmm
+};
+#define NELEMS(array) (sizeof(array)/sizeof(array[0]))
+void externalsAndGlobalsCheck(const Module *m) {
+  std::map<std::string, bool> externals;
+  std::set<std::string> modelled(modelledExternals, 
+                                 modelledExternals+NELEMS(modelledExternals));
+  std::set<std::string> dontCare(dontCareExternals, 
+                                 dontCareExternals+NELEMS(dontCareExternals));
+  std::set<std::string> unsafe(unsafeExternals, 
+                               unsafeExternals+NELEMS(unsafeExternals));
+
+  switch (Libc) {
+  case KleeLibc: 
+    dontCare.insert(dontCareKlee, dontCareKlee+NELEMS(dontCareKlee));
+    break;
+  case UcLibc:
+    dontCare.insert(dontCareUclibc,
+                    dontCareUclibc+NELEMS(dontCareUclibc));
+    break;
+  case NoLibc: /* silence compiler warning */
+    break;
+  }
+  
+
+  if (WithPOSIXRuntime)
+    dontCare.insert("syscall");
+
+  for (Module::const_iterator fnIt = m->begin(), fn_ie = m->end(); 
+       fnIt != fn_ie; ++fnIt) {
+    if (fnIt->isDeclaration() && !fnIt->use_empty())
+      externals.insert(std::make_pair(fnIt->getName(), false));
+    for (Function::const_iterator bbIt = fnIt->begin(), bb_ie = fnIt->end(); 
+         bbIt != bb_ie; ++bbIt) {
+      for (BasicBlock::const_iterator it = bbIt->begin(), ie = bbIt->end(); 
+           it != it; ++it) {
+        if (const CallInst *ci = dyn_cast<CallInst>(it)) {
+          if (isa<InlineAsm>(ci->getCalledValue())) {
+            klee_warning_once(&*fnIt,
+                              "function \"%s\" has inline asm", 
+                              fnIt->getName().c_str());
+          }
+        }
+      }
+    }
+  }
+  for (Module::const_global_iterator 
+         it = m->global_begin(), ie = m->global_end(); 
+       it != ie; ++it)
+    if (it->isDeclaration() && !it->use_empty())
+      externals.insert(std::make_pair(it->getName(), true));
+  // and remove aliases (they define the symbol after global
+  // initialization)
+  for (Module::const_alias_iterator 
+         it = m->alias_begin(), ie = m->alias_end(); 
+       it != ie; ++it) {
+    std::map<std::string, bool>::iterator it2 = 
+      externals.find(it->getName());
+    if (it2!=externals.end())
+      externals.erase(it2);
+  }
+
+  std::map<std::string, bool> foundUnsafe;
+  for (std::map<std::string, bool>::iterator
+         it = externals.begin(), ie = externals.end();
+       it != ie; ++it) {
+    const std::string &ext = it->first;
+    if (!modelled.count(ext) && (WarnAllExternals || 
+                                 !dontCare.count(ext))) {
+      if (unsafe.count(ext)) {
+        foundUnsafe.insert(*it);
+      } else {
+        klee_warning("undefined reference to %s: %s",
+                     it->second ? "variable" : "function",
+                     ext.c_str());
+      }
+    }
+  }
+
+  for (std::map<std::string, bool>::iterator
+         it = foundUnsafe.begin(), ie = foundUnsafe.end();
+       it != ie; ++it) {
+    const std::string &ext = it->first;
+    klee_warning("undefined reference to %s: %s (UNSAFE)!",
+                 it->second ? "variable" : "function",
+                 ext.c_str());
+  }
+}
+
+static Interpreter *theInterpreter = 0;
+
+static bool interrupted = false;
+
+// Pulled out so it can be easily called from a debugger.
+extern "C"
+void halt_execution() {
+  theInterpreter->setHaltExecution(true);
+}
+
+extern "C"
+void stop_forking() {
+  theInterpreter->setInhibitForking(true);
+}
+
+static void interrupt_handle() {
+  if (!interrupted && theInterpreter) {
+    llvm::cerr << "KLEE: ctrl-c detected, requesting interpreter to halt.\n";
+    halt_execution();
+    sys::SetInterruptFunction(interrupt_handle);
+  } else {
+    llvm::cerr << "KLEE: ctrl-c detected, exiting.\n";
+    exit(1);
+  }
+  interrupted = true;
+}
+
+// This is a temporary hack. If the running process has access to
+// externals then it can disable interrupts, which screws up the
+// normal "nice" watchdog termination process. We try to request the
+// interpreter to halt using this mechanism as a last resort to save
+// the state data before going ahead and killing it.
+static void halt_via_gdb(int pid) {
+  char buffer[256];
+  sprintf(buffer, 
+          "gdb --batch --eval-command=\"p halt_execution()\" "
+          "--eval-command=detach --pid=%d &> /dev/null",
+          pid);
+  //  fprintf(stderr, "KLEE: WATCHDOG: running: %s\n", buffer);
+  if (system(buffer)==-1) 
+    perror("system");
+}
+
+// returns the end of the string put in buf
+static char *format_tdiff(char *buf, long seconds)
+{
+  assert(seconds >= 0);
+
+  long minutes = seconds / 60;  seconds %= 60;
+  long hours   = minutes / 60;  minutes %= 60;
+  long days    = hours   / 24;  hours   %= 24;
+
+  buf = strrchr(buf, '\0');
+  if (days > 0) buf += sprintf(buf, "%ld days, ", days);
+  buf += sprintf(buf, "%02ld:%02ld:%02ld", hours, minutes, seconds);
+  return buf;
+}
+
+#ifndef KLEE_UCLIBC
+static llvm::Module *linkWithUclibc(llvm::Module *mainModule) {
+  fprintf(stderr, "error: invalid libc, no uclibc support!\n");
+  exit(1);
+  return 0;
+}
+#else
+static llvm::Module *linkWithUclibc(llvm::Module *mainModule) {
+  Function *f;
+  // force import of __uClibc_main
+  mainModule->getOrInsertFunction("__uClibc_main",
+                                  FunctionType::get(Type::VoidTy,
+                                                    std::vector<const Type*>(),
+                                                    true));
+  
+  // force various imports
+  if (WithPOSIXRuntime) {
+    mainModule->getOrInsertFunction("realpath",
+                                    PointerType::getUnqual(Type::Int8Ty),
+                                    PointerType::getUnqual(Type::Int8Ty),
+                                    PointerType::getUnqual(Type::Int8Ty),
+                                    NULL);
+    mainModule->getOrInsertFunction("getutent",
+                                    PointerType::getUnqual(Type::Int8Ty),
+                                    NULL);
+    mainModule->getOrInsertFunction("__fgetc_unlocked",
+                                    Type::Int32Ty,
+                                    PointerType::getUnqual(Type::Int8Ty),
+                                    NULL);
+    mainModule->getOrInsertFunction("__fputc_unlocked",
+                                    Type::Int32Ty,
+                                    Type::Int32Ty,
+                                    PointerType::getUnqual(Type::Int8Ty),
+                                    NULL);
+  }
+
+  f = mainModule->getFunction("__ctype_get_mb_cur_max");
+  if (f) f->setName("_stdlib_mb_cur_max");
+
+  // Strip of asm prefixes for 64 bit versions because they are not
+  // present in uclibc and we want to make sure stuff will get
+  // linked. In the off chance that both prefixed and unprefixed
+  // versions are present in the module, make sure we don't create a
+  // naming conflict.
+  for (Module::iterator fi = mainModule->begin(), fe = mainModule->end();
+       fi != fe;) {
+    Function *f = fi;
+    ++fi;
+    const std::string &name = f->getName();
+    if (name[0]=='\01') {
+      unsigned size = name.size();
+      if (name[size-2]=='6' && name[size-1]=='4') {
+        std::string unprefixed = name.substr(1);
+
+        // See if the unprefixed version exists.
+        if (Function *f2 = mainModule->getFunction(unprefixed)) {
+          f->replaceAllUsesWith(f2);
+          f->eraseFromParent();
+        } else {
+          f->setName(unprefixed);
+        }
+      }
+    }
+  }
+  
+  mainModule = klee::linkWithLibrary(mainModule, 
+                                     KLEE_UCLIBC "/lib/libc.a");
+  assert(mainModule && "unable to link with uclibc");
+
+  // more sighs, this is horrible but just a temp hack
+  //    f = mainModule->getFunction("__fputc_unlocked");
+  //    if (f) f->setName("fputc_unlocked");
+  //    f = mainModule->getFunction("__fgetc_unlocked");
+  //    if (f) f->setName("fgetc_unlocked");
+  
+  Function *f2;
+  f = mainModule->getFunction("open");
+  f2 = mainModule->getFunction("__libc_open");
+  if (f2) {
+    if (f) {
+      f2->replaceAllUsesWith(f);
+      f2->eraseFromParent();
+    } else {
+      f2->setName("open");
+      assert(f2->getName() == "open");
+    }
+  }
+
+  f = mainModule->getFunction("fcntl");
+  f2 = mainModule->getFunction("__libc_fcntl");
+  if (f2) {
+    if (f) {
+      f2->replaceAllUsesWith(f);
+      f2->eraseFromParent();
+    } else {
+      f2->setName("fcntl");
+      assert(f2->getName() == "fcntl");
+    }
+  }
+
+  // XXX we need to rearchitect so this can also be used with
+  // programs externally linked with uclibc.
+
+  // We now need to swap things so that __uClibc_main is the entry
+  // point, in such a way that the arguments are passed to
+  // __uClibc_main correctly. We do this by renaming the user main
+  // and generating a stub function to call __uClibc_main. There is
+  // also an implicit cooperation in that runFunctionAsMain sets up
+  // the environment arguments to what uclibc expects (following
+  // argv), since it does not explicitly take an envp argument.
+  Function *userMainFn = mainModule->getFunction("main");
+  assert(userMainFn && "unable to get user main");    
+  Function *uclibcMainFn = mainModule->getFunction("__uClibc_main");
+  assert(uclibcMainFn && "unable to get uclibc main");    
+  userMainFn->setName("__user_main");
+
+  const FunctionType *ft = uclibcMainFn->getFunctionType();
+  assert(ft->getNumParams() == 7);
+
+  std::vector<const Type*> fArgs;
+  fArgs.push_back(ft->getParamType(1)); // argc
+  fArgs.push_back(ft->getParamType(2)); // argv
+  Function *stub = Function::Create(FunctionType::get(Type::Int32Ty, fArgs, false),
+      			      GlobalVariable::ExternalLinkage,
+      			      "main",
+      			      mainModule);
+  BasicBlock *bb = BasicBlock::Create("entry", stub);
+
+  std::vector<llvm::Value*> args;
+  args.push_back(llvm::ConstantExpr::getBitCast(userMainFn, 
+                                                ft->getParamType(0)));
+  args.push_back(stub->arg_begin()); // argc
+  args.push_back(++stub->arg_begin()); // argv    
+  args.push_back(Constant::getNullValue(ft->getParamType(3))); // app_init
+  args.push_back(Constant::getNullValue(ft->getParamType(4))); // app_fini
+  args.push_back(Constant::getNullValue(ft->getParamType(5))); // rtld_fini
+  args.push_back(Constant::getNullValue(ft->getParamType(6))); // stack_end
+  CallInst::Create(uclibcMainFn, args.begin(), args.end(), "", bb);
+  
+  new UnreachableInst(bb);
+
+  return mainModule;
+}
+#endif
+
+int main(int argc, char **argv, char **envp) {  
+#if ENABLE_STPLOG == 1
+  STPLOG_init("stplog.c");
+#endif
+
+  atexit(llvm_shutdown);  // Call llvm_shutdown() on exit.
+  parseArguments(argc, argv);
+  sys::PrintStackTraceOnErrorSignal();
+
+  if (Watchdog) {
+    if (MaxTime==0) {
+      klee_error("--watchdog used without --max-time");
+    }
+
+    int pid = fork();
+    if (pid<0) {
+      klee_error("unable to fork watchdog");
+    } else if (pid) {
+      fprintf(stderr, "KLEE: WATCHDOG: watching %d\n", pid);
+      fflush(stderr);
+
+      double nextStep = util::getWallTime() + MaxTime*1.1;
+      int level = 0;
+
+      // Simple stupid code...
+      while (1) {
+        sleep(1);
+
+        int status, res = waitpid(pid, &status, WNOHANG);
+
+        if (res < 0) {
+          if (errno==ECHILD) { // No child, no need to watch but
+                               // return error since we didn't catch
+                               // the exit.
+            fprintf(stderr, "KLEE: watchdog exiting (no child)\n");
+            return 1;
+          } else if (errno!=EINTR) {
+            perror("watchdog waitpid");
+            exit(1);
+          }
+        } else if (res==pid && WIFEXITED(status)) {
+          return WEXITSTATUS(status);
+        } else {
+          double time = util::getWallTime();
+
+          if (time > nextStep) {
+            ++level;
+            
+            if (level==1) {
+              fprintf(stderr, "KLEE: WATCHDOG: time expired, attempting halt via INT\n");
+              kill(pid, SIGINT);
+            } else if (level==2) {
+              fprintf(stderr, "KLEE: WATCHDOG: time expired, attempting halt via gdb\n");
+              halt_via_gdb(pid);
+            } else {
+              fprintf(stderr, "KLEE: WATCHDOG: kill(9)ing child (I tried to be nice)\n");
+              kill(pid, SIGKILL);
+              return 1; // what more can we do
+            }
+
+            // Ideally this triggers a dump, which may take a while,
+            // so try and give the process extra time to clean up.
+            nextStep = util::getWallTime() + std::max(15., MaxTime*.1);
+          }
+        }
+      }
+
+      return 0;
+    }
+  }
+
+  sys::SetInterruptFunction(interrupt_handle);
+
+  // Load the bytecode...
+  std::string ErrorMsg;
+  ModuleProvider *MP = 0;
+  if (MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(InputFile, &ErrorMsg)) {
+    MP = getBitcodeModuleProvider(Buffer, &ErrorMsg);
+    if (!MP) delete Buffer;
+  }
+  
+  if (!MP)
+    klee_error("error loading program '%s': %s", InputFile.c_str(), ErrorMsg.c_str());
+
+  Module *mainModule = MP->materializeModule();
+  MP->releaseModule();
+  delete MP;
+
+  assert(mainModule && "unable to materialize");
+  
+  if (WithPOSIXRuntime)
+    InitEnv = true;
+
+  if (InitEnv) {
+    int r = initEnv(mainModule);
+    if (r != 0)
+      return r;
+  }
+
+  llvm::sys::Path LibraryDir(KLEE_DIR "/" RUNTIME_CONFIGURATION "/lib");
+  Interpreter::ModuleOptions Opts(LibraryDir.c_str(),
+                                  /*Optimize=*/OptimizeModule, 
+                                  /*CheckDivZero=*/CheckDivZero);
+  
+  switch (Libc) {
+  case NoLibc: /* silence compiler warning */
+    break;
+
+  case KleeLibc: {
+    // FIXME: Find a reasonable solution for this.
+    llvm::sys::Path Path(Opts.LibraryDir);
+    Path.appendComponent("libklee-libc.bca");
+    mainModule = klee::linkWithLibrary(mainModule, Path.c_str());
+    assert(mainModule && "unable to link with klee-libc");
+    break;
+  }
+
+  case UcLibc:
+    mainModule = linkWithUclibc(mainModule);
+    break;
+  }
+
+  if (WithPOSIXRuntime) {
+    llvm::sys::Path Path(Opts.LibraryDir);
+    Path.appendComponent("libkleeRuntimePOSIX.bca");
+    klee_message("NOTE: Using model: %s", Path.c_str());
+    mainModule = klee::linkWithLibrary(mainModule, Path.c_str());
+    assert(mainModule && "unable to link with simple model");
+  }  
+
+  // Get the desired main function.  klee_main initializes uClibc
+  // locale and other data and then calls main.
+  Function *mainFn = mainModule->getFunction("main");
+  if (!mainFn) {
+    llvm::cerr << "'main' function not found in module.\n";
+    return -1;
+  }
+
+  // FIXME: Change me to std types.
+  int pArgc;
+  char **pArgv;
+  char **pEnvp;
+  if (Environ != "") {
+    std::vector<std::string> items;
+    std::ifstream f(Environ.c_str());
+    if (!f.good())
+      klee_error("unable to open --environ file: %s", Environ.c_str());
+    while (!f.eof()) {
+      std::string line;
+      std::getline(f, line);
+      line = strip(line);
+      if (!line.empty())
+        items.push_back(line);
+    }
+    f.close();
+    pEnvp = new char *[items.size()+1];
+    unsigned i=0;
+    for (; i != items.size(); ++i)
+      pEnvp[i] = strdup(items[i].c_str());
+    pEnvp[i] = 0;
+  } else {
+    pEnvp = envp;
+  }
+
+  pArgc = InputArgv.size() + 1; 
+  pArgv = new char *[pArgc];
+  for (unsigned i=0; i<InputArgv.size()+1; i++) {
+    std::string &arg = (i==0 ? InputFile : InputArgv[i-1]);
+    unsigned size = arg.size() + 1;
+    char *pArg = new char[size];
+    
+    std::copy(arg.begin(), arg.end(), pArg);
+    pArg[size - 1] = 0;
+    
+    pArgv[i] = pArg;
+  }
+
+  std::vector<bool> replayPath;
+
+  if (ReplayPathFile != "") {
+    KleeHandler::loadPathFile(ReplayPathFile, replayPath);
+  }
+
+  Interpreter::InterpreterOptions IOpts;
+  IOpts.MakeConcreteSymbolic = MakeConcreteSymbolic;
+  KleeHandler *handler = new KleeHandler(pArgc, pArgv);
+  Interpreter *interpreter = 
+    theInterpreter = Interpreter::create(IOpts, handler);
+  handler->setInterpreter(interpreter);
+  
+  std::ostream &infoFile = handler->getInfoStream();
+  for (int i=0; i<argc; i++) {
+    infoFile << argv[i] << (i+1<argc ? " ":"\n");
+  }
+  infoFile << "PID: " << getpid() << "\n";
+
+  const Module *finalModule = 
+    interpreter->setModule(mainModule, Opts);
+  externalsAndGlobalsCheck(finalModule);
+
+  if (ReplayPathFile != "") {
+    interpreter->setReplayPath(&replayPath);
+  }
+
+  char buf[256];
+  time_t t[2];
+  t[0] = time(NULL);
+  strftime(buf, sizeof(buf), "Started: %Y-%m-%d %H:%M:%S\n", localtime(&t[0]));
+  infoFile << buf;
+  infoFile.flush();
+
+  if (!ReplayOutDir.empty() || !ReplayOutFile.empty()) {
+    assert(SeedOutFile.empty());
+    assert(SeedOutDir.empty());
+
+    std::vector<std::string> outFiles = ReplayOutFile;
+    for (std::vector<std::string>::iterator
+           it = ReplayOutDir.begin(), ie = ReplayOutDir.end();
+         it != ie; ++it)
+      KleeHandler::getOutFiles(*it, outFiles);    
+    std::vector<BOut*> bOuts;
+    for (std::vector<std::string>::iterator
+           it = outFiles.begin(), ie = outFiles.end();
+         it != ie; ++it) {
+      BOut *out = bOut_fromFile(it->c_str());
+      if (out) {
+        bOuts.push_back(out);
+      } else {
+        llvm::cerr << "KLEE: unable to open: " << *it << "\n";
+      }
+    }
+
+    if (RunInDir != "") {
+      int res = chdir(RunInDir.c_str());
+      if (res < 0) {
+        klee_error("Unable to change directory to: %s", RunInDir.c_str());
+      }
+    }
+
+    unsigned i=0;
+    for (std::vector<BOut*>::iterator
+           it = bOuts.begin(), ie = bOuts.end();
+         it != ie; ++it) {
+      BOut *out = *it;
+      interpreter->setReplayOut(out);
+      llvm::cerr << "KLEE: replaying: " << *it << " (" << bOut_numBytes(out) << " bytes)"
+                 << " (" << ++i << "/" << outFiles.size() << ")\n";
+      // XXX should put envp in .bout ?
+      interpreter->runFunctionAsMain(mainFn, out->numArgs, out->args, pEnvp);
+      if (interrupted) break;
+    }
+    interpreter->setReplayOut(0);
+    while (!bOuts.empty()) {
+      bOut_free(bOuts.back());
+      bOuts.pop_back();
+    }
+  } else {
+    std::vector<BOut *> seeds;
+    for (std::vector<std::string>::iterator
+           it = SeedOutFile.begin(), ie = SeedOutFile.end();
+         it != ie; ++it) {
+      BOut *out = bOut_fromFile(it->c_str());
+      if (!out) {
+        llvm::cerr << "KLEE: unable to open: " << *it << "\n";
+        exit(1);
+      }
+      seeds.push_back(out);
+    } 
+    for (std::vector<std::string>::iterator
+           it = SeedOutDir.begin(), ie = SeedOutDir.end();
+         it != ie; ++it) {
+      std::vector<std::string> outFiles;
+      KleeHandler::getOutFiles(*it, outFiles);
+      for (std::vector<std::string>::iterator
+             it2 = outFiles.begin(), ie = outFiles.end();
+           it2 != ie; ++it2) {
+        BOut *out = bOut_fromFile(it2->c_str());
+        if (!out) {
+          llvm::cerr << "KLEE: unable to open: " << *it2 << "\n";
+          exit(1);
+        }
+        seeds.push_back(out);
+      }
+      if (outFiles.empty()) {
+        llvm::cerr << "KLEE: seeds directory is empty: " << *it << "\n";
+        exit(1);
+      }
+    }
+       
+    if (!seeds.empty()) {
+      llvm::cerr << "KLEE: using " << seeds.size() << " seeds\n";
+      interpreter->useSeeds(&seeds);
+    }
+    if (RunInDir != "") {
+      int res = chdir(RunInDir.c_str());
+      if (res < 0) {
+        klee_error("Unable to change directory to: %s", RunInDir.c_str());
+      }
+    }
+    interpreter->runFunctionAsMain(mainFn, pArgc, pArgv, pEnvp);
+
+    while (!seeds.empty()) {
+      bOut_free(seeds.back());
+      seeds.pop_back();
+    }
+  }
+      
+  t[1] = time(NULL);
+  strftime(buf, sizeof(buf), "Finished: %Y-%m-%d %H:%M:%S\n", localtime(&t[1]));
+  infoFile << buf;
+
+  strcpy(buf, "Elapsed: ");
+  strcpy(format_tdiff(buf, t[1] - t[0]), "\n");
+  infoFile << buf;
+
+  // Free all the args.
+  for (unsigned i=0; i<InputArgv.size()+1; i++)
+    delete[] pArgv[i];
+  delete[] pArgv;
+
+  delete interpreter;
+
+  uint64_t queries = 
+    *theStatisticManager->getStatisticByName("Queries");
+  uint64_t queriesValid = 
+    *theStatisticManager->getStatisticByName("QueriesValid");
+  uint64_t queriesInvalid = 
+    *theStatisticManager->getStatisticByName("QueriesInvalid");
+  uint64_t queryCounterexamples = 
+    *theStatisticManager->getStatisticByName("QueriesCEX");
+  uint64_t queryConstructs = 
+    *theStatisticManager->getStatisticByName("QueriesConstructs");
+  uint64_t instructions = 
+    *theStatisticManager->getStatisticByName("Instructions");
+  uint64_t forks = 
+    *theStatisticManager->getStatisticByName("Forks");
+
+  handler->getInfoStream() 
+    << "KLEE: done: explored paths = " << 1 + forks << "\n";
+
+  // Write some extra information in the info file which users won't
+  // necessarily care about or understand.
+  if (queries)
+    handler->getInfoStream() 
+      << "KLEE: done: avg. constructs per query = " 
+                             << queryConstructs / queries << "\n";  
+  handler->getInfoStream() 
+    << "KLEE: done: total queries = " << queries << "\n"
+    << "KLEE: done: valid queries = " << queriesValid << "\n"
+    << "KLEE: done: invalid queriers = " << queriesInvalid << "\n"
+    << "KLEE: done: query cex = " << queryCounterexamples << "\n";
+
+  std::stringstream stats;
+  stats << "KLEE: done: total instructions = " 
+             << instructions << "\n";
+  stats << "KLEE: done: completed paths = " 
+             << handler->getNumPathsExplored() << "\n";
+  stats << "KLEE: done: generated tests = " 
+             << handler->getNumTestCases() << "\n";
+  llvm::cerr << stats.str();
+  handler->getInfoStream() << stats.str();
+
+  delete handler;
+
+  return 0;
+}