diff options
author | Ting-Yuan Huang <laszio@chromium.org> | 2018-02-28 14:35:48 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-03-02 20:47:16 -0800 |
commit | 340542b21c30cd62a68d19f086edef36d849971b (patch) | |
tree | cae122ce8c6126141c298516d0575a067a9efe7d /debug_info_test | |
parent | edcf3d33a602438104cafd76f534fa8007e9de7b (diff) | |
download | toolchain-utils-340542b21c30cd62a68d19f086edef36d849971b.tar.gz |
debug_info_test: Run tests based on debug info
debug_info_test calls tests on the given ELF files. When a directory is
supplied, all ELFs will be searched and tested recursively.
BUG=chromium:817648
TEST=debug_info_test /build/kip/usr/lib/debug
Change-Id: Ibcb1ac2de19df9227eb6e242d611ec841d4b589f
Reviewed-on: https://chromium-review.googlesource.com/942465
Commit-Ready: Ting-Yuan Huang <laszio@chromium.org>
Tested-by: Ting-Yuan Huang <laszio@chromium.org>
Reviewed-by: Ting-Yuan Huang <laszio@chromium.org>
Reviewed-by: Yunlian Jiang <yunlian@chromium.org>
Diffstat (limited to 'debug_info_test')
-rw-r--r-- | debug_info_test/check_clang.py | 26 | ||||
-rw-r--r-- | debug_info_test/check_cus.py | 67 | ||||
-rw-r--r-- | debug_info_test/clang_comp_path.whitelist | 4 | ||||
-rw-r--r-- | debug_info_test/clang_dso_path.whitelist | 12 | ||||
-rwxr-xr-x | debug_info_test/debug_info_test.py | 53 | ||||
-rw-r--r-- | debug_info_test/whitelist.py | 57 |
6 files changed, 219 insertions, 0 deletions
diff --git a/debug_info_test/check_clang.py b/debug_info_test/check_clang.py new file mode 100644 index 00000000..a6d056ed --- /dev/null +++ b/debug_info_test/check_clang.py @@ -0,0 +1,26 @@ +# Copyright 2018 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +from whitelist import is_whitelisted + +def is_built_with_clang(dso_path, producer, comp_path): + """Check whether the compile unit is built by clang. + + Args: + dso_path: path to the elf/dso + producer: DW_AT_producer contains the compiler command line. + comp_path: DW_AT_comp_dir + DW_AT_name + + Returns: + False if compiled by gcc otherwise True + """ + if is_whitelisted('clang_comp_path', comp_path): + return True + + if is_whitelisted('clang_dso_path', dso_path): + return True + + if 'clang version' not in producer: + return False + return True diff --git a/debug_info_test/check_cus.py b/debug_info_test/check_cus.py new file mode 100644 index 00000000..88fcf275 --- /dev/null +++ b/debug_info_test/check_cus.py @@ -0,0 +1,67 @@ +# Copyright 2018 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import subprocess + +import check_clang + +cu_checks = [check_clang.is_built_with_clang] + +def check_compile_unit(dso_path, producer, comp_path): + """check all compiler flags used to build the compile unit. + + Args: + dso_path: path to the elf/dso + producer: DW_AT_producer contains the compiler command line. + comp_path: DW_AT_comp_dir + DW_AT_name + + Returns: + A set of failed tests. + """ + failed = set() + for c in cu_checks: + if not c(dso_path, producer, comp_path): + failed.add(c.__module__) + + return failed + +def check_compile_units(dso_path): + """check all compile units in the given dso. + + Args: + dso_path: path to the dso + Return: + True if everything looks fine otherwise False. + """ + + failed = set() + producer = '' + comp_path = '' + + readelf = subprocess.Popen(['readelf', '--debug-dump=info', + '--dwarf-depth=1', dso_path], + stdout=subprocess.PIPE, + stderr=open(os.devnull, 'w')) + for l in readelf.stdout: + if 'DW_TAG_compile_unit' in l: + if producer: + failed = failed.union(check_compile_unit(dso_path, producer, + comp_path)) + producer = '' + comp_path = '' + elif 'DW_AT_producer' in l: + producer = l + elif 'DW_AT_name' in l: + comp_path = os.path.join(comp_path, l.split(':')[-1].strip()) + elif 'DW_AT_comp_dir' in l: + comp_path = os.path.join(l.split(':')[-1].strip(), comp_path) + if producer: + failed = failed.union(check_compile_unit(dso_path, producer, comp_path)) + + if failed: + print('%s failed check: %s' % (dso_path, ' '.join(failed))) + return False + + return True diff --git a/debug_info_test/clang_comp_path.whitelist b/debug_info_test/clang_comp_path.whitelist new file mode 100644 index 00000000..45df0547 --- /dev/null +++ b/debug_info_test/clang_comp_path.whitelist @@ -0,0 +1,4 @@ +# These are generally objects linked from system libraries such as glibc +# and libgcc. +.*/glibc-.*/ +.*/libgcc/.* diff --git a/debug_info_test/clang_dso_path.whitelist b/debug_info_test/clang_dso_path.whitelist new file mode 100644 index 00000000..74f520ea --- /dev/null +++ b/debug_info_test/clang_dso_path.whitelist @@ -0,0 +1,12 @@ +# modules we don't care: +.*/binutils/.* +.*/binutils-bin/.* +.*/libpepflashplayer\.so\.debug +.*/opt/punybench/bin/.* +.*/telemetry_dep/.* +.*/unixbench/.* +.*/opt/google/containers/android/.* +.*/libmali\.so.*\.debug +# todos: +.*/flashrom_s.debug +.*/ec_ctl.debug diff --git a/debug_info_test/debug_info_test.py b/debug_info_test/debug_info_test.py new file mode 100755 index 00000000..cf3148db --- /dev/null +++ b/debug_info_test/debug_info_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/python + +# Copyright 2018 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import subprocess +import sys + +import check_cus + +elf_checks = [check_cus.check_compile_units] + +def scanelf(root): + """find ELFs in root + + Args: + root: root dir to start with the search. + Returns: + Filenames of ELFs in root. + """ + p = subprocess.Popen(['scanelf', '-y', '-B', '-F', '%F', '-R', root], + stdout=subprocess.PIPE) + return [l.strip() for l in p.stdout] + +def Main(argv): + if len(argv) < 2: + print('usage: %s [file|dir]') + return 1 + + files = [] + cand = argv[1] + if os.path.isfile(cand): + files = [cand] + elif os.path.isdir(cand): + files = scanelf(cand) + else: + print('usage: %s [file|dir]') + return 1 + + failed = False + for f in files: + for c in elf_checks: + if not c(f): + failed = True + + if failed: + return 1 + return 0 + +if __name__ == '__main__': + sys.exit(Main(sys.argv)) diff --git a/debug_info_test/whitelist.py b/debug_info_test/whitelist.py new file mode 100644 index 00000000..99a457c0 --- /dev/null +++ b/debug_info_test/whitelist.py @@ -0,0 +1,57 @@ +# Copyright 2018 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import glob +import re + +# Matching a string of length m in an NFA of size n is O(mn^2), but the +# performance also depends largely on the implementation. It appears to be fast +# enough according to the tests. +# +# The performance bottleneck of this script is readelf. Unless this becomes +# slower than readelf, don't waste time here. +def is_whitelisted(list_name, pattern): + """chech whether the given pattern is specified in the whitelist. + + Args: + list_name: name of the whitelist + pattern: the target string + Returns: + True if matched otherwise False + """ + return pattern and whitelists[list_name].match(pattern) + +def prepare_whitelist(patterns): + """Join and compile the re patterns. + + Args: + patterns: regex patterns. + Return: + A compiled re object + """ + return re.compile('|'.join(patterns)) + +def load_whitelists(dirname): + """Load whitelists under dirname. + + A whitelist ends with .whitelist. + + Args: + dirname: path to the dir. + Returns: + A dictionary of 'filename' -> whitelist matcher. + """ + wlist = {} + for fn in glob.glob(os.path.join(dirname, '*.whitelist')): + key = os.path.splitext(os.path.basename(fn))[0] + with open(fn, 'r') as f: + patterns = f.read().splitlines() + patterns = [l for l in patterns if l[0] != '#'] + patterns = [l for l in patterns if l != ''] + wlist[key] = prepare_whitelist(patterns) + return wlist + + +whitelists = load_whitelists(os.path.dirname(__file__)) |