]> granicus.if.org Git - esp-idf/blob - tools/esp_app_trace/logtrace_proc.py
Merge branch 'bugfix/rom_export_functions' into 'master'
[esp-idf] / tools / esp_app_trace / logtrace_proc.py
1 #!/usr/bin/env python
2 #
3
4 import argparse
5 import struct
6 import sys
7 import pylibelf as elf
8 import pylibelf.util as elfutil
9 import pylibelf.iterators as elfiter
10 import pylibelf.constants as elfconst
11 from ctypes import *
12
13 class ESPLogTraceParserError(RuntimeError):
14     def __init__(self, message):
15         RuntimeError.__init__(self, message)
16
17
18 class ESPLogTraceRecord(object):
19     def __init__(self, fmt_addr, log_args):
20         super(ESPLogTraceRecord, self).__init__()
21         self.fmt_addr = fmt_addr
22         self.args = log_args
23
24     def __repr__(self):
25         return "fmt_addr = 0x%x, args = %d/%s" % (self.fmt_addr, len(self.args), self.args)
26
27
28 def logtrace_parse(fname):
29     ESP32_LOGTRACE_HDR_FMT = '<BL'
30     ESP32_LOGTRACE_HDR_SZ = struct.calcsize(ESP32_LOGTRACE_HDR_FMT)
31
32     recs = []
33     try:
34         ftrc = open(fname, 'rb')
35     except OSError as e:
36         raise ESPLogTraceParserError("Failed to open trace file (%s)!" % e)
37     # data_ok = True
38     while True:
39         # read args num and format str addr
40         try:
41             trc_buf = ftrc.read(ESP32_LOGTRACE_HDR_SZ)
42         except IOError as e:
43             raise ESPLogTraceParserError("Failed to read log record header (%s)!" % e)
44         if len(trc_buf) < ESP32_LOGTRACE_HDR_SZ:
45             # print "EOF"
46             if len(trc_buf) > 0:
47                 print "Unprocessed %d bytes of log record header!" % len(trc_buf)
48                 # data_ok = False
49             break
50         try:
51             nargs,fmt_addr = struct.unpack(ESP32_LOGTRACE_HDR_FMT, trc_buf)
52         except struct.error as e:
53             raise ESPLogTraceParserError("Failed to unpack log record header (%s)!" % e)
54         # read args
55         args_sz = struct.calcsize('<%sL' % nargs)
56         try:
57             trc_buf = ftrc.read(args_sz)
58         except IOError as e:
59             raise ESPLogTraceParserError("Failed to read log record args (%s)!" % e)
60         if len(trc_buf) < args_sz:
61             # print "EOF"
62             if len(trc_buf) > 0:
63                 print "Unprocessed %d bytes of log record args!" % len(trc_buf)
64                 # data_ok = False
65             break
66         try:
67             log_args = struct.unpack('<%sL' % nargs, trc_buf)
68         except struct.error as e:
69             raise ESPLogTraceParserError("Failed to unpack log record args (%s)!" % e)
70         # print log_args
71         recs.append(ESPLogTraceRecord(fmt_addr, list(log_args)))    
72
73     ftrc.close()
74     # sorted(recs, key=lambda rec: rec.fmt_addr)
75     return recs
76
77
78 def logtrace_get_str_from_elf(felf, str_addr):
79     tgt_str = ""
80     for sect in elfiter.sections(felf):
81         hdr = elfutil.section_hdr(felf, sect)
82         if hdr.sh_addr == 0 or hdr.sh_type != elfconst.SHT_PROGBITS:
83             continue
84         if str_addr < hdr.sh_addr or str_addr >= hdr.sh_addr + hdr.sh_size:
85             continue
86         # print "Found SECT: %x..%x @ %x" % (hdr.sh_addr, hdr.sh_addr + hdr.sh_size, str_addr - hdr.sh_addr)
87         sec_data = elfiter.getOnlyData(sect).contents
88         buf = cast(sec_data.d_buf, POINTER(c_char))
89         for i in range(str_addr - hdr.sh_addr, hdr.sh_size):
90             if buf[i] == "\0":
91                 break
92             tgt_str += buf[i]
93         if len(tgt_str) > 0:
94             return tgt_str
95     return None
96
97 def logtrace_formated_print(recs, elfname, no_err):
98     try:
99         felf = elfutil.open_elf(elfname)
100     except OSError as e:
101         raise ESPLogTraceParserError("Failed to open ELF file (%s)!" % e)
102
103     for lrec in recs:
104         fmt_str = logtrace_get_str_from_elf(felf, lrec.fmt_addr)
105         i = 0
106         prcnt_idx = 0
107         while i < len(lrec.args):
108             prcnt_idx = fmt_str.find('%', prcnt_idx, -2) # TODO: check str ending with %
109             if prcnt_idx == -1:
110                 break
111             prcnt_idx += 1 #  goto next char
112             if fmt_str[prcnt_idx] == 's':
113                 # find string
114                 arg_str = logtrace_get_str_from_elf(felf, lrec.args[i])
115                 if arg_str:
116                     lrec.args[i] = arg_str
117             i += 1
118         # print "\nFmt = {%s}, args = %d/%s" % lrec
119         fmt_str = fmt_str.replace('%p', '%x')
120         # print "=====> " + fmt_str % lrec.args
121         try:
122             print fmt_str % tuple(lrec.args),
123             # print ".",
124             pass
125         except Exception as e:
126             if not no_err:
127                 print "Print error (%s)" % e
128                 print "\nFmt = {%s}, args = %d/%s" % (fmt_str, len(lrec.args), lrec.args)
129
130     elf.elf_end(felf)
131
132 def main():
133
134     parser = argparse.ArgumentParser(description='ESP32 Log Trace Parsing Tool')
135
136     parser.add_argument('trace_file', help='Path to log trace file', type=str)
137     parser.add_argument('elf_file', help='Path to program ELF file', type=str)
138     # parser.add_argument('--print-details', '-d', help='Print detailed stats', action='store_true')
139     parser.add_argument('--no-errors', '-n', help='Do not print errors', action='store_true')
140     args = parser.parse_args()
141
142     # parse trace file
143     try:
144         print "Parse trace file '%s'..." % args.trace_file
145         lrecs = logtrace_parse(args.trace_file);
146         print "Parsing completed."
147     except ESPLogTraceParserError as e:
148         print "Failed to parse log trace (%s)!" % e
149         sys.exit(2)
150     # print recs
151     # get format strings and print info
152     print "===================================================================="
153     try:
154         logtrace_formated_print(lrecs, args.elf_file, args.no_errors);
155     except ESPLogTraceParserError as e:
156         print "Failed to print log trace (%s)!" % e
157         sys.exit(2)
158     print "\n====================================================================\n"
159
160     print "Log records count: %d" % len(lrecs)
161
162 if __name__ == '__main__':
163     main()