Skip to content

Commit 4a9e74d

Browse files
committed
Merge branch 'release/v2.4.0'
2 parents 1fcddf6 + 3f48535 commit 4a9e74d

File tree

5 files changed

+300
-7
lines changed

5 files changed

+300
-7
lines changed

builder/frameworks/esp8266-nonos-sdk.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@
9191
],
9292

9393
LIBPATH=[
94-
join(FRAMEWORK_DIR, "lib")
94+
join(FRAMEWORK_DIR, "lib"),
95+
join(FRAMEWORK_DIR, "ld")
9596
],
9697

9798
LIBS=[
@@ -103,7 +104,7 @@
103104
BUILDERS=dict(
104105
ElfToBin=Builder(
105106
action=env.VerboseAction(" ".join([
106-
join(platform.get_package_dir("tool-esptool"), "esptool"),
107+
'"%s"' % join(platform.get_package_dir("tool-esptool"), "esptool"),
107108
"-eo", "$SOURCE",
108109
"-bo", "${TARGET}",
109110
"-bm", "$BOARD_FLASH_MODE",

builder/frameworks/esp8266-rtos-sdk.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@
9292
],
9393

9494
LIBPATH=[
95-
join(FRAMEWORK_DIR, "lib")
95+
join(FRAMEWORK_DIR, "lib"),
96+
join(FRAMEWORK_DIR, "ld")
9697
],
9798

9899
LIBS=[
@@ -104,7 +105,7 @@
104105
BUILDERS=dict(
105106
ElfToBin=Builder(
106107
action=env.VerboseAction(" ".join([
107-
join(platform.get_package_dir("tool-esptool"), "esptool"),
108+
'"%s"' % join(platform.get_package_dir("tool-esptool"), "esptool"),
108109
"-eo", "$SOURCE",
109110
"-bo", "${TARGET}",
110111
"-bm", "$BOARD_FLASH_MODE",

builder/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,13 +205,13 @@ def _update_max_upload_size(env):
205205
target_elf = join("$BUILD_DIR", "${PROGNAME}.elf")
206206
if set(["uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
207207
fetch_spiffs_size(env)
208-
target_firm = join("$BUILD_DIR", "spiffs.bin")
208+
target_firm = join("$BUILD_DIR", "%s.bin" % env.get("SPIFFSNAME", "spiffs"))
209209
else:
210210
target_firm = join("$BUILD_DIR", "${PROGNAME}.bin")
211211
else:
212212
if set(["buildfs", "uploadfs", "uploadfsota"]) & set(COMMAND_LINE_TARGETS):
213213
target_firm = env.DataToBin(
214-
join("$BUILD_DIR", "spiffs"), "$PROJECTDATA_DIR")
214+
join("$BUILD_DIR", env.get("SPIFFSNAME", "spiffs")), "$PROJECTDATA_DIR")
215215
AlwaysBuild(target_firm)
216216
AlwaysBuild(env.Alias("buildfs", target_firm))
217217
else:

monitor/filter_exception_decoder.py

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
# Copyright (c) 2014-present PlatformIO <[email protected]>
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import os
16+
import re
17+
import subprocess
18+
import sys
19+
20+
from platformio.commands.device import DeviceMonitorFilter
21+
from platformio.compat import path_to_unicode, WINDOWS, PY2
22+
from platformio.project.exception import PlatformioException
23+
from platformio.project.helpers import load_project_ide_data
24+
25+
26+
# By design, __init__ is called inside miniterm and we can't pass context to it.
27+
# pylint: disable=attribute-defined-outside-init
28+
29+
30+
class Esp8266ExceptionDecoder(
31+
DeviceMonitorFilter
32+
): # pylint: disable=too-many-instance-attributes
33+
NAME = "esp8266_exception_decoder"
34+
35+
# https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map
36+
ADDR_MIN = 0x40000000
37+
ADDR_MAX = 0x40300000
38+
39+
STATE_DEFAULT = 0
40+
STATE_READ_EXCEPTION = 1
41+
STATE_IN_STACK = 2
42+
43+
EXCEPTION_MARKER = "Exception ("
44+
45+
# https://github.com/me-no-dev/EspExceptionDecoder/blob/a78672da204151cc93979a96ed9f89139a73893f/src/EspExceptionDecoder.java#L59
46+
EXCEPTION_CODES = (
47+
"Illegal instruction",
48+
"SYSCALL instruction",
49+
"InstructionFetchError: Processor internal physical address or data error during "
50+
"instruction fetch",
51+
"LoadStoreError: Processor internal physical address or data error during load or store",
52+
"Level1Interrupt: Level-1 interrupt as indicated by set level-1 bits in "
53+
"the INTERRUPT register",
54+
"Alloca: MOVSP instruction, if caller's registers are not in the register file",
55+
"IntegerDivideByZero: QUOS, QUOU, REMS, or REMU divisor operand is zero",
56+
"reserved",
57+
"Privileged: Attempt to execute a privileged operation when CRING ? 0",
58+
"LoadStoreAlignmentCause: Load or store to an unaligned address",
59+
"reserved",
60+
"reserved",
61+
"InstrPIFDataError: PIF data error during instruction fetch",
62+
"LoadStorePIFDataError: Synchronous PIF data error during LoadStore access",
63+
"InstrPIFAddrError: PIF address error during instruction fetch",
64+
"LoadStorePIFAddrError: Synchronous PIF address error during LoadStore access",
65+
"InstTLBMiss: Error during Instruction TLB refill",
66+
"InstTLBMultiHit: Multiple instruction TLB entries matched",
67+
"InstFetchPrivilege: An instruction fetch referenced a virtual address at a ring level "
68+
"less than CRING",
69+
"reserved",
70+
"InstFetchProhibited: An instruction fetch referenced a page mapped with an attribute "
71+
"that does not permit instruction fetch",
72+
"reserved",
73+
"reserved",
74+
"reserved",
75+
"LoadStoreTLBMiss: Error during TLB refill for a load or store",
76+
"LoadStoreTLBMultiHit: Multiple TLB entries matched for a load or store",
77+
"LoadStorePrivilege: A load or store referenced a virtual address at a ring level "
78+
"less than CRING",
79+
"reserved",
80+
"LoadProhibited: A load referenced a page mapped with an attribute that does not "
81+
"permit loads",
82+
"StoreProhibited: A store referenced a page mapped with an attribute that does not "
83+
"permit stores",
84+
)
85+
86+
def __call__(self):
87+
self.buffer = ""
88+
self.previous_line = ""
89+
self.state = self.STATE_DEFAULT
90+
self.no_match_counter = 0
91+
self.stack_lines = []
92+
93+
self.exception_re = re.compile(
94+
r"^([0-9]{1,2})\):\n([a-z0-9]+=0x[0-9a-f]{8} ?)+$"
95+
)
96+
self.stack_re = re.compile(r"^[0-9a-f]{8}:\s+([0-9a-f]{8} ?)+ *$")
97+
98+
self.firmware_path = None
99+
self.addr2line_path = None
100+
self.enabled = self.setup_paths()
101+
102+
if self.config.get("env:" + self.environment, "build_type") != "debug":
103+
print(
104+
"""
105+
Please build project in debug configuration to get more details about an exception.
106+
See https://docs.platformio.org/page/projectconf/build_configurations.html
107+
108+
"""
109+
)
110+
111+
return self
112+
113+
def setup_paths(self):
114+
self.project_dir = path_to_unicode(os.path.abspath(self.project_dir))
115+
try:
116+
data = load_project_ide_data(self.project_dir, self.environment)
117+
self.firmware_path = data["prog_path"]
118+
if not os.path.isfile(self.firmware_path):
119+
sys.stderr.write(
120+
"%s: firmware at %s does not exist, rebuild the project?\n"
121+
% (self.__class__.__name__, self.firmware_path)
122+
)
123+
return False
124+
125+
cc_path = data.get("cc_path", "")
126+
if "-gcc" in cc_path:
127+
path = cc_path.replace("-gcc", "-addr2line")
128+
if os.path.isfile(path):
129+
self.addr2line_path = path
130+
return True
131+
except PlatformioException as e:
132+
sys.stderr.write(
133+
"%s: disabling, exception while looking for addr2line: %s\n"
134+
% (self.__class__.__name__, e)
135+
)
136+
return False
137+
sys.stderr.write(
138+
"%s: disabling, failed to find addr2line.\n" % self.__class__.__name__
139+
)
140+
return False
141+
142+
def rx(self, text):
143+
if not self.enabled:
144+
return text
145+
146+
last = 0
147+
while True:
148+
idx = text.find("\n", last)
149+
if idx == -1:
150+
if len(self.buffer) < 4096:
151+
self.buffer += text[last:]
152+
break
153+
154+
line = text[last:idx]
155+
if self.buffer:
156+
line = self.buffer + line
157+
self.buffer = ""
158+
last = idx + 1
159+
160+
extra = self.process_line(line)
161+
self.previous_line = line
162+
if extra is not None:
163+
text = text[: idx + 1] + extra + text[idx + 1 :]
164+
last += len(extra)
165+
return text
166+
167+
def advance_state(self):
168+
self.state += 1
169+
self.no_match_counter = 0
170+
171+
def is_addr_ok(self, hex_addr):
172+
try:
173+
addr = int(hex_addr, 16)
174+
return addr >= self.ADDR_MIN and addr < self.ADDR_MAX
175+
except ValueError:
176+
return False
177+
178+
def process_line(self, line): # pylint: disable=too-many-return-statements
179+
if self.state == self.STATE_DEFAULT:
180+
if self.previous_line.startswith(self.EXCEPTION_MARKER):
181+
two_lines = (
182+
self.previous_line[len(self.EXCEPTION_MARKER) :] + "\n" + line
183+
)
184+
match = self.exception_re.match(two_lines)
185+
if match is not None:
186+
self.advance_state()
187+
return self.process_exception_match(match)
188+
return None
189+
elif self.state == self.STATE_READ_EXCEPTION:
190+
if line == ">>>stack>>>":
191+
self.advance_state()
192+
return None
193+
elif self.state == self.STATE_IN_STACK:
194+
if line == "<<<stack<<<":
195+
self.state = self.STATE_DEFAULT
196+
return self.take_stack_lines()
197+
198+
match = self.stack_re.match(line)
199+
if match is not None:
200+
self.process_stack_match(line)
201+
return None
202+
203+
self.no_match_counter += 1
204+
if self.no_match_counter > 4:
205+
self.state = self.STATE_DEFAULT
206+
results = [self.take_stack_lines(), self.process_line(line)]
207+
results = [r for r in results if r is not None]
208+
if results:
209+
return "\n".join(results)
210+
return None
211+
212+
def process_exception_match(self, match):
213+
extra = "\n"
214+
try:
215+
code = int(match.group(1))
216+
if code >= 0 and code < len(self.EXCEPTION_CODES):
217+
extra += "%s\n" % self.EXCEPTION_CODES[code]
218+
except ValueError:
219+
pass
220+
221+
header = match.group(0)
222+
registers = header[header.index("\n") + 1 :].split()
223+
pairs = [reg.split("=", 2) for reg in registers]
224+
225+
lines = self.get_lines([p[1] for p in pairs])
226+
227+
for i, p in enumerate(pairs):
228+
if lines[i] is not None:
229+
l = lines[i].replace(
230+
"\n", "\n "
231+
) # newlines happen with inlined methods
232+
extra += " %s=%s in %s\n" % (p[0], p[1], l)
233+
return extra
234+
235+
def process_stack_match(self, line):
236+
if len(self.stack_lines) > 128:
237+
return
238+
239+
addresses = line[line.index(":") + 1 :].split()
240+
lines = self.get_lines(addresses)
241+
for i, l in enumerate(lines):
242+
if l is not None:
243+
self.stack_lines.append("0x%s in %s" % (addresses[i], l))
244+
245+
def take_stack_lines(self):
246+
if self.stack_lines:
247+
res = "\n%s\n\n" % "\n".join(self.stack_lines)
248+
self.stack_lines = []
249+
return res
250+
return None
251+
252+
def get_lines(self, addresses):
253+
result = []
254+
255+
enc = "mbcs" if WINDOWS else "utf-8"
256+
args = [self.addr2line_path, u"-fipC", u"-e", self.firmware_path]
257+
if PY2:
258+
args = [a.encode(enc) for a in args]
259+
260+
for addr in addresses:
261+
if not self.is_addr_ok(addr):
262+
result.append(None)
263+
continue
264+
265+
if PY2:
266+
addr = addr.encode(enc)
267+
268+
to_append = None
269+
try:
270+
output = (
271+
subprocess.check_output(args + [addr])
272+
.decode(enc)
273+
.strip()
274+
)
275+
if output != "?? ??:0":
276+
to_append = self.strip_project_dir(output)
277+
except subprocess.CalledProcessError as e:
278+
sys.stderr.write(
279+
"%s: failed to call %s: %s\n"
280+
% (self.__class__.__name__, self.addr2line_path, e)
281+
)
282+
result.append(to_append)
283+
return result
284+
285+
def strip_project_dir(self, trace):
286+
while True:
287+
idx = trace.find(self.project_dir)
288+
if idx == -1:
289+
break
290+
trace = trace[:idx] + trace[idx + len(self.project_dir) + 1 :]
291+
return trace

platform.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"type": "git",
1313
"url": "https://github.com/platformio/platform-espressif8266.git"
1414
},
15-
"version": "2.3.3",
15+
"version": "2.4.0",
1616
"packageRepositories": [
1717
"https://dl.bintray.com/platformio/dl-packages/manifest.json",
1818
"http://dl.platformio.org/packages/manifest.json",

0 commit comments

Comments
 (0)