aboutsummaryrefslogtreecommitdiff
path: root/scripts/event_dump.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/event_dump.py')
-rwxr-xr-xscripts/event_dump.py115
1 files changed, 115 insertions, 0 deletions
diff --git a/scripts/event_dump.py b/scripts/event_dump.py
new file mode 100755
index 0000000..751f41b
--- /dev/null
+++ b/scripts/event_dump.py
@@ -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:])