| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  | #!/usr/bin/env python | 
					
						
							| 
									
										
										
										
											2023-03-09 20:18:32 +03:00
										 |  |  | # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD | 
					
						
							| 
									
										
										
										
											2022-05-23 15:30:13 +02:00
										 |  |  | # SPDX-License-Identifier: Apache-2.0 | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  | from __future__ import print_function | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  | import argparse | 
					
						
							|  |  |  | import struct | 
					
						
							|  |  |  | import sys | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-12 20:38:23 +03:00
										 |  |  | import elftools.elf.elffile as elffile | 
					
						
							|  |  |  | import espytrace.apptrace as apptrace | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03: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 10:49:01 +08:00
										 |  |  |         return 'fmt_addr = 0x%x, args = %d/%s' % (self.fmt_addr, len(self.args), self.args) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03: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 10:49:01 +08:00
										 |  |  |         raise ESPLogTraceParserError('Failed to open trace file (%s)!' % e) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03: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 10:49:01 +08:00
										 |  |  |             raise ESPLogTraceParserError('Failed to read log record header (%s)!' % e) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |         if len(trc_buf) < ESP32_LOGTRACE_HDR_SZ: | 
					
						
							|  |  |  |             # print "EOF" | 
					
						
							|  |  |  |             if len(trc_buf) > 0: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |                 print('Unprocessed %d bytes of log record header!' % len(trc_buf)) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03: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 10:49:01 +08:00
										 |  |  |             raise ESPLogTraceParserError('Failed to unpack log record header (%s)!' % e) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |         # read args | 
					
						
							|  |  |  |         args_sz = struct.calcsize('<%sL' % nargs) | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             trc_buf = ftrc.read(args_sz) | 
					
						
							|  |  |  |         except IOError as e: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |             raise ESPLogTraceParserError('Failed to read log record args (%s)!' % e) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |         if len(trc_buf) < args_sz: | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  |             # print("EOF") | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |             if len(trc_buf) > 0: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |                 print('Unprocessed %d bytes of log record args!' % len(trc_buf)) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |                 # data_ok = False | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             log_args = struct.unpack('<%sL' % nargs, trc_buf) | 
					
						
							|  |  |  |         except struct.error as e: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |             raise ESPLogTraceParserError('Failed to unpack log record args (%s)!' % e) | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  |         # print(log_args) | 
					
						
							|  |  |  |         recs.append(ESPLogTraceRecord(fmt_addr, list(log_args))) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03: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 20:38:23 +03:00
										 |  |  |         felf = elffile.ELFFile(open(elfname, 'rb')) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |     except OSError as e: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         raise ESPLogTraceParserError('Failed to open ELF file (%s)!' % e) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for lrec in recs: | 
					
						
							| 
									
										
										
										
											2018-12-12 20:38:23 +03:00
										 |  |  |         fmt_str = apptrace.get_str_from_elf(felf, lrec.fmt_addr) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |         i = 0 | 
					
						
							|  |  |  |         prcnt_idx = 0 | 
					
						
							|  |  |  |         while i < len(lrec.args): | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  |             prcnt_idx = fmt_str.find('%', prcnt_idx, -2)  # TODO: check str ending with % | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |             if prcnt_idx == -1: | 
					
						
							|  |  |  |                 break | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  |             prcnt_idx += 1  # goto next char | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |             if fmt_str[prcnt_idx] == 's': | 
					
						
							|  |  |  |                 # find string | 
					
						
							| 
									
										
										
										
											2018-12-12 20:38:23 +03:00
										 |  |  |                 arg_str = apptrace.get_str_from_elf(felf, lrec.args[i]) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |                 if arg_str: | 
					
						
							|  |  |  |                     lrec.args[i] = arg_str | 
					
						
							|  |  |  |             i += 1 | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  |         # print("\nFmt = {%s}, args = %d/%s" % lrec) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |         fmt_str = fmt_str.replace('%p', '%x') | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  |         # print("=====> " + fmt_str % lrec.args) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  |             print(fmt_str % tuple(lrec.args), end='') | 
					
						
							|  |  |  |             # print(".", end='') | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |             pass | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             if not no_err: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |                 print('Print error (%s)' % e) | 
					
						
							|  |  |  |                 print('\nFmt = {%s}, args = %d/%s' % (fmt_str, len(lrec.args), lrec.args)) | 
					
						
							| 
									
										
										
										
											2018-12-12 20:38:23 +03:00
										 |  |  |     felf.stream.close() | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03: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 13:46:48 +01:00
										 |  |  |         print("Parse trace file '%s'..." % args.trace_file) | 
					
						
							|  |  |  |         lrecs = logtrace_parse(args.trace_file) | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         print('Parsing completed.') | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |     except ESPLogTraceParserError as e: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         print('Failed to parse log trace (%s)!' % e) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |         sys.exit(2) | 
					
						
							|  |  |  |     # print recs | 
					
						
							|  |  |  |     # get format strings and print info | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     print('====================================================================') | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  |         logtrace_formated_print(lrecs, args.elf_file, args.no_errors) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |     except ESPLogTraceParserError as e: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         print('Failed to print log trace (%s)!' % e) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  |         sys.exit(2) | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     print('\n====================================================================\n') | 
					
						
							| 
									
										
										
										
											2018-12-04 13:46:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     print('Log records count: %d' % len(lrecs)) | 
					
						
							| 
									
										
										
										
											2017-01-25 19:35:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     main() |