| # ===----------------------------------------------------------------------===## |
| # |
| # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| # See https://llvm.org/LICENSE.txt for license information. |
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| # |
| # ===----------------------------------------------------------------------===## |
| |
| from pprint import pformat |
| import ast |
| import re |
| import shutil |
| import subprocess |
| import sys |
| |
| |
| def read_syms_from_list(slist): |
| """ |
| Read a list of symbols from a list of strings. |
| Each string is one symbol. |
| """ |
| return [ast.literal_eval(l) for l in slist] |
| |
| |
| def read_syms_from_file(filename): |
| """ |
| Read a list of symbols in from a file. |
| """ |
| with open(filename, "r") as f: |
| data = f.read() |
| return read_syms_from_list(data.splitlines()) |
| |
| |
| def read_exclusions(filename): |
| with open(filename, "r") as f: |
| data = f.read() |
| lines = [l.strip() for l in data.splitlines() if l.strip()] |
| lines = [l for l in lines if not l.startswith("#")] |
| return lines |
| |
| |
| def write_syms(sym_list, out=None, names_only=False, filter=None): |
| """ |
| Write a list of symbols to the file named by out. |
| """ |
| out_str = "" |
| out_list = sym_list |
| out_list.sort(key=lambda x: x["name"]) |
| if filter is not None: |
| out_list = filter(out_list) |
| if names_only: |
| out_list = [sym["name"] for sym in out_list] |
| for sym in out_list: |
| # Use pformat for consistent ordering of keys. |
| out_str += pformat(sym, width=100000) + "\n" |
| if out is None: |
| sys.stdout.write(out_str) |
| else: |
| with open(out, "w") as f: |
| f.write(out_str) |
| |
| |
| _cppfilt_exe = shutil.which("c++filt") |
| |
| |
| def demangle_symbol(symbol): |
| if _cppfilt_exe is None: |
| return symbol |
| result = subprocess.run([_cppfilt_exe], input=symbol.encode(), capture_output=True) |
| if result.returncode != 0: |
| return symbol |
| return result.stdout.decode() |
| |
| |
| def is_elf(filename): |
| with open(filename, "rb") as f: |
| magic_bytes = f.read(4) |
| return magic_bytes == b"\x7fELF" |
| |
| |
| def is_mach_o(filename): |
| with open(filename, "rb") as f: |
| magic_bytes = f.read(4) |
| return magic_bytes in [ |
| b"\xfe\xed\xfa\xce", # MH_MAGIC |
| b"\xce\xfa\xed\xfe", # MH_CIGAM |
| b"\xfe\xed\xfa\xcf", # MH_MAGIC_64 |
| b"\xcf\xfa\xed\xfe", # MH_CIGAM_64 |
| b"\xca\xfe\xba\xbe", # FAT_MAGIC |
| b"\xbe\xba\xfe\xca", # FAT_CIGAM |
| ] |
| |
| |
| def is_xcoff_or_big_ar(filename): |
| with open(filename, "rb") as f: |
| magic_bytes = f.read(7) |
| return ( |
| magic_bytes[:4] in [b"\x01DF", b"\x01F7"] # XCOFF32 # XCOFF64 |
| or magic_bytes == b"<bigaf>" |
| ) |
| |
| |
| def is_library_file(filename): |
| if sys.platform == "darwin": |
| return is_mach_o(filename) |
| elif sys.platform.startswith("aix"): |
| return is_xcoff_or_big_ar(filename) |
| else: |
| return is_elf(filename) |
| |
| |
| def extract_or_load(filename): |
| import libcxx.sym_check.extract |
| |
| if is_library_file(filename): |
| return libcxx.sym_check.extract.extract_symbols(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"] |
| |
| cxxabi_symbols = [ |
| "___dynamic_cast", |
| "___gxx_personality_v0", |
| "_ZTIDi", |
| "_ZTIDn", |
| "_ZTIDs", |
| "_ZTIPDi", |
| "_ZTIPDn", |
| "_ZTIPDs", |
| "_ZTIPKDi", |
| "_ZTIPKDn", |
| "_ZTIPKDs", |
| "_ZTIPKa", |
| "_ZTIPKb", |
| "_ZTIPKc", |
| "_ZTIPKd", |
| "_ZTIPKe", |
| "_ZTIPKf", |
| "_ZTIPKh", |
| "_ZTIPKi", |
| "_ZTIPKj", |
| "_ZTIPKl", |
| "_ZTIPKm", |
| "_ZTIPKs", |
| "_ZTIPKt", |
| "_ZTIPKv", |
| "_ZTIPKw", |
| "_ZTIPKx", |
| "_ZTIPKy", |
| "_ZTIPa", |
| "_ZTIPb", |
| "_ZTIPc", |
| "_ZTIPd", |
| "_ZTIPe", |
| "_ZTIPf", |
| "_ZTIPh", |
| "_ZTIPi", |
| "_ZTIPj", |
| "_ZTIPl", |
| "_ZTIPm", |
| "_ZTIPs", |
| "_ZTIPt", |
| "_ZTIPv", |
| "_ZTIPw", |
| "_ZTIPx", |
| "_ZTIPy", |
| "_ZTIa", |
| "_ZTIb", |
| "_ZTIc", |
| "_ZTId", |
| "_ZTIe", |
| "_ZTIf", |
| "_ZTIh", |
| "_ZTIi", |
| "_ZTIj", |
| "_ZTIl", |
| "_ZTIm", |
| "_ZTIs", |
| "_ZTIt", |
| "_ZTIv", |
| "_ZTIw", |
| "_ZTIx", |
| "_ZTIy", |
| "_ZTSDi", |
| "_ZTSDn", |
| "_ZTSDs", |
| "_ZTSPDi", |
| "_ZTSPDn", |
| "_ZTSPDs", |
| "_ZTSPKDi", |
| "_ZTSPKDn", |
| "_ZTSPKDs", |
| "_ZTSPKa", |
| "_ZTSPKb", |
| "_ZTSPKc", |
| "_ZTSPKd", |
| "_ZTSPKe", |
| "_ZTSPKf", |
| "_ZTSPKh", |
| "_ZTSPKi", |
| "_ZTSPKj", |
| "_ZTSPKl", |
| "_ZTSPKm", |
| "_ZTSPKs", |
| "_ZTSPKt", |
| "_ZTSPKv", |
| "_ZTSPKw", |
| "_ZTSPKx", |
| "_ZTSPKy", |
| "_ZTSPa", |
| "_ZTSPb", |
| "_ZTSPc", |
| "_ZTSPd", |
| "_ZTSPe", |
| "_ZTSPf", |
| "_ZTSPh", |
| "_ZTSPi", |
| "_ZTSPj", |
| "_ZTSPl", |
| "_ZTSPm", |
| "_ZTSPs", |
| "_ZTSPt", |
| "_ZTSPv", |
| "_ZTSPw", |
| "_ZTSPx", |
| "_ZTSPy", |
| "_ZTSa", |
| "_ZTSb", |
| "_ZTSc", |
| "_ZTSd", |
| "_ZTSe", |
| "_ZTSf", |
| "_ZTSh", |
| "_ZTSi", |
| "_ZTSj", |
| "_ZTSl", |
| "_ZTSm", |
| "_ZTSs", |
| "_ZTSt", |
| "_ZTSv", |
| "_ZTSw", |
| "_ZTSx", |
| "_ZTSy", |
| ] |
| |
| |
| def is_stdlib_symbol_name(name, sym): |
| name = adjust_mangled_name(name) |
| if re.search("@GLIBC|@GCC", name): |
| # Only when symbol is defined do we consider it ours |
| return sym["is_defined"] |
| if re.search("(St[0-9])|(__cxa)|(__cxxabi)", name): |
| return True |
| if name in new_delete_std_symbols: |
| return True |
| if name in cxxabi_symbols: |
| return True |
| if name.startswith("_Z"): |
| return True |
| return False |
| |
| |
| 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, s): |
| other_symbols += [s] |
| else: |
| stdlib_symbols += [s] |
| return stdlib_symbols, other_symbols |