2023-02-19 04:33:21 +01:00
|
|
|
#!/usr/bin/env python3
|
2022-09-28 11:07:10 +02:00
|
|
|
############################################################################
|
|
|
|
# tools/mkallsyms.py
|
|
|
|
#
|
2024-09-10 14:15:58 +02:00
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
#
|
2022-09-28 11:07:10 +02:00
|
|
|
# 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.
|
|
|
|
#
|
|
|
|
############################################################################
|
|
|
|
|
2023-11-27 10:28:38 +01:00
|
|
|
import argparse
|
2022-09-28 11:07:10 +02:00
|
|
|
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")
|
2023-11-27 10:28:38 +01:00
|
|
|
os._exit(errno.EINVAL)
|
2022-09-28 11:07:10 +02:00
|
|
|
|
|
|
|
|
|
|
|
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")
|
2023-05-30 06:51:09 +02:00
|
|
|
self.emitline("extern int g_nallsyms;\n")
|
|
|
|
self.emitline(
|
|
|
|
"extern struct symtab_s g_allsyms[%d + 2];\n" % len(self.symbol_list)
|
|
|
|
)
|
2022-09-28 11:07:10 +02:00
|
|
|
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
|
|
|
|
|
2023-11-27 10:28:38 +01:00
|
|
|
def parse_symbol(self, orderbyname=False):
|
2022-09-28 11:07:10 +02:00
|
|
|
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:
|
2023-05-10 05:46:02 +02:00
|
|
|
try:
|
|
|
|
symbol_name = cxxfilt.demangle(symbol.name)
|
|
|
|
func_name = re.sub(r"\(.*$", "", symbol_name)
|
|
|
|
except cxxfilt.InvalidName:
|
|
|
|
symbol_name = symbol.name
|
libs: fix the problem that the address obtained in thumb mode cannot be executed.
The lowest bit of the thumb instruction is 1 by default, which is used to distinguish arm instructions and thumb instructions.
Fixed the problem of misalignment of symbol table when performing binary search
In arm, the lowest bit of the instruction is 1, which is a thumb instruction, and 0, which is an arm instruction.
The nm command was used in mkallsym.sh before, and the result it will return will set the lowest bit of the thumb instruction to 0. There will be a one-byte deviation during binary search, so mkallsyms.py will also set the lowest bit to 0 according to the previous format.
```sh
arm-none-eabi-nm -Cn nuttx | grep hello
0801c384 T hello_main
arm-none-eabi-objdump nuttx -t |grep hello
0801c384 g F .text 0000004c hello_main
arm-none-eabi-readelf nuttx -s |grep hello
4558: 0801c385 76 FUNC GLOBAL DEFAULT 1 hello_main
```
However, in the following case, when you need to find the function address according to the symbol name and execute the corresponding function, the lowest address obtained is 0. It will follow the arm instruction, causing an exception.
```c
void sym_test(void)
{
printf("call sym_test\n");
}
int main(int argc, FAR char *argv[])
{
FAR void *addr = sym_test;
printf("sym_test:%p %pS\n",addr, addr);
printf("sym_test - 1: %pS\n", (char *)addr - 1);
printf("sym_test + 1: %pS\n", (char *)addr + 1);
size_t size;
void (*func)(void);
const struct symtab_s *sym = allsyms_findbyname("sym_test", &size);
printf("sym_test:%p %pS\n",sym, sym);
func = sym->sym_value;
func();
return 0;
}
```
Therefore, you need to change mkallsyms.py back to the correct result and correct the binary search.
Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
2023-11-27 13:04:46 +01:00
|
|
|
self.symbol_list.append((symbol["st_value"], func_name))
|
2023-11-27 10:28:38 +01:00
|
|
|
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])
|
2022-09-28 11:07:10 +02:00
|
|
|
|
|
|
|
def emitline(self, s=""):
|
|
|
|
self.output.write(str(s) + "\n")
|
|
|
|
|
|
|
|
|
|
|
|
def usage():
|
2023-11-27 10:28:38 +01:00
|
|
|
print(
|
|
|
|
"Usage: mkallsyms.py [noconst] <ELFBIN> [output file] [order symbols by name]"
|
|
|
|
)
|
2022-09-28 11:07:10 +02:00
|
|
|
os._exit(errno.ENOENT)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2023-11-27 10:28:38 +01:00
|
|
|
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)
|