Skip to content

Commit 784be10

Browse files
committed
[Scripts] provide fuzzilli toolchain
1 parent 70c71f0 commit 784be10

File tree

12 files changed

+499
-75
lines changed

12 files changed

+499
-75
lines changed

instrumentation/Makefile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
CXX = clang++
1+
CXX ?= clang++
22
LLVM_CONFIG ?= llvm-config
3+
4+
ifdef BASE
5+
CXX := $(BASE)/bin/clang++
6+
LLVM_CONFIG := $(BASE)/bin/llvm-config
7+
endif
8+
39
CXXFLAGS = $(shell $(LLVM_CONFIG) --cxxflags) -std=c++17 -fno-rtti -fPIC
410
LDFLAGS = $(shell $(LLVM_CONFIG) --ldflags)
511
PLUGIN_FLAGS = -Xclang -fpass-plugin=./inst-pass.so
@@ -9,7 +15,7 @@ DISTANCE = $(HOME)/llfuzz-experiment/optimuzz/_build/default/src/program/distanc
915
all: inst-pass.so coverage.o
1016

1117
inst-pass.so: InstPass.cpp
12-
$(CXX) -g -shared -o $@ $^ $(CXXFLAGS) $(LLVM_LDFLAGS)
18+
$(CXX) -g -shared -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
1319

1420
coverage.o: coverage.cpp
1521
$(CXX) -fPIC -c $< -o $@

scripts/alive.sh

Lines changed: 0 additions & 19 deletions
This file was deleted.

scripts/cfg_preprocess.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
from pathlib import Path
5+
import logging
6+
import pydot
7+
import networkx as nx
8+
import sys
9+
from collections import defaultdict
10+
11+
parser = argparse.ArgumentParser()
12+
parser.add_argument("cfg_dir", help="directory of CFG files and callgraph.txt")
13+
parser.add_argument('targets_file', help="file containing <target_file>:<target_line> pairs")
14+
args = parser.parse_args()
15+
16+
logging.basicConfig(
17+
filename='cfg_preprocess.log',
18+
level=logging.INFO,
19+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
20+
)
21+
22+
cfg_dir = Path(args.cfg_dir)
23+
24+
targets = []
25+
26+
for line in open(args.targets_file):
27+
target_file, target_line = line.strip().split(':')
28+
target_line = int(target_line)
29+
targets.append((target_file, target_line))
30+
31+
print(target_file, target_line, file=sys.stderr)
32+
33+
for target in targets:
34+
logging.info(f'Target: {target[0]}:{target[1]}')
35+
36+
# each line looks like
37+
# simplified-lowering.cc:_ZN2v88internal8compiler22RepresentationSelector12EnqueueInputILNS1_5PhaseE0EEEvPNS1_4NodeEiNS1_7UseInfoE:0:0:384103392 _ZN2v88internal8compiler22RepresentationSelector7GetInfoEPNS1_4NodeE
38+
def parse_callgraph(callgraph_txt):
39+
with open(callgraph_txt, 'r') as f:
40+
for line in f:
41+
caller, callee = line.strip().split()
42+
# print(f'{caller} -> {callee}')
43+
filename, funcname, lineno, order, bbid = caller.split(':')
44+
yield (filename, funcname, lineno, order, hex(int(bbid))), callee
45+
46+
target_nodes = []
47+
48+
# need to extract (function name -> first block id)
49+
def parse_cfg(cfg_file):
50+
graph: pydot.Graph = pydot.graph_from_dot_file(cfg_file)[0]
51+
graph: nx.MultiDiGraph = nx.drawing.nx_pydot.from_pydot(graph)
52+
# print('graph name', graph.name)
53+
# set edge weight as 1
54+
for u, v, k, d in graph.edges(keys=True, data=True):
55+
d['weight'] = 1
56+
57+
for n, d in graph.nodes(data=True):
58+
label = d['label'].strip('{}"')
59+
filename, funcname, lineno, order = label.split(':')
60+
d['filename'] = filename
61+
d['funcname'] = funcname
62+
d['lineno'] = int(lineno)
63+
d['order'] = int(order)
64+
65+
for filename, lineno in targets:
66+
if d['filename'] in filename and d['lineno'] == lineno:
67+
target_nodes.append(n)
68+
logging.info(f'Found target node {n} in {cfg_file}')
69+
break
70+
71+
# print('graph nodes', graph.nodes(data=True))
72+
# print('graph edges', graph.edges(keys=True, data=True))
73+
return graph
74+
75+
callgraph = list(parse_callgraph(cfg_dir / 'callgraph.txt'))
76+
cfgs = []
77+
func_to_node = {}
78+
for f in cfg_dir.glob('*.dot'):
79+
g = parse_cfg(f)
80+
cfgs.append(g)
81+
82+
the_node = min(g.nodes(data=True), key=lambda n: n[1]['order'])
83+
# print(the_node)
84+
func_to_node[g.name] = the_node[0]
85+
86+
# for func, first_node in func_to_node.items():
87+
# print(f'{func} -> {first_node}')
88+
89+
logging.info(f'{len(target_nodes)} target nodes found')
90+
91+
logging.info(f'{len(callgraph)} call edges found in callgraph.txt')
92+
logging.info(f'{len(cfgs)} CFG files found in {cfg_dir}')
93+
94+
node_cnt = sum([cfg.number_of_nodes() for cfg in cfgs])
95+
edge_cnt = sum([cfg.number_of_edges() for cfg in cfgs])
96+
97+
logging.info(f'Total number of nodes: {node_cnt}')
98+
logging.info(f'Total number of edges: {edge_cnt}')
99+
100+
# merge cfgs into one
101+
entire_cfg = nx.MultiDiGraph()
102+
for cfg in cfgs:
103+
entire_cfg = nx.compose(entire_cfg, cfg)
104+
105+
for caller, callee in callgraph:
106+
filename, funcname, lineno, order, bbid = caller
107+
node = 'Node' + bbid
108+
assert node in entire_cfg, f'Node {node} not found in entire CFG'
109+
entire_cfg.add_edge(node, func_to_node[callee], weight=10)
110+
111+
logging.info(f'Number of nodes in entire CFG: {entire_cfg.number_of_nodes()}')
112+
logging.info(f'Number of edges in entire CFG: {entire_cfg.number_of_edges()}')
113+
114+
fulldistmap = defaultdict(list)
115+
for v in target_nodes:
116+
distmap = nx.single_source_dijkstra_path_length(entire_cfg, v)
117+
for n, distance in distmap.items():
118+
fulldistmap[n].append(distance)
119+
120+
for n, distances in fulldistmap.items():
121+
bbid = n[4:]
122+
# compute harmonic mean
123+
if 0 not in distances:
124+
harmonic_mean = len(distances) / sum([1/d for d in distances])
125+
print(f'{bbid} {harmonic_mean}')
126+
else:
127+
print(f'{bbid} 0.0')
128+

