Skip to content

Commit

Permalink
scripts: add dump_init_order.py
Browse files Browse the repository at this point in the history
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
fabiobaltieri committed Sep 8, 2023
1 parent d218b20 commit ca9df0a
Showing 1 changed file with 117 additions and 0 deletions.
117 changes: 117 additions & 0 deletions scripts/dump_init_order.py
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:]))

0 comments on commit ca9df0a

Please sign in to comment.