|
@@ -1,290 +0,0 @@
|
|
|
-# HG changeset patch
|
|
|
-# User Mike Hommey <mh+mozilla@glandium.org>
|
|
|
-# Date 1548372749 0
|
|
|
-# Node ID d1b523e67100557e4adceabe8ca6ea434f6cb5e7
|
|
|
-# Parent 2e12f8ff052c6449f80f0b4fe0cca5fb00a6e313
|
|
|
-Bug 1516228 - Use llvm-objdump for symbol related tests in check_binary.py. r=mshal
|
|
|
-
|
|
|
-Depends on D17466
|
|
|
-
|
|
|
-Differential Revision: https://phabricator.services.mozilla.com/D17467
|
|
|
-
|
|
|
-diff --git a/python/mozbuild/mozbuild/action/check_binary.py b/python/mozbuild/mozbuild/action/check_binary.py
|
|
|
---- a/python/mozbuild/mozbuild/action/check_binary.py
|
|
|
-+++ b/python/mozbuild/mozbuild/action/check_binary.py
|
|
|
-@@ -1,53 +1,54 @@
|
|
|
- # This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
- # License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
- # file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
-
|
|
|
- from __future__ import absolute_import, print_function, unicode_literals
|
|
|
-
|
|
|
- import argparse
|
|
|
- import os
|
|
|
-+import re
|
|
|
- import subprocess
|
|
|
- import sys
|
|
|
-
|
|
|
- from packaging.version import Version
|
|
|
-
|
|
|
- import buildconfig
|
|
|
- from mozbuild.util import memoize
|
|
|
- from mozpack.executables import (
|
|
|
- get_type,
|
|
|
- ELF,
|
|
|
- MACHO,
|
|
|
-+ UNKNOWN,
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
- STDCXX_MAX_VERSION = Version('3.4.19')
|
|
|
- CXXABI_MAX_VERSION = Version('1.3.7')
|
|
|
- GLIBC_MAX_VERSION = Version('2.17')
|
|
|
- LIBGCC_MAX_VERSION = Version('4.8')
|
|
|
-
|
|
|
- HOST = {
|
|
|
- 'MOZ_LIBSTDCXX_VERSION':
|
|
|
- buildconfig.substs.get('MOZ_LIBSTDCXX_HOST_VERSION'),
|
|
|
- 'platform': buildconfig.substs['HOST_OS_ARCH'],
|
|
|
- 'readelf': 'readelf',
|
|
|
-- 'nm': 'nm',
|
|
|
- }
|
|
|
-
|
|
|
- TARGET = {
|
|
|
- 'MOZ_LIBSTDCXX_VERSION':
|
|
|
- buildconfig.substs.get('MOZ_LIBSTDCXX_TARGET_VERSION'),
|
|
|
- 'platform': buildconfig.substs['OS_TARGET'],
|
|
|
- 'readelf': '{}readelf'.format(
|
|
|
- buildconfig.substs.get('TOOLCHAIN_PREFIX', '')),
|
|
|
-- 'nm': '{}nm'.format(buildconfig.substs.get('TOOLCHAIN_PREFIX', '')),
|
|
|
-- 'readobj': '{}readobj'.format(buildconfig.substs.get('TOOLCHAIN_PREFIX', '')),
|
|
|
- }
|
|
|
-
|
|
|
-+ADDR_RE = re.compile(r'[0-9a-f]{8,16}')
|
|
|
-+
|
|
|
- if buildconfig.substs.get('HAVE_64BIT_BUILD'):
|
|
|
- GUESSED_NSMODULE_SIZE = 8
|
|
|
- else:
|
|
|
- GUESSED_NSMODULE_SIZE = 4
|
|
|
-
|
|
|
-
|
|
|
- get_type = memoize(get_type)
|
|
|
-
|
|
|
-@@ -71,62 +72,107 @@ def at_least_one(iter):
|
|
|
- saw_one = False
|
|
|
- for item in iter:
|
|
|
- saw_one = True
|
|
|
- yield item
|
|
|
- if not saw_one:
|
|
|
- raise Empty()
|
|
|
-
|
|
|
-
|
|
|
--def iter_readelf_symbols(target, binary):
|
|
|
-- for line in get_output(target['readelf'], '-sW', binary):
|
|
|
-- data = line.split()
|
|
|
-- if len(data) >= 8 and data[0].endswith(':') and data[0][:-1].isdigit():
|
|
|
-- n, addr, size, type, bind, vis, index, name = data[:8]
|
|
|
-+# Iterates the symbol table on ELF and MACHO, and the export table on
|
|
|
-+# COFF/PE.
|
|
|
-+def iter_symbols(binary):
|
|
|
-+ ty = get_type(binary)
|
|
|
-+ # XXX: Static libraries on ELF, MACHO and COFF/PE systems are all
|
|
|
-+ # ar archives. So technically speaking, the following is wrong
|
|
|
-+ # but is enough for now. llvm-objdump -t can actually be used on all
|
|
|
-+ # platforms for static libraries, but its format is different for
|
|
|
-+ # Windows .obj files, so the following won't work for them, but
|
|
|
-+ # it currently doesn't matter.
|
|
|
-+ if ty == UNKNOWN and open(binary).read(8) == '!<arch>\n':
|
|
|
-+ ty = ELF
|
|
|
-+ if ty in (ELF, MACHO):
|
|
|
-+ for line in get_output(buildconfig.substs['LLVM_OBJDUMP'], '-t',
|
|
|
-+ binary):
|
|
|
-+ m = ADDR_RE.match(line)
|
|
|
-+ if not m:
|
|
|
-+ continue
|
|
|
-+ addr = int(m.group(0), 16)
|
|
|
-+ # The second "column" is 7 one-character items that can be
|
|
|
-+ # whitespaces. We don't have use for their value, so just skip
|
|
|
-+ # those.
|
|
|
-+ rest = line[m.end() + 9:].split()
|
|
|
-+ # The number of remaining colums will vary between ELF and MACHO.
|
|
|
-+ # On ELF, we have:
|
|
|
-+ # Section Size .hidden? Name
|
|
|
-+ # On Macho, the size is skipped.
|
|
|
-+ # In every case, the symbol name is last.
|
|
|
-+ name = rest[-1]
|
|
|
- if '@' in name:
|
|
|
- name, ver = name.rsplit('@', 1)
|
|
|
- while name.endswith('@'):
|
|
|
- name = name[:-1]
|
|
|
- else:
|
|
|
- ver = None
|
|
|
- yield {
|
|
|
-- 'addr': int(addr, 16),
|
|
|
-- # readelf output may contain decimal values or hexadecimal
|
|
|
-- # values prefixed with 0x for the size. Let python autodetect.
|
|
|
-- 'size': int(size, 0),
|
|
|
-- 'type': type,
|
|
|
-- 'binding': bind,
|
|
|
-- 'visibility': vis,
|
|
|
-- 'index': index,
|
|
|
-+ 'addr': addr,
|
|
|
-+ 'size': int(rest[1], 16) if ty == ELF else 0,
|
|
|
- 'name': name,
|
|
|
-- 'version': ver,
|
|
|
-+ 'version': ver or None,
|
|
|
-+ }
|
|
|
-+ else:
|
|
|
-+ export_table = False
|
|
|
-+ for line in get_output(buildconfig.substs['LLVM_OBJDUMP'], '-p',
|
|
|
-+ binary):
|
|
|
-+ if line.strip() == 'Export Table:':
|
|
|
-+ export_table = True
|
|
|
-+ continue
|
|
|
-+ elif not export_table:
|
|
|
-+ continue
|
|
|
-+
|
|
|
-+ cols = line.split()
|
|
|
-+ # The data we're interested in comes in 3 columns, and the first
|
|
|
-+ # column is a number.
|
|
|
-+ if len(cols) != 3 or not cols[0].isdigit():
|
|
|
-+ continue
|
|
|
-+ _, rva, name = cols
|
|
|
-+ # - The MSVC mangling has some type info following `@@`
|
|
|
-+ # - Any namespacing that can happen on the symbol appears as a
|
|
|
-+ # suffix, after a `@`.
|
|
|
-+ # - Mangled symbols are prefixed with `?`.
|
|
|
-+ name = name.split('@@')[0].split('@')[0].lstrip('?')
|
|
|
-+ yield {
|
|
|
-+ 'addr': int(rva, 16),
|
|
|
-+ 'size': 0,
|
|
|
-+ 'name': name,
|
|
|
-+ 'version': None,
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- def iter_readelf_dynamic(target, binary):
|
|
|
- for line in get_output(target['readelf'], '-d', binary):
|
|
|
- data = line.split(None, 2)
|
|
|
- if data and len(data) == 3 and data[0].startswith('0x'):
|
|
|
- yield data[1].rstrip(')').lstrip('('), data[2]
|
|
|
-
|
|
|
-
|
|
|
- def check_dep_versions(target, binary, lib, prefix, max_version):
|
|
|
- if get_type(binary) != ELF:
|
|
|
- raise Skip()
|
|
|
- unwanted = []
|
|
|
- prefix = prefix + '_'
|
|
|
- try:
|
|
|
-- for sym in at_least_one(iter_readelf_symbols(target, binary)):
|
|
|
-- if sym['index'] == 'UND' and sym['version'] and \
|
|
|
-+ for sym in at_least_one(iter_symbols(binary)):
|
|
|
-+ if sym['addr'] == 0 and sym['version'] and \
|
|
|
- sym['version'].startswith(prefix):
|
|
|
- version = Version(sym['version'][len(prefix):])
|
|
|
- if version > max_version:
|
|
|
- unwanted.append(sym)
|
|
|
- except Empty:
|
|
|
-- raise RuntimeError('Could not parse readelf output?')
|
|
|
-+ raise RuntimeError('Could not parse llvm-objdump output?')
|
|
|
- if unwanted:
|
|
|
- print('\n'.join([
|
|
|
- 'TEST-NOTICE We do not want these {} symbol versions to be used:'.format(lib)
|
|
|
- ] + [
|
|
|
- ' {} ({})'.format(s['name'], s['version']) for s in unwanted
|
|
|
- ]), file=sys.stderr)
|
|
|
-
|
|
|
-
|
|
|
-@@ -178,73 +224,35 @@ def check_nsmodules(target, binary):
|
|
|
-
|
|
|
- test_msvc = (buildconfig.substs.get('CC_TYPE') in ('msvc', 'clang-cl') and \
|
|
|
- buildconfig.substs.get('DEVELOPER_OPTIONS'))
|
|
|
- test_clang_win = (buildconfig.substs.get('CC_TYPE') == 'clang' and \
|
|
|
- buildconfig.substs.get('OS_ARCH') == 'WINNT')
|
|
|
- test_gcc_win = (buildconfig.substs.get('CC_TYPE') == 'gcc' and \
|
|
|
- buildconfig.substs.get('OS_ARCH') == 'WINNT')
|
|
|
-
|
|
|
-- if buildconfig.substs.get('CC_TYPE') in ('msvc', 'clang-cl'):
|
|
|
-- for line in get_output('dumpbin.exe', '-exports', binary):
|
|
|
-- data = line.split(None, 3)
|
|
|
-- if data and len(data) == 4 and data[0].isdigit() and \
|
|
|
-- ishex(data[1]) and ishex(data[2]):
|
|
|
-- # - Some symbols in the table can be aliases, and appear as
|
|
|
-- # `foo = bar`.
|
|
|
-- # - The MSVC mangling has some type info following `@@`
|
|
|
-- # - Any namespacing that can happen on the symbol appears as a
|
|
|
-- # suffix, after a `@`.
|
|
|
-- # - Mangled symbols are prefixed with `?`.
|
|
|
-- name = data[3].split(' = ')[0].split('@@')[0].split('@')[0] \
|
|
|
-- .lstrip('?')
|
|
|
-- if name.endswith('_NSModule') or name in (
|
|
|
-- '__start_kPStaticModules',
|
|
|
-- '__stop_kPStaticModules'):
|
|
|
-- symbols.append((int(data[2], 16), GUESSED_NSMODULE_SIZE,
|
|
|
-- name))
|
|
|
-- else:
|
|
|
-- # MinGW-Clang, when building pdbs, doesn't include the symbol table into
|
|
|
-- # the final module. To get the NSModule info, we can look at the exported
|
|
|
-- # symbols. (#1475562)
|
|
|
-- if test_clang_win:
|
|
|
-- readobj_output = get_output(target['readobj'], '-coff-exports', binary)
|
|
|
-- # Transform the output of readobj into nm-like output
|
|
|
-- output = []
|
|
|
-- for line in readobj_output:
|
|
|
-- if "Name" in line:
|
|
|
-- name = line.replace("Name:", "").strip()
|
|
|
-- elif "RVA" in line:
|
|
|
-- rva = line.replace("RVA:", "").strip()
|
|
|
-- output.append("%s r %s" % (name, rva))
|
|
|
-- else:
|
|
|
-- output = get_output(target['nm'], '-P', binary)
|
|
|
--
|
|
|
-- for line in output:
|
|
|
-- data = line.split()
|
|
|
-- # Some symbols may not have a size listed at all.
|
|
|
-- if len(data) == 3:
|
|
|
-- data.append('0')
|
|
|
-- if len(data) == 4:
|
|
|
-- sym, _, addr, size = data
|
|
|
-- # NSModules symbols end with _NSModule or _NSModuleE when
|
|
|
-- # C++-mangled.
|
|
|
-- if sym.endswith(('_NSModule', '_NSModuleE')):
|
|
|
-- if test_gcc_win and any(x in data[0] for x in [".refptr", "_GLOBAL"]):
|
|
|
-- continue
|
|
|
-- # On mac, nm doesn't actually print anything other than 0
|
|
|
-- # for the size. So take our best guess.
|
|
|
-- size = int(size, 16) or GUESSED_NSMODULE_SIZE
|
|
|
-- symbols.append((int(addr, 16), size, sym))
|
|
|
-- elif sym.endswith(('__start_kPStaticModules',
|
|
|
-- '__stop_kPStaticModules')):
|
|
|
-- # On ELF and mac systems, these symbols have no size, such
|
|
|
-- # that the first actual NSModule has the same address as
|
|
|
-- # the start symbol.
|
|
|
-- symbols.append((int(addr, 16), 0, sym))
|
|
|
-+ for sym in iter_symbols(binary):
|
|
|
-+ if sym['addr'] == 0:
|
|
|
-+ continue
|
|
|
-+ name = sym['name']
|
|
|
-+ # NSModules symbols end with _NSModule or _NSModuleE when C++-mangled.
|
|
|
-+ if name.endswith(('_NSModule', '_NSModuleE')):
|
|
|
-+ if test_gcc_win and any(x in data[0] for x in [".refptr", "_GLOBAL"]):
|
|
|
-+ continue
|
|
|
-+ # We don't have a valid size in the symbol list for macho and coff.
|
|
|
-+ # Use our guesstimate.
|
|
|
-+ size = sym['size'] or GUESSED_NSMODULE_SIZE
|
|
|
-+ symbols.append((sym['addr'], size, name))
|
|
|
-+ elif name in ('__start_kPStaticModules', '__stop_kPStaticModules'):
|
|
|
-+ # For coff, these symbols have a size.
|
|
|
-+ if get_type(binary) not in (ELF, MACHO):
|
|
|
-+ size = GUESSED_NSMODULE_SIZE
|
|
|
-+ else:
|
|
|
-+ size = 0
|
|
|
-+ symbols.append((sym['addr'], size, name))
|
|
|
- if not symbols:
|
|
|
- raise RuntimeError('Could not find NSModules')
|
|
|
-
|
|
|
- def print_symbols(symbols):
|
|
|
- for addr, size, sym in symbols:
|
|
|
- print('%x %d %s' % (addr, size, sym))
|
|
|
-
|
|
|
- symbols = sorted(symbols)
|