-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a dump_init_order.py script to dump a human readable list of init function and device structs in linking order. This can be useful for troubleshooting priority change breakages due to unclear interactions between SYS_INIT and devices or devices declared with DEVICE_DEFINE. Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
- Loading branch information
1 parent
d218b20
commit ca9df0a
Showing
1 changed file
with
117 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# Copyright 2023 Google LLC | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
""" | ||
Dump the initlevel and device_area in a human readable format. | ||
""" | ||
|
||
import argparse | ||
import sys | ||
|
||
from elftools.elf.elffile import ELFFile | ||
from elftools.elf.relocation import Section | ||
from elftools.elf.sections import SymbolTableSection | ||
|
||
def _parse_args(argv): | ||
"""Parse the command line arguments.""" | ||
parser = argparse.ArgumentParser( | ||
description=__doc__, | ||
formatter_class=argparse.RawDescriptionHelpFormatter, | ||
allow_abbrev=False) | ||
|
||
parser.add_argument("-f", "--elf-file", default="build/zephyr/zephyr.elf", | ||
help="ELF file to use") | ||
return parser.parse_args(argv) | ||
|
||
|
||
def load_objects(elf): | ||
"""Initialize the object table.""" | ||
objects = {} | ||
|
||
for section in elf.iter_sections(): | ||
if not isinstance(section, SymbolTableSection): | ||
continue | ||
|
||
for sym in section.iter_symbols(): | ||
if (sym.name and | ||
sym.entry.st_size > 0 and | ||
sym.entry.st_info.type in ["STT_OBJECT", "STT_FUNC"]): | ||
objects[sym.entry.st_value] = (sym.name, sym.entry.st_size) | ||
|
||
return objects | ||
|
||
|
||
def _print_initlevel(section, objects): | ||
size = section.header.sh_size | ||
base_addr = section.header.sh_addr | ||
offset = 0 | ||
data = section.data() | ||
|
||
print("initlevel:") | ||
|
||
while offset < size: | ||
addr = base_addr + offset | ||
if addr not in objects: | ||
print(f"no symbol at addr {addr:08x}") | ||
obj = objects[addr] | ||
|
||
arg0 = int.from_bytes(data[offset:offset+4], byteorder='little') | ||
arg1 = int.from_bytes(data[offset+4:offset+8], byteorder='little') | ||
|
||
if arg0 in objects: | ||
arg0s = objects[arg0][0] | ||
else: | ||
arg0s = "unknown" | ||
|
||
if not arg1: | ||
arg1s = "NULL" | ||
elif arg1 in objects: | ||
arg1s = objects[arg1][0] | ||
else: | ||
arg1s = "unknown" | ||
|
||
print(f" {obj[0]}({arg0s}, {arg1s})") | ||
offset += obj[1] | ||
|
||
|
||
def _print_device_area(section, objects): | ||
size = section.header.sh_size | ||
base_addr = section.header.sh_addr | ||
offset = 0 | ||
|
||
print("device_area:") | ||
|
||
while offset < size: | ||
addr = base_addr + offset | ||
if addr not in objects: | ||
print(f"no symbol at addr {addr:08x}") | ||
obj = objects[addr] | ||
|
||
print(f" {obj[0]}") | ||
offset += obj[1] | ||
|
||
|
||
def main(argv=None): | ||
args = _parse_args(argv) | ||
|
||
print(f"Working on: {args.elf_file}") | ||
|
||
elf = ELFFile(open(args.elf_file, "rb")) | ||
objects = load_objects(elf) | ||
|
||
for section in elf.iter_sections(): | ||
if not isinstance(section, Section): | ||
continue | ||
|
||
if section.name == "initlevel": | ||
_print_initlevel(section, objects) | ||
elif section.name == "device_area": | ||
_print_device_area(section, objects) | ||
|
||
return 0 | ||
|
||
|
||
if __name__ == "__main__": | ||
sys.exit(main(sys.argv[1:])) |