scripts/check-format

Lines changed: 0 additions & 15 deletions
This file was deleted.

scripts/edit_rule.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env python3
2+
3+
import sys
4+
5+
toolchain = sys.argv[1]
6+
target_rule = sys.argv[2]
7+
prepends = sys.argv[3]
8+
appends = sys.argv[4]
9+
10+
# print(toolchain, target_rule, prepends, appends)
11+
12+
command_line = None
13+
14+
with open(toolchain, 'r') as f:
15+
lines = f.readlines()
16+
for i, l in enumerate(lines):
17+
if l.strip() == f"rule {target_rule}":
18+
command_line = lines[i + 1].strip()
19+
break
20+
21+
22+
if command_line is None:
23+
sys.stderr.write("target rule not found")
24+
exit(1)
25+
26+
command_line = ' command = ' + prepends + ' ' + command_line.lstrip('command =').strip() + ' ' + appends + '\n'
27+
lines[i + 1] = command_line
28+
29+
with open(toolchain, 'w') as f:
30+
f.write(''.join(lines))

scripts/install-clang-13.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
cd $HOME
2+
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz
3+
tar -xvf clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz

scripts/install-pyenv.sh

Whitespace-only changes.

scripts/llvm20.sh

Lines changed: 0 additions & 39 deletions
This file was deleted.

