32
32
class Esp32ExceptionDecoder (DeviceMonitorFilterBase ):
33
33
NAME = "esp32_exception_decoder"
34
34
35
- BACKTRACE_PATTERN = re .compile (r"^Backtrace:(((\s?0x[0-9a-fA-F]{8}:0x[0-9a-fA-F]{8}))+)" )
36
- BACKTRACE_ADDRESS_PATTERN = re .compile (r'0x[0-9a-fA-F]{8}:0x[0-9a-fA-F]{8}' )
35
+ ADDR_PATTERN = re .compile (r"((?:0x[0-9a-fA-F]{8}[: ]?)+)\s?$" )
36
+ ADDR_SPLIT = re .compile (r"[ :]" )
37
+ PREFIX_RE = re .compile (r"^ *" )
37
38
38
39
def __call__ (self ):
39
40
self .buffer = ""
@@ -56,7 +57,8 @@ def __call__(self):
56
57
def setup_paths (self ):
57
58
self .project_dir = os .path .abspath (self .project_dir )
58
59
try :
59
- data = load_build_metadata (self .project_dir , self .environment )
60
+ data = load_build_metadata (self .project_dir , self .environment , cache = True )
61
+
60
62
self .firmware_path = data ["prog_path" ]
61
63
if not os .path .isfile (self .firmware_path ):
62
64
sys .stderr .write (
@@ -100,38 +102,65 @@ def rx(self, text):
100
102
self .buffer = ""
101
103
last = idx + 1
102
104
103
- m = self .BACKTRACE_PATTERN . match (line )
105
+ m = self .ADDR_PATTERN . search (line )
104
106
if m is None :
105
107
continue
106
108
107
- trace = self .get_backtrace ( m )
108
- if len ( trace ) != "" :
109
+ trace = self .build_backtrace ( line , m . group ( 1 ) )
110
+ if trace :
109
111
text = text [: idx + 1 ] + trace + text [idx + 1 :]
110
112
last += len (trace )
111
113
return text
112
114
113
- def get_backtrace (self , match ):
114
- trace = "\n "
115
+ def is_address_ignored (self , address ):
116
+ return address in ("" , "0x00000000" )
117
+
118
+ def filter_addresses (self , adresses_str ):
119
+ addresses = self .ADDR_SPLIT .split (adresses_str )
120
+ size = len (addresses )
121
+ while size > 1 and self .is_address_ignored (addresses [size - 1 ]):
122
+ size -= 1
123
+ return addresses [:size ]
124
+
125
+ def build_backtrace (self , line , address_match ):
126
+ addresses = self .filter_addresses (address_match )
127
+ if not addresses :
128
+ return ""
129
+
130
+ prefix_match = self .PREFIX_RE .match (line )
131
+ prefix = prefix_match .group (0 ) if prefix_match is not None else ""
132
+
133
+ trace = ""
115
134
enc = "mbcs" if IS_WINDOWS else "utf-8"
116
135
args = [self .addr2line_path , u"-fipC" , u"-e" , self .firmware_path ]
117
136
try :
118
- for i , addr in enumerate (self .BACKTRACE_ADDRESS_PATTERN .findall (match .group (1 ))):
137
+ i = 0
138
+ for addr in addresses :
119
139
output = (
120
140
subprocess .check_output (args + [addr ])
121
141
.decode (enc )
122
142
.strip ()
123
143
)
144
+
145
+ # newlines happen with inlined methods
124
146
output = output .replace (
125
147
"\n " , "\n "
126
- ) # newlines happen with inlined methods
148
+ )
149
+
150
+ # throw out addresses not from ELF
151
+ if output == "?? ??:0" :
152
+ continue
153
+
127
154
output = self .strip_project_dir (output )
128
- trace += " #%-2d %s in %s\n " % (i , addr , output )
155
+ trace += "%s #%-2d %s in %s\n " % (prefix , i , addr , output )
156
+ i += 1
129
157
except subprocess .CalledProcessError as e :
130
158
sys .stderr .write (
131
159
"%s: failed to call %s: %s\n "
132
160
% (self .__class__ .__name__ , self .addr2line_path , e )
133
161
)
134
- return trace
162
+
163
+ return trace + "\n " if trace else ""
135
164
136
165
def strip_project_dir (self , trace ):
137
166
while True :
0 commit comments