diff options
Diffstat (limited to 'scripts/event_dump.py')
-rwxr-xr-x | scripts/event_dump.py | 115 |
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:]) |