u-boot/scripts/event_dump.py
Simon Glass b5001cb4bd event: Allow multiple spy declarations for each event
At present only one spy is allowed per event. Update the naming to allow
more than one, since some need this flexibility, e.g. the EVT_FT_FIXUP
event.

Signed-off-by: Simon Glass <sjg@chromium.org>
2022-09-29 16:07:57 -04:00

118 lines
3.8 KiB
Python
Executable File

#!/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
# A typical symbol looks like this:
# _u_boot_list_2_evspy_info_2_EVT_MISC_INIT_F_3_sandbox_misc_init_f
PREFIX = '_u_boot_list_2_evspy_info_2_'
RE_EVTYPE = re.compile('%s(.*)_3_.*' % 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:])