Skip to content

Commit 3f8a061

Browse files
authored
Merge pull request #6301 from gottesmm/sil-bug-reducer-3
2 parents 2d3c2ff + 7209d4d commit 3f8a061

9 files changed

+9716
-52
lines changed

utils/bug_reducer/bug_reducer/bug_reducer.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,29 @@
22

33
import argparse
44

5+
import func_bug_reducer
6+
57
import opt_bug_reducer
68

79
import random_bug_finder
810

911

12+
def add_subparser(subparsers, module, name):
13+
sparser = subparsers.add_parser(name)
14+
sparser.add_argument('swift_build_dir',
15+
help='Path to the swift build directory '
16+
'containing tools to use')
17+
module.add_parser_arguments(sparser)
18+
19+
1020
def main():
1121
parser = argparse.ArgumentParser(description="""\
1222
A program for reducing sib/sil crashers""")
1323
subparsers = parser.add_subparsers()
1424

15-
opt_subparser = subparsers.add_parser("opt")
16-
opt_subparser.add_argument('swift_build_dir',
17-
help='Path to the swift build directory '
18-
'containing tools to use')
19-
opt_bug_reducer.add_parser_arguments(opt_subparser)
20-
21-
random_search_subparser = subparsers.add_parser("random-search")
22-
random_search_subparser.add_argument('swift_build_dir',
23-
help='Path to the swift build '
24-
'directory containing tools to use')
25-
random_bug_finder.add_parser_arguments(random_search_subparser)
25+
add_subparser(subparsers, opt_bug_reducer, 'opt')
26+
add_subparser(subparsers, random_bug_finder, 'random-search')
27+
add_subparser(subparsers, func_bug_reducer, 'func')
2628

2729
args = parser.parse_args()
2830
args.func(args)

utils/bug_reducer/bug_reducer/bug_reducer_utils.py

Lines changed: 137 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
11

2-
import json
32
import os
43
import subprocess
54

65
DRY_RUN = False
6+
SQUELCH_STDERR = True
7+
ECHO_CALLS = False
78

89

9-
def br_call(args):
10-
if DRY_RUN:
11-
print('DRY RUN: ' + ' '.join(args))
10+
def br_call(args, dry_run=DRY_RUN, echo=ECHO_CALLS):
11+
if dry_run or echo:
12+
print('BRCALL: ' + ' '.join(args))
13+
if dry_run:
1214
return 0
13-
return subprocess.call(args, stdout=open('/dev/null'), stderr=open('/dev/null'))
15+
if SQUELCH_STDERR:
16+
return subprocess.call(args, stdout=open('/dev/null'),
17+
stderr=open('/dev/null'))
18+
else:
19+
# Useful for debugging.
20+
return subprocess.call(args, stdout=open('/dev/null'))
21+
22+
23+
# We use this since our squelching of stderr can hide missing file errors.
24+
def sanity_check_file_exists(f):
25+
if not os.access(f, os.F_OK):
26+
raise RuntimeError('Error! Could not find file: ' + f)
1427

1528

1629
class SwiftTools(object):
@@ -50,7 +63,7 @@ def sil_opt(self):
5063
def sil_func_extractor(self):
5164
"""Return the path to sil-func-extractor in the specified swift build
5265
directory. Throws a runtime error if the tool does not exist."""
53-
return self._get_tool('sil-opt')
66+
return self._get_tool('sil-func-extractor')
5467

5568
@property
5669
def sil_passpipeline_dumper(self):
@@ -67,54 +80,93 @@ def maybe_abspath(x):
6780
return os.path.abspath(x)
6881

6982

70-
class SILOptInvoker(object):
83+
class SILToolInvokerConfig(object):
7184

72-
def __init__(self, args, tools, extra_args):
73-
self.tools = tools
85+
def __init__(self, args):
7486
self.module_cache = args.module_cache
7587
self.sdk = args.sdk
7688
self.target = args.target
7789
self.resource_dir = maybe_abspath(args.resource_dir)
7890
self.work_dir = maybe_abspath(args.work_dir)
7991
self.module_name = args.module_name
92+
93+
94+
class SILToolInvoker(object):
95+
96+
def __init__(self, config, extra_args=None):
97+
self.config = config
8098
self.extra_args = extra_args
8199

100+
@property
101+
def base_args(self):
102+
x = [self.tool]
103+
if self.config.sdk is not None:
104+
x.append("-sdk=%s" % self.config.sdk)
105+
if self.config.target is not None:
106+
x.append("-target=%s" % self.config.target)
107+
if self.config.resource_dir is not None:
108+
x.append("-resource-dir=%s" % self.config.resource_dir)
109+
if self.config.module_cache is not None:
110+
x.append("-module-cache-path=%s" % self.config.module_cache)
111+
if self.config.module_name is not None:
112+
x.append("-module-name=%s" % self.config.module_name)
113+
return x
114+
115+
@property
116+
def tool(self):
117+
raise RuntimeError('Abstract Method')
118+
119+
120+
class SILConstantInputToolInvoker(SILToolInvoker):
121+
122+
def __init__(self, config, tools, initial_input_file, extra_args):
123+
SILToolInvoker.__init__(self, config, extra_args)
124+
self.tools = tools
125+
82126
# Start by creating our workdir if necessary
83-
subprocess.check_call(["mkdir", "-p", self.work_dir])
127+
subprocess.check_call(["mkdir", "-p", self.config.work_dir])
84128

