u-boot/scripts/event_dump.py
Simon Glass 4583c00236 patman: Move library functions into a library directory
The patman directory has a number of modules which are used by other tools
in U-Boot. This makes it hard to package the tools using pypi since the
common files must be copied along with the tool that uses them.

To address this, move these files into a new u_boot_pylib library. This
can be packaged separately and listed as a dependency of each tool.

Signed-off-by: Simon Glass <sjg@chromium.org>
2023-03-08 11:40:49 -08:00

116 lines
3.7 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 u_boot_pylib 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')
args = parser.parse_args(argv)
show_event_spy_list(args.elf, args.endian)
if __name__ == "__main__":
main(sys.argv[1:])