160 lines
5.4 KiB
Python
Executable File
160 lines
5.4 KiB
Python
Executable File
#!/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 <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)
|