blob: ac20506a645b56cf77596386cf52c3d8de04435d [file] [log] [blame]
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +08001#!/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
Yong Cong Sin408d0be2024-05-27 15:40:27 +080010import re
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +080011
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:
Yong Cong Sinf5934de2024-05-27 21:38:55 +080058 def __init__(self, addr, size, offset, name):
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +080059 self.addr = addr
Yong Cong Sinf5934de2024-05-27 21:38:55 +080060 self.size = size
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +080061 self.offset = offset
62 self.name = name
63
Yong Cong Sin29423eb2024-05-28 12:26:58 +080064 def __eq__(self, other):
65 return self.addr == other.addr
66
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +080067
Yong Cong Sin043f5952024-05-27 17:25:39 +080068first_addr = 0
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +080069symtab_list = []
70
71
Yong Cong Sin408d0be2024-05-27 15:40:27 +080072def 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
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +080083def 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
Yong Cong Sin408d0be2024-05-27 15:40:27 +080094 for nsym, symbol in enumerate(symtab.iter_symbols()): # pylint: disable=unused-variable
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +080095 symbol_type = describe_symbol_type(symbol['st_info']['type'])
96 symbol_addr = symbol['st_value']
Yong Cong Sinf5934de2024-05-27 21:38:55 +080097 symbol_size = symbol['st_size']
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +080098
99 if symbol_type == 'FUNC' and symbol_addr != 0:
Yong Cong Sin408d0be2024-05-27 15:40:27 +0800100 symbol_name = sanitize_func_name(symbol.name)
Yong Cong Sin29423eb2024-05-28 12:26:58 +0800101 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)
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +0800107
Yong Cong Sin29423eb2024-05-28 12:26:58 +0800108 # Sort the address in ascending order
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +0800109 symtab_list.sort(key=lambda x: x.addr, reverse=False)
110
111 # Get the address of the first symbol
Yong Cong Sin043f5952024-05-27 17:25:39 +0800112 first_addr = symtab_list[0].addr
Yong Cong Sin29423eb2024-05-28 12:26:58 +0800113
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +0800114 for i, entry in enumerate(symtab_list):
Yong Cong Sin29423eb2024-05-28 12:26:58 +0800115 # Offset is calculated here
Yong Cong Sin043f5952024-05-27 17:25:39 +0800116 entry.offset = entry.addr - first_addr
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +0800117
Yong Cong Sin29423eb2024-05-28 12:26:58 +0800118 # Debug print
119 log.debug('%6d: %s %s %.25s' % (
120 i,
121 hex(entry.addr),
122 hex(entry.size),
123 entry.name))
124
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +0800125 with open(args.output, 'w') as wf:
126 print("/* AUTO-GENERATED by gen_symtab.py, do not edit! */", file=wf)
127 print("", file=wf)
Yong Cong Sin13a5c8a2024-05-29 16:08:21 +0800128 print("#include <zephyr/linker/sections.h>", file=wf)
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +0800129 print("#include <zephyr/debug/symtab.h>", file=wf)
130 print("", file=wf)
131 print(
Yong Cong Sin13a5c8a2024-05-29 16:08:21 +0800132 f"const struct z_symtab_entry __symtab_entry z_symtab_entries[{len(symtab_list) + 1}] = {{", file=wf)
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +0800133 for i, entry in enumerate(symtab_list):
134 print(
Yong Cong Sinf5934de2024-05-27 21:38:55 +0800135 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)
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +0800147 print(f"}};\n", file=wf)
148
Yong Cong Sin13a5c8a2024-05-29 16:08:21 +0800149 print(f"const struct symtab_info __symtab_info z_symtab = {{", file=wf)
Yong Cong Sin043f5952024-05-27 17:25:39 +0800150 print(f"\t.first_addr = {hex(first_addr)},", file=wf)
Yong Cong Sine1ce0ae2024-05-18 16:45:44 +0800151 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()