1#!/usr/bin/env python3 2# 3# Copyright (c) 2024 Meta Platforms 4# 5# SPDX-License-Identifier: Apache-2.0 6 7import argparse 8import sys 9import os 10import re 11 12from elftools.elf.elffile import ELFFile 13from elftools.elf.descriptions import ( 14 describe_symbol_type, 15) 16 17 18class gen_symtab_log: 19 20 def __init__(self, debug=False): 21 self.__debug = debug 22 23 def debug(self, text): 24 """Print debug message if debugging is enabled. 25 26 Note - this function requires config global variable to be initialized. 27 """ 28 if self.__debug: 29 sys.stdout.write(os.path.basename( 30 sys.argv[0]) + ": " + text + "\n") 31 32 @staticmethod 33 def error(text): 34 sys.exit(os.path.basename(sys.argv[0]) + ": error: " + text + "\n") 35 36 def set_debug(self, state): 37 self.__debug = state 38 39 40log = gen_symtab_log() 41 42 43def parse_args(): 44 parser = argparse.ArgumentParser(description=__doc__, 45 formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) 46 47 parser.add_argument("-k", "--kernel", required=True, 48 help="Zephyr kernel image") 49 parser.add_argument("-o", "--output", required=True, 50 help="Output source file") 51 parser.add_argument("-d", "--debug", action="store_true", 52 help="Print additional debugging information") 53 54 return parser.parse_args() 55 56 57class symtab_entry: 58 def __init__(self, addr, size, offset, name): 59 self.addr = addr 60 self.size = size 61 self.offset = offset 62 self.name = name 63 64 def __eq__(self, other): 65 return self.addr == other.addr 66 67 68first_addr = 0 69symtab_list = [] 70 71 72def sanitize_func_name(name): 73 pattern = r'(^[a-zA-Z_][a-zA-Z0-9_]*)' 74 match = re.match(pattern, name) 75 if match: 76 return match.group(0) 77 else: 78 log.error(f"Failed to sanitize function name: {name}") 79 80 return name 81 82 83def main(): 84 args = parse_args() 85 log.set_debug(args.debug) 86 87 with open(args.kernel, "rb") as rf: 88 elf = ELFFile(rf) 89 90 # Find the symbol table. 91 symtab = elf.get_section_by_name('.symtab') 92 93 i = 1 94 for nsym, symbol in enumerate(symtab.iter_symbols()): # pylint: disable=unused-variable 95 symbol_type = describe_symbol_type(symbol['st_info']['type']) 96 symbol_addr = symbol['st_value'] 97 symbol_size = symbol['st_size'] 98 99 if symbol_type == 'FUNC' and symbol_addr != 0: 100 symbol_name = sanitize_func_name(symbol.name) 101 dummy_offset = 0 # offsets will be calculated later after we know the first address 102 entry = symtab_entry( 103 symbol_addr, symbol_size, dummy_offset, symbol_name) 104 # Prevent entries with duplicated addresses 105 if entry not in symtab_list: 106 symtab_list.append(entry) 107 108 # Sort the address in ascending order 109 symtab_list.sort(key=lambda x: x.addr, reverse=False) 110 111 # Get the address of the first symbol 112 first_addr = symtab_list[0].addr 113 114 for i, entry in enumerate(symtab_list): 115 # Offset is calculated here 116 entry.offset = entry.addr - first_addr 117 118 # Debug print 119 log.debug('%6d: %s %s %.25s' % ( 120 i, 121 hex(entry.addr), 122 hex(entry.size), 123 entry.name)) 124 125 with open(args.output, 'w') as wf: 126 print("/* AUTO-GENERATED by gen_symtab.py, do not edit! */", file=wf) 127 print("", file=wf) 128 print("#include <zephyr/linker/sections.h>", file=wf) 129 print("#include <zephyr/debug/symtab.h>", file=wf) 130 print("", file=wf) 131 print( 132 f"const struct z_symtab_entry __symtab_entry z_symtab_entries[{len(symtab_list) + 1}] = {{", file=wf) 133 for i, entry in enumerate(symtab_list): 134 print( 135 f"\t/* ADDR: {hex(entry.addr)} SIZE: {hex(entry.size)} */", file=wf) 136 print( 137 f"\t[{i}] = {{.offset = {hex(entry.offset)}, .name = \"{entry.name}\"}},", file=wf) 138 139 # Append a dummy entry at the end to facilitate the binary search 140 if symtab_list[-1].size == 0: 141 dummy_offset = f"{hex(symtab_list[-1].offset)} + sizeof(uintptr_t)" 142 else: 143 dummy_offset = f"{hex(symtab_list[-1].offset + symtab_list[-1].size)}" 144 print("\t/* dummy entry */", file=wf) 145 print( 146 f"\t[{len(symtab_list)}] = {{.offset = {dummy_offset}, .name = \"?\"}},", file=wf) 147 print(f"}};\n", file=wf) 148 149 print(f"const struct symtab_info __symtab_info z_symtab = {{", file=wf) 150 print(f"\t.first_addr = {hex(first_addr)},", file=wf) 151 print(f"\t.length = {len(symtab_list)},", file=wf) 152 print(f"\t.entries = z_symtab_entries,", file=wf) 153 print(f"}};\n", file=wf) 154 155 156if __name__ == "__main__": 157 main() 158