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
,
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 a filter was specified then pass it on to the instrumenter.
81 cmd
.append('--filter=%s' % os
.path
.abspath(filter_file
))
87 # Make sure the destination directory exists.
88 if not os
.path
.isdir(options
.destination_dir
):
89 _LOGGER
.info('Creating destination directory "%s".',
90 options
.destination_dir
)
91 os
.makedirs(options
.destination_dir
)
93 # Compile the filter if one was provided.
95 _CompileFilter(options
.syzygy_dir
,
96 options
.input_executable
,
99 options
.output_filter_file
)
101 # Instruments the binaries into the destination directory.
102 _InstrumentBinary(options
.syzygy_dir
,
104 options
.input_executable
,
105 options
.input_symbol
,
106 options
.destination_dir
,
107 options
.output_filter_file
)
111 option_parser
= optparse
.OptionParser()
112 option_parser
.add_option('--input_executable',
113 help='The path to the input executable.')
114 option_parser
.add_option('--input_symbol',
115 help='The path to the input symbol file.')
116 option_parser
.add_option('--mode',
117 help='Specifies which instrumentation mode is to be used.')
118 option_parser
.add_option('--syzygy-dir', default
=_DEFAULT_SYZYGY_DIR
,
119 help='Instrumenter executable to use, defaults to "%default".')
120 option_parser
.add_option('-d', '--destination_dir',
121 help='Destination directory for instrumented files.')
122 option_parser
.add_option('--filter',
123 help='An optional filter. This will be compiled and passed to the '
124 'instrumentation executable.')
125 option_parser
.add_option('--output-filter-file',
126 help='The path where the compiled filter will be written. This is '
127 'required if --filter is specified.')
128 options
, args
= option_parser
.parse_args()
131 option_parser
.error('You must provide an instrumentation mode.')
132 if not options
.input_executable
:
133 option_parser
.error('You must provide an input executable.')
134 if not options
.input_symbol
:
135 option_parser
.error('You must provide an input symbol file.')
136 if not options
.destination_dir
:
137 option_parser
.error('You must provide a destination directory.')
138 if options
.filter and not options
.output_filter_file
:
139 option_parser
.error('You must provide a filter output file.')
144 if '__main__' == __name__
:
145 logging
.basicConfig(level
=logging
.INFO
)
146 sys
.exit(main(_ParseOptions()))