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 = 'asan_rtl.dll' |
| 26 |
| 27 # Default agents for known modes. |
| 28 _DEFAULT_AGENT_DLLS = { 'asan': _ASAN_AGENT_DLL } |
25 | 29 |
26 _LOGGER = logging.getLogger() | 30 _LOGGER = logging.getLogger() |
27 | 31 |
28 | 32 |
29 def _Shell(*cmd, **kw): | 33 def _Shell(*cmd, **kw): |
30 """Shells out to "cmd". Returns a tuple of cmd's stdout, stderr.""" | 34 """Shells out to "cmd". Returns a tuple of cmd's stdout, stderr.""" |
31 _LOGGER.info('Running command "%s".', cmd) | 35 _LOGGER.info('Running command "%s".', cmd) |
32 prog = subprocess.Popen(cmd, **kw) | 36 prog = subprocess.Popen(cmd, **kw) |
33 | 37 |
34 stdout, stderr = prog.communicate() | 38 stdout, stderr = prog.communicate() |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 if mode == "asan": | 80 if mode == "asan": |
77 cmd.append('--no-augment-pdb') | 81 cmd.append('--no-augment-pdb') |
78 | 82 |
79 # If a filter was specified then pass it on to the instrumenter. | 83 # If a filter was specified then pass it on to the instrumenter. |
80 if filter_file: | 84 if filter_file: |
81 cmd.append('--filter=%s' % os.path.abspath(filter_file)) | 85 cmd.append('--filter=%s' % os.path.abspath(filter_file)) |
82 | 86 |
83 return _Shell(*cmd) | 87 return _Shell(*cmd) |
84 | 88 |
85 | 89 |
| 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 |
86 def main(options): | 108 def main(options): |
87 # Make sure the destination directory exists. | 109 # Make sure the destination directory exists. |
88 if not os.path.isdir(options.destination_dir): | 110 if not os.path.isdir(options.destination_dir): |
89 _LOGGER.info('Creating destination directory "%s".', | 111 _LOGGER.info('Creating destination directory "%s".', |
90 options.destination_dir) | 112 options.destination_dir) |
91 os.makedirs(options.destination_dir) | 113 os.makedirs(options.destination_dir) |
92 | 114 |
93 # Compile the filter if one was provided. | 115 # Compile the filter if one was provided. |
94 if options.filter: | 116 if options.filter: |
95 _CompileFilter(options.syzygy_dir, | 117 _CompileFilter(options.syzygy_dir, |
96 options.input_executable, | 118 options.input_executable, |
97 options.input_symbol, | 119 options.input_symbol, |
98 options.filter, | 120 options.filter, |
99 options.output_filter_file) | 121 options.output_filter_file) |
100 | 122 |
101 # Instruments the binaries into the destination directory. | 123 # Instruments the binaries into the destination directory. |
102 _InstrumentBinary(options.syzygy_dir, | 124 _InstrumentBinary(options.syzygy_dir, |
103 options.mode, | 125 options.mode, |
104 options.input_executable, | 126 options.input_executable, |
105 options.input_symbol, | 127 options.input_symbol, |
106 options.destination_dir, | 128 options.destination_dir, |
107 options.output_filter_file) | 129 options.output_filter_file) |
108 | 130 |
| 131 # Copy the agent DLL and PDB to the destination directory. |
| 132 _CopyAgentDLL(options.agent_dll, options.destination_dir); |
| 133 |
109 | 134 |
110 def _ParseOptions(): | 135 def _ParseOptions(): |
111 option_parser = optparse.OptionParser() | 136 option_parser = optparse.OptionParser() |
112 option_parser.add_option('--input_executable', | 137 option_parser.add_option('--input_executable', |
113 help='The path to the input executable.') | 138 help='The path to the input executable.') |
114 option_parser.add_option('--input_symbol', | 139 option_parser.add_option('--input_symbol', |
115 help='The path to the input symbol file.') | 140 help='The path to the input symbol file.') |
116 option_parser.add_option('--mode', | 141 option_parser.add_option('--mode', |
117 help='Specifies which instrumentation mode is to be used.') | 142 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.') |
118 option_parser.add_option('--syzygy-dir', default=_DEFAULT_SYZYGY_DIR, | 146 option_parser.add_option('--syzygy-dir', default=_DEFAULT_SYZYGY_DIR, |
119 help='Instrumenter executable to use, defaults to "%default".') | 147 help='Instrumenter executable to use, defaults to "%default".') |
120 option_parser.add_option('-d', '--destination_dir', | 148 option_parser.add_option('-d', '--destination_dir', |
121 help='Destination directory for instrumented files.') | 149 help='Destination directory for instrumented files.') |
122 option_parser.add_option('--filter', | 150 option_parser.add_option('--filter', |
123 help='An optional filter. This will be compiled and passed to the ' | 151 help='An optional filter. This will be compiled and passed to the ' |
124 'instrumentation executable.') | 152 'instrumentation executable.') |
125 option_parser.add_option('--output-filter-file', | 153 option_parser.add_option('--output-filter-file', |
126 help='The path where the compiled filter will be written. This is ' | 154 help='The path where the compiled filter will be written. This is ' |
127 'required if --filter is specified.') | 155 'required if --filter is specified.') |
128 options, args = option_parser.parse_args() | 156 options, args = option_parser.parse_args() |
129 | 157 |
130 if not options.mode: | 158 if not options.mode: |
131 option_parser.error('You must provide an instrumentation mode.') | 159 option_parser.error('You must provide an instrumentation mode.') |
132 if not options.input_executable: | 160 if not options.input_executable: |
133 option_parser.error('You must provide an input executable.') | 161 option_parser.error('You must provide an input executable.') |
134 if not options.input_symbol: | 162 if not options.input_symbol: |
135 option_parser.error('You must provide an input symbol file.') | 163 option_parser.error('You must provide an input symbol file.') |
136 if not options.destination_dir: | 164 if not options.destination_dir: |
137 option_parser.error('You must provide a destination directory.') | 165 option_parser.error('You must provide a destination directory.') |
138 if options.filter and not options.output_filter_file: | 166 if options.filter and not options.output_filter_file: |
139 option_parser.error('You must provide a filter output file.') | 167 option_parser.error('You must provide a filter output file.') |
140 | 168 |
| 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 |
141 return options | 177 return options |
142 | 178 |
143 | 179 |
144 if '__main__' == __name__: | 180 if '__main__' == __name__: |
145 logging.basicConfig(level=logging.INFO) | 181 logging.basicConfig(level=logging.INFO) |
146 sys.exit(main(_ParseOptions())) | 182 sys.exit(main(_ParseOptions())) |
OLD | NEW |