about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
-rwxr-xr-xtools/klee-psychic/klee-psychic171
1 files changed, 43 insertions, 128 deletions
diff --git a/tools/klee-psychic/klee-psychic b/tools/klee-psychic/klee-psychic
index 6f1c1bcf..df066a41 100755
--- a/tools/klee-psychic/klee-psychic
+++ b/tools/klee-psychic/klee-psychic
@@ -1,128 +1,43 @@
-#!/usr/bin/env python3
-import sys
-import os
-import subprocess
-import tempfile
-import select
-import shutil
-from itertools import dropwhile, takewhile
-from pathlib import Path
-
-HELP="""OVERVIEW: ZESTI like wrapper of KLEE/Psychic
-
-USAGE: klee-psychic [klee-options] <input bytecode> <concrete program>
-    <concrete program arguments>
-
-WARNING this script is not equivalent to ZESTI in ICSE 2012. It just provides a similar interface to KLEE. Namely it first explores the path of <concrete program arguments> and then continues symbolic execution from that point. Most importantly it does not implement the ZESTI searcher.
-"""
-
-
-KLEE="klee"
-KTEST_GEN="ktest-gen"
-
-def find_klee_bin_dir():
-  global KLEE
-  global KTEST_GEN
-  bin_dir = os.path.dirname(os.path.realpath(__file__))
-  KLEE = bin_dir + "/klee"
-  KTEST_GEN = bin_dir + "/ktest-gen"
-  if not os.path.isfile(KLEE):
-      print("WARNING can't find klee at " + KLEE)
-      KLEE= shutil.which("klee")
-      print("Using klee in PATH", KLEE)
-  if not os.path.isfile(KTEST_GEN):
-      print("WARNING can't find ktest-gen at " + KTEST_GEN)
-      KTEST_GEN= shutil.which("ktest-gen")
-      print("Using ktest-gen in PATH", KTEST_GEN)
-  if KTEST_GEN is None or KLEE is None:
-      print("Failed to find KLEE at this script location or in PATH. Quitting ...")
-      sys.exit(1)
-  print("Using", KLEE)
-
-
-def is_option(arg):
-    """Check if argument is optional."""
-    return arg.startswith('-')
-
-
-def split_args():
-    """Return KLEE options, bitcode, executable and its arguments."""
-    klee_args = tuple(takewhile(is_option, sys.argv[1:]))
-    rest = dropwhile(is_option, sys.argv[1:])
-    return klee_args, next(rest), next(rest), tuple(rest)
-
-
-def maybe_file_size(name):
-  try:
-    return os.path.getsize(name)
-  except:
-    return None
-
-def get_stdin_file(tmpdir):
-  stdin = ""
-  stdin_size = 0
-  if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
-    stdin += sys.stdin.readline()
-  if stdin == "":
-      return None, stdin_size
-  stdin_file_name = tmpdir.name + "/stdin.file"
-  with open(stdin_file_name, 'w') as f:
-    stdin_size = f.write(stdin)
-  return stdin_file_name, stdin_size
-    
-  
-
-def prog_args_to_posix(prog_args):
-  posix_args = []
-  sym_file = 'A'
-  sym_file_sizes = [] 
-  gen_out_args = []
-  for parg in prog_args:
-      file_size = maybe_file_size(parg)
-      if file_size is None:
-          posix_args += ['--sym-arg', str(len(parg))]
-          gen_out_args += [parg]
-      else:
-          sym_file_sizes += [file_size]
-          posix_args += [sym_file]
-          sym_file = chr(ord(sym_file) + 1)
-          gen_out_args += ['--sym-file', parg]
-
-  if ord(sym_file) - ord('A') > 0:
-      posix_args += ['--sym-files', str(ord(sym_file) - ord('A')), str(max(sym_file_sizes))]
-  return posix_args, gen_out_args
-
-def create_ktest_file(gen_out_args, tmpdir):
-  out_file=tmpdir + "/test.ktest"
-  subprocess.run([KTEST_GEN, "--bout-file", out_file] + gen_out_args, check=True)
-  return out_file
-
-
-def main():
-  try:
-      klee_args, bc, prog, prog_args = split_args()
-  except StopIteration:
-      print(HELP)
-      return
-  find_klee_bin_dir()
-  tmpdir = tempfile.TemporaryDirectory()
-  stdin_file, stdin_size = get_stdin_file(tmpdir)
-  posix_args, gen_out_args = prog_args_to_posix(prog_args)
-  if stdin_file is not None:
-      gen_out_args += ["--sym-stdin", stdin_file]
-      posix_args += ["--sym-stdin", str(stdin_size)]
-  ktest_file = create_ktest_file(gen_out_args,tmpdir.name)
-  Path('test.ktest').write_bytes(Path(ktest_file).read_bytes())
-  proc = subprocess.Popen([KLEE, *klee_args, f'-seed-file={ktest_file}',
-                           bc, prog, *posix_args],
-                          stdout=sys.stdout, stderr=sys.stderr)
-  while proc.returncode is None:
-      try:
-        proc.wait()
-      except KeyboardInterrupt:
-        pass # This is expected when stopping KLEE, so we wait for KLEE to finish
-  sys.exit(proc.returncode)
-
-
-if __name__ == "__main__":
-  main()
+#!/bin/sh
+set -eux
+
+ktest_file=$(mktemp -t ktest.XXXXXXXXXX)
+trap 'rm "$ktest_file"' EXIT
+klee_args="--allow-seed-extension --only-replay-seeds --seed-file=$ktest_file"
+while test "$1" != "${1#-}" # hyphen-prefixed
+do
+  klee_args+=" $1"
+  shift
+done
+program_bc="$1"
+shift
+program_bin="$1"
+shift
+
+stdin=$(mktemp -t in.XXXXXXXXXX)
+trap 'rm "$stdin"' EXIT
+cat > $stdin
+stdout=$(mktemp -t out.XXXXXXXXXX)
+trap 'rm "$stdout"' EXIT
+"$program_bin" "$@" < $stdin > $stdout
+
+ktest_args="--sym-stdin $stdin"
+sym_args=
+for arg in $@
+do
+  if test -r $arg
+  then
+    ktest_args+=" --sym-file $arg"
+    # TODO: --sym-files
+  else
+    ktest_args+=" $arg"
+    sym_args+=" --sym-arg=${#arg}"
+  fi
+done
+
+ktest_gen=$KLEE_PREFIX/bin/ktest-gen
+test -x "$ktest_gen"
+"$ktest_gen" "${ktest_args[@]}" --bout-file "$ktest_file"
+klee_bin=$KLEE_PREFIX/bin/klee
+test -x "$klee_bin"
+"$klee_bin" ${klee_args[@]} "$program_bc" "$program_bin" ${sym_args[@]}