| 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 |