OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """A utility script to help building Syzygy-instrumented Chrome binaries.""" | 6 """A utility script to help building Syzygy-instrumented Chrome binaries.""" |
7 | 7 |
8 import glob | 8 import glob |
9 import logging | 9 import logging |
10 import optparse | 10 import optparse |
11 import os | 11 import os |
12 import shutil | 12 import shutil |
13 import subprocess | 13 import subprocess |
14 import sys | 14 import sys |
15 | 15 |
16 | 16 |
17 # The default directory containing the Syzygy toolchain. | 17 # The default directory containing the Syzygy toolchain. |
18 _DEFAULT_SYZYGY_DIR = os.path.abspath(os.path.join( | 18 _DEFAULT_SYZYGY_DIR = os.path.abspath(os.path.join( |
19 os.path.dirname(__file__), '../../../..', | 19 os.path.dirname(__file__), '../../../..', |
20 'third_party/syzygy/binaries/exe/')) | 20 'third_party/syzygy/binaries/exe/')) |
21 | 21 |
22 # Basenames of various tools. | 22 # Basenames of various tools. |
23 _INSTRUMENT_EXE = 'instrument.exe' | 23 _INSTRUMENT_EXE = 'instrument.exe' |
24 _GENFILTER_EXE = 'genfilter.exe' | 24 _GENFILTER_EXE = 'genfilter.exe' |
25 _ASAN_AGENT_DLL = 'syzyasan_rtl.dll' | |
26 | |
27 # Default agents for known modes. | |
28 _DEFAULT_AGENT_DLLS = { 'asan': _ASAN_AGENT_DLL } | |
29 | 25 |
30 _LOGGER = logging.getLogger() | 26 _LOGGER = logging.getLogger() |
31 | 27 |
32 | 28 |
33 def _Shell(*cmd, **kw): | 29 def _Shell(*cmd, **kw): |
34 """Shells out to "cmd". Returns a tuple of cmd's stdout, stderr.""" | 30 """Shells out to "cmd". Returns a tuple of cmd's stdout, stderr.""" |
35 _LOGGER.info('Running command "%s".', cmd) | 31 _LOGGER.info('Running command "%s".', cmd) |
36 prog = subprocess.Popen(cmd, **kw) | 32 prog = subprocess.Popen(cmd, **kw) |
37 | 33 |
38 stdout, stderr = prog.communicate() | 34 stdout, stderr = prog.communicate() |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 if mode == "asan": | 76 if mode == "asan": |
81 cmd.append('--no-augment-pdb') | 77 cmd.append('--no-augment-pdb') |
82 | 78 |
83 # If a filter was specified then pass it on to the instrumenter. | 79 # If a filter was specified then pass it on to the instrumenter. |
84 if filter_file: | 80 if filter_file: |
85 cmd.append('--filter=%s' % os.path.abspath(filter_file)) | 81 cmd.append('--filter=%s' % os.path.abspath(filter_file)) |
86 | 82 |
87 return _Shell(*cmd) | 83 return _Shell(*cmd) |
88 | 84 |
89 | 85 |
90 def _CopyAgentDLL(agent_dll, destination_dir): | |
91 """Copy the agent DLL and PDB to the destination directory.""" | |
92 dirname, agent_name = os.path.split(agent_dll); | |
93 agent_dst_name = os.path.join(destination_dir, agent_name); | |
94 shutil.copyfile(agent_dll, agent_dst_name) | |
95 | |
96 # Search for the corresponding PDB file. We use this approach because | |
97 # the naming convention for PDBs has changed recently (from 'foo.pdb' | |
98 # to 'foo.dll.pdb') and we want to support both conventions during the | |
99 # transition. | |
100 agent_pdbs = glob.glob(os.path.splitext(agent_dll)[0] + '*.pdb') | |
101 if len(agent_pdbs) != 1: | |
102 raise RuntimeError('Failed to locate PDB file for %s' % agent_name) | |
103 agent_pdb = agent_pdbs[0] | |
104 agent_dst_pdb = os.path.join(destination_dir, os.path.split(agent_pdb)[1]) | |
105 shutil.copyfile(agent_pdb, agent_dst_pdb) | |
106 | |
107 | |
108 def main(options): | 86 def main(options): |
109 # Make sure the destination directory exists. | 87 # Make sure the destination directory exists. |
110 if not os.path.isdir(options.destination_dir): | 88 if not os.path.isdir(options.destination_dir): |
111 _LOGGER.info('Creating destination directory "%s".', | 89 _LOGGER.info('Creating destination directory "%s".', |
112 options.destination_dir) | 90 options.destination_dir) |
113 os.makedirs(options.destination_dir) | 91 os.makedirs(options.destination_dir) |
114 | 92 |
115 # Compile the filter if one was provided. | 93 # Compile the filter if one was provided. |
116 if options.filter: | 94 if options.filter: |
117 _CompileFilter(options.syzygy_dir, | 95 _CompileFilter(options.syzygy_dir, |
118 options.input_executable, | 96 options.input_executable, |
119 options.input_symbol, | 97 options.input_symbol, |
120 options.filter, | 98 options.filter, |
121 options.output_filter_file) | 99 options.output_filter_file) |
122 | 100 |
123 # Instruments the binaries into the destination directory. | 101 # Instruments the binaries into the destination directory. |
124 _InstrumentBinary(options.syzygy_dir, | 102 _InstrumentBinary(options.syzygy_dir, |
125 options.mode, | 103 options.mode, |
126 options.input_executable, | 104 options.input_executable, |
127 options.input_symbol, | 105 options.input_symbol, |
128 options.destination_dir, | 106 options.destination_dir, |
129 options.output_filter_file) | 107 options.output_filter_file) |
130 | 108 |
131 # Copy the agent DLL and PDB to the destination directory. | |
132 _CopyAgentDLL(options.agent_dll, options.destination_dir); | |
133 | |
134 | 109 |
135 def _ParseOptions(): | 110 def _ParseOptions(): |
136 option_parser = optparse.OptionParser() | 111 option_parser = optparse.OptionParser() |
137 option_parser.add_option('--input_executable', | 112 option_parser.add_option('--input_executable', |
138 help='The path to the input executable.') | 113 help='The path to the input executable.') |
139 option_parser.add_option('--input_symbol', | 114 option_parser.add_option('--input_symbol', |
140 help='The path to the input symbol file.') | 115 help='The path to the input symbol file.') |
141 option_parser.add_option('--mode', | 116 option_parser.add_option('--mode', |
142 help='Specifies which instrumentation mode is to be used.') | 117 help='Specifies which instrumentation mode is to be used.') |
143 option_parser.add_option('--agent_dll', | |
144 help='The agent DLL used by this instrumentation. If not specified a ' | |
145 'default will be searched for.') | |
146 option_parser.add_option('--syzygy-dir', default=_DEFAULT_SYZYGY_DIR, | 118 option_parser.add_option('--syzygy-dir', default=_DEFAULT_SYZYGY_DIR, |
147 help='Instrumenter executable to use, defaults to "%default".') | 119 help='Instrumenter executable to use, defaults to "%default".') |
148 option_parser.add_option('-d', '--destination_dir', | 120 option_parser.add_option('-d', '--destination_dir', |
149 help='Destination directory for instrumented files.') | 121 help='Destination directory for instrumented files.') |
150 option_parser.add_option('--filter', | 122 option_parser.add_option('--filter', |
151 help='An optional filter. This will be compiled and passed to the ' | 123 help='An optional filter. This will be compiled and passed to the ' |
152 'instrumentation executable.') | 124 'instrumentation executable.') |
153 option_parser.add_option('--output-filter-file', | 125 option_parser.add_option('--output-filter-file', |
154 help='The path where the compiled filter will be written. This is ' | 126 help='The path where the compiled filter will be written. This is ' |
155 'required if --filter is specified.') | 127 'required if --filter is specified.') |
156 options, args = option_parser.parse_args() | 128 options, args = option_parser.parse_args() |
157 | 129 |
158 if not options.mode: | 130 if not options.mode: |
159 option_parser.error('You must provide an instrumentation mode.') | 131 option_parser.error('You must provide an instrumentation mode.') |
160 if not options.input_executable: | 132 if not options.input_executable: |
161 option_parser.error('You must provide an input executable.') | 133 option_parser.error('You must provide an input executable.') |
162 if not options.input_symbol: | 134 if not options.input_symbol: |
163 option_parser.error('You must provide an input symbol file.') | 135 option_parser.error('You must provide an input symbol file.') |
164 if not options.destination_dir: | 136 if not options.destination_dir: |
165 option_parser.error('You must provide a destination directory.') | 137 option_parser.error('You must provide a destination directory.') |
166 if options.filter and not options.output_filter_file: | 138 if options.filter and not options.output_filter_file: |
167 option_parser.error('You must provide a filter output file.') | 139 option_parser.error('You must provide a filter output file.') |
168 | 140 |
169 if not options.agent_dll: | |
170 if not options.mode in _DEFAULT_AGENT_DLLS: | |
171 option_parser.error('No known default agent DLL for mode "%s".' % | |
172 options.mode) | |
173 options.agent_dll = os.path.abspath(os.path.join(options.syzygy_dir, | |
174 _DEFAULT_AGENT_DLLS[options.mode])) | |
175 _LOGGER.info('Using default agent DLL: %s' % options.agent_dll) | |
176 | |
177 return options | 141 return options |
178 | 142 |
179 | 143 |
180 if '__main__' == __name__: | 144 if '__main__' == __name__: |
181 logging.basicConfig(level=logging.INFO) | 145 logging.basicConfig(level=logging.INFO) |
182 sys.exit(main(_ParseOptions())) | 146 sys.exit(main(_ParseOptions())) |
OLD | NEW |