Change sym_check to filter non-stdlib symbols.

Currently sym_check almost all names found in the binary, including those
which are defined in other libraries. This makes our ABI lists harder to maintain.

This patch adds a --only-stdlib-symbols option to sym_check which removes
all symbols which aren't possibly provided by libc++. It also re-generates
the linux ABI list after making this change.


git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@287294 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2016-11-18 01:40:20 +00:00
parent a93ebeca94
commit 0d6941834c
6 changed files with 1948 additions and 2013 deletions

View File

@@ -22,7 +22,7 @@ if (LIBCXX_HAS_ABILIST_CONFIGURATION)
set(ABILIST_FILE "${CMAKE_CURRENT_LIST_DIR}/${TARGET_TRIPLE}.abilist") set(ABILIST_FILE "${CMAKE_CURRENT_LIST_DIR}/${TARGET_TRIPLE}.abilist")
set(SYMDIFF_EXE "${LIBCXX_SOURCE_DIR}/utils/sym_check/sym_diff.py") set(SYMDIFF_EXE "${LIBCXX_SOURCE_DIR}/utils/sym_check/sym_diff.py")
add_custom_target(check-cxx-abilist add_custom_target(check-cxx-abilist
${SYMDIFF_EXE} ${ABILIST_FILE} $<TARGET_SONAME_FILE:cxx_shared> ${SYMDIFF_EXE} --only-stdlib-symbols ${ABILIST_FILE} $<TARGET_SONAME_FILE:cxx_shared>
DEPENDS cxx_shared DEPENDS cxx_shared
COMMENT "Testing ABI compatibility...") COMMENT "Testing ABI compatibility...")
endif() endif()

File diff suppressed because it is too large Load Diff

View File

@@ -12,9 +12,11 @@ extract - A set of function that extract symbol lists from shared libraries.
""" """
import distutils.spawn import distutils.spawn
import sys import sys
import re
from sym_check import util from sym_check import util
extract_ignore_names = ['_init', '_fini']
class NMExtractor(object): class NMExtractor(object):
""" """
@@ -65,7 +67,8 @@ class NMExtractor(object):
return None return None
new_sym = { new_sym = {
'name': bits[0], 'name': bits[0],
'type': bits[1] 'type': bits[1],
'is_defined': (bits[1].lower() != 'u')
} }
new_sym['name'] = new_sym['name'].replace('@@', '@') new_sym['name'] = new_sym['name'].replace('@@', '@')
new_sym = self._transform_sym_type(new_sym) new_sym = self._transform_sym_type(new_sym)
@@ -81,6 +84,8 @@ class NMExtractor(object):
""" """
if sym is None or len(sym) < 2: if sym is None or len(sym) < 2:
return False return False
if sym['name'] in extract_ignore_names:
return False
bad_types = ['t', 'b', 'r', 'd', 'w'] bad_types = ['t', 'b', 'r', 'd', 'w']
return (sym['type'] not in bad_types return (sym['type'] not in bad_types
and sym['name'] not in ['__bss_start', '_end', '_edata']) and sym['name'] not in ['__bss_start', '_end', '_edata'])
@@ -148,8 +153,11 @@ class ReadElfExtractor(object):
'name': parts[7], 'name': parts[7],
'size': int(parts[2]), 'size': int(parts[2]),
'type': parts[3], 'type': parts[3],
'is_defined': (parts[6] != 'UND')
} }
assert new_sym['type'] in ['OBJECT', 'FUNC', 'NOTYPE'] assert new_sym['type'] in ['OBJECT', 'FUNC', 'NOTYPE']
if new_sym['name'] in extract_ignore_names:
continue
if new_sym['type'] == 'NOTYPE': if new_sym['type'] == 'NOTYPE':
continue continue
if new_sym['type'] == 'FUNC': if new_sym['type'] == 'FUNC':

View File

@@ -12,7 +12,7 @@ import distutils.spawn
import signal import signal
import subprocess import subprocess
import sys import sys
import re
def execute_command(cmd, input_str=None): def execute_command(cmd, input_str=None):
""" """
@@ -135,3 +135,40 @@ def extract_or_load(filename):
if is_library_file(filename): if is_library_file(filename):
return sym_check.extract.extract_symbols(filename) return sym_check.extract.extract_symbols(filename)
return read_syms_from_file(filename) return read_syms_from_file(filename)
def adjust_mangled_name(name):
if not name.startswith('__Z'):
return name
return name[1:]
new_delete_std_symbols = [
'_Znam',
'_Znwm',
'_ZdaPv',
'_ZdaPvm',
'_ZdlPv',
'_ZdlPvm'
]
def is_stdlib_symbol_name(name):
name = adjust_mangled_name(name)
if name in new_delete_std_symbols:
return True
if re.search("@GLIBC|@GCC", name):
return False
if re.search('(St[0-9])|(__cxa)|(__cxxabi)', name):
return True
return True
def filter_stdlib_symbols(syms):
stdlib_symbols = []
other_symbols = []
for s in syms:
canon_name = adjust_mangled_name(s['name'])
if not is_stdlib_symbol_name(canon_name):
assert not s['is_defined'] and \
'have non-stdlib symbol defined in stdlib'
other_symbols += [s]
else:
stdlib_symbols += [s]
return stdlib_symbols, other_symbols

View File

@@ -27,6 +27,9 @@ def main():
'--removed-only', dest='removed_only', '--removed-only', dest='removed_only',
help='Only print removed symbols', help='Only print removed symbols',
action='store_true', default=False) action='store_true', default=False)
parser.add_argument('--only-stdlib-symbols', dest='only_stdlib',
help="Filter all symbols not related to the stdlib",
action='store_true', default=False)
parser.add_argument( parser.add_argument(
'-o', '--output', dest='output', '-o', '--output', dest='output',
help='The output file. stdout is used if not given', help='The output file. stdout is used if not given',
@@ -44,6 +47,10 @@ def main():
old_syms_list = util.extract_or_load(args.old_syms) old_syms_list = util.extract_or_load(args.old_syms)
new_syms_list = util.extract_or_load(args.new_syms) new_syms_list = util.extract_or_load(args.new_syms)
if args.only_stdlib:
old_syms_list, _ = util.filter_stdlib_symbols(old_syms_list)
new_syms_list, _ = util.filter_stdlib_symbols(new_syms_list)
added, removed, changed = diff.diff(old_syms_list, new_syms_list) added, removed, changed = diff.diff(old_syms_list, new_syms_list)
if args.removed_only: if args.removed_only:
added = {} added = {}

View File

@@ -25,11 +25,16 @@ def main():
parser.add_argument('--names-only', dest='names_only', parser.add_argument('--names-only', dest='names_only',
help='Output only the name of the symbol', help='Output only the name of the symbol',
action='store_true', default=False) action='store_true', default=False)
parser.add_argument('--only-stdlib-symbols', dest='only_stdlib',
help="Filter all symbols not related to the stdlib",
action='store_true', default=False)
args = parser.parse_args() args = parser.parse_args()
if args.output is not None: if args.output is not None:
print('Extracting symbols from %s to %s.' print('Extracting symbols from %s to %s.'
% (args.library, args.output)) % (args.library, args.output))
syms = extract.extract_symbols(args.library) syms = extract.extract_symbols(args.library)
if args.only_stdlib:
syms, other_syms = util.filter_stdlib_symbols(syms)
util.write_syms(syms, out=args.output, names_only=args.names_only) util.write_syms(syms, out=args.output, names_only=args.names_only)