mirror of
https://xff.cz/git/u-boot/
synced 2025-09-30 15:01:27 +02:00
event: Add a script to decode the event-spy list
For debugging and dicoverability it is useful to be able to see a list of each event spy in a U-Boot ELF file. Add a script which shows this, along with the event type and the source location. This makes events a little easier to use than weak functions, for example. Add a basic sandbox test as well. We could provide a test for other boards, but for now, few use events. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -815,7 +815,9 @@ S: Maintained
|
|||||||
F: cmd/event.c
|
F: cmd/event.c
|
||||||
F: common/event.c
|
F: common/event.c
|
||||||
F: include/event.h
|
F: include/event.h
|
||||||
|
F: scripts/event_dump.py
|
||||||
F: test/common/event.c
|
F: test/common/event.c
|
||||||
|
F: test/py/tests/test_event_dump.py
|
||||||
|
|
||||||
FASTBOOT
|
FASTBOOT
|
||||||
S: Orphaned
|
S: Orphaned
|
||||||
|
115
scripts/event_dump.py
Executable file
115
scripts/event_dump.py
Executable file
@@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
"""Decode the evspy_info linker list in a U-Boot ELF image"""
|
||||||
|
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
our_path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
src_path = os.path.dirname(our_path)
|
||||||
|
|
||||||
|
sys.path.insert(1, os.path.join(our_path, '../tools'))
|
||||||
|
|
||||||
|
from binman import elf
|
||||||
|
from patman import tools
|
||||||
|
|
||||||
|
PREFIX = '_u_boot_list_2_evspy_info_2_'
|
||||||
|
RE_EVTYPE = re.compile('%s(.*)' % PREFIX)
|
||||||
|
|
||||||
|
def show_sym(fname, data, endian, evtype, sym):
|
||||||
|
"""Show information about an evspy entry
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fname (str): Filename of ELF file
|
||||||
|
data (bytes): Data for this symbol
|
||||||
|
endian (str): Endianness to use ('little', 'big', 'auto')
|
||||||
|
evtype (str): Event type, e.g. 'MISC_INIT_F'
|
||||||
|
sym (elf.Symbol): Symbol to show
|
||||||
|
"""
|
||||||
|
def _unpack_val(sym_data, offset):
|
||||||
|
start = offset * func_size
|
||||||
|
val_data = sym_data[start:start + func_size]
|
||||||
|
fmt = '%s%s' % ('>' if endian == 'big' else '<',
|
||||||
|
'L' if func_size == 4 else 'Q')
|
||||||
|
val = struct.unpack(fmt, val_data)[0]
|
||||||
|
return val
|
||||||
|
|
||||||
|
# Get the data, which is a struct evspy_info
|
||||||
|
sym_data = data[sym.offset:sym.offset + sym.size]
|
||||||
|
|
||||||
|
# Figure out the word size of the struct
|
||||||
|
func_size = 4 if sym.size < 16 else 8
|
||||||
|
|
||||||
|
# Read the function name for evspy_info->func
|
||||||
|
while True:
|
||||||
|
# Switch to big-endian if we see a failure
|
||||||
|
func_addr = _unpack_val(sym_data, 0)
|
||||||
|
func_name = elf.GetSymbolFromAddress(fname, func_addr)
|
||||||
|
if not func_name and endian == 'auto':
|
||||||
|
endian = 'big'
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
has_id = sym.size in [12, 24]
|
||||||
|
if has_id:
|
||||||
|
# Find the address of evspy_info->id in the ELF
|
||||||
|
id_addr = _unpack_val(sym_data, 2)
|
||||||
|
|
||||||
|
# Get the file offset for that address
|
||||||
|
id_ofs = elf.GetFileOffset(fname, id_addr)
|
||||||
|
|
||||||
|
# Read out a nul-terminated string
|
||||||
|
id_data = data[id_ofs:id_ofs + 80]
|
||||||
|
pos = id_data.find(0)
|
||||||
|
if pos:
|
||||||
|
id_data = id_data[:pos]
|
||||||
|
id_str = id_data.decode('utf-8')
|
||||||
|
else:
|
||||||
|
id_str = None
|
||||||
|
|
||||||
|
# Find the file/line for the function
|
||||||
|
cmd = ['addr2line', '-e', fname, '%x' % func_addr]
|
||||||
|
out = tools.run(*cmd).strip()
|
||||||
|
|
||||||
|
# Drop the full path if it is the current directory
|
||||||
|
if out.startswith(src_path):
|
||||||
|
out = out[len(src_path) + 1:]
|
||||||
|
print('%-20s %-30s %s' % (evtype, id_str or f'f:{func_name}', out))
|
||||||
|
|
||||||
|
def show_event_spy_list(fname, endian):
|
||||||
|
"""Show a the event-spy- list from a U-Boot image
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fname (str): Filename of ELF file
|
||||||
|
endian (str): Endianness to use ('little', 'big', 'auto')
|
||||||
|
"""
|
||||||
|
syms = elf.GetSymbolFileOffset(fname, [PREFIX])
|
||||||
|
data = tools.read_file(fname)
|
||||||
|
print('%-20s %-30s %s' % ('Event type', 'Id', 'Source location'))
|
||||||
|
print('%-20s %-30s %s' % ('-' * 20, '-' * 30, '-' * 30))
|
||||||
|
for name, sym in syms.items():
|
||||||
|
m_evtype = RE_EVTYPE.search(name)
|
||||||
|
evtype = m_evtype .group(1)
|
||||||
|
show_sym(fname, data, endian, evtype, sym)
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
"""Main program
|
||||||
|
|
||||||
|
Args:
|
||||||
|
argv (list of str): List of program arguments, excluding arvg[0]
|
||||||
|
"""
|
||||||
|
epilog = 'Show a list of even spies in a U-Boot EFL file'
|
||||||
|
parser = ArgumentParser(epilog=epilog)
|
||||||
|
parser.add_argument('elf', type=str, help='ELF file to decode')
|
||||||
|
parser.add_argument('-e', '--endian', type=str, default='auto',
|
||||||
|
help='Big-endian image')
|
||||||
|
parser.add_argument('-t', '--test', action='store_true',
|
||||||
|
help='Big-endian image')
|
||||||
|
args = parser.parse_args(argv)
|
||||||
|
show_event_spy_list(args.elf, args.endian)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(sys.argv[1:])
|
20
test/py/tests/test_event_dump.py
Normal file
20
test/py/tests/test_event_dump.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright 2021 Google LLC
|
||||||
|
# Written by Simon Glass <sjg@chromium.org>
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import re
|
||||||
|
import u_boot_utils as util
|
||||||
|
|
||||||
|
# This is only a partial test - coverting 64-bit sandbox. It does not test
|
||||||
|
# big-endian images, nor 32-bit images
|
||||||
|
@pytest.mark.boardspec('sandbox')
|
||||||
|
def test_event_dump(u_boot_console):
|
||||||
|
"""Test that the "help" command can be executed."""
|
||||||
|
cons = u_boot_console
|
||||||
|
sandbox = cons.config.build_dir + '/u-boot'
|
||||||
|
out = util.run_and_log(cons, ['scripts/event_dump.py', sandbox])
|
||||||
|
expect = '''.*Event type Id Source location
|
||||||
|
-------------------- ------------------------------ ------------------------------
|
||||||
|
EVT_MISC_INIT_F sandbox_misc_init_f .*arch/sandbox/cpu/start.c:'''
|
||||||
|
assert re.match(expect, out, re.MULTILINE) is not None
|
Reference in New Issue
Block a user