1*523fa7a6SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*523fa7a6SAndroid Build Coastguard Worker# Copyright (c) Meta Platforms, Inc. and affiliates. 3*523fa7a6SAndroid Build Coastguard Worker# All rights reserved. 4*523fa7a6SAndroid Build Coastguard Worker# 5*523fa7a6SAndroid Build Coastguard Worker# This source code is licensed under the BSD-style license found in the 6*523fa7a6SAndroid Build Coastguard Worker# LICENSE file in the root directory of this source tree. 7*523fa7a6SAndroid Build Coastguard Worker 8*523fa7a6SAndroid Build Coastguard Worker# pyre-strict 9*523fa7a6SAndroid Build Coastguard Worker 10*523fa7a6SAndroid Build Coastguard Worker""" 11*523fa7a6SAndroid Build Coastguard WorkerA script to help check binary dependencies and disallowed symbols in intermediate build files. 12*523fa7a6SAndroid Build Coastguard Worker""" 13*523fa7a6SAndroid Build Coastguard Worker 14*523fa7a6SAndroid Build Coastguard Workerimport argparse 15*523fa7a6SAndroid Build Coastguard Workerimport os 16*523fa7a6SAndroid Build Coastguard Workerimport re 17*523fa7a6SAndroid Build Coastguard Workerimport subprocess 18*523fa7a6SAndroid Build Coastguard Workerimport sys 19*523fa7a6SAndroid Build Coastguard Workerfrom dataclasses import dataclass 20*523fa7a6SAndroid Build Coastguard Workerfrom pathlib import Path 21*523fa7a6SAndroid Build Coastguard Workerfrom typing import Dict, Iterable, List, NoReturn, Optional, Tuple 22*523fa7a6SAndroid Build Coastguard Worker 23*523fa7a6SAndroid Build Coastguard Worker# Script output statuses. 24*523fa7a6SAndroid Build Coastguard WorkerSTATUS_OK = 0 25*523fa7a6SAndroid Build Coastguard WorkerSTATUS_SCRIPT_ERROR = 1 26*523fa7a6SAndroid Build Coastguard WorkerSTATUS_ERROR = 2 27*523fa7a6SAndroid Build Coastguard WorkerSTATUS_WARNING = 3 28*523fa7a6SAndroid Build Coastguard Worker 29*523fa7a6SAndroid Build Coastguard Worker# Object file suffix. 30*523fa7a6SAndroid Build Coastguard WorkerOBJECT_SUFFIX = ".o" 31*523fa7a6SAndroid Build Coastguard Worker 32*523fa7a6SAndroid Build Coastguard Worker# Project root, assuming this script is in `<root>/scripts/` 33*523fa7a6SAndroid Build Coastguard WorkerPROJECT_ROOT = Path(__file__).parent.parent.resolve() 34*523fa7a6SAndroid Build Coastguard Worker 35*523fa7a6SAndroid Build Coastguard Worker# Regex to strip info from nm and readelf. 36*523fa7a6SAndroid Build Coastguard WorkerNM_REGEX = re.compile(r"\d*\s+(?P<status>\S)\s+(?P<symbol>.*)") 37*523fa7a6SAndroid Build Coastguard WorkerREADELF_DEP_REGEX = re.compile(r".*\(NEEDED\)\s+(?P<so>.*)") 38*523fa7a6SAndroid Build Coastguard WorkerREADELF_DYN_SYM_REGEX = re.compile(r"(UND|\d+)\s+(?P<symbol>[^@\s:]+)(@.*)?$") 39*523fa7a6SAndroid Build Coastguard Worker 40*523fa7a6SAndroid Build Coastguard Worker# Disallow list of prefixes for standard library symbols. 41*523fa7a6SAndroid Build Coastguard WorkerDISALLOW_LIST = [ 42*523fa7a6SAndroid Build Coastguard Worker "operator new", 43*523fa7a6SAndroid Build Coastguard Worker "operator delete", 44*523fa7a6SAndroid Build Coastguard Worker "std::__cxx11::basic_string", 45*523fa7a6SAndroid Build Coastguard Worker "std::__throw", 46*523fa7a6SAndroid Build Coastguard Worker "std::deque", 47*523fa7a6SAndroid Build Coastguard Worker "std::exception", 48*523fa7a6SAndroid Build Coastguard Worker "std::forward_list", 49*523fa7a6SAndroid Build Coastguard Worker "std::list", 50*523fa7a6SAndroid Build Coastguard Worker "std::map", 51*523fa7a6SAndroid Build Coastguard Worker "std::multimap", 52*523fa7a6SAndroid Build Coastguard Worker "std::multiset", 53*523fa7a6SAndroid Build Coastguard Worker "std::priority_queue", 54*523fa7a6SAndroid Build Coastguard Worker "std::queue", 55*523fa7a6SAndroid Build Coastguard Worker "std::set", 56*523fa7a6SAndroid Build Coastguard Worker "std::stack", 57*523fa7a6SAndroid Build Coastguard Worker "std::unordered_map", 58*523fa7a6SAndroid Build Coastguard Worker "std::unordered_multimap", 59*523fa7a6SAndroid Build Coastguard Worker "std::unordered_multiset", 60*523fa7a6SAndroid Build Coastguard Worker "std::unordered_set", 61*523fa7a6SAndroid Build Coastguard Worker "std::vector", 62*523fa7a6SAndroid Build Coastguard Worker] 63*523fa7a6SAndroid Build Coastguard Worker 64*523fa7a6SAndroid Build Coastguard Worker 65*523fa7a6SAndroid Build Coastguard Worker@dataclass 66*523fa7a6SAndroid Build Coastguard Workerclass Symbol: 67*523fa7a6SAndroid Build Coastguard Worker """Symbol scraped from ELF binary object.""" 68*523fa7a6SAndroid Build Coastguard Worker 69*523fa7a6SAndroid Build Coastguard Worker mangled: str 70*523fa7a6SAndroid Build Coastguard Worker demangled: str 71*523fa7a6SAndroid Build Coastguard Worker defined: bool 72*523fa7a6SAndroid Build Coastguard Worker disallowed: bool 73*523fa7a6SAndroid Build Coastguard Worker sources: List[Path] 74*523fa7a6SAndroid Build Coastguard Worker 75*523fa7a6SAndroid Build Coastguard Worker 76*523fa7a6SAndroid Build Coastguard Worker# Cached symbols dictionary. 77*523fa7a6SAndroid Build Coastguard Workersymbols_cache: Optional[Dict[str, Symbol]] = None 78*523fa7a6SAndroid Build Coastguard Worker 79*523fa7a6SAndroid Build Coastguard Worker 80*523fa7a6SAndroid Build Coastguard Workerdef error(message: str) -> NoReturn: 81*523fa7a6SAndroid Build Coastguard Worker """Emit an error message and kill the script.""" 82*523fa7a6SAndroid Build Coastguard Worker print(message) 83*523fa7a6SAndroid Build Coastguard Worker sys.exit(STATUS_SCRIPT_ERROR) 84*523fa7a6SAndroid Build Coastguard Worker 85*523fa7a6SAndroid Build Coastguard Worker 86*523fa7a6SAndroid Build Coastguard Workerdef get_tool_output(args: List[str]) -> str: 87*523fa7a6SAndroid Build Coastguard Worker """Execute a command in the shell and return the output.""" 88*523fa7a6SAndroid Build Coastguard Worker result = subprocess.run(args, stdout=subprocess.PIPE) 89*523fa7a6SAndroid Build Coastguard Worker output = result.stdout.decode("utf-8") 90*523fa7a6SAndroid Build Coastguard Worker return output 91*523fa7a6SAndroid Build Coastguard Worker 92*523fa7a6SAndroid Build Coastguard Worker 93*523fa7a6SAndroid Build Coastguard Workerdef read_nm( 94*523fa7a6SAndroid Build Coastguard Worker nm: str, file: Path, exclude: Optional[List[str]] = None 95*523fa7a6SAndroid Build Coastguard Worker) -> List[Tuple[str, str]]: 96*523fa7a6SAndroid Build Coastguard Worker """Read a set of symbols using the nm tool.""" 97*523fa7a6SAndroid Build Coastguard Worker if exclude is None: 98*523fa7a6SAndroid Build Coastguard Worker exclude = ["N"] 99*523fa7a6SAndroid Build Coastguard Worker 100*523fa7a6SAndroid Build Coastguard Worker output = get_tool_output([nm, file]) 101*523fa7a6SAndroid Build Coastguard Worker result = [] 102*523fa7a6SAndroid Build Coastguard Worker for line in output.splitlines(): 103*523fa7a6SAndroid Build Coastguard Worker match = re.search(NM_REGEX, line) 104*523fa7a6SAndroid Build Coastguard Worker if not match: 105*523fa7a6SAndroid Build Coastguard Worker continue 106*523fa7a6SAndroid Build Coastguard Worker 107*523fa7a6SAndroid Build Coastguard Worker status = match.group("status").upper() 108*523fa7a6SAndroid Build Coastguard Worker if exclude is None or status not in exclude: 109*523fa7a6SAndroid Build Coastguard Worker result.append((status, match.group("symbol"))) 110*523fa7a6SAndroid Build Coastguard Worker return result 111*523fa7a6SAndroid Build Coastguard Worker 112*523fa7a6SAndroid Build Coastguard Worker 113*523fa7a6SAndroid Build Coastguard Workerdef get_object_symbols( 114*523fa7a6SAndroid Build Coastguard Worker nm: str, symbols: Dict[str, Symbol], object_file: Path, source_file: Path 115*523fa7a6SAndroid Build Coastguard Worker) -> None: 116*523fa7a6SAndroid Build Coastguard Worker """Scrape symbols from a binary object.""" 117*523fa7a6SAndroid Build Coastguard Worker symbol_table = read_nm(nm, object_file) 118*523fa7a6SAndroid Build Coastguard Worker for t, symbol in symbol_table: 119*523fa7a6SAndroid Build Coastguard Worker if symbol not in symbols: 120*523fa7a6SAndroid Build Coastguard Worker symbols[symbol] = Symbol( 121*523fa7a6SAndroid Build Coastguard Worker mangled=symbol, 122*523fa7a6SAndroid Build Coastguard Worker demangled="", 123*523fa7a6SAndroid Build Coastguard Worker defined=(t != "U"), 124*523fa7a6SAndroid Build Coastguard Worker disallowed=False, 125*523fa7a6SAndroid Build Coastguard Worker sources=[], 126*523fa7a6SAndroid Build Coastguard Worker ) 127*523fa7a6SAndroid Build Coastguard Worker if source_file in symbols[symbol].sources: 128*523fa7a6SAndroid Build Coastguard Worker continue 129*523fa7a6SAndroid Build Coastguard Worker symbols[symbol].sources.append(source_file) 130*523fa7a6SAndroid Build Coastguard Worker 131*523fa7a6SAndroid Build Coastguard Worker 132*523fa7a6SAndroid Build Coastguard Workerdef get_elf_dependencies(readelf: str, binary_file: Path) -> List[str]: 133*523fa7a6SAndroid Build Coastguard Worker """Get the shared object dependencies of a binary executable.""" 134*523fa7a6SAndroid Build Coastguard Worker shared_objects = [] 135*523fa7a6SAndroid Build Coastguard Worker output = get_tool_output([readelf, "-d", binary_file]) 136*523fa7a6SAndroid Build Coastguard Worker for line in output.splitlines(): 137*523fa7a6SAndroid Build Coastguard Worker match = re.search(READELF_DEP_REGEX, line) 138*523fa7a6SAndroid Build Coastguard Worker if not match: 139*523fa7a6SAndroid Build Coastguard Worker continue 140*523fa7a6SAndroid Build Coastguard Worker shared_objects.append(match.group("so")) 141*523fa7a6SAndroid Build Coastguard Worker 142*523fa7a6SAndroid Build Coastguard Worker return shared_objects 143*523fa7a6SAndroid Build Coastguard Worker 144*523fa7a6SAndroid Build Coastguard Worker 145*523fa7a6SAndroid Build Coastguard Workerdef get_binary_dynamic_symbols(readelf: str, binary_file: Path) -> List[str]: 146*523fa7a6SAndroid Build Coastguard Worker """Get the dynamic symbols required by a binary executable.""" 147*523fa7a6SAndroid Build Coastguard Worker dynamic_symbols = [] 148*523fa7a6SAndroid Build Coastguard Worker output = get_tool_output([readelf, "--dyn-syms", "--wide", binary_file]) 149*523fa7a6SAndroid Build Coastguard Worker for line in output.splitlines(): 150*523fa7a6SAndroid Build Coastguard Worker match = re.search(READELF_DYN_SYM_REGEX, line) 151*523fa7a6SAndroid Build Coastguard Worker if not match: 152*523fa7a6SAndroid Build Coastguard Worker continue 153*523fa7a6SAndroid Build Coastguard Worker dynamic_symbols.append(match.group("symbol")) 154*523fa7a6SAndroid Build Coastguard Worker return list(set(dynamic_symbols)) 155*523fa7a6SAndroid Build Coastguard Worker 156*523fa7a6SAndroid Build Coastguard Worker 157*523fa7a6SAndroid Build Coastguard Workerdef demangle_symbols(cxxfilt: str, mangled_symbols: Iterable[Symbol]) -> None: 158*523fa7a6SAndroid Build Coastguard Worker """Demangle a collection of symbols using the cxxfilt tool.""" 159*523fa7a6SAndroid Build Coastguard Worker output = get_tool_output([cxxfilt] + [symbol.mangled for symbol in mangled_symbols]) 160*523fa7a6SAndroid Build Coastguard Worker for symbol, demangled in zip(mangled_symbols, output.splitlines()): 161*523fa7a6SAndroid Build Coastguard Worker symbol.demangled = demangled 162*523fa7a6SAndroid Build Coastguard Worker 163*523fa7a6SAndroid Build Coastguard Worker 164*523fa7a6SAndroid Build Coastguard Workerdef check_disallowed_symbols(cxxfilt: str, symbols: Iterable[Symbol]) -> None: 165*523fa7a6SAndroid Build Coastguard Worker """Check a collection of symbols for disallowed prefixes.""" 166*523fa7a6SAndroid Build Coastguard Worker for symbol in symbols: 167*523fa7a6SAndroid Build Coastguard Worker assert len(symbol.demangled) > 0 168*523fa7a6SAndroid Build Coastguard Worker if symbol.demangled.startswith(tuple(DISALLOW_LIST)): 169*523fa7a6SAndroid Build Coastguard Worker symbol.disallowed = True 170*523fa7a6SAndroid Build Coastguard Worker 171*523fa7a6SAndroid Build Coastguard Worker 172*523fa7a6SAndroid Build Coastguard Workerdef get_cached_symbols(nm: str, build_root: Path) -> Dict[str, Symbol]: 173*523fa7a6SAndroid Build Coastguard Worker """Return a dictionary of symbols scraped from build files""" 174*523fa7a6SAndroid Build Coastguard Worker global symbols_cache 175*523fa7a6SAndroid Build Coastguard Worker 176*523fa7a6SAndroid Build Coastguard Worker if symbols_cache is not None: 177*523fa7a6SAndroid Build Coastguard Worker return symbols_cache 178*523fa7a6SAndroid Build Coastguard Worker symbols = {} 179*523fa7a6SAndroid Build Coastguard Worker 180*523fa7a6SAndroid Build Coastguard Worker if not build_root.is_dir(): 181*523fa7a6SAndroid Build Coastguard Worker error("Specified buck-out is not a directory") 182*523fa7a6SAndroid Build Coastguard Worker 183*523fa7a6SAndroid Build Coastguard Worker for root, _, files in os.walk(build_root): 184*523fa7a6SAndroid Build Coastguard Worker root_path = Path(root) 185*523fa7a6SAndroid Build Coastguard Worker for file_name in files: 186*523fa7a6SAndroid Build Coastguard Worker file_path = root_path / file_name 187*523fa7a6SAndroid Build Coastguard Worker if file_path.suffix == OBJECT_SUFFIX: 188*523fa7a6SAndroid Build Coastguard Worker object_file_path = file_path 189*523fa7a6SAndroid Build Coastguard Worker source_file_name = object_file_path.name[: -len(OBJECT_SUFFIX)] 190*523fa7a6SAndroid Build Coastguard Worker 191*523fa7a6SAndroid Build Coastguard Worker object_file_rel = Path(os.path.relpath(object_file_path, build_root)) 192*523fa7a6SAndroid Build Coastguard Worker if "codegen" in str(object_file_path): 193*523fa7a6SAndroid Build Coastguard Worker source_file_path = source_file_name + " (generated)" 194*523fa7a6SAndroid Build Coastguard Worker else: 195*523fa7a6SAndroid Build Coastguard Worker source_file_path = ( 196*523fa7a6SAndroid Build Coastguard Worker PROJECT_ROOT / object_file_rel.parent.parent / source_file_name 197*523fa7a6SAndroid Build Coastguard Worker ) 198*523fa7a6SAndroid Build Coastguard Worker get_object_symbols(nm, symbols, object_file_path, source_file_path) 199*523fa7a6SAndroid Build Coastguard Worker 200*523fa7a6SAndroid Build Coastguard Worker symbols_cache = symbols 201*523fa7a6SAndroid Build Coastguard Worker return symbols_cache 202*523fa7a6SAndroid Build Coastguard Worker 203*523fa7a6SAndroid Build Coastguard Worker 204*523fa7a6SAndroid Build Coastguard Workerdef check_dependencies(readelf: str, binary_file: Path) -> int: 205*523fa7a6SAndroid Build Coastguard Worker """Check that there are no shared object dependencies of a binary executable.""" 206*523fa7a6SAndroid Build Coastguard Worker elf_dependencies = get_elf_dependencies(readelf, binary_file) 207*523fa7a6SAndroid Build Coastguard Worker if len(elf_dependencies) > 0: 208*523fa7a6SAndroid Build Coastguard Worker print("Found the following shared object dependencies:") 209*523fa7a6SAndroid Build Coastguard Worker for dependency in elf_dependencies: 210*523fa7a6SAndroid Build Coastguard Worker print(" *", dependency) 211*523fa7a6SAndroid Build Coastguard Worker print() 212*523fa7a6SAndroid Build Coastguard Worker return STATUS_ERROR 213*523fa7a6SAndroid Build Coastguard Worker return STATUS_OK 214*523fa7a6SAndroid Build Coastguard Worker 215*523fa7a6SAndroid Build Coastguard Worker 216*523fa7a6SAndroid Build Coastguard Workerdef check_disallowed_symbols_build_dir(nm: str, cxxfilt: str, build_root: Path) -> int: 217*523fa7a6SAndroid Build Coastguard Worker """Check that there are no disallowed symbols used in intermediate build files.""" 218*523fa7a6SAndroid Build Coastguard Worker symbols = get_cached_symbols(nm, build_root) 219*523fa7a6SAndroid Build Coastguard Worker symbol_list = list(symbols.values()) 220*523fa7a6SAndroid Build Coastguard Worker demangle_symbols(cxxfilt, symbol_list) 221*523fa7a6SAndroid Build Coastguard Worker check_disallowed_symbols(cxxfilt, symbol_list) 222*523fa7a6SAndroid Build Coastguard Worker disallowed_symbols = filter(lambda symbol: symbol.disallowed, symbol_list) 223*523fa7a6SAndroid Build Coastguard Worker 224*523fa7a6SAndroid Build Coastguard Worker disallowed_by_file = {} 225*523fa7a6SAndroid Build Coastguard Worker for symbol in disallowed_symbols: 226*523fa7a6SAndroid Build Coastguard Worker for file in symbol.sources: 227*523fa7a6SAndroid Build Coastguard Worker if file not in disallowed_by_file: 228*523fa7a6SAndroid Build Coastguard Worker disallowed_by_file[file] = [] 229*523fa7a6SAndroid Build Coastguard Worker disallowed_by_file[file].append(symbol) 230*523fa7a6SAndroid Build Coastguard Worker 231*523fa7a6SAndroid Build Coastguard Worker for file, symbols in disallowed_by_file.items(): 232*523fa7a6SAndroid Build Coastguard Worker print(f"{file} contains disallowed symbols:") 233*523fa7a6SAndroid Build Coastguard Worker for symbol in symbols: 234*523fa7a6SAndroid Build Coastguard Worker print(" *", symbol.demangled) 235*523fa7a6SAndroid Build Coastguard Worker print() 236*523fa7a6SAndroid Build Coastguard Worker 237*523fa7a6SAndroid Build Coastguard Worker if len(disallowed_by_file) > 0: 238*523fa7a6SAndroid Build Coastguard Worker return STATUS_ERROR 239*523fa7a6SAndroid Build Coastguard Worker 240*523fa7a6SAndroid Build Coastguard Worker return STATUS_OK 241*523fa7a6SAndroid Build Coastguard Worker 242*523fa7a6SAndroid Build Coastguard Worker 243*523fa7a6SAndroid Build Coastguard Workerdef check_dynamic( 244*523fa7a6SAndroid Build Coastguard Worker nm: str, readelf: str, cxxfilt: str, binary_file: Path, build_root: Optional[Path] 245*523fa7a6SAndroid Build Coastguard Worker) -> int: 246*523fa7a6SAndroid Build Coastguard Worker """Check for dynamic symbols required by an executable, categorizing them from the 247*523fa7a6SAndroid Build Coastguard Worker intermediate files that may have included those symbols. 248*523fa7a6SAndroid Build Coastguard Worker """ 249*523fa7a6SAndroid Build Coastguard Worker symbols = get_cached_symbols(nm, build_root) if build_root is not None else {} 250*523fa7a6SAndroid Build Coastguard Worker 251*523fa7a6SAndroid Build Coastguard Worker dynamic_symbols = [] 252*523fa7a6SAndroid Build Coastguard Worker binary_dyn_sym = get_binary_dynamic_symbols(readelf, binary_file) 253*523fa7a6SAndroid Build Coastguard Worker for symbol in binary_dyn_sym: 254*523fa7a6SAndroid Build Coastguard Worker if symbols is not None and symbol in symbols: 255*523fa7a6SAndroid Build Coastguard Worker dynamic_symbols.append(symbols[symbol]) 256*523fa7a6SAndroid Build Coastguard Worker else: 257*523fa7a6SAndroid Build Coastguard Worker dynamic_symbols.append(Symbol(symbol, "", False, False, [])) 258*523fa7a6SAndroid Build Coastguard Worker demangle_symbols(cxxfilt, dynamic_symbols) 259*523fa7a6SAndroid Build Coastguard Worker check_disallowed_symbols(cxxfilt, dynamic_symbols) 260*523fa7a6SAndroid Build Coastguard Worker 261*523fa7a6SAndroid Build Coastguard Worker dynamic_by_file = {} 262*523fa7a6SAndroid Build Coastguard Worker global_dynamic = [] 263*523fa7a6SAndroid Build Coastguard Worker for symbol in dynamic_symbols: 264*523fa7a6SAndroid Build Coastguard Worker if len(symbol.sources) == 0: 265*523fa7a6SAndroid Build Coastguard Worker global_dynamic.append(symbol) 266*523fa7a6SAndroid Build Coastguard Worker continue 267*523fa7a6SAndroid Build Coastguard Worker 268*523fa7a6SAndroid Build Coastguard Worker for file in symbol.sources: 269*523fa7a6SAndroid Build Coastguard Worker if file not in dynamic_by_file: 270*523fa7a6SAndroid Build Coastguard Worker dynamic_by_file[file] = [] 271*523fa7a6SAndroid Build Coastguard Worker dynamic_by_file[file].append(symbol) 272*523fa7a6SAndroid Build Coastguard Worker 273*523fa7a6SAndroid Build Coastguard Worker print("Executable relies on the following dynamic symbols:") 274*523fa7a6SAndroid Build Coastguard Worker for file, symbols in dynamic_by_file.items(): 275*523fa7a6SAndroid Build Coastguard Worker print(f"{file} contains dynamic symbols:") 276*523fa7a6SAndroid Build Coastguard Worker for symbol in symbols: 277*523fa7a6SAndroid Build Coastguard Worker print(" *", symbol.demangled) 278*523fa7a6SAndroid Build Coastguard Worker print() 279*523fa7a6SAndroid Build Coastguard Worker 280*523fa7a6SAndroid Build Coastguard Worker if len(dynamic_by_file) > 0: 281*523fa7a6SAndroid Build Coastguard Worker return STATUS_ERROR 282*523fa7a6SAndroid Build Coastguard Worker 283*523fa7a6SAndroid Build Coastguard Worker return STATUS_OK 284*523fa7a6SAndroid Build Coastguard Worker 285*523fa7a6SAndroid Build Coastguard Worker 286*523fa7a6SAndroid Build Coastguard Workerdef bubble_error(program_status, routine_status) -> int: 287*523fa7a6SAndroid Build Coastguard Worker """Bubble a routine's error status up to the program status.""" 288*523fa7a6SAndroid Build Coastguard Worker # A non-OK error status overrides an OK error status. 289*523fa7a6SAndroid Build Coastguard Worker if routine_status == STATUS_OK: 290*523fa7a6SAndroid Build Coastguard Worker return program_status 291*523fa7a6SAndroid Build Coastguard Worker elif program_status == STATUS_OK: 292*523fa7a6SAndroid Build Coastguard Worker return routine_status 293*523fa7a6SAndroid Build Coastguard Worker else: 294*523fa7a6SAndroid Build Coastguard Worker return min(program_status, routine_status) 295*523fa7a6SAndroid Build Coastguard Worker 296*523fa7a6SAndroid Build Coastguard Worker 297*523fa7a6SAndroid Build Coastguard Workerdef main() -> int: 298*523fa7a6SAndroid Build Coastguard Worker """Parse command line arguments and execute tool.""" 299*523fa7a6SAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 300*523fa7a6SAndroid Build Coastguard Worker description="A tool to help check binary dependencies and statically included symbols." 301*523fa7a6SAndroid Build Coastguard Worker ) 302*523fa7a6SAndroid Build Coastguard Worker parser.add_argument( 303*523fa7a6SAndroid Build Coastguard Worker "--nm", 304*523fa7a6SAndroid Build Coastguard Worker metavar="executable", 305*523fa7a6SAndroid Build Coastguard Worker type=str, 306*523fa7a6SAndroid Build Coastguard Worker help="Path of the nm tool executable", 307*523fa7a6SAndroid Build Coastguard Worker default="nm", 308*523fa7a6SAndroid Build Coastguard Worker ) 309*523fa7a6SAndroid Build Coastguard Worker parser.add_argument( 310*523fa7a6SAndroid Build Coastguard Worker "--readelf", 311*523fa7a6SAndroid Build Coastguard Worker metavar="executable", 312*523fa7a6SAndroid Build Coastguard Worker type=str, 313*523fa7a6SAndroid Build Coastguard Worker help="Path of the readelf tool executable", 314*523fa7a6SAndroid Build Coastguard Worker default="readelf", 315*523fa7a6SAndroid Build Coastguard Worker ) 316*523fa7a6SAndroid Build Coastguard Worker parser.add_argument( 317*523fa7a6SAndroid Build Coastguard Worker "--cxxfilt", 318*523fa7a6SAndroid Build Coastguard Worker metavar="executable", 319*523fa7a6SAndroid Build Coastguard Worker type=str, 320*523fa7a6SAndroid Build Coastguard Worker help="Path of the cxxfilt tool executable", 321*523fa7a6SAndroid Build Coastguard Worker default="c++filt", 322*523fa7a6SAndroid Build Coastguard Worker ) 323*523fa7a6SAndroid Build Coastguard Worker parser.add_argument("--binary", metavar="binary", type=str, help="Binary to check") 324*523fa7a6SAndroid Build Coastguard Worker parser.add_argument( 325*523fa7a6SAndroid Build Coastguard Worker "--buck-out", metavar="dir", type=str, help="Buck output directory" 326*523fa7a6SAndroid Build Coastguard Worker ) 327*523fa7a6SAndroid Build Coastguard Worker parser.add_argument( 328*523fa7a6SAndroid Build Coastguard Worker "--check-dependencies", 329*523fa7a6SAndroid Build Coastguard Worker action="store_true", 330*523fa7a6SAndroid Build Coastguard Worker help="Check shared library dependencies for a binary", 331*523fa7a6SAndroid Build Coastguard Worker ) 332*523fa7a6SAndroid Build Coastguard Worker parser.add_argument( 333*523fa7a6SAndroid Build Coastguard Worker "--check-disallowed-symbols", 334*523fa7a6SAndroid Build Coastguard Worker action="store_true", 335*523fa7a6SAndroid Build Coastguard Worker help="Check for usage of disallowed symbols", 336*523fa7a6SAndroid Build Coastguard Worker ) 337*523fa7a6SAndroid Build Coastguard Worker parser.add_argument( 338*523fa7a6SAndroid Build Coastguard Worker "--check-dynamic", 339*523fa7a6SAndroid Build Coastguard Worker action="store_true", 340*523fa7a6SAndroid Build Coastguard Worker help="Check for usage of dynamic symbols", 341*523fa7a6SAndroid Build Coastguard Worker ) 342*523fa7a6SAndroid Build Coastguard Worker 343*523fa7a6SAndroid Build Coastguard Worker args = parser.parse_args() 344*523fa7a6SAndroid Build Coastguard Worker 345*523fa7a6SAndroid Build Coastguard Worker exit_status = STATUS_OK 346*523fa7a6SAndroid Build Coastguard Worker 347*523fa7a6SAndroid Build Coastguard Worker if args.check_dependencies: 348*523fa7a6SAndroid Build Coastguard Worker if args.binary is None: 349*523fa7a6SAndroid Build Coastguard Worker error("--binary flag must be specified when checking dependencies") 350*523fa7a6SAndroid Build Coastguard Worker status = check_dependencies(args.readelf, Path(args.binary)) 351*523fa7a6SAndroid Build Coastguard Worker exit_status = bubble_error(exit_status, status) 352*523fa7a6SAndroid Build Coastguard Worker 353*523fa7a6SAndroid Build Coastguard Worker if args.check_disallowed_symbols: 354*523fa7a6SAndroid Build Coastguard Worker if args.buck_out is None: 355*523fa7a6SAndroid Build Coastguard Worker error("--buck-out flag must be specified when checking disallowed symbols") 356*523fa7a6SAndroid Build Coastguard Worker status = check_disallowed_symbols_build_dir( 357*523fa7a6SAndroid Build Coastguard Worker args.nm, args.cxxfilt, Path(args.buck_out) 358*523fa7a6SAndroid Build Coastguard Worker ) 359*523fa7a6SAndroid Build Coastguard Worker exit_status = bubble_error(exit_status, status) 360*523fa7a6SAndroid Build Coastguard Worker 361*523fa7a6SAndroid Build Coastguard Worker if args.check_dynamic: 362*523fa7a6SAndroid Build Coastguard Worker if args.binary is None: 363*523fa7a6SAndroid Build Coastguard Worker error("--binary flag must be specified when checking dynamic symbol usage") 364*523fa7a6SAndroid Build Coastguard Worker status = check_dynamic( 365*523fa7a6SAndroid Build Coastguard Worker args.nm, 366*523fa7a6SAndroid Build Coastguard Worker args.readelf, 367*523fa7a6SAndroid Build Coastguard Worker args.cxxfilt, 368*523fa7a6SAndroid Build Coastguard Worker Path(args.binary), 369*523fa7a6SAndroid Build Coastguard Worker Path(args.buck_out) if args.buck_out is not None else None, 370*523fa7a6SAndroid Build Coastguard Worker ) 371*523fa7a6SAndroid Build Coastguard Worker exit_status = bubble_error(exit_status, status) 372*523fa7a6SAndroid Build Coastguard Worker 373*523fa7a6SAndroid Build Coastguard Worker return exit_status 374*523fa7a6SAndroid Build Coastguard Worker 375*523fa7a6SAndroid Build Coastguard Worker 376*523fa7a6SAndroid Build Coastguard Workerif __name__ == "__main__": 377*523fa7a6SAndroid Build Coastguard Worker sys.exit(main()) 378