#!/usr/bin/env python3 ############################################################################ # tools/mkallsyms.py # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. The # ASF licenses this file to you 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. # ############################################################################ import argparse import errno import os import re import sys try: import cxxfilt from elftools import __version__ from elftools.elf.elffile import ELFFile from elftools.elf.sections import SymbolTableSection except ModuleNotFoundError: print("Please execute the following command to install dependencies:") print("pip install pyelftools cxxfilt") os._exit(errno.EINVAL) class SymbolTables(object): def __init__(self, elffile, output): try: file = open(elffile, "rb") self.elffile = ELFFile(file) except FileNotFoundError: self.elffile = None self.output = output self.symbol_list = [] def symbol_filter(self, symbol): if symbol["st_info"]["type"] != "STT_FUNC": return None if symbol["st_info"]["bind"] == "STB_WEAK": return None if symbol["st_shndx"] == "SHN_UNDEF": return None return symbol def print_symbol_tables(self, isnoconst=False): noconst = "const" if not isnoconst: noconst = "" self.emitline("#include ") self.emitline("#include \n") self.emitline("extern int g_nallsyms;\n") self.emitline( "extern struct symtab_s g_allsyms[%d + 2];\n" % len(self.symbol_list) ) self.emitline("%s int g_nallsyms = %d + 2;" % (noconst, len(self.symbol_list))) self.emitline( "%s struct symtab_s g_allsyms[%d + 2] =\n{" % (noconst, len(self.symbol_list)) ) self.emitline(' { "Unknown", (FAR %s void *)0x00000000 },' % (noconst)) for symbol in self.symbol_list: self.emitline( ' { "%s", (FAR %s void *)%s },' % (symbol[1], noconst, hex(symbol[0])) ) self.emitline(' { "Unknown", (FAR %s void *)0xffffffff }\n};' % (noconst)) def get_symtable(self): symbol_tables = [ (idx, s) for idx, s in enumerate(self.elffile.iter_sections()) if isinstance(s, SymbolTableSection) ] if not symbol_tables and self.elffile.num_sections() == 0: self.emitline("") return for section_index, section in symbol_tables: if not isinstance(section, SymbolTableSection): continue if section["sh_entsize"] == 0 or section.name != ".symtab": continue return section def parse_symbol(self, orderbyname=False): if self.elffile is None: return symtable = self.get_symtable() for nsym, symbol in enumerate(symtable.iter_symbols()): if self.symbol_filter(symbol) is not None: try: symbol_name = cxxfilt.demangle(symbol.name) func_name = re.sub(r"\(.*$", "", symbol_name) except cxxfilt.InvalidName: symbol_name = symbol.name self.symbol_list.append((symbol["st_value"], func_name)) if orderbyname: self.symbol_list = sorted(self.symbol_list, key=lambda item: item[1]) else: self.symbol_list = sorted(self.symbol_list, key=lambda item: item[0]) def emitline(self, s=""): self.output.write(str(s) + "\n") def usage(): print( "Usage: mkallsyms.py [noconst] [output file] [order symbols by name]" ) os._exit(errno.ENOENT) if __name__ == "__main__": parser = argparse.ArgumentParser( description="Process ELF binary to extract symbols." ) parser.add_argument("elffile", help="Path to the ELF binary file.") parser.add_argument( "outfile", nargs="?", type=argparse.FileType("w"), default=sys.stdout, help="Output file to write symbols to (default: stdout).", ) parser.add_argument("--noconst", action="store_true", help="Exclude const symbols.") parser.add_argument( "--version", action="version", version="mkallsyms.py: based on pyelftools %s" % __version__, ) parser.add_argument( "--orderbyname", nargs="?", const=False, default=False, help='Order symbols by name (specify "y" to enable, default: False).', ) args = parser.parse_args() readelf = SymbolTables(args.elffile, args.outfile) readelf.parse_symbol(args.orderbyname) readelf.print_symbol_tables(args.noconst)