-
Notifications
You must be signed in to change notification settings - Fork 152
/
int_maketodo.py
298 lines (260 loc) · 9.94 KB
/
int_maketodo.py
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2017-2020 The Project X-Ray Authors.
#
# Use of this source code is governed by a ISC-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/ISC
#
# SPDX-License-Identifier: ISC
import os, re
from prjxray import util
def noprefix(tag):
n = tag.find('.')
assert n > 0
return tag[n + 1:]
def getprefix(tag):
n = tag.find('.')
assert n > 0
return tag[0:n]
def load_pipfile(pipfile, verbose=False):
'''Returns a set of tags containing real tile type prefixes (ex: INT_L)'''
todos = set()
tile_type = None
with open(pipfile, "r") as f:
# INT_L.WW2BEG0.SR1BEG_S0
for line in f:
tag = line.strip().split(' ')[0]
prefix_line = getprefix(tag)
if tile_type is None:
tile_type = prefix_line
else:
assert tile_type == prefix_line
todos.add(tag)
return todos, tile_type
def balance_todo_list(
pipfile,
todos,
balance_wire_re,
balance_wire_direction,
balance_wire_cnt,
verbose=False):
"""Balance the contents of the todo list
Todo list balancing allows to specify the name, direction and minimal number of
occurrences of a PIP wire in the final todo list.
The mechanism should be used in cases where a fuzzer times out because of an
unsolvable todo list, i.e. the netlist and resulting segdata generated from an
iteration keep segmatch from properly disambiguating the bits for some features.
When the balance wire name regexp is specified it's guaranteed that all PIPs
with matching wire name (whether we want to match a src or dst wire has to be
specified with the --balance-wire-direction switch) will have at least the number
of entries specified with the --balance-wire-cnt switch in the final todo list.
"""
orig_todos, tile_type = load_pipfile(pipfile, verbose=verbose)
if balance_wire_re is not None:
todo_wires = {}
verbose and print("Start balancing the TODO list")
for todo in todos:
tile_type, dst, src = todo.split(".")
wire = src
other_wire = dst
if balance_wire_direction not in "src":
wire = dst
other_wire = src
balance_wire_match = re.match(balance_wire_re, wire)
if balance_wire_match is None:
continue
if wire not in todo_wires:
todo_wires[wire] = set()
todo_wires[wire].add(other_wire)
for wire, other_wires in todo_wires.items():
if len(other_wires) >= balance_wire_cnt:
continue
else:
for todo in orig_todos:
tile_type, dst, src = todo.split(".")
if balance_wire_direction in "src":
if wire in src and dst not in todo_wires[wire]:
todo_wires[wire].add(dst)
else:
if wire in dst and src not in todo_wires[wire]:
todo_wires[wire].add(src)
if len(todo_wires[wire]) == balance_wire_cnt:
break
for wire, other_wires in todo_wires.items():
if len(other_wires) < balance_wire_cnt:
verbose and print(
"Warning: failed to balance the todo list for wire {}, there are only {} PIPs which meet the requirement: {}"
.format(wire, len(other_wires), other_wires))
for other_wire in other_wires:
line = tile_type + "."
if balance_wire_direction in "src":
line += other_wire + "." + wire
else:
line += wire + "." + other_wire
verbose and print("Adding {}".format(line))
todos.add(line)
verbose and print("Finished balancing the TODO list")
def maketodo(
pipfile,
dbfile,
intre,
exclude_re=None,
balance_wire_re=None,
balance_wire_direction=None,
balance_wire_cnt=None,
not_endswith=None,
verbose=False):
'''
db files start with INT., but pipfile lines start with INT_L
Normalize by removing before the first dot
050-intpips doesn't care about contents, but most fuzzers use the tile type prefix
'''
todos, tile_type = load_pipfile(pipfile, verbose=verbose)
verbose and print('%s: %u entries' % (pipfile, len(todos)))
if not todos:
verbose and print('%s: %u entries, done!' % (pipfile, len(todos)))
return
verbose and print("pipfile todo sample: %s" % list(todos)[0])
if 0 and verbose:
print("TODOs")
for todo in sorted(list(todos)):
print(' %s' % todo)
verbose and print('Pre db %s: %u entries' % (dbfile, len(todos)))
# Allow against empty db
if os.path.exists(dbfile):
verbose and print("Loading %s" % dbfile)
with open(dbfile, "r") as f:
# INT.BYP_ALT0.BYP_BOUNCE_N3_3 !22_07 !23_07 !25_07 21_07 24_07
for line in f:
tag, _bits, mode, _ = util.parse_db_line(line.strip())
# Only count resolved entries
if mode:
continue
# INT.BLAH => INT_L.BLAH
tag = tile_type + '.' + noprefix(tag)
# bipips works on a subset
if tag in todos:
todos.remove(tag)
else:
verbose and print(
"WARNING: couldnt remove %s (line %s)" %
(tag, line.strip()))
else:
verbose and print("WARNING: dbfile doesnt exist: %s" % dbfile)
verbose and print('Post db %s: %u entries' % (dbfile, len(todos)))
drops = 0
lines = 0
filtered_todos = set()
for line in todos:
include = re.match(intre, line) is not None
if include and not_endswith is not None:
include = not line.endswith(not_endswith)
if include and exclude_re is not None:
include = re.match(exclude_re, line) is None
if include:
filtered_todos.add(line)
else:
drops += 1
lines += 1
verbose and print('Print %u entries w/ %u drops' % (lines, drops))
balance_todo_list(
pipfile, filtered_todos, balance_wire_re, balance_wire_direction,
balance_wire_cnt, verbose)
for todo in filtered_todos:
print(todo)
def run(
build_dir,
db_dir,
pip_dir,
intre,
sides,
l,
r,
pip_type,
seg_type,
exclude_re=None,
balance_wire_re=None,
balance_wire_direction=None,
balance_wire_cnt=None,
not_endswith=None,
verbose=False):
if db_dir is None:
db_dir = "%s/%s" % (
os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"))
if pip_dir is None:
pip_dir = "%s/piplist/build/%s" % (
os.getenv("XRAY_FUZZERS_DIR"), pip_type)
assert intre, "RE is required"
for side in sides:
if side == "l" and not l:
continue
if side == "r" and not r:
continue
if side == "xl":
segfile = "l{}".format(seg_type)
pipfile = "l{}".format(pip_type)
elif side == "xr":
segfile = "r{}".format(seg_type)
pipfile = "r{}".format(pip_type)
elif side != "":
segfile = "{}_{}".format(seg_type, side)
pipfile = "{}_{}".format(pip_type, side)
else:
segfile = "{}".format(seg_type)
pipfile = "{}".format(pip_type)
maketodo(
"%s/%s.txt" % (pip_dir, pipfile),
"%s/segbits_%s.db" % (db_dir, segfile),
intre,
exclude_re=exclude_re,
balance_wire_re=balance_wire_re,
balance_wire_direction=balance_wire_direction,
balance_wire_cnt=balance_wire_cnt,
not_endswith=not_endswith,
verbose=verbose)
def main():
import argparse
parser = argparse.ArgumentParser(
description="Print list of known but unsolved PIPs")
parser.add_argument('--verbose', action='store_true', help='')
parser.add_argument('--build-dir', default="build", help='')
parser.add_argument('--db-dir', default=None, help='')
parser.add_argument('--pip-dir', default=None, help='')
parser.add_argument('--re', required=True, help='')
parser.add_argument('--exclude-re', required=False, default=None, help='')
parser.add_argument(
'--balance-wire-re', required=False, default=None, help='')
parser.add_argument(
'--balance-wire-direction', required=False, default="src", help='')
parser.add_argument(
'--balance-wire-cnt', required=False, default="1", help='')
parser.add_argument(
'--balance-re-wire', required=False, default="src", help='')
parser.add_argument('--pip-type', default="pips_int", help='')
parser.add_argument('--seg-type', default="int", help='')
parser.add_argument('--sides', default="l,r", help='')
util.add_bool_arg(parser, '--l', default=True, help='')
util.add_bool_arg(parser, '--r', default=True, help='')
parser.add_argument(
'--not-endswith', help='Drop lines if they end with this')
args = parser.parse_args()
run(
build_dir=args.build_dir,
db_dir=args.db_dir,
pip_dir=args.pip_dir,
intre=args.re,
exclude_re=args.exclude_re,
balance_wire_re=args.balance_wire_re,
balance_wire_direction=args.balance_wire_direction,
balance_wire_cnt=int(args.balance_wire_cnt),
sides=args.sides.split(','),
l=args.l,
r=args.r,
pip_type=args.pip_type,
seg_type=args.seg_type,
not_endswith=args.not_endswith,
verbose=args.verbose)
if __name__ == '__main__':
main()