#!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 # ----------------------------------------------------------------------------- # Copyright 2021 Arm Limited # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy # of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # ----------------------------------------------------------------------------- """ The ``astc_dump_binary`` utility provides a wrapper around the ``objdump`` utility to extract disassembly of specific functions. Currently only matches the root name, for sake of command line sanity, so all overloads get dumped. Using __attribute__((noinline)) can be useful during profiling to stop any functions of interest getting inlined once they get too small ... """ import argparse import re import shutil import subprocess as sp import sys def run_objdump(binary, symbol): """ Run objdump on a single binary and extract the range for a given symbol. Output is printed to stdout. Args: binary (str): The path of the binary file to process. symbol (str): The symbol to match. Raises: CalledProcessException: The ``objdump`` subprocess failed for any reason. """ args = [ "objdump", "-C", "-M", "intel", "--no-show-raw", "-d", "-S", binary ] result = sp.run(args, stdout=sp.PIPE, stderr=sp.PIPE, check=True, universal_newlines=True) funcPattern = re.compile(r"^[0-9a-f]{16} <(.*)\(.*\)>:$") funcLines = [] funcActive = False lines = result.stdout.splitlines() for line in lines: match = funcPattern.match(line) if match: funcName = match.group(1) if funcName == symbol: funcActive = True else: funcActive = False if funcActive: funcLines.append(line) print("\n".join(funcLines)) def parse_command_line(): """ Parse the command line. Returns: Namespace: The parsed command line container. """ parser = argparse.ArgumentParser() parser.add_argument("binary", type=argparse.FileType("r"), help="The new binary to dump") parser.add_argument("symbol", type=str, help="The function name to dump") return parser.parse_args() def main(): """ The main function. Returns: int: The process return code. """ args = parse_command_line() # Preflight - check that size exists. Note that size might still fail at # runtime later, e.g. if the binary is not of the correct format path = shutil.which("objdump") if not path: print("ERROR: The 'objdump' utility is not installed on the PATH") return 1 # Collect the data try: run_objdump(args.binary.name, args.symbol) except sp.CalledProcessError as ex: print("ERROR: The 'objdump' utility failed") print(" %s" % ex.stderr.strip()) return 1 return 0 if __name__ == "__main__": sys.exit(main())