2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """A utility script to help building Syzygy-instrumented Chrome binaries."""
17 # The default directory containing the Syzygy toolchain.
18 _DEFAULT_SYZYGY_DIR
= os
.path
.abspath(os
.path
.join(
19 os
.path
.dirname(__file__
), '../../../../..',
20 'third_party/syzygy/binaries/exe/'))
22 # Basenames of various tools.
23 _INSTRUMENT_EXE
= 'instrument.exe'
24 _GENFILTER_EXE
= 'genfilter.exe'
26 _LOGGER
= logging
.getLogger()
29 def _Shell(*cmd
, **kw
):
30 """Shells out to "cmd". Returns a tuple of cmd's stdout, stderr."""
31 _LOGGER
.info('Running command "%s".', cmd
)
32 prog
= subprocess
.Popen(cmd
, **kw
)
34 stdout
, stderr
= prog
.communicate()
35 if prog
.returncode
!= 0:
36 raise RuntimeError('Command "%s" returned %d.' % (cmd
, prog
.returncode
))
41 def _CompileFilter(syzygy_dir
, executable
, symbol
, filter_file
,
43 """Compiles the provided filter writing the compiled filter file to
46 cmd
= [os
.path
.abspath(os
.path
.join(syzygy_dir
, _GENFILTER_EXE
)),
48 '--input-image=%s' % executable
,
49 '--input-pdb=%s' % symbol
,
50 '--output-file=%s' % output_filter_file
,
52 os
.path
.abspath(filter_file
)]
55 if not os
.path
.exists(output_filter_file
):
56 raise RuntimeError('Compiled filter file missing: %s' % output_filter_file
)
60 def _InstrumentBinary(syzygy_dir
, mode
, executable
, symbol
, dst_dir
,
61 filter_file
, allocation_filter_file
):
62 """Instruments the executable found in input_dir, and writes the resultant
63 instrumented executable and symbol files to dst_dir.
65 cmd
= [os
.path
.abspath(os
.path
.join(syzygy_dir
, _INSTRUMENT_EXE
)),
69 '--input-image=%s' % executable
,
70 '--input-pdb=%s' % symbol
,
71 '--output-image=%s' % os
.path
.abspath(
72 os
.path
.join(dst_dir
, os
.path
.basename(executable
))),
73 '--output-pdb=%s' % os
.path
.abspath(
74 os
.path
.join(dst_dir
, os
.path
.basename(symbol
)))]
77 cmd
.append('--no-augment-pdb')
79 # If any filters were specified then pass them on to the instrumenter.
81 cmd
.append('--filter=%s' % os
.path
.abspath(filter_file
))
82 if allocation_filter_file
:
83 cmd
.append('--allocation-filter-config-file=%s' %
84 os
.path
.abspath(allocation_filter_file
))
90 # Make sure the destination directory exists.
91 if not os
.path
.isdir(options
.destination_dir
):
92 _LOGGER
.info('Creating destination directory "%s".',
93 options
.destination_dir
)
94 os
.makedirs(options
.destination_dir
)
96 # Compile the filter if one was provided.
98 _CompileFilter(options
.syzygy_dir
,
99 options
.input_executable
,
100 options
.input_symbol
,
102 options
.output_filter_file
)
104 # Instruments the binaries into the destination directory.
105 _InstrumentBinary(options
.syzygy_dir
,
107 options
.input_executable
,
108 options
.input_symbol
,
109 options
.destination_dir
,
110 options
.output_filter_file
,
111 options
.allocation_filter_file
)
115 option_parser
= optparse
.OptionParser()
116 option_parser
.add_option('--input_executable',
117 help='The path to the input executable.')
118 option_parser
.add_option('--input_symbol',
119 help='The path to the input symbol file.')
120 option_parser
.add_option('--mode',
121 help='Specifies which instrumentation mode is to be used.')
122 option_parser
.add_option('--syzygy-dir', default
=_DEFAULT_SYZYGY_DIR
,
123 help='Instrumenter executable to use, defaults to "%default".')
124 option_parser
.add_option('-d', '--destination_dir',
125 help='Destination directory for instrumented files.')
126 option_parser
.add_option('--filter',
127 help='An optional filter. This will be compiled and passed to the '
128 'instrumentation executable.')
129 option_parser
.add_option('--output-filter-file',
130 help='The path where the compiled filter will be written. This is '
131 'required if --filter is specified.')
132 option_parser
.add_option('--allocation-filter-file',
133 help='The path to the SyzyASAN allocation filter to use.')
134 options
, args
= option_parser
.parse_args()
137 option_parser
.error('You must provide an instrumentation mode.')
138 if not options
.input_executable
:
139 option_parser
.error('You must provide an input executable.')
140 if not options
.input_symbol
:
141 option_parser
.error('You must provide an input symbol file.')
142 if not options
.destination_dir
:
143 option_parser
.error('You must provide a destination directory.')
144 if options
.filter and not options
.output_filter_file
:
145 option_parser
.error('You must provide a filter output file.')
150 if '__main__' == __name__
:
151 logging
.basicConfig(level
=logging
.INFO
)
152 sys
.exit(main(_ParseOptions()))