You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.8 KiB
157 lines
4.8 KiB
#!/usr/bin/env python3 |
|
# |
|
# Copyright (c) 2024 Meta Platforms |
|
# |
|
# SPDX-License-Identifier: Apache-2.0 |
|
|
|
import argparse |
|
import sys |
|
import os |
|
import re |
|
|
|
from elftools.elf.elffile import ELFFile |
|
from elftools.elf.descriptions import ( |
|
describe_symbol_type, |
|
) |
|
|
|
|
|
class gen_symtab_log: |
|
|
|
def __init__(self, debug=False): |
|
self.__debug = debug |
|
|
|
def debug(self, text): |
|
"""Print debug message if debugging is enabled. |
|
|
|
Note - this function requires config global variable to be initialized. |
|
""" |
|
if self.__debug: |
|
sys.stdout.write(os.path.basename( |
|
sys.argv[0]) + ": " + text + "\n") |
|
|
|
@staticmethod |
|
def error(text): |
|
sys.exit(os.path.basename(sys.argv[0]) + ": error: " + text + "\n") |
|
|
|
def set_debug(self, state): |
|
self.__debug = state |
|
|
|
|
|
log = gen_symtab_log() |
|
|
|
|
|
def parse_args(): |
|
parser = argparse.ArgumentParser(description=__doc__, |
|
formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) |
|
|
|
parser.add_argument("-k", "--kernel", required=True, |
|
help="Zephyr kernel image") |
|
parser.add_argument("-o", "--output", required=True, |
|
help="Output source file") |
|
parser.add_argument("-d", "--debug", action="store_true", |
|
help="Print additional debugging information") |
|
|
|
return parser.parse_args() |
|
|
|
|
|
class symtab_entry: |
|
def __init__(self, addr, size, offset, name): |
|
self.addr = addr |
|
self.size = size |
|
self.offset = offset |
|
self.name = name |
|
|
|
def __eq__(self, other): |
|
return self.addr == other.addr |
|
|
|
|
|
first_addr = 0 |
|
symtab_list = [] |
|
|
|
|
|
def sanitize_func_name(name): |
|
pattern = r'(^[a-zA-Z_][a-zA-Z0-9_]*)' |
|
match = re.match(pattern, name) |
|
if match: |
|
return match.group(0) |
|
else: |
|
log.error(f"Failed to sanitize function name: {name}") |
|
|
|
return name |
|
|
|
|
|
def main(): |
|
args = parse_args() |
|
log.set_debug(args.debug) |
|
|
|
with open(args.kernel, "rb") as rf: |
|
elf = ELFFile(rf) |
|
|
|
# Find the symbol table. |
|
symtab = elf.get_section_by_name('.symtab') |
|
|
|
i = 1 |
|
for nsym, symbol in enumerate(symtab.iter_symbols()): # pylint: disable=unused-variable |
|
symbol_type = describe_symbol_type(symbol['st_info']['type']) |
|
symbol_addr = symbol['st_value'] |
|
symbol_size = symbol['st_size'] |
|
|
|
if symbol_type == 'FUNC' and symbol_addr != 0: |
|
symbol_name = sanitize_func_name(symbol.name) |
|
dummy_offset = 0 # offsets will be calculated later after we know the first address |
|
entry = symtab_entry( |
|
symbol_addr, symbol_size, dummy_offset, symbol_name) |
|
# Prevent entries with duplicated addresses |
|
if entry not in symtab_list: |
|
symtab_list.append(entry) |
|
|
|
# Sort the address in ascending order |
|
symtab_list.sort(key=lambda x: x.addr, reverse=False) |
|
|
|
# Get the address of the first symbol |
|
first_addr = symtab_list[0].addr |
|
|
|
for i, entry in enumerate(symtab_list): |
|
# Offset is calculated here |
|
entry.offset = entry.addr - first_addr |
|
|
|
# Debug print |
|
log.debug('%6d: %s %s %.25s' % ( |
|
i, |
|
hex(entry.addr), |
|
hex(entry.size), |
|
entry.name)) |
|
|
|
with open(args.output, 'w') as wf: |
|
print("/* AUTO-GENERATED by gen_symtab.py, do not edit! */", file=wf) |
|
print("", file=wf) |
|
print("#include <zephyr/linker/sections.h>", file=wf) |
|
print("#include <zephyr/debug/symtab.h>", file=wf) |
|
print("", file=wf) |
|
print( |
|
f"const struct z_symtab_entry __symtab_entry z_symtab_entries[{len(symtab_list) + 1}] = {{", file=wf) |
|
for i, entry in enumerate(symtab_list): |
|
print( |
|
f"\t/* ADDR: {hex(entry.addr)} SIZE: {hex(entry.size)} */", file=wf) |
|
print( |
|
f"\t[{i}] = {{.offset = {hex(entry.offset)}, .name = \"{entry.name}\"}},", file=wf) |
|
|
|
# Append a dummy entry at the end to facilitate the binary search |
|
if symtab_list[-1].size == 0: |
|
dummy_offset = f"{hex(symtab_list[-1].offset)} + sizeof(uintptr_t)" |
|
else: |
|
dummy_offset = f"{hex(symtab_list[-1].offset + symtab_list[-1].size)}" |
|
print("\t/* dummy entry */", file=wf) |
|
print( |
|
f"\t[{len(symtab_list)}] = {{.offset = {dummy_offset}, .name = \"?\"}},", file=wf) |
|
print(f"}};\n", file=wf) |
|
|
|
print(f"const struct symtab_info __symtab_info z_symtab = {{", file=wf) |
|
print(f"\t.first_addr = {hex(first_addr)},", file=wf) |
|
print(f"\t.length = {len(symtab_list)},", file=wf) |
|
print(f"\t.entries = z_symtab_entries,", file=wf) |
|
print(f"}};\n", file=wf) |
|
|
|
|
|
if __name__ == "__main__": |
|
main()
|
|
|