1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*9e94795aSAndroid Build Coastguard Worker# 3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2019 The Android Open Source Project 4*9e94795aSAndroid Build Coastguard Worker# 5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*9e94795aSAndroid Build Coastguard Worker# 9*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*9e94795aSAndroid Build Coastguard Worker# 11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Worker"""ELF file checker. 18*9e94795aSAndroid Build Coastguard Worker 19*9e94795aSAndroid Build Coastguard WorkerThis command ensures all undefined symbols in an ELF file can be resolved to 20*9e94795aSAndroid Build Coastguard Workerglobal (or weak) symbols defined in shared objects specified in DT_NEEDED 21*9e94795aSAndroid Build Coastguard Workerentries. 22*9e94795aSAndroid Build Coastguard Worker""" 23*9e94795aSAndroid Build Coastguard Worker 24*9e94795aSAndroid Build Coastguard Workerfrom __future__ import print_function 25*9e94795aSAndroid Build Coastguard Worker 26*9e94795aSAndroid Build Coastguard Workerimport argparse 27*9e94795aSAndroid Build Coastguard Workerimport collections 28*9e94795aSAndroid Build Coastguard Workerimport os 29*9e94795aSAndroid Build Coastguard Workerimport os.path 30*9e94795aSAndroid Build Coastguard Workerimport re 31*9e94795aSAndroid Build Coastguard Workerimport struct 32*9e94795aSAndroid Build Coastguard Workerimport subprocess 33*9e94795aSAndroid Build Coastguard Workerimport sys 34*9e94795aSAndroid Build Coastguard Worker 35*9e94795aSAndroid Build Coastguard Worker 36*9e94795aSAndroid Build Coastguard Worker_ELF_MAGIC = b'\x7fELF' 37*9e94795aSAndroid Build Coastguard Worker 38*9e94795aSAndroid Build Coastguard Worker 39*9e94795aSAndroid Build Coastguard Worker# Known machines 40*9e94795aSAndroid Build Coastguard Worker_EM_386 = 3 41*9e94795aSAndroid Build Coastguard Worker_EM_ARM = 40 42*9e94795aSAndroid Build Coastguard Worker_EM_X86_64 = 62 43*9e94795aSAndroid Build Coastguard Worker_EM_AARCH64 = 183 44*9e94795aSAndroid Build Coastguard Worker 45*9e94795aSAndroid Build Coastguard Worker_KNOWN_MACHINES = {_EM_386, _EM_ARM, _EM_X86_64, _EM_AARCH64} 46*9e94795aSAndroid Build Coastguard Worker 47*9e94795aSAndroid Build Coastguard Worker 48*9e94795aSAndroid Build Coastguard Worker# ELF header struct 49*9e94795aSAndroid Build Coastguard Worker_ELF_HEADER_STRUCT = ( 50*9e94795aSAndroid Build Coastguard Worker ('ei_magic', '4s'), 51*9e94795aSAndroid Build Coastguard Worker ('ei_class', 'B'), 52*9e94795aSAndroid Build Coastguard Worker ('ei_data', 'B'), 53*9e94795aSAndroid Build Coastguard Worker ('ei_version', 'B'), 54*9e94795aSAndroid Build Coastguard Worker ('ei_osabi', 'B'), 55*9e94795aSAndroid Build Coastguard Worker ('ei_pad', '8s'), 56*9e94795aSAndroid Build Coastguard Worker ('e_type', 'H'), 57*9e94795aSAndroid Build Coastguard Worker ('e_machine', 'H'), 58*9e94795aSAndroid Build Coastguard Worker ('e_version', 'I'), 59*9e94795aSAndroid Build Coastguard Worker) 60*9e94795aSAndroid Build Coastguard Worker 61*9e94795aSAndroid Build Coastguard Worker_ELF_HEADER_STRUCT_FMT = ''.join(_fmt for _, _fmt in _ELF_HEADER_STRUCT) 62*9e94795aSAndroid Build Coastguard Worker 63*9e94795aSAndroid Build Coastguard Worker 64*9e94795aSAndroid Build Coastguard WorkerELFHeader = collections.namedtuple( 65*9e94795aSAndroid Build Coastguard Worker 'ELFHeader', [_name for _name, _ in _ELF_HEADER_STRUCT]) 66*9e94795aSAndroid Build Coastguard Worker 67*9e94795aSAndroid Build Coastguard Worker 68*9e94795aSAndroid Build Coastguard WorkerELF = collections.namedtuple( 69*9e94795aSAndroid Build Coastguard Worker 'ELF', 70*9e94795aSAndroid Build Coastguard Worker ('alignments', 'dt_soname', 'dt_needed', 'imported', 'exported', 'header')) 71*9e94795aSAndroid Build Coastguard Worker 72*9e94795aSAndroid Build Coastguard Worker 73*9e94795aSAndroid Build Coastguard Workerdef _get_os_name(): 74*9e94795aSAndroid Build Coastguard Worker """Get the host OS name.""" 75*9e94795aSAndroid Build Coastguard Worker if sys.platform.startswith('linux'): 76*9e94795aSAndroid Build Coastguard Worker return 'linux' 77*9e94795aSAndroid Build Coastguard Worker if sys.platform.startswith('darwin'): 78*9e94795aSAndroid Build Coastguard Worker return 'darwin' 79*9e94795aSAndroid Build Coastguard Worker raise ValueError(sys.platform + ' is not supported') 80*9e94795aSAndroid Build Coastguard Worker 81*9e94795aSAndroid Build Coastguard Worker 82*9e94795aSAndroid Build Coastguard Workerdef _get_build_top(): 83*9e94795aSAndroid Build Coastguard Worker """Find the build top of the source tree ($ANDROID_BUILD_TOP).""" 84*9e94795aSAndroid Build Coastguard Worker prev_path = None 85*9e94795aSAndroid Build Coastguard Worker curr_path = os.path.abspath(os.getcwd()) 86*9e94795aSAndroid Build Coastguard Worker while prev_path != curr_path: 87*9e94795aSAndroid Build Coastguard Worker if os.path.exists(os.path.join(curr_path, '.repo')): 88*9e94795aSAndroid Build Coastguard Worker return curr_path 89*9e94795aSAndroid Build Coastguard Worker prev_path = curr_path 90*9e94795aSAndroid Build Coastguard Worker curr_path = os.path.dirname(curr_path) 91*9e94795aSAndroid Build Coastguard Worker return None 92*9e94795aSAndroid Build Coastguard Worker 93*9e94795aSAndroid Build Coastguard Worker 94*9e94795aSAndroid Build Coastguard Workerdef _select_latest_llvm_version(versions): 95*9e94795aSAndroid Build Coastguard Worker """Select the latest LLVM prebuilts version from a set of versions.""" 96*9e94795aSAndroid Build Coastguard Worker pattern = re.compile('clang-r([0-9]+)([a-z]?)') 97*9e94795aSAndroid Build Coastguard Worker found_rev = 0 98*9e94795aSAndroid Build Coastguard Worker found_ver = None 99*9e94795aSAndroid Build Coastguard Worker for curr_ver in versions: 100*9e94795aSAndroid Build Coastguard Worker match = pattern.match(curr_ver) 101*9e94795aSAndroid Build Coastguard Worker if not match: 102*9e94795aSAndroid Build Coastguard Worker continue 103*9e94795aSAndroid Build Coastguard Worker curr_rev = int(match.group(1)) 104*9e94795aSAndroid Build Coastguard Worker if not found_ver or curr_rev > found_rev or ( 105*9e94795aSAndroid Build Coastguard Worker curr_rev == found_rev and curr_ver > found_ver): 106*9e94795aSAndroid Build Coastguard Worker found_rev = curr_rev 107*9e94795aSAndroid Build Coastguard Worker found_ver = curr_ver 108*9e94795aSAndroid Build Coastguard Worker return found_ver 109*9e94795aSAndroid Build Coastguard Worker 110*9e94795aSAndroid Build Coastguard Worker 111*9e94795aSAndroid Build Coastguard Workerdef _get_latest_llvm_version(llvm_dir): 112*9e94795aSAndroid Build Coastguard Worker """Find the latest LLVM prebuilts version from `llvm_dir`.""" 113*9e94795aSAndroid Build Coastguard Worker return _select_latest_llvm_version(os.listdir(llvm_dir)) 114*9e94795aSAndroid Build Coastguard Worker 115*9e94795aSAndroid Build Coastguard Worker 116*9e94795aSAndroid Build Coastguard Workerdef _get_llvm_dir(): 117*9e94795aSAndroid Build Coastguard Worker """Find the path to LLVM prebuilts.""" 118*9e94795aSAndroid Build Coastguard Worker build_top = _get_build_top() 119*9e94795aSAndroid Build Coastguard Worker 120*9e94795aSAndroid Build Coastguard Worker llvm_prebuilts_base = os.environ.get('LLVM_PREBUILTS_BASE') 121*9e94795aSAndroid Build Coastguard Worker if not llvm_prebuilts_base: 122*9e94795aSAndroid Build Coastguard Worker llvm_prebuilts_base = os.path.join('prebuilts', 'clang', 'host') 123*9e94795aSAndroid Build Coastguard Worker 124*9e94795aSAndroid Build Coastguard Worker llvm_dir = os.path.join( 125*9e94795aSAndroid Build Coastguard Worker build_top, llvm_prebuilts_base, _get_os_name() + '-x86') 126*9e94795aSAndroid Build Coastguard Worker 127*9e94795aSAndroid Build Coastguard Worker if not os.path.exists(llvm_dir): 128*9e94795aSAndroid Build Coastguard Worker return None 129*9e94795aSAndroid Build Coastguard Worker 130*9e94795aSAndroid Build Coastguard Worker llvm_prebuilts_version = os.environ.get('LLVM_PREBUILTS_VERSION') 131*9e94795aSAndroid Build Coastguard Worker if not llvm_prebuilts_version: 132*9e94795aSAndroid Build Coastguard Worker llvm_prebuilts_version = _get_latest_llvm_version(llvm_dir) 133*9e94795aSAndroid Build Coastguard Worker 134*9e94795aSAndroid Build Coastguard Worker llvm_dir = os.path.join(llvm_dir, llvm_prebuilts_version) 135*9e94795aSAndroid Build Coastguard Worker 136*9e94795aSAndroid Build Coastguard Worker if not os.path.exists(llvm_dir): 137*9e94795aSAndroid Build Coastguard Worker return None 138*9e94795aSAndroid Build Coastguard Worker 139*9e94795aSAndroid Build Coastguard Worker return llvm_dir 140*9e94795aSAndroid Build Coastguard Worker 141*9e94795aSAndroid Build Coastguard Worker 142*9e94795aSAndroid Build Coastguard Workerdef _get_llvm_readobj(): 143*9e94795aSAndroid Build Coastguard Worker """Find the path to llvm-readobj executable.""" 144*9e94795aSAndroid Build Coastguard Worker llvm_dir = _get_llvm_dir() 145*9e94795aSAndroid Build Coastguard Worker llvm_readobj = os.path.join(llvm_dir, 'bin', 'llvm-readobj') 146*9e94795aSAndroid Build Coastguard Worker return llvm_readobj if os.path.exists(llvm_readobj) else 'llvm-readobj' 147*9e94795aSAndroid Build Coastguard Worker 148*9e94795aSAndroid Build Coastguard Worker 149*9e94795aSAndroid Build Coastguard Workerclass ELFError(ValueError): 150*9e94795aSAndroid Build Coastguard Worker """Generic ELF parse error""" 151*9e94795aSAndroid Build Coastguard Worker pass 152*9e94795aSAndroid Build Coastguard Worker 153*9e94795aSAndroid Build Coastguard Worker 154*9e94795aSAndroid Build Coastguard Workerclass ELFInvalidMagicError(ELFError): 155*9e94795aSAndroid Build Coastguard Worker """Invalid ELF magic word error""" 156*9e94795aSAndroid Build Coastguard Worker def __init__(self): 157*9e94795aSAndroid Build Coastguard Worker super(ELFInvalidMagicError, self).__init__('bad ELF magic') 158*9e94795aSAndroid Build Coastguard Worker 159*9e94795aSAndroid Build Coastguard Worker 160*9e94795aSAndroid Build Coastguard Workerclass ELFParser(object): 161*9e94795aSAndroid Build Coastguard Worker """ELF file parser""" 162*9e94795aSAndroid Build Coastguard Worker 163*9e94795aSAndroid Build Coastguard Worker @classmethod 164*9e94795aSAndroid Build Coastguard Worker def _read_elf_header(cls, elf_file_path): 165*9e94795aSAndroid Build Coastguard Worker """Read the ELF magic word from the beginning of the file.""" 166*9e94795aSAndroid Build Coastguard Worker with open(elf_file_path, 'rb') as elf_file: 167*9e94795aSAndroid Build Coastguard Worker buf = elf_file.read(struct.calcsize(_ELF_HEADER_STRUCT_FMT)) 168*9e94795aSAndroid Build Coastguard Worker try: 169*9e94795aSAndroid Build Coastguard Worker return ELFHeader(*struct.unpack(_ELF_HEADER_STRUCT_FMT, buf)) 170*9e94795aSAndroid Build Coastguard Worker except struct.error: 171*9e94795aSAndroid Build Coastguard Worker return None 172*9e94795aSAndroid Build Coastguard Worker 173*9e94795aSAndroid Build Coastguard Worker 174*9e94795aSAndroid Build Coastguard Worker @classmethod 175*9e94795aSAndroid Build Coastguard Worker def open(cls, elf_file_path, llvm_readobj): 176*9e94795aSAndroid Build Coastguard Worker """Open and parse the ELF file.""" 177*9e94795aSAndroid Build Coastguard Worker # Parse the ELF header to check the magic word. 178*9e94795aSAndroid Build Coastguard Worker header = cls._read_elf_header(elf_file_path) 179*9e94795aSAndroid Build Coastguard Worker if not header or header.ei_magic != _ELF_MAGIC: 180*9e94795aSAndroid Build Coastguard Worker raise ELFInvalidMagicError() 181*9e94795aSAndroid Build Coastguard Worker 182*9e94795aSAndroid Build Coastguard Worker # Run llvm-readobj and parse the output. 183*9e94795aSAndroid Build Coastguard Worker return cls._read_llvm_readobj(elf_file_path, header, llvm_readobj) 184*9e94795aSAndroid Build Coastguard Worker 185*9e94795aSAndroid Build Coastguard Worker 186*9e94795aSAndroid Build Coastguard Worker @classmethod 187*9e94795aSAndroid Build Coastguard Worker def _find_prefix(cls, pattern, lines_it): 188*9e94795aSAndroid Build Coastguard Worker """Iterate `lines_it` until finding a string that starts with `pattern`.""" 189*9e94795aSAndroid Build Coastguard Worker for line in lines_it: 190*9e94795aSAndroid Build Coastguard Worker if line.startswith(pattern): 191*9e94795aSAndroid Build Coastguard Worker return True 192*9e94795aSAndroid Build Coastguard Worker return False 193*9e94795aSAndroid Build Coastguard Worker 194*9e94795aSAndroid Build Coastguard Worker 195*9e94795aSAndroid Build Coastguard Worker @classmethod 196*9e94795aSAndroid Build Coastguard Worker def _read_llvm_readobj(cls, elf_file_path, header, llvm_readobj): 197*9e94795aSAndroid Build Coastguard Worker """Run llvm-readobj and parse the output.""" 198*9e94795aSAndroid Build Coastguard Worker cmd = [llvm_readobj, '--program-headers', '--dynamic-table', 199*9e94795aSAndroid Build Coastguard Worker '--dyn-symbols', elf_file_path] 200*9e94795aSAndroid Build Coastguard Worker out = subprocess.check_output(cmd, text=True) 201*9e94795aSAndroid Build Coastguard Worker lines = out.splitlines() 202*9e94795aSAndroid Build Coastguard Worker return cls._parse_llvm_readobj(elf_file_path, header, lines) 203*9e94795aSAndroid Build Coastguard Worker 204*9e94795aSAndroid Build Coastguard Worker 205*9e94795aSAndroid Build Coastguard Worker @classmethod 206*9e94795aSAndroid Build Coastguard Worker def _parse_llvm_readobj(cls, elf_file_path, header, lines): 207*9e94795aSAndroid Build Coastguard Worker """Parse the output of llvm-readobj.""" 208*9e94795aSAndroid Build Coastguard Worker lines_it = iter(lines) 209*9e94795aSAndroid Build Coastguard Worker alignments = cls._parse_program_headers(lines_it) 210*9e94795aSAndroid Build Coastguard Worker dt_soname, dt_needed = cls._parse_dynamic_table(elf_file_path, lines_it) 211*9e94795aSAndroid Build Coastguard Worker imported, exported = cls._parse_dynamic_symbols(lines_it) 212*9e94795aSAndroid Build Coastguard Worker return ELF(alignments, dt_soname, dt_needed, imported, exported, header) 213*9e94795aSAndroid Build Coastguard Worker 214*9e94795aSAndroid Build Coastguard Worker 215*9e94795aSAndroid Build Coastguard Worker _PROGRAM_HEADERS_START_PATTERN = 'ProgramHeaders [' 216*9e94795aSAndroid Build Coastguard Worker _PROGRAM_HEADERS_END_PATTERN = ']' 217*9e94795aSAndroid Build Coastguard Worker _PROGRAM_HEADER_START_PATTERN = 'ProgramHeader {' 218*9e94795aSAndroid Build Coastguard Worker _PROGRAM_HEADER_TYPE_PATTERN = re.compile('^\\s+Type:\\s+(.*)$') 219*9e94795aSAndroid Build Coastguard Worker _PROGRAM_HEADER_ALIGN_PATTERN = re.compile('^\\s+Alignment:\\s+(.*)$') 220*9e94795aSAndroid Build Coastguard Worker _PROGRAM_HEADER_END_PATTERN = '}' 221*9e94795aSAndroid Build Coastguard Worker 222*9e94795aSAndroid Build Coastguard Worker 223*9e94795aSAndroid Build Coastguard Worker @classmethod 224*9e94795aSAndroid Build Coastguard Worker def _parse_program_headers(cls, lines_it): 225*9e94795aSAndroid Build Coastguard Worker """Parse the dynamic table section.""" 226*9e94795aSAndroid Build Coastguard Worker alignments = [] 227*9e94795aSAndroid Build Coastguard Worker 228*9e94795aSAndroid Build Coastguard Worker if not cls._find_prefix(cls._PROGRAM_HEADERS_START_PATTERN, lines_it): 229*9e94795aSAndroid Build Coastguard Worker raise ELFError() 230*9e94795aSAndroid Build Coastguard Worker 231*9e94795aSAndroid Build Coastguard Worker for line in lines_it: 232*9e94795aSAndroid Build Coastguard Worker # Parse each program header 233*9e94795aSAndroid Build Coastguard Worker if line.strip() == cls._PROGRAM_HEADER_START_PATTERN: 234*9e94795aSAndroid Build Coastguard Worker p_align = None 235*9e94795aSAndroid Build Coastguard Worker p_type = None 236*9e94795aSAndroid Build Coastguard Worker for line in lines_it: 237*9e94795aSAndroid Build Coastguard Worker if line.strip() == cls._PROGRAM_HEADER_END_PATTERN: 238*9e94795aSAndroid Build Coastguard Worker if not p_align: 239*9e94795aSAndroid Build Coastguard Worker raise ELFError("Could not parse alignment from program header!") 240*9e94795aSAndroid Build Coastguard Worker if not p_type: 241*9e94795aSAndroid Build Coastguard Worker raise ELFError("Could not parse type from program header!") 242*9e94795aSAndroid Build Coastguard Worker 243*9e94795aSAndroid Build Coastguard Worker if p_type.startswith("PT_LOAD "): 244*9e94795aSAndroid Build Coastguard Worker alignments.append(int(p_align)) 245*9e94795aSAndroid Build Coastguard Worker break 246*9e94795aSAndroid Build Coastguard Worker 247*9e94795aSAndroid Build Coastguard Worker match = cls._PROGRAM_HEADER_TYPE_PATTERN.match(line) 248*9e94795aSAndroid Build Coastguard Worker if match: 249*9e94795aSAndroid Build Coastguard Worker p_type = match.group(1) 250*9e94795aSAndroid Build Coastguard Worker 251*9e94795aSAndroid Build Coastguard Worker match = cls._PROGRAM_HEADER_ALIGN_PATTERN.match(line) 252*9e94795aSAndroid Build Coastguard Worker if match: 253*9e94795aSAndroid Build Coastguard Worker p_align = match.group(1) 254*9e94795aSAndroid Build Coastguard Worker 255*9e94795aSAndroid Build Coastguard Worker if line == cls._PROGRAM_HEADERS_END_PATTERN: 256*9e94795aSAndroid Build Coastguard Worker break 257*9e94795aSAndroid Build Coastguard Worker 258*9e94795aSAndroid Build Coastguard Worker return alignments 259*9e94795aSAndroid Build Coastguard Worker 260*9e94795aSAndroid Build Coastguard Worker 261*9e94795aSAndroid Build Coastguard Worker _DYNAMIC_SECTION_START_PATTERN = 'DynamicSection [' 262*9e94795aSAndroid Build Coastguard Worker 263*9e94795aSAndroid Build Coastguard Worker _DYNAMIC_SECTION_NEEDED_PATTERN = re.compile( 264*9e94795aSAndroid Build Coastguard Worker '^ 0x[0-9a-fA-F]+\\s+NEEDED\\s+Shared library: \\[(.*)\\]$') 265*9e94795aSAndroid Build Coastguard Worker 266*9e94795aSAndroid Build Coastguard Worker _DYNAMIC_SECTION_SONAME_PATTERN = re.compile( 267*9e94795aSAndroid Build Coastguard Worker '^ 0x[0-9a-fA-F]+\\s+SONAME\\s+Library soname: \\[(.*)\\]$') 268*9e94795aSAndroid Build Coastguard Worker 269*9e94795aSAndroid Build Coastguard Worker _DYNAMIC_SECTION_END_PATTERN = ']' 270*9e94795aSAndroid Build Coastguard Worker 271*9e94795aSAndroid Build Coastguard Worker 272*9e94795aSAndroid Build Coastguard Worker @classmethod 273*9e94795aSAndroid Build Coastguard Worker def _parse_dynamic_table(cls, elf_file_path, lines_it): 274*9e94795aSAndroid Build Coastguard Worker """Parse the dynamic table section.""" 275*9e94795aSAndroid Build Coastguard Worker dt_soname = os.path.basename(elf_file_path) 276*9e94795aSAndroid Build Coastguard Worker dt_needed = [] 277*9e94795aSAndroid Build Coastguard Worker 278*9e94795aSAndroid Build Coastguard Worker dynamic = cls._find_prefix(cls._DYNAMIC_SECTION_START_PATTERN, lines_it) 279*9e94795aSAndroid Build Coastguard Worker if not dynamic: 280*9e94795aSAndroid Build Coastguard Worker return (dt_soname, dt_needed) 281*9e94795aSAndroid Build Coastguard Worker 282*9e94795aSAndroid Build Coastguard Worker for line in lines_it: 283*9e94795aSAndroid Build Coastguard Worker if line == cls._DYNAMIC_SECTION_END_PATTERN: 284*9e94795aSAndroid Build Coastguard Worker break 285*9e94795aSAndroid Build Coastguard Worker 286*9e94795aSAndroid Build Coastguard Worker match = cls._DYNAMIC_SECTION_NEEDED_PATTERN.match(line) 287*9e94795aSAndroid Build Coastguard Worker if match: 288*9e94795aSAndroid Build Coastguard Worker dt_needed.append(match.group(1)) 289*9e94795aSAndroid Build Coastguard Worker continue 290*9e94795aSAndroid Build Coastguard Worker 291*9e94795aSAndroid Build Coastguard Worker match = cls._DYNAMIC_SECTION_SONAME_PATTERN.match(line) 292*9e94795aSAndroid Build Coastguard Worker if match: 293*9e94795aSAndroid Build Coastguard Worker dt_soname = match.group(1) 294*9e94795aSAndroid Build Coastguard Worker continue 295*9e94795aSAndroid Build Coastguard Worker 296*9e94795aSAndroid Build Coastguard Worker return (dt_soname, dt_needed) 297*9e94795aSAndroid Build Coastguard Worker 298*9e94795aSAndroid Build Coastguard Worker 299*9e94795aSAndroid Build Coastguard Worker _DYNAMIC_SYMBOLS_START_PATTERN = 'DynamicSymbols [' 300*9e94795aSAndroid Build Coastguard Worker _DYNAMIC_SYMBOLS_END_PATTERN = ']' 301*9e94795aSAndroid Build Coastguard Worker 302*9e94795aSAndroid Build Coastguard Worker _SYMBOL_ENTRY_START_PATTERN = ' Symbol {' 303*9e94795aSAndroid Build Coastguard Worker _SYMBOL_ENTRY_PATTERN = re.compile('^ ([A-Za-z0-9_]+): (.*)$') 304*9e94795aSAndroid Build Coastguard Worker _SYMBOL_ENTRY_PAREN_PATTERN = re.compile( 305*9e94795aSAndroid Build Coastguard Worker '\\s+\\((?:(?:\\d+)|(?:0x[0-9a-fA-F]+))\\)$') 306*9e94795aSAndroid Build Coastguard Worker _SYMBOL_ENTRY_END_PATTERN = ' }' 307*9e94795aSAndroid Build Coastguard Worker 308*9e94795aSAndroid Build Coastguard Worker 309*9e94795aSAndroid Build Coastguard Worker @staticmethod 310*9e94795aSAndroid Build Coastguard Worker def _parse_symbol_name(name_with_version): 311*9e94795aSAndroid Build Coastguard Worker """Split `name_with_version` into name and version. This function may split 312*9e94795aSAndroid Build Coastguard Worker at last occurrence of `@@` or `@`.""" 313*9e94795aSAndroid Build Coastguard Worker pos = name_with_version.rfind('@') 314*9e94795aSAndroid Build Coastguard Worker if pos == -1: 315*9e94795aSAndroid Build Coastguard Worker name = name_with_version 316*9e94795aSAndroid Build Coastguard Worker version = '' 317*9e94795aSAndroid Build Coastguard Worker else: 318*9e94795aSAndroid Build Coastguard Worker if pos > 0 and name_with_version[pos - 1] == '@': 319*9e94795aSAndroid Build Coastguard Worker name = name_with_version[0:pos - 1] 320*9e94795aSAndroid Build Coastguard Worker else: 321*9e94795aSAndroid Build Coastguard Worker name = name_with_version[0:pos] 322*9e94795aSAndroid Build Coastguard Worker version = name_with_version[pos + 1:] 323*9e94795aSAndroid Build Coastguard Worker return (name, version) 324*9e94795aSAndroid Build Coastguard Worker 325*9e94795aSAndroid Build Coastguard Worker 326*9e94795aSAndroid Build Coastguard Worker @classmethod 327*9e94795aSAndroid Build Coastguard Worker def _parse_dynamic_symbols(cls, lines_it): 328*9e94795aSAndroid Build Coastguard Worker """Parse dynamic symbol table and collect imported and exported symbols.""" 329*9e94795aSAndroid Build Coastguard Worker imported = collections.defaultdict(set) 330*9e94795aSAndroid Build Coastguard Worker exported = collections.defaultdict(set) 331*9e94795aSAndroid Build Coastguard Worker 332*9e94795aSAndroid Build Coastguard Worker for symbol in cls._parse_dynamic_symbols_internal(lines_it): 333*9e94795aSAndroid Build Coastguard Worker name, version = cls._parse_symbol_name(symbol['Name']) 334*9e94795aSAndroid Build Coastguard Worker if name: 335*9e94795aSAndroid Build Coastguard Worker if symbol['Section'] == 'Undefined': 336*9e94795aSAndroid Build Coastguard Worker if symbol['Binding'] != 'Weak': 337*9e94795aSAndroid Build Coastguard Worker imported[name].add(version) 338*9e94795aSAndroid Build Coastguard Worker else: 339*9e94795aSAndroid Build Coastguard Worker if symbol['Binding'] != 'Local': 340*9e94795aSAndroid Build Coastguard Worker exported[name].add(version) 341*9e94795aSAndroid Build Coastguard Worker 342*9e94795aSAndroid Build Coastguard Worker # Freeze the returned imported/exported dict. 343*9e94795aSAndroid Build Coastguard Worker return (dict(imported), dict(exported)) 344*9e94795aSAndroid Build Coastguard Worker 345*9e94795aSAndroid Build Coastguard Worker 346*9e94795aSAndroid Build Coastguard Worker @classmethod 347*9e94795aSAndroid Build Coastguard Worker def _parse_dynamic_symbols_internal(cls, lines_it): 348*9e94795aSAndroid Build Coastguard Worker """Parse symbols entries and yield each symbols.""" 349*9e94795aSAndroid Build Coastguard Worker 350*9e94795aSAndroid Build Coastguard Worker if not cls._find_prefix(cls._DYNAMIC_SYMBOLS_START_PATTERN, lines_it): 351*9e94795aSAndroid Build Coastguard Worker return 352*9e94795aSAndroid Build Coastguard Worker 353*9e94795aSAndroid Build Coastguard Worker for line in lines_it: 354*9e94795aSAndroid Build Coastguard Worker if line == cls._DYNAMIC_SYMBOLS_END_PATTERN: 355*9e94795aSAndroid Build Coastguard Worker return 356*9e94795aSAndroid Build Coastguard Worker 357*9e94795aSAndroid Build Coastguard Worker if line == cls._SYMBOL_ENTRY_START_PATTERN: 358*9e94795aSAndroid Build Coastguard Worker symbol = {} 359*9e94795aSAndroid Build Coastguard Worker continue 360*9e94795aSAndroid Build Coastguard Worker 361*9e94795aSAndroid Build Coastguard Worker if line == cls._SYMBOL_ENTRY_END_PATTERN: 362*9e94795aSAndroid Build Coastguard Worker yield symbol 363*9e94795aSAndroid Build Coastguard Worker symbol = None 364*9e94795aSAndroid Build Coastguard Worker continue 365*9e94795aSAndroid Build Coastguard Worker 366*9e94795aSAndroid Build Coastguard Worker match = cls._SYMBOL_ENTRY_PATTERN.match(line) 367*9e94795aSAndroid Build Coastguard Worker if match: 368*9e94795aSAndroid Build Coastguard Worker key = match.group(1) 369*9e94795aSAndroid Build Coastguard Worker value = cls._SYMBOL_ENTRY_PAREN_PATTERN.sub('', match.group(2)) 370*9e94795aSAndroid Build Coastguard Worker symbol[key] = value 371*9e94795aSAndroid Build Coastguard Worker continue 372*9e94795aSAndroid Build Coastguard Worker 373*9e94795aSAndroid Build Coastguard Worker 374*9e94795aSAndroid Build Coastguard Workerclass Checker(object): 375*9e94795aSAndroid Build Coastguard Worker """ELF file checker that checks DT_SONAME, DT_NEEDED, and symbols.""" 376*9e94795aSAndroid Build Coastguard Worker 377*9e94795aSAndroid Build Coastguard Worker def __init__(self, llvm_readobj): 378*9e94795aSAndroid Build Coastguard Worker self._file_path = '' 379*9e94795aSAndroid Build Coastguard Worker self._file_under_test = None 380*9e94795aSAndroid Build Coastguard Worker self._shared_libs = [] 381*9e94795aSAndroid Build Coastguard Worker 382*9e94795aSAndroid Build Coastguard Worker self._llvm_readobj = llvm_readobj 383*9e94795aSAndroid Build Coastguard Worker 384*9e94795aSAndroid Build Coastguard Worker 385*9e94795aSAndroid Build Coastguard Worker if sys.stderr.isatty(): 386*9e94795aSAndroid Build Coastguard Worker _ERROR_TAG = '\033[0;1;31merror:\033[m' # Red error 387*9e94795aSAndroid Build Coastguard Worker _NOTE_TAG = '\033[0;1;30mnote:\033[m' # Black note 388*9e94795aSAndroid Build Coastguard Worker else: 389*9e94795aSAndroid Build Coastguard Worker _ERROR_TAG = 'error:' # Red error 390*9e94795aSAndroid Build Coastguard Worker _NOTE_TAG = 'note:' # Black note 391*9e94795aSAndroid Build Coastguard Worker 392*9e94795aSAndroid Build Coastguard Worker 393*9e94795aSAndroid Build Coastguard Worker def _error(self, *args): 394*9e94795aSAndroid Build Coastguard Worker """Emit an error to stderr.""" 395*9e94795aSAndroid Build Coastguard Worker print(self._file_path + ': ' + self._ERROR_TAG, *args, file=sys.stderr) 396*9e94795aSAndroid Build Coastguard Worker 397*9e94795aSAndroid Build Coastguard Worker 398*9e94795aSAndroid Build Coastguard Worker def _note(self, *args): 399*9e94795aSAndroid Build Coastguard Worker """Emit a note to stderr.""" 400*9e94795aSAndroid Build Coastguard Worker print(self._file_path + ': ' + self._NOTE_TAG, *args, file=sys.stderr) 401*9e94795aSAndroid Build Coastguard Worker 402*9e94795aSAndroid Build Coastguard Worker 403*9e94795aSAndroid Build Coastguard Worker def _load_elf_file(self, path, skip_bad_elf_magic): 404*9e94795aSAndroid Build Coastguard Worker """Load an ELF file from the `path`.""" 405*9e94795aSAndroid Build Coastguard Worker try: 406*9e94795aSAndroid Build Coastguard Worker return ELFParser.open(path, self._llvm_readobj) 407*9e94795aSAndroid Build Coastguard Worker except (IOError, OSError): 408*9e94795aSAndroid Build Coastguard Worker self._error('Failed to open "{}".'.format(path)) 409*9e94795aSAndroid Build Coastguard Worker sys.exit(2) 410*9e94795aSAndroid Build Coastguard Worker except ELFInvalidMagicError: 411*9e94795aSAndroid Build Coastguard Worker if skip_bad_elf_magic: 412*9e94795aSAndroid Build Coastguard Worker sys.exit(0) 413*9e94795aSAndroid Build Coastguard Worker else: 414*9e94795aSAndroid Build Coastguard Worker self._error('File "{}" must have a valid ELF magic word.'.format(path)) 415*9e94795aSAndroid Build Coastguard Worker sys.exit(2) 416*9e94795aSAndroid Build Coastguard Worker except: 417*9e94795aSAndroid Build Coastguard Worker self._error('An unknown error occurred while opening "{}".'.format(path)) 418*9e94795aSAndroid Build Coastguard Worker raise 419*9e94795aSAndroid Build Coastguard Worker 420*9e94795aSAndroid Build Coastguard Worker 421*9e94795aSAndroid Build Coastguard Worker def load_file_under_test(self, path, skip_bad_elf_magic, 422*9e94795aSAndroid Build Coastguard Worker skip_unknown_elf_machine): 423*9e94795aSAndroid Build Coastguard Worker """Load file-under-test (either an executable or a shared lib).""" 424*9e94795aSAndroid Build Coastguard Worker self._file_path = path 425*9e94795aSAndroid Build Coastguard Worker self._file_under_test = self._load_elf_file(path, skip_bad_elf_magic) 426*9e94795aSAndroid Build Coastguard Worker 427*9e94795aSAndroid Build Coastguard Worker if skip_unknown_elf_machine and \ 428*9e94795aSAndroid Build Coastguard Worker self._file_under_test.header.e_machine not in _KNOWN_MACHINES: 429*9e94795aSAndroid Build Coastguard Worker sys.exit(0) 430*9e94795aSAndroid Build Coastguard Worker 431*9e94795aSAndroid Build Coastguard Worker 432*9e94795aSAndroid Build Coastguard Worker def load_shared_libs(self, shared_lib_paths): 433*9e94795aSAndroid Build Coastguard Worker """Load shared libraries.""" 434*9e94795aSAndroid Build Coastguard Worker for path in shared_lib_paths: 435*9e94795aSAndroid Build Coastguard Worker self._shared_libs.append(self._load_elf_file(path, False)) 436*9e94795aSAndroid Build Coastguard Worker 437*9e94795aSAndroid Build Coastguard Worker 438*9e94795aSAndroid Build Coastguard Worker def check_dt_soname(self, soname): 439*9e94795aSAndroid Build Coastguard Worker """Check whether DT_SONAME matches installation file name.""" 440*9e94795aSAndroid Build Coastguard Worker if self._file_under_test.dt_soname != soname: 441*9e94795aSAndroid Build Coastguard Worker self._error('DT_SONAME "{}" must be equal to the file name "{}".' 442*9e94795aSAndroid Build Coastguard Worker .format(self._file_under_test.dt_soname, soname)) 443*9e94795aSAndroid Build Coastguard Worker sys.exit(2) 444*9e94795aSAndroid Build Coastguard Worker 445*9e94795aSAndroid Build Coastguard Worker 446*9e94795aSAndroid Build Coastguard Worker def check_dt_needed(self, system_shared_lib_names): 447*9e94795aSAndroid Build Coastguard Worker """Check whether all DT_NEEDED entries are specified in the build 448*9e94795aSAndroid Build Coastguard Worker system.""" 449*9e94795aSAndroid Build Coastguard Worker 450*9e94795aSAndroid Build Coastguard Worker missing_shared_libs = False 451*9e94795aSAndroid Build Coastguard Worker 452*9e94795aSAndroid Build Coastguard Worker # Collect the DT_SONAMEs from shared libs specified in the build system. 453*9e94795aSAndroid Build Coastguard Worker specified_sonames = {lib.dt_soname for lib in self._shared_libs} 454*9e94795aSAndroid Build Coastguard Worker 455*9e94795aSAndroid Build Coastguard Worker # Chech whether all DT_NEEDED entries are specified. 456*9e94795aSAndroid Build Coastguard Worker for lib in self._file_under_test.dt_needed: 457*9e94795aSAndroid Build Coastguard Worker if lib not in specified_sonames: 458*9e94795aSAndroid Build Coastguard Worker self._error(f'DT_NEEDED "{lib}" is not specified in shared_libs.') 459*9e94795aSAndroid Build Coastguard Worker missing_shared_libs = True 460*9e94795aSAndroid Build Coastguard Worker 461*9e94795aSAndroid Build Coastguard Worker if missing_shared_libs: 462*9e94795aSAndroid Build Coastguard Worker dt_needed = sorted(set(self._file_under_test.dt_needed)) 463*9e94795aSAndroid Build Coastguard Worker modules = [re.sub('\\.so$', '', lib) for lib in dt_needed] 464*9e94795aSAndroid Build Coastguard Worker 465*9e94795aSAndroid Build Coastguard Worker # Remove system shared libraries from the suggestion since they are added 466*9e94795aSAndroid Build Coastguard Worker # by default. 467*9e94795aSAndroid Build Coastguard Worker modules = [name for name in modules 468*9e94795aSAndroid Build Coastguard Worker if name not in system_shared_lib_names] 469*9e94795aSAndroid Build Coastguard Worker 470*9e94795aSAndroid Build Coastguard Worker self._note() 471*9e94795aSAndroid Build Coastguard Worker self._note('Fix suggestions:') 472*9e94795aSAndroid Build Coastguard Worker self._note( 473*9e94795aSAndroid Build Coastguard Worker ' Android.bp: shared_libs: [' + 474*9e94795aSAndroid Build Coastguard Worker ', '.join('"' + module + '"' for module in modules) + '],') 475*9e94795aSAndroid Build Coastguard Worker self._note( 476*9e94795aSAndroid Build Coastguard Worker ' Android.mk: LOCAL_SHARED_LIBRARIES := ' + ' '.join(modules)) 477*9e94795aSAndroid Build Coastguard Worker 478*9e94795aSAndroid Build Coastguard Worker self._note() 479*9e94795aSAndroid Build Coastguard Worker self._note('If the fix above doesn\'t work, bypass this check with:') 480*9e94795aSAndroid Build Coastguard Worker self._note(' Android.bp: check_elf_files: false,') 481*9e94795aSAndroid Build Coastguard Worker self._note(' Android.mk: LOCAL_CHECK_ELF_FILES := false') 482*9e94795aSAndroid Build Coastguard Worker 483*9e94795aSAndroid Build Coastguard Worker sys.exit(2) 484*9e94795aSAndroid Build Coastguard Worker 485*9e94795aSAndroid Build Coastguard Worker def check_max_page_size(self, max_page_size): 486*9e94795aSAndroid Build Coastguard Worker for alignment in self._file_under_test.alignments: 487*9e94795aSAndroid Build Coastguard Worker if alignment % max_page_size != 0: 488*9e94795aSAndroid Build Coastguard Worker self._error(f'Load segment has alignment {alignment} but ' 489*9e94795aSAndroid Build Coastguard Worker f'{max_page_size} required.') 490*9e94795aSAndroid Build Coastguard Worker self._note() 491*9e94795aSAndroid Build Coastguard Worker self._note('Fix suggestions:') 492*9e94795aSAndroid Build Coastguard Worker self._note(f' use linker flag "-Wl,-z,max-page-size={max_page_size}" ' 493*9e94795aSAndroid Build Coastguard Worker f'when compiling this lib') 494*9e94795aSAndroid Build Coastguard Worker self._note() 495*9e94795aSAndroid Build Coastguard Worker self._note('If the fix above doesn\'t work, bypass this check with:') 496*9e94795aSAndroid Build Coastguard Worker self._note(' Android.bp: ignore_max_page_size: true,') 497*9e94795aSAndroid Build Coastguard Worker self._note(' Android.mk: LOCAL_IGNORE_MAX_PAGE_SIZE := true') 498*9e94795aSAndroid Build Coastguard Worker self._note(' Device mk: PRODUCT_CHECK_PREBUILT_MAX_PAGE_SIZE := false') 499*9e94795aSAndroid Build Coastguard Worker 500*9e94795aSAndroid Build Coastguard Worker # TODO: instead of exiting immediately, we may want to collect the 501*9e94795aSAndroid Build Coastguard Worker # errors from all checks and emit them at once 502*9e94795aSAndroid Build Coastguard Worker sys.exit(2) 503*9e94795aSAndroid Build Coastguard Worker 504*9e94795aSAndroid Build Coastguard Worker @staticmethod 505*9e94795aSAndroid Build Coastguard Worker def _find_symbol(lib, name, version): 506*9e94795aSAndroid Build Coastguard Worker """Check whether the symbol name and version matches a definition in 507*9e94795aSAndroid Build Coastguard Worker lib.""" 508*9e94795aSAndroid Build Coastguard Worker try: 509*9e94795aSAndroid Build Coastguard Worker lib_sym_vers = lib.exported[name] 510*9e94795aSAndroid Build Coastguard Worker except KeyError: 511*9e94795aSAndroid Build Coastguard Worker return False 512*9e94795aSAndroid Build Coastguard Worker if version == '': # Symbol version is not requested 513*9e94795aSAndroid Build Coastguard Worker return True 514*9e94795aSAndroid Build Coastguard Worker return version in lib_sym_vers 515*9e94795aSAndroid Build Coastguard Worker 516*9e94795aSAndroid Build Coastguard Worker 517*9e94795aSAndroid Build Coastguard Worker @classmethod 518*9e94795aSAndroid Build Coastguard Worker def _find_symbol_from_libs(cls, libs, name, version): 519*9e94795aSAndroid Build Coastguard Worker """Check whether the symbol name and version is defined in one of the 520*9e94795aSAndroid Build Coastguard Worker shared libraries in libs.""" 521*9e94795aSAndroid Build Coastguard Worker for lib in libs: 522*9e94795aSAndroid Build Coastguard Worker if cls._find_symbol(lib, name, version): 523*9e94795aSAndroid Build Coastguard Worker return lib 524*9e94795aSAndroid Build Coastguard Worker return None 525*9e94795aSAndroid Build Coastguard Worker 526*9e94795aSAndroid Build Coastguard Worker 527*9e94795aSAndroid Build Coastguard Worker def check_symbols(self): 528*9e94795aSAndroid Build Coastguard Worker """Check whether all undefined symbols are resolved to a definition.""" 529*9e94795aSAndroid Build Coastguard Worker all_elf_files = [self._file_under_test] + self._shared_libs 530*9e94795aSAndroid Build Coastguard Worker missing_symbols = [] 531*9e94795aSAndroid Build Coastguard Worker for sym, imported_vers in self._file_under_test.imported.items(): 532*9e94795aSAndroid Build Coastguard Worker for imported_ver in imported_vers: 533*9e94795aSAndroid Build Coastguard Worker lib = self._find_symbol_from_libs(all_elf_files, sym, imported_ver) 534*9e94795aSAndroid Build Coastguard Worker if not lib: 535*9e94795aSAndroid Build Coastguard Worker missing_symbols.append((sym, imported_ver)) 536*9e94795aSAndroid Build Coastguard Worker 537*9e94795aSAndroid Build Coastguard Worker if missing_symbols: 538*9e94795aSAndroid Build Coastguard Worker for sym, ver in sorted(missing_symbols): 539*9e94795aSAndroid Build Coastguard Worker if ver: 540*9e94795aSAndroid Build Coastguard Worker sym += '@' + ver 541*9e94795aSAndroid Build Coastguard Worker self._error(f'Unresolved symbol: {sym}') 542*9e94795aSAndroid Build Coastguard Worker 543*9e94795aSAndroid Build Coastguard Worker self._note() 544*9e94795aSAndroid Build Coastguard Worker self._note('Some dependencies might be changed, thus the symbol(s) ' 545*9e94795aSAndroid Build Coastguard Worker 'above cannot be resolved.') 546*9e94795aSAndroid Build Coastguard Worker self._note(f'Please re-build the prebuilt file: "{self._file_path}".') 547*9e94795aSAndroid Build Coastguard Worker 548*9e94795aSAndroid Build Coastguard Worker self._note() 549*9e94795aSAndroid Build Coastguard Worker self._note('If this is a new prebuilt file and it is designed to have ' 550*9e94795aSAndroid Build Coastguard Worker 'unresolved symbols, add one of the following properties:') 551*9e94795aSAndroid Build Coastguard Worker self._note(' Android.bp: allow_undefined_symbols: true,') 552*9e94795aSAndroid Build Coastguard Worker self._note(' Android.mk: LOCAL_ALLOW_UNDEFINED_SYMBOLS := true') 553*9e94795aSAndroid Build Coastguard Worker 554*9e94795aSAndroid Build Coastguard Worker sys.exit(2) 555*9e94795aSAndroid Build Coastguard Worker 556*9e94795aSAndroid Build Coastguard Worker 557*9e94795aSAndroid Build Coastguard Workerdef _parse_args(): 558*9e94795aSAndroid Build Coastguard Worker """Parse command line options.""" 559*9e94795aSAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 560*9e94795aSAndroid Build Coastguard Worker 561*9e94795aSAndroid Build Coastguard Worker # Input file 562*9e94795aSAndroid Build Coastguard Worker parser.add_argument('file', 563*9e94795aSAndroid Build Coastguard Worker help='Path to the input file to be checked') 564*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--soname', 565*9e94795aSAndroid Build Coastguard Worker help='Shared object name of the input file') 566*9e94795aSAndroid Build Coastguard Worker 567*9e94795aSAndroid Build Coastguard Worker # Shared library dependencies 568*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--shared-lib', action='append', default=[], 569*9e94795aSAndroid Build Coastguard Worker help='Path to shared library dependencies') 570*9e94795aSAndroid Build Coastguard Worker 571*9e94795aSAndroid Build Coastguard Worker # System Shared library names 572*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--system-shared-lib', action='append', default=[], 573*9e94795aSAndroid Build Coastguard Worker help='System shared libraries to be hidden from fix ' 574*9e94795aSAndroid Build Coastguard Worker 'suggestions') 575*9e94795aSAndroid Build Coastguard Worker 576*9e94795aSAndroid Build Coastguard Worker # Check options 577*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--skip-bad-elf-magic', action='store_true', 578*9e94795aSAndroid Build Coastguard Worker help='Ignore the input file without the ELF magic word') 579*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--skip-unknown-elf-machine', action='store_true', 580*9e94795aSAndroid Build Coastguard Worker help='Ignore the input file with unknown machine ID') 581*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--allow-undefined-symbols', action='store_true', 582*9e94795aSAndroid Build Coastguard Worker help='Ignore unresolved undefined symbols') 583*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--max-page-size', action='store', type=int, 584*9e94795aSAndroid Build Coastguard Worker help='Required page size alignment support') 585*9e94795aSAndroid Build Coastguard Worker 586*9e94795aSAndroid Build Coastguard Worker # Other options 587*9e94795aSAndroid Build Coastguard Worker parser.add_argument('--llvm-readobj', 588*9e94795aSAndroid Build Coastguard Worker help='Path to the llvm-readobj executable') 589*9e94795aSAndroid Build Coastguard Worker 590*9e94795aSAndroid Build Coastguard Worker return parser.parse_args() 591*9e94795aSAndroid Build Coastguard Worker 592*9e94795aSAndroid Build Coastguard Worker 593*9e94795aSAndroid Build Coastguard Workerdef main(): 594*9e94795aSAndroid Build Coastguard Worker """Main function""" 595*9e94795aSAndroid Build Coastguard Worker args = _parse_args() 596*9e94795aSAndroid Build Coastguard Worker 597*9e94795aSAndroid Build Coastguard Worker llvm_readobj = args.llvm_readobj 598*9e94795aSAndroid Build Coastguard Worker if not llvm_readobj: 599*9e94795aSAndroid Build Coastguard Worker llvm_readobj = _get_llvm_readobj() 600*9e94795aSAndroid Build Coastguard Worker 601*9e94795aSAndroid Build Coastguard Worker # Load ELF files 602*9e94795aSAndroid Build Coastguard Worker checker = Checker(llvm_readobj) 603*9e94795aSAndroid Build Coastguard Worker checker.load_file_under_test( 604*9e94795aSAndroid Build Coastguard Worker args.file, args.skip_bad_elf_magic, args.skip_unknown_elf_machine) 605*9e94795aSAndroid Build Coastguard Worker checker.load_shared_libs(args.shared_lib) 606*9e94795aSAndroid Build Coastguard Worker 607*9e94795aSAndroid Build Coastguard Worker # Run checks 608*9e94795aSAndroid Build Coastguard Worker if args.soname: 609*9e94795aSAndroid Build Coastguard Worker checker.check_dt_soname(args.soname) 610*9e94795aSAndroid Build Coastguard Worker 611*9e94795aSAndroid Build Coastguard Worker checker.check_dt_needed(args.system_shared_lib) 612*9e94795aSAndroid Build Coastguard Worker 613*9e94795aSAndroid Build Coastguard Worker if args.max_page_size: 614*9e94795aSAndroid Build Coastguard Worker checker.check_max_page_size(args.max_page_size) 615*9e94795aSAndroid Build Coastguard Worker 616*9e94795aSAndroid Build Coastguard Worker if not args.allow_undefined_symbols: 617*9e94795aSAndroid Build Coastguard Worker checker.check_symbols() 618*9e94795aSAndroid Build Coastguard Worker 619*9e94795aSAndroid Build Coastguard Worker 620*9e94795aSAndroid Build Coastguard Workerif __name__ == '__main__': 621*9e94795aSAndroid Build Coastguard Worker main() 622