Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2008 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 # purify_test.py | 6 # purify_test.py |
| 7 | 7 |
| 8 '''Runs an exe through Valgrind and puts the intermediate files in a | 8 '''Runs an exe through Valgrind and puts the intermediate files in a |
| 9 directory. | 9 directory. |
| 10 ''' | 10 ''' |
| 11 | 11 |
| 12 import datetime | 12 import datetime |
| 13 import glob | 13 import glob |
| 14 import logging | 14 import logging |
| 15 import optparse | 15 import optparse |
| 16 import os | 16 import os |
| 17 import re | |
| 17 import shutil | 18 import shutil |
| 18 import stat | 19 import stat |
| 19 import sys | 20 import sys |
| 20 import tempfile | 21 import tempfile |
| 21 | 22 |
| 22 import common | 23 import common |
| 23 | 24 |
| 24 import valgrind_analyze | 25 import valgrind_analyze |
| 25 | 26 |
| 26 import google.logging_utils | 27 import google.logging_utils |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 93 if self._options.verbose: | 94 if self._options.verbose: |
| 94 google.logging_utils.config_root(logging.DEBUG) | 95 google.logging_utils.config_root(logging.DEBUG) |
| 95 else: | 96 else: |
| 96 google.logging_utils.config_root() | 97 google.logging_utils.config_root() |
| 97 | 98 |
| 98 return True | 99 return True |
| 99 | 100 |
| 100 def Setup(self): | 101 def Setup(self): |
| 101 return self.ParseArgv() | 102 return self.ParseArgv() |
| 102 | 103 |
| 104 def PrepareForTest(self): | |
| 105 """Perform necessary tasks prior to executing the test.""" | |
| 106 pass | |
| 107 | |
| 103 def ValgrindCommand(self): | 108 def ValgrindCommand(self): |
| 104 """Get the valgrind command to run.""" | 109 """Get the valgrind command to run.""" |
| 105 raise RuntimeError, "Never use Valgrind directly. Always subclass and " \ | 110 raise RuntimeError, "Never use Valgrind directly. Always subclass and " \ |
| 106 "implement ValgrindCommand() at least" | 111 "implement ValgrindCommand() at least" |
| 107 | 112 |
| 108 def Execute(self): | 113 def Execute(self): |
| 109 ''' Execute the app to be tested after successful instrumentation. | 114 ''' Execute the app to be tested after successful instrumentation. |
| 110 Full execution command-line provided by subclassers via proc.''' | 115 Full execution command-line provided by subclassers via proc.''' |
| 111 logging.info("starting execution...") | 116 logging.info("starting execution...") |
| 112 | 117 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 129 analyzer = valgrind_analyze.ValgrindAnalyze(self._source_dir, filenames, sel f._options.show_all_leaks) | 134 analyzer = valgrind_analyze.ValgrindAnalyze(self._source_dir, filenames, sel f._options.show_all_leaks) |
| 130 return analyzer.Report() | 135 return analyzer.Report() |
| 131 | 136 |
| 132 def Cleanup(self): | 137 def Cleanup(self): |
| 133 # Right now, we can cleanup by deleting our temporary directory. Other | 138 # Right now, we can cleanup by deleting our temporary directory. Other |
| 134 # cleanup is still a TODO? | 139 # cleanup is still a TODO? |
| 135 shutil.rmtree(self.TMP_DIR) | 140 shutil.rmtree(self.TMP_DIR) |
| 136 return True | 141 return True |
| 137 | 142 |
| 138 def RunTestsAndAnalyze(self): | 143 def RunTestsAndAnalyze(self): |
| 144 self.PrepareForTest() | |
| 145 | |
| 139 self.Execute() | 146 self.Execute() |
| 140 if self._generate_suppressions: | 147 if self._generate_suppressions: |
| 141 logging.info("Skipping analysis to let you look at the raw output...") | 148 logging.info("Skipping analysis to let you look at the raw output...") |
| 142 return 0 | 149 return 0 |
| 143 | 150 |
| 144 retcode = self.Analyze() | 151 retcode = self.Analyze() |
| 145 if retcode: | 152 if retcode: |
| 146 logging.error("Analyze failed.") | 153 logging.error("Analyze failed.") |
| 147 return retcode | 154 return retcode |
| 148 logging.info("Execution and analysis completed successfully.") | 155 logging.info("Execution and analysis completed successfully.") |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 233 class ValgrindMac(Valgrind): | 240 class ValgrindMac(Valgrind): |
| 234 | 241 |
| 235 """Valgrind on Mac OS X. | 242 """Valgrind on Mac OS X. |
| 236 | 243 |
| 237 Valgrind on OS X does not support suppressions (yet). | 244 Valgrind on OS X does not support suppressions (yet). |
| 238 """ | 245 """ |
| 239 | 246 |
| 240 def __init__(self): | 247 def __init__(self): |
| 241 Valgrind.__init__(self) | 248 Valgrind.__init__(self) |
| 242 | 249 |
| 250 def PrepareForTest(self): | |
| 251 """Runs dsymutil if needed. | |
| 252 | |
| 253 Valgrind for Mac OS X requires that debugging information be in a .dSYM | |
| 254 bundle generated by dsymutil. It is not currently able to chase DWARF | |
| 255 data into .o files like gdb does, so executables without .dSYM bundles or | |
| 256 with the Chromium-specific "fake_dsym" bundles generated by | |
| 257 build/mac/strip_save_dsym won't give source file and line number | |
| 258 information in valgrind. | |
| 259 | |
| 260 This function will run dsymutil if the .dSYM bundle is missing or if | |
| 261 it looks like a fake_dsym. A non-fake dsym that already exists is assumed | |
| 262 to be up-to-date. | |
| 263 """ | |
| 264 | |
| 265 test_command = self._args[0] | |
| 266 dsym_bundle = self._args[0] + '.dSYM' | |
| 267 dsym_file = os.path.join(dsym_bundle, 'Contents', 'Resources', 'DWARF', | |
| 268 os.path.basename(test_command)) | |
| 269 dsym_info_plist = os.path.join(dsym_bundle, 'Contents', 'Info.plist') | |
| 270 | |
| 271 needs_dsymutil = True | |
| 272 saved_test_command = None | |
| 273 | |
| 274 if os.path.exists(dsym_file) and os.path.exists(dsym_info_plist): | |
| 275 # Look for the special fake_dsym tag in dsym_info_plist. | |
| 276 dsym_info_plist_contents = open(dsym_info_plist).read() | |
| 277 | |
| 278 if not re.search('^\s*<key>fake_dsym</key>$', dsym_info_plist_contents, | |
| 279 re.MULTILINE): | |
| 280 # fake_dsym is not set, this is a real .dSYM bundle produced by | |
| 281 # dsymutil. dsymutil does not need to be run again. | |
| 282 needs_dsymutil = False | |
| 283 else: | |
| 284 # fake_dsym is set. dsym_file is a copy of the original test_command | |
| 285 # before it was stripped. Copy it back to test_command so that | |
| 286 # dsymutil has unstripped input to work with. Move the stripped | |
| 287 # test_command out of the way, it will be restored when this is | |
| 288 # done. | |
| 289 saved_test_command = test_command + '.stripped' | |
| 290 os.rename(test_command, saved_test_command) | |
| 291 shutil.copyfile(dsym_file, test_command) | |
| 292 | |
| 293 if needs_dsymutil: | |
| 294 # Remove the .dSYM bundle if it exists. | |
| 295 shutil.rmtree(dsym_bundle, True) | |
| 296 | |
| 297 dsymutil_command = ['dsymutil', test_command] | |
| 298 | |
| 299 # dsymutil is crazy slow. Let it run for up to a half hour. I hope | |
| 300 # that's enough. | |
| 301 common.RunSubprocess(dsymutil_command, 30 * 60) | |
| 302 | |
| 303 if saved_test_command: | |
| 304 os.rename(saved_test_command, test_command) | |
|
TVL
2009/03/27 20:04:31
do you want an exception handler on any of this to
| |
| 305 | |
| 243 def ValgrindCommand(self): | 306 def ValgrindCommand(self): |
| 244 """Get the valgrind command to run.""" | 307 """Get the valgrind command to run.""" |
| 245 proc = ["valgrind", "--smc-check=all", "--leak-check=full", | 308 proc = ["valgrind", "--smc-check=all", "--leak-check=full", |
| 246 "--num-callers=30"] | 309 "--num-callers=30"] |
| 247 | 310 |
| 248 if self._options.show_all_leaks: | 311 if self._options.show_all_leaks: |
| 249 proc += ["--show-reachable=yes"]; | 312 proc += ["--show-reachable=yes"]; |
| 250 | 313 |
| 251 # Either generate suppressions or load them. | 314 # Either generate suppressions or load them. |
| 252 # TODO(nirnimesh): Enable when Analyze() is implemented | 315 # TODO(nirnimesh): Enable when Analyze() is implemented |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 281 valgrind = ValgrindMac() | 344 valgrind = ValgrindMac() |
| 282 retcode = valgrind.Main() | 345 retcode = valgrind.Main() |
| 283 sys.exit(retcode) | 346 sys.exit(retcode) |
| 284 elif sys.platform == 'linux2': # Linux | 347 elif sys.platform == 'linux2': # Linux |
| 285 valgrind = ValgrindLinux() | 348 valgrind = ValgrindLinux() |
| 286 retcode = valgrind.Main() | 349 retcode = valgrind.Main() |
| 287 sys.exit(retcode) | 350 sys.exit(retcode) |
| 288 else: | 351 else: |
| 289 logging.error("Unknown platform: %s" % sys.platform) | 352 logging.error("Unknown platform: %s" % sys.platform) |
| 290 sys.exit(1) | 353 sys.exit(1) |
| OLD | NEW |