3232class Esp32ExceptionDecoder (DeviceMonitorFilterBase ):
3333 NAME = "esp32_exception_decoder"
3434
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"^ *" )
3738
3839 def __call__ (self ):
3940 self .buffer = ""
@@ -56,7 +57,8 @@ def __call__(self):
5657 def setup_paths (self ):
5758 self .project_dir = os .path .abspath (self .project_dir )
5859 try :
59- data = load_build_metadata (self .project_dir , self .environment )
60+ data = load_build_metadata (self .project_dir , self .environment , cache = True )
61+
6062 self .firmware_path = data ["prog_path" ]
6163 if not os .path .isfile (self .firmware_path ):
6264 sys .stderr .write (
@@ -100,38 +102,65 @@ def rx(self, text):
100102 self .buffer = ""
101103 last = idx + 1
102104
103- m = self .BACKTRACE_PATTERN . match (line )
105+ m = self .ADDR_PATTERN . search (line )
104106 if m is None :
105107 continue
106108
107- trace = self .get_backtrace ( m )
108- if len ( trace ) != "" :
109+ trace = self .build_backtrace ( line , m . group ( 1 ) )
110+ if trace :
109111 text = text [: idx + 1 ] + trace + text [idx + 1 :]
110112 last += len (trace )
111113 return text
112114
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 = ""
115134 enc = "mbcs" if IS_WINDOWS else "utf-8"
116135 args = [self .addr2line_path , u"-fipC" , u"-e" , self .firmware_path ]
117136 try :
118- for i , addr in enumerate (self .BACKTRACE_ADDRESS_PATTERN .findall (match .group (1 ))):
137+ i = 0
138+ for addr in addresses :
119139 output = (
120140 subprocess .check_output (args + [addr ])
121141 .decode (enc )
122142 .strip ()
123143 )
144+
145+ # newlines happen with inlined methods
124146 output = output .replace (
125147 "\n " , "\n "
126- ) # newlines happen with inlined methods
148+ )
149+
150+ # throw out addresses not from ELF
151+ if output == "?? ??:0" :
152+ continue
153+
127154 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
129157 except subprocess .CalledProcessError as e :
130158 sys .stderr .write (
131159 "%s: failed to call %s: %s\n "
132160 % (self .__class__ .__name__ , self .addr2line_path , e )
133161 )
134- return trace
162+
163+ return trace + "\n " if trace else ""
135164
136165 def strip_project_dir (self , trace ):
137166 while True :
0 commit comments