forked from eurecom-s3/symcc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pure_concolic_execution.sh
executable file
·144 lines (124 loc) · 3.79 KB
/
pure_concolic_execution.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/bin/bash
set -u
function usage() {
echo "Usage: $0 -i INPUT_DIR [-o OUTPUT_DIR] TARGET..."
echo
echo "Run SymCC-instrumented TARGET in a loop, feeding newly generated inputs back "
echo "into it. Initial inputs are expected in INPUT_DIR, and new inputs are "
echo "continuously read from there. If OUTPUT_DIR is specified, a copy of the corpus "
echo "and of each generated input is preserved there. TARGET may contain the special "
echo "string \"@@\", which is replaced with the name of the current input file."
echo
echo "Note that SymCC never changes the length of the input, so be sure that the "
echo "initial inputs cover all required input lengths."
}
while getopts "i:o:" opt; do
case "$opt" in
i)
in=$OPTARG
;;
o)
out=$OPTARG
;;
*)
usage
exit 1
;;
esac
done
shift $((OPTIND-1))
target=$@
timeout="timeout -k 5 90"
if [[ ! -v in ]]; then
echo "Please specify the input directory!"
usage
exit 1
fi
# Create the work environment
work_dir=$(mktemp -d)
mkdir $work_dir/{next,symcc_out}
touch $work_dir/analyzed_inputs
if [[ -v out ]]; then
mkdir -p $out
fi
function cleanup() {
rm -rf $work_dir
}
trap cleanup EXIT
# Copy all files in the source directory to the destination directory, renaming
# them according to their hash.
function copy_with_unique_name() {
local source_dir="$1"
local dest_dir="$2"
if [ -n "$(ls -A $source_dir)" ]; then
local f
for f in $source_dir/*; do
local dest="$dest_dir/$(sha256sum $f | cut -d' ' -f1)"
cp "$f" "$dest"
done
fi
}
# Copy files from the source directory into the next generation.
function add_to_next_generation() {
local source_dir="$1"
copy_with_unique_name "$source_dir" "$work_dir/next"
}
# If an output directory is set, copy the files in the source directory there.
function maybe_export() {
local source_dir="$1"
if [[ -v out ]]; then
copy_with_unique_name "$source_dir" "$out"
fi
}
# Copy those files from the input directory to the next generation that haven't
# been analyzed yet.
function maybe_import() {
if [ -n "$(ls -A $in)" ]; then
local f
for f in $in/*; do
if grep -q "$(basename $f)" $work_dir/analyzed_inputs; then
continue
fi
if [ -e "$work_dir/next/$(basename $f)" ]; then
continue
fi
echo "Importing $f from the input directory"
cp "$f" "$work_dir/next"
done
fi
}
# Set up the shell environment
export SYMCC_OUTPUT_DIR=$work_dir/symcc_out
export SYMCC_ENABLE_LINEARIZATION=1
# export SYMCC_AFL_COVERAGE_MAP=$work_dir/map
# Run generation after generation until we don't generate new inputs anymore
gen_count=0
while true; do
# Initialize the generation
maybe_import
mv $work_dir/{next,cur}
mkdir $work_dir/next
# Run it (or wait if there's nothing to run on)
if [ -n "$(ls -A $work_dir/cur)" ]; then
echo "Generation $gen_count..."
for f in $work_dir/cur/*; do
echo "Running on $f"
if [[ "$target " =~ " @@ " ]]; then
env SYMCC_INPUT_FILE=$f $timeout ${target[@]/@@/$f} >/dev/null 2>&1
else
$timeout $target <$f >/dev/null 2>&1
fi
# Make the new test cases part of the next generation
add_to_next_generation $work_dir/symcc_out
maybe_export $work_dir/symcc_out
echo $(basename $f) >> $work_dir/analyzed_inputs
rm -f $f
done
rm -rf $work_dir/cur
gen_count=$((gen_count+1))
else
echo "Waiting for more input..."
rmdir $work_dir/cur
sleep 5
fi
done