Chromium Code Reviews| Index: tools/valgrind/asan/asan_symbolize.py |
| diff --git a/tools/valgrind/asan/asan_symbolize.py b/tools/valgrind/asan/asan_symbolize.py |
| index cd61daeb29ae867cf3dbffce876ba0a92b0aa6b6..9280d7a893ecf3bf3f07275a14cca3efe506fa76 100755 |
| --- a/tools/valgrind/asan/asan_symbolize.py |
| +++ b/tools/valgrind/asan/asan_symbolize.py |
| @@ -10,6 +10,8 @@ import argparse |
| import base64 |
| import json |
| import os |
| +import re |
| +import subprocess |
| import sys |
| class LineBuffered(object): |
| @@ -48,6 +50,73 @@ def set_symbolizer_path(): |
| os.environ['LLVM_SYMBOLIZER_PATH'] = os.path.abspath(symbolizer_path) |
| +def is_hash_name(name): |
| + match = re.match('[0-9a-f]+$', name) |
| + return bool(match) |
| + |
| + |
| +def split_path(path): |
| + ret = [] |
| + while True: |
| + head, tail = os.path.split(path) |
| + if head == path: |
| + return [head] + ret |
| + ret, path = [tail] + ret, head |
| + |
| + |
| +def chrome_product_dir_path(exe_path): |
| + if exe_path is None: |
| + return None |
| + path_parts = split_path(exe_path) |
| + # Make sure the product dir path isn't empty if |exe_path| consists of |
| + # a single component. |
| + if len(path_parts) == 1: |
| + path_parts = ['.'] + path_parts |
| + for index, part in enumerate(path_parts): |
| + if part.endswith('.app'): |
| + return os.path.join(*path_parts[:index]) |
| + # If the executable isn't an .app bundle, it's a commandline binary that |
| + # resides right in the product dir. |
| + return os.path.join(*path_parts[:-1]) |
| + |
| + |
| +inode_path_cache = {} |
| + |
| + |
| +def find_inode_at_path(inode, path): |
| + if inode in inode_path_cache: |
| + return inode_path_cache[inode] |
| + cmd = ['find', path, '-inum', str(inode)] |
| + find_line = subprocess.check_output(cmd).rstrip() |
| + lines = find_line.split('\n') |
| + ret = None |
| + if lines: |
| + # `find` may give us several paths (e.g. 'Chromium Framework' in the |
| + # product dir and 'Chromium Framework' inside 'Chromium.app', |
| + # chrome_dsym_hints() will produce correct .dSYM path for any of them. |
| + ret = lines[0] |
| + inode_path_cache[inode] = ret |
| + return ret |
| + |
| + |
| +# Create a binary name filter that works around https://crbug.com/444835. |
| +# When running tests on OSX swarming servers, ASan sometimes prints paths to |
| +# files in cache (ending with SHA1 filenames) instead of paths to hardlinks to |
| +# those files in the product dir. |
| +# For a given |binary_path| chrome_osx_binary_name_filter() returns one of the |
| +# hardlinks to the same inode in |product_dir_path|. |
| +def make_chrome_osx_binary_name_filter(product_dir_path=''): |
| + def chrome_osx_binary_name_filter(binary_path): |
| + basename = os.path.basename(binary_path) |
| + if is_hash_name(basename) and product_dir_path: |
| + inode = os.stat(binary_path).st_ino |
| + new_binary_path = find_inode_at_path(inode, product_dir_path) |
| + if new_binary_path: |
| + return new_binary_path |
| + return binary_path |
| + return chrome_osx_binary_name_filter |
| + |
| + |
| # Construct a path to the .dSYM bundle for the given binary. |
| # There are three possible cases for binary location in Chromium: |
| # 1. The binary is a standalone executable or dynamic library in the product |
| @@ -63,7 +132,7 @@ def set_symbolizer_path(): |
| # path. Only one of these bundles may be a framework and frameworks cannot |
| # contain other bundles. |
| def chrome_dsym_hints(binary): |
| - path_parts = binary.split(os.path.sep) |
| + path_parts = split_path(binary) |
| app_positions = [] |
| framework_positions = [] |
| for index, part in enumerate(path_parts): |
| @@ -89,7 +158,7 @@ def chrome_dsym_hints(binary): |
| # In case 2 this is the same as |outermost_bundle|. |
| innermost_bundle = bundle_positions[-1] |
| dsym_path = product_dir + [path_parts[innermost_bundle]] |
| - result = '%s.dSYM' % os.path.sep.join(dsym_path) |
| + result = '%s.dSYM' % os.path.join(*dsym_path) |
| return [result] |
| @@ -169,13 +238,22 @@ def main(): |
| parser.add_argument('strip_path_prefix', nargs='*', |
| help='When printing source file names, the longest prefix ending in one ' |
| 'of these substrings will be stripped. E.g.: "Release/../../".') |
| + parser.add_argument('--executable-path', |
| + help='Path to program executable. Used on OSX swarming bots to locate ' |
| + 'dSYM bundles for associated frameworks and bundles.') |
| args = parser.parse_args() |
| disable_buffering() |
| set_symbolizer_path() |
| asan_symbolize.demangle = True |
| asan_symbolize.fix_filename_patterns = args.strip_path_prefix |
| - loop = asan_symbolize.SymbolizationLoop(dsym_hint_producer=chrome_dsym_hints) |
| + binary_name_filter = None |
| + if os.uname()[0] == 'Darwin': |
|
Timur Iskhodzhanov
2015/02/11 21:36:16
this asserts on Windows, again.
|
| + binary_name_filter = make_chrome_osx_binary_name_filter( |
| + chrome_product_dir_path(args.executable_path)) |
| + loop = asan_symbolize.SymbolizationLoop( |
| + binary_name_filter=binary_name_filter, |
| + dsym_hint_producer=chrome_dsym_hints) |
| if args.test_summary_json_file: |
| symbolize_snippets_in_json(args.test_summary_json_file, loop) |