]>
Commit | Line | Data |
---|---|---|
9de3773a SG |
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:]) |