logtrace_proc.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #!/usr/bin/env python
  2. #
  3. from __future__ import print_function
  4. import argparse
  5. import struct
  6. import sys
  7. import elftools.elf.elffile as elffile
  8. import espytrace.apptrace as apptrace
  9. class ESPLogTraceParserError(RuntimeError):
  10. def __init__(self, message):
  11. RuntimeError.__init__(self, message)
  12. class ESPLogTraceRecord(object):
  13. def __init__(self, fmt_addr, log_args):
  14. super(ESPLogTraceRecord, self).__init__()
  15. self.fmt_addr = fmt_addr
  16. self.args = log_args
  17. def __repr__(self):
  18. return 'fmt_addr = 0x%x, args = %d/%s' % (self.fmt_addr, len(self.args), self.args)
  19. def logtrace_parse(fname):
  20. ESP32_LOGTRACE_HDR_FMT = '<BL'
  21. ESP32_LOGTRACE_HDR_SZ = struct.calcsize(ESP32_LOGTRACE_HDR_FMT)
  22. recs = []
  23. try:
  24. ftrc = open(fname, 'rb')
  25. except OSError as e:
  26. raise ESPLogTraceParserError('Failed to open trace file (%s)!' % e)
  27. # data_ok = True
  28. while True:
  29. # read args num and format str addr
  30. try:
  31. trc_buf = ftrc.read(ESP32_LOGTRACE_HDR_SZ)
  32. except IOError as e:
  33. raise ESPLogTraceParserError('Failed to read log record header (%s)!' % e)
  34. if len(trc_buf) < ESP32_LOGTRACE_HDR_SZ:
  35. # print "EOF"
  36. if len(trc_buf) > 0:
  37. print('Unprocessed %d bytes of log record header!' % len(trc_buf))
  38. # data_ok = False
  39. break
  40. try:
  41. nargs,fmt_addr = struct.unpack(ESP32_LOGTRACE_HDR_FMT, trc_buf)
  42. except struct.error as e:
  43. raise ESPLogTraceParserError('Failed to unpack log record header (%s)!' % e)
  44. # read args
  45. args_sz = struct.calcsize('<%sL' % nargs)
  46. try:
  47. trc_buf = ftrc.read(args_sz)
  48. except IOError as e:
  49. raise ESPLogTraceParserError('Failed to read log record args (%s)!' % e)
  50. if len(trc_buf) < args_sz:
  51. # print("EOF")
  52. if len(trc_buf) > 0:
  53. print('Unprocessed %d bytes of log record args!' % len(trc_buf))
  54. # data_ok = False
  55. break
  56. try:
  57. log_args = struct.unpack('<%sL' % nargs, trc_buf)
  58. except struct.error as e:
  59. raise ESPLogTraceParserError('Failed to unpack log record args (%s)!' % e)
  60. # print(log_args)
  61. recs.append(ESPLogTraceRecord(fmt_addr, list(log_args)))
  62. ftrc.close()
  63. # sorted(recs, key=lambda rec: rec.fmt_addr)
  64. return recs
  65. def logtrace_formated_print(recs, elfname, no_err):
  66. try:
  67. felf = elffile.ELFFile(open(elfname, 'rb'))
  68. except OSError as e:
  69. raise ESPLogTraceParserError('Failed to open ELF file (%s)!' % e)
  70. for lrec in recs:
  71. fmt_str = apptrace.get_str_from_elf(felf, lrec.fmt_addr)
  72. i = 0
  73. prcnt_idx = 0
  74. while i < len(lrec.args):
  75. prcnt_idx = fmt_str.find('%', prcnt_idx, -2) # TODO: check str ending with %
  76. if prcnt_idx == -1:
  77. break
  78. prcnt_idx += 1 # goto next char
  79. if fmt_str[prcnt_idx] == 's':
  80. # find string
  81. arg_str = apptrace.get_str_from_elf(felf, lrec.args[i])
  82. if arg_str:
  83. lrec.args[i] = arg_str
  84. i += 1
  85. # print("\nFmt = {%s}, args = %d/%s" % lrec)
  86. fmt_str = fmt_str.replace('%p', '%x')
  87. # print("=====> " + fmt_str % lrec.args)
  88. try:
  89. print(fmt_str % tuple(lrec.args), end='')
  90. # print(".", end='')
  91. pass
  92. except Exception as e:
  93. if not no_err:
  94. print('Print error (%s)' % e)
  95. print('\nFmt = {%s}, args = %d/%s' % (fmt_str, len(lrec.args), lrec.args))
  96. felf.stream.close()
  97. def main():
  98. parser = argparse.ArgumentParser(description='ESP32 Log Trace Parsing Tool')
  99. parser.add_argument('trace_file', help='Path to log trace file', type=str)
  100. parser.add_argument('elf_file', help='Path to program ELF file', type=str)
  101. # parser.add_argument('--print-details', '-d', help='Print detailed stats', action='store_true')
  102. parser.add_argument('--no-errors', '-n', help='Do not print errors', action='store_true')
  103. args = parser.parse_args()
  104. # parse trace file
  105. try:
  106. print("Parse trace file '%s'..." % args.trace_file)
  107. lrecs = logtrace_parse(args.trace_file)
  108. print('Parsing completed.')
  109. except ESPLogTraceParserError as e:
  110. print('Failed to parse log trace (%s)!' % e)
  111. sys.exit(2)
  112. # print recs
  113. # get format strings and print info
  114. print('====================================================================')
  115. try:
  116. logtrace_formated_print(lrecs, args.elf_file, args.no_errors)
  117. except ESPLogTraceParserError as e:
  118. print('Failed to print log trace (%s)!' % e)
  119. sys.exit(2)
  120. print('\n====================================================================\n')
  121. print('Log records count: %d' % len(lrecs))
  122. if __name__ == '__main__':
  123. main()