event_dump.py 3.7 KB

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