Merge tag 'xilinx-for-v2022.07-rc1' of https://source.denx.de/u-boot/custodians/u...
[platform/kernel/u-boot.git] / scripts / event_dump.py
1 #!/usr/bin/env python3
2 # SPDX-License-Identifier: GPL-2.0+
3
4 """Decode the evspy_info linker list in a U-Boot ELF image"""
5
6 from argparse import ArgumentParser
7 import os
8 import re
9 import struct
10 import sys
11
12 our_path = os.path.dirname(os.path.realpath(__file__))
13 src_path = os.path.dirname(our_path)
14
15 sys.path.insert(1, os.path.join(our_path, '../tools'))
16
17 from binman import elf
18 from patman import tools
19
20 PREFIX = '_u_boot_list_2_evspy_info_2_'
21 RE_EVTYPE = re.compile('%s(.*)' % PREFIX)
22
23 def show_sym(fname, data, endian, evtype, sym):
24     """Show information about an evspy entry
25
26     Args:
27         fname (str): Filename of ELF file
28         data (bytes): Data for this symbol
29         endian (str): Endianness to use ('little', 'big', 'auto')
30         evtype (str): Event type, e.g. 'MISC_INIT_F'
31         sym (elf.Symbol): Symbol to show
32     """
33     def _unpack_val(sym_data, offset):
34         start = offset * func_size
35         val_data = sym_data[start:start + func_size]
36         fmt = '%s%s' % ('>' if endian == 'big' else '<',
37                         'L' if func_size == 4 else 'Q')
38         val = struct.unpack(fmt, val_data)[0]
39         return val
40
41     # Get the data, which is a struct evspy_info
42     sym_data = data[sym.offset:sym.offset + sym.size]
43
44     # Figure out the word size of the struct
45     func_size = 4 if sym.size < 16 else 8
46
47     # Read the function name for evspy_info->func
48     while True:
49         # Switch to big-endian if we see a failure
50         func_addr = _unpack_val(sym_data, 0)
51         func_name = elf.GetSymbolFromAddress(fname, func_addr)
52         if not func_name and endian == 'auto':
53             endian = 'big'
54         else:
55             break
56     has_id = sym.size in [12, 24]
57     if has_id:
58         # Find the address of evspy_info->id in the ELF
59         id_addr = _unpack_val(sym_data, 2)
60
61         # Get the file offset for that address
62         id_ofs = elf.GetFileOffset(fname, id_addr)
63
64         # Read out a nul-terminated string
65         id_data = data[id_ofs:id_ofs + 80]
66         pos = id_data.find(0)
67         if pos:
68             id_data = id_data[:pos]
69         id_str = id_data.decode('utf-8')
70     else:
71         id_str = None
72
73     # Find the file/line for the function
74     cmd = ['addr2line', '-e', fname, '%x' % func_addr]
75     out = tools.run(*cmd).strip()
76
77     # Drop the full path if it is the current directory
78     if out.startswith(src_path):
79         out = out[len(src_path) + 1:]
80     print('%-20s  %-30s  %s' % (evtype, id_str or f'f:{func_name}', out))
81
82 def show_event_spy_list(fname, endian):
83     """Show a the event-spy- list from a U-Boot image
84
85     Args:
86         fname (str): Filename of ELF file
87         endian (str): Endianness to use ('little', 'big', 'auto')
88     """
89     syms = elf.GetSymbolFileOffset(fname, [PREFIX])
90     data = tools.read_file(fname)
91     print('%-20s  %-30s  %s' % ('Event type', 'Id', 'Source location'))
92     print('%-20s  %-30s  %s' % ('-' * 20, '-' * 30, '-' * 30))
93     for name, sym in syms.items():
94         m_evtype = RE_EVTYPE.search(name)
95         evtype = m_evtype .group(1)
96         show_sym(fname, data, endian, evtype, sym)
97
98 def main(argv):
99     """Main program
100
101     Args:
102         argv (list of str): List of program arguments, excluding arvg[0]
103     """
104     epilog = 'Show a list of even spies in a U-Boot EFL file'
105     parser = ArgumentParser(epilog=epilog)
106     parser.add_argument('elf', type=str, help='ELF file to decode')
107     parser.add_argument('-e', '--endian', type=str, default='auto',
108                         help='Big-endian image')
109     parser.add_argument('-t', '--test', action='store_true',
110                         help='Big-endian image')
111     args = parser.parse_args(argv)
112     show_event_spy_list(args.elf, args.endian)
113
114 if __name__ == "__main__":
115     main(sys.argv[1:])