85129
# Then copy our input file into the work dir
86-
base_input_file = os.path.basename(args.input_file)
130+
base_input_file = os.path.basename(initial_input_file)
87131
(base, ext) = os.path.splitext(base_input_file)
88132
self.base_input_file_stem = base
89133
self.base_input_file_ext = ".sib"
90134

91135
# First emit an initial *.sib file. This ensures no matter if we have a
92136
# *.swiftmodule, *.sil, or *.sib file, we are always using *.sib.
93-
self.input_file = self.get_suffixed_filename('initial')
94-
self._invoke(args.input_file, [], self.input_file)
137+
self.input_file = initial_input_file
138+
sanity_check_file_exists(initial_input_file)
139+
140+
def _invoke(self, input_file, passes, output_filename):
141+
raise RuntimeError('Abstract method')
142+
143+
@property
144+
def base_args(self):
145+
base_args = SILToolInvoker.base_args.fget(self)
146+
base_args.append('-emit-sib')
147+
return base_args
95148

96149
def get_suffixed_filename(self, suffix):
97150
basename = self.base_input_file_stem + '_' + suffix
98151
basename += self.base_input_file_ext
99-
return os.path.join(self.work_dir, basename)
152+
return os.path.join(self.config.work_dir, basename)
153+
154+
155+
class SILOptInvoker(SILConstantInputToolInvoker):
156+
157+
def __init__(self, config, tools, input_file, extra_args):
158+
SILConstantInputToolInvoker.__init__(self, config, tools, input_file,
159+
extra_args)
160+
self.input_file = self.get_suffixed_filename('initial')
161+
self._invoke(input_file, [], self.input_file)
100162

101163
@property
102-
def base_args(self):
103-
x = [self.tools.sil_opt, "-emit-sib"]
104-
if self.sdk is not None:
105-
x.append("-sdk=%s" % self.sdk)
106-
if self.target is not None:
107-
x.append("-target=%s" % self.target)
108-
if self.resource_dir is not None:
109-
x.append("-resource-dir=%s" % self.resource_dir)
110-
if self.module_cache is not None:
111-
x.append("-module-cache-path=%s" % self.module_cache)
112-
if self.module_name is not None:
113-
x.append("-module-name=%s" % self.module_name)
114-
return x
164+
def tool(self):
165+
return self.tools.sil_opt
115166

116167
def _cmdline(self, input_file, passes, output_file='-'):
117168
base_args = self.base_args
169+
sanity_check_file_exists(input_file)
118170
base_args.extend([input_file, '-o', output_file])
119171
base_args.extend(self.extra_args)
120172
base_args.extend(passes)
@@ -129,3 +181,61 @@ def invoke_with_passlist(self, passes, output_filename):
129181

130182
def cmdline_with_passlist(self, passes):
131183
return self._cmdline(self.input_file, passes)
184+
185+
186+
class SILFuncExtractorInvoker(SILConstantInputToolInvoker):
187+
188+
def __init__(self, config, tools, input_file):
189+
SILConstantInputToolInvoker.__init__(self, config, tools, input_file,
190+
[])
191+
192+
@property
193+
def tool(self):
194+
return self.tools.sil_func_extractor
195+
196+
def _cmdline(self, input_file, funclist_path, output_file='-', invert=False):
197+
sanity_check_file_exists(input_file)
198+
sanity_check_file_exists(funclist_path)
199+
assert(isinstance(funclist_path, str))
200+
base_args = self.base_args
201+
base_args.extend([input_file, '-o', output_file,
202+
'-func-file=%s' % funclist_path])
203+
if invert:
204+
base_args.append('-invert')
205+
return base_args
206+
207+
def _invoke(self, input_file, funclist_path, output_filename, invert=False):
208+
assert(isinstance(funclist_path, str))
209+
cmdline = self._cmdline(input_file, funclist_path, output_filename,
210+
invert)
211+
return br_call(cmdline)
212+
213+
def invoke_with_functions(self, funclist_path, output_filename, invert=False):
214+
assert(isinstance(funclist_path, str))
215+
return self._invoke(self.input_file, funclist_path, output_filename,
216+
invert)
217+
218+
def cmdline_with_functions(self, funclist_path, invert=False):
219+
assert(isinstance(funclist_path, str))
220+
return self._cmdline(self.input_file, funclist_path, invert)
221+
222+
223+
class SILNMInvoker(SILToolInvoker):
224+
225+
def __init__(self, config, tools):
226+
self.tools = tools
227+
SILToolInvoker.__init__(self, config)
228+
229+
@property
230+
def tool(self):
231+
return self.tools.sil_nm
232+
233+
def get_symbols(self, input_file):
234+
sanity_check_file_exists(input_file)
235+
cmdline = self.base_args
236+
cmdline.append(input_file)
237+
output = subprocess.check_output(cmdline)
238+
for l in output.split("\n")[:-1]:
239+
t = tuple(l.split(" "))
240+
assert(len(t) == 2)
241+
yield t

0 commit comments

Comments
 (0)