2017-01-25 16:35:28 +00:00
|
|
|
#!/usr/bin/env python
|
2023-03-09 17:18:32 +00:00
|
|
|
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
2022-05-23 13:30:13 +00:00
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
2017-01-25 16:35:28 +00:00
|
|
|
#
|
|
|
|
|
2018-12-04 12:46:48 +00:00
|
|
|
from __future__ import print_function
|
2021-01-26 02:49:01 +00:00
|
|
|
|
2017-01-25 16:35:28 +00:00
|
|
|
import argparse
|
|
|
|
import struct
|
|
|
|
import sys
|
2021-01-26 02:49:01 +00:00
|
|
|
|
2018-12-12 17:38:23 +00:00
|
|
|
import elftools.elf.elffile as elffile
|
|
|
|
import espytrace.apptrace as apptrace
|
2018-12-04 12:46:48 +00:00
|
|
|
|
2017-01-25 16:35:28 +00:00
|
|
|
|
|
|
|
class ESPLogTraceParserError(RuntimeError):
|
|
|
|
def __init__(self, message):
|
|
|
|
RuntimeError.__init__(self, message)
|
|
|
|
|
|
|
|
|
|
|
|
class ESPLogTraceRecord(object):
|
|
|
|
def __init__(self, fmt_addr, log_args):
|
|
|
|
super(ESPLogTraceRecord, self).__init__()
|
|
|
|
self.fmt_addr = fmt_addr
|
|
|
|
self.args = log_args
|
|
|
|
|
|
|
|
def __repr__(self):
|
2021-01-26 02:49:01 +00:00
|
|
|
return 'fmt_addr = 0x%x, args = %d/%s' % (self.fmt_addr, len(self.args), self.args)
|
2017-01-25 16:35:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
def logtrace_parse(fname):
|
|
|
|
ESP32_LOGTRACE_HDR_FMT = '<BL'
|
|
|
|
ESP32_LOGTRACE_HDR_SZ = struct.calcsize(ESP32_LOGTRACE_HDR_FMT)
|
|
|
|
|
|
|
|
recs = []
|
|
|
|
try:
|
|
|
|
ftrc = open(fname, 'rb')
|
|
|
|
except OSError as e:
|
2021-01-26 02:49:01 +00:00
|
|
|
raise ESPLogTraceParserError('Failed to open trace file (%s)!' % e)
|
2017-01-25 16:35:28 +00:00
|
|
|
# data_ok = True
|
|
|
|
while True:
|
|
|
|
# read args num and format str addr
|
|
|
|
try:
|
|
|
|
trc_buf = ftrc.read(ESP32_LOGTRACE_HDR_SZ)
|
|
|
|
except IOError as e:
|
2021-01-26 02:49:01 +00:00
|
|
|
raise ESPLogTraceParserError('Failed to read log record header (%s)!' % e)
|
2017-01-25 16:35:28 +00:00
|
|
|
if len(trc_buf) < ESP32_LOGTRACE_HDR_SZ:
|
|
|
|
# print "EOF"
|
|
|
|
if len(trc_buf) > 0:
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Unprocessed %d bytes of log record header!' % len(trc_buf))
|
2017-01-25 16:35:28 +00:00
|
|
|
# data_ok = False
|
|
|
|
break
|
|
|
|
try:
|
|
|
|
nargs,fmt_addr = struct.unpack(ESP32_LOGTRACE_HDR_FMT, trc_buf)
|
|
|
|
except struct.error as e:
|
2021-01-26 02:49:01 +00:00
|
|
|
raise ESPLogTraceParserError('Failed to unpack log record header (%s)!' % e)
|
2017-01-25 16:35:28 +00:00
|
|
|
# read args
|
|
|
|
args_sz = struct.calcsize('<%sL' % nargs)
|
|
|
|
try:
|
|
|
|
trc_buf = ftrc.read(args_sz)
|
|
|
|
except IOError as e:
|
2021-01-26 02:49:01 +00:00
|
|
|
raise ESPLogTraceParserError('Failed to read log record args (%s)!' % e)
|
2017-01-25 16:35:28 +00:00
|
|
|
if len(trc_buf) < args_sz:
|
2018-12-04 12:46:48 +00:00
|
|
|
# print("EOF")
|
2017-01-25 16:35:28 +00:00
|
|
|
if len(trc_buf) > 0:
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Unprocessed %d bytes of log record args!' % len(trc_buf))
|
2017-01-25 16:35:28 +00:00
|
|
|
# data_ok = False
|
|
|
|
break
|
|
|
|
try:
|
|
|
|
log_args = struct.unpack('<%sL' % nargs, trc_buf)
|
|
|
|
except struct.error as e:
|
2021-01-26 02:49:01 +00:00
|
|
|
raise ESPLogTraceParserError('Failed to unpack log record args (%s)!' % e)
|
2018-12-04 12:46:48 +00:00
|
|
|
# print(log_args)
|
|
|
|
recs.append(ESPLogTraceRecord(fmt_addr, list(log_args)))
|
2017-01-25 16:35:28 +00:00
|
|
|
|
|
|
|
ftrc.close()
|
|
|
|
# sorted(recs, key=lambda rec: rec.fmt_addr)
|
|
|
|
return recs
|
|
|
|
|
|
|
|
|
|
|
|
def logtrace_formated_print(recs, elfname, no_err):
|
|
|
|
try:
|
2018-12-12 17:38:23 +00:00
|
|
|
felf = elffile.ELFFile(open(elfname, 'rb'))
|
2017-01-25 16:35:28 +00:00
|
|
|
except OSError as e:
|
2021-01-26 02:49:01 +00:00
|
|
|
raise ESPLogTraceParserError('Failed to open ELF file (%s)!' % e)
|
2017-01-25 16:35:28 +00:00
|
|
|
|
|
|
|
for lrec in recs:
|
2018-12-12 17:38:23 +00:00
|
|
|
fmt_str = apptrace.get_str_from_elf(felf, lrec.fmt_addr)
|
2017-01-25 16:35:28 +00:00
|
|
|
i = 0
|
|
|
|
prcnt_idx = 0
|
|
|
|
while i < len(lrec.args):
|
2018-12-04 12:46:48 +00:00
|
|
|
prcnt_idx = fmt_str.find('%', prcnt_idx, -2) # TODO: check str ending with %
|
2017-01-25 16:35:28 +00:00
|
|
|
if prcnt_idx == -1:
|
|
|
|
break
|
2018-12-04 12:46:48 +00:00
|
|
|
prcnt_idx += 1 # goto next char
|
2017-01-25 16:35:28 +00:00
|
|
|
if fmt_str[prcnt_idx] == 's':
|
|
|
|
# find string
|
2018-12-12 17:38:23 +00:00
|
|
|
arg_str = apptrace.get_str_from_elf(felf, lrec.args[i])
|
2017-01-25 16:35:28 +00:00
|
|
|
if arg_str:
|
|
|
|
lrec.args[i] = arg_str
|
|
|
|
i += 1
|
2018-12-04 12:46:48 +00:00
|
|
|
# print("\nFmt = {%s}, args = %d/%s" % lrec)
|
2017-01-25 16:35:28 +00:00
|
|
|
fmt_str = fmt_str.replace('%p', '%x')
|
2018-12-04 12:46:48 +00:00
|
|
|
# print("=====> " + fmt_str % lrec.args)
|
2017-01-25 16:35:28 +00:00
|
|
|
try:
|
2018-12-04 12:46:48 +00:00
|
|
|
print(fmt_str % tuple(lrec.args), end='')
|
|
|
|
# print(".", end='')
|
2017-01-25 16:35:28 +00:00
|
|
|
pass
|
|
|
|
except Exception as e:
|
|
|
|
if not no_err:
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Print error (%s)' % e)
|
|
|
|
print('\nFmt = {%s}, args = %d/%s' % (fmt_str, len(lrec.args), lrec.args))
|
2018-12-12 17:38:23 +00:00
|
|
|
felf.stream.close()
|
2017-01-25 16:35:28 +00:00
|
|
|
|
2018-12-04 12:46:48 +00:00
|
|
|
|
2017-01-25 16:35:28 +00:00
|
|
|
def main():
|
|
|
|
|
|
|
|
parser = argparse.ArgumentParser(description='ESP32 Log Trace Parsing Tool')
|
|
|
|
|
|
|
|
parser.add_argument('trace_file', help='Path to log trace file', type=str)
|
|
|
|
parser.add_argument('elf_file', help='Path to program ELF file', type=str)
|
|
|
|
# parser.add_argument('--print-details', '-d', help='Print detailed stats', action='store_true')
|
|
|
|
parser.add_argument('--no-errors', '-n', help='Do not print errors', action='store_true')
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
# parse trace file
|
|
|
|
try:
|
2018-12-04 12:46:48 +00:00
|
|
|
print("Parse trace file '%s'..." % args.trace_file)
|
|
|
|
lrecs = logtrace_parse(args.trace_file)
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Parsing completed.')
|
2017-01-25 16:35:28 +00:00
|
|
|
except ESPLogTraceParserError as e:
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Failed to parse log trace (%s)!' % e)
|
2017-01-25 16:35:28 +00:00
|
|
|
sys.exit(2)
|
|
|
|
# print recs
|
|
|
|
# get format strings and print info
|
2021-01-26 02:49:01 +00:00
|
|
|
print('====================================================================')
|
2017-01-25 16:35:28 +00:00
|
|
|
try:
|
2018-12-04 12:46:48 +00:00
|
|
|
logtrace_formated_print(lrecs, args.elf_file, args.no_errors)
|
2017-01-25 16:35:28 +00:00
|
|
|
except ESPLogTraceParserError as e:
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Failed to print log trace (%s)!' % e)
|
2017-01-25 16:35:28 +00:00
|
|
|
sys.exit(2)
|
2021-01-26 02:49:01 +00:00
|
|
|
print('\n====================================================================\n')
|
2018-12-04 12:46:48 +00:00
|
|
|
|
2021-01-26 02:49:01 +00:00
|
|
|
print('Log records count: %d' % len(lrecs))
|
2017-01-25 16:35:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|