scripts/repro-turbofan.sh

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env bash
2+
3+
ROOT=$PWD
4+
NUMBER=$1 # 1195650 1198705 1199345 1200490 1234764 1234770
5+
6+
if [[ -z $NUMBER ]]; then
7+
echo "Usage: $0 <number>"
8+
exit 1
9+
fi
10+
11+
if [[ $(basename "$ROOT") != "optimuzz" ]]; then
12+
echo "Please run this script from the root of the optimuzz repository."
13+
exit 1
14+
fi
15+
16+
echo $ROOT
17+
18+
set -e
19+
20+
# Our TurboFan benchmark requires Python 2
21+
if [[ ! -d $HOME/.pyenv ]]; then
22+
curl https://pyenv.run | bash
23+
fi
24+
export PYENV_ROOT="$HOME/.pyenv"
25+
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
26+
eval "$(pyenv init - bash)"
27+
# pyenv install 2
28+
29+
30+
TURBOFAN_BUILDS=$HOME/turbofan-builds
31+
32+
mkdir -p $TURBOFAN_BUILDS
33+
pushd $TURBOFAN_BUILDS
34+
if [[ ! -d tools/depot_tools ]]; then
35+
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git tools/depot_tools
36+
fi
37+
export PATH=$PWD/tools/depot_tools:$PATH
38+
echo "Fetching v8..."
39+
# fetch v8
40+
41+
echo "Checking out v8..."
42+
# gclient sync
43+
44+
45+
COMMIT_ID=$(grep "^$NUMBER" $ROOT/turbotv-fuzzilli/d8-targets/commits.txt | awk '{print $2}')
46+
echo $COMMIT_ID
47+
pyenv global 2 # Our targets need python 2.7
48+
pyenv exec gclient sync -D -R --revision=$COMMIT_ID
49+
50+
if [[ ! -f $HOME/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz ]]; then
51+
pushd $HOME
52+
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.0/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz
53+
tar -xvf clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz
54+
popd
55+
fi
56+
57+
pushd v8
58+
tools/dev/v8gen.py x64.debug
59+
60+
cat > out.gn/x64.debug/args.gn <<EOF
61+
clang_base_path = "$HOME/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04"
62+
clang_use_chrome_plugins = false
63+
treat_warnings_as_errors = false
64+
is_debug = true
65+
target_cpu = "x64"
66+
v8_enable_backtrace = true
67+
v8_enable_slow_dchecks = true
68+
v8_optimized_debug = false
69+
EOF
70+
71+
gn gen out.gn/x64.debug
72+
73+
cat out.gn/x64.debug/args.gn
74+
75+
echo -e "\033[34mBuilding instrumentation...\033[0m"
76+
77+
make -C $ROOT/instrumentation/ clean
78+
make -C $ROOT/instrumentation/ BASE=$HOME/clang+llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04
79+
80+
echo -e "\033[34mEditing build rules...\033[0m"
81+
export SCRIPTS=$ROOT/scripts
82+
TARGET_FILE=$(cat $ROOT/turbotv-fuzzilli/d8-targets/$NUMBER.txt | cut -d':' -f1)
83+
$SCRIPTS/edit_rule.py out.gn/x64.debug/toolchain.ninja cxx "VERBOSE=1 TARGET_FILE=$TARGET_FILE OUT_DIR=\"$PWD/out.gn/x64.debug/cfg\"" "-fexperimental-new-pass-manager -Xclang -fpass-plugin=$ROOT/instrumentation/inst-pass.so"
84+
$SCRIPTS/edit_rule.py out.gn/x64.debug/toolchain.ninja link "" "$ROOT/instrumentation/coverage.o"
85+
$SCRIPTS/edit_rule.py out.gn/x64.debug/toolchain.ninja solink "" "$ROOT/instrumentation/coverage.o"
86+
87+
echo -e "\033[34mBuilding d8...\033[0m"
88+
ninja -C out.gn/x64.debug d8 > out.gn/x64.debug/ninja.log
89+
$SCRIPTS/cfg_preprocess.py out.gn/x64.debug/cfg $HOME/optimuzz-experiment/cases/turbofan/targets/$NUMBER.txt > distmap.txt
90+
cd $ROOT
91+
mv $TURBOFAN_BUILDS/v8/out.gn/x64.debug/ d8s/$NUMBER/
92+
cp $TURBOFAN_BUILDS/v8/distmap.txt d8s/$NUMBER/distmap.txt
93+
94+
tools/turbofan-reproduce.py $NUMBER

0 commit comments

Comments
 (0)