1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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 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:])
|