| #!/usr/bin/env python3 |
| ############################################################################ |
| # tools/mkallsyms.py |
| # |
| # SPDX-License-Identifier: Apache-2.0 |
| # |
| # 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 <nuttx/compiler.h>") |
| self.emitline("#include <nuttx/symtab.h>\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] <ELFBIN> [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) |