Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commiteda64f6

Browse files
authored
Stack decoder script (#8661)
* stack decoder* +x* cut here* last alloc explain, line breaks* capture* print ctx line* ...and dont ignore sp* non-hyphenated arg for elf, toolchain path to bin/either for when tools are already in PATHor, using `pio pkg exec --package toolchain-xtensa python decoder.py ...`(where package is a full version spec for pio registry)
1 parent9dce076 commiteda64f6

File tree

1 file changed

+212
-0
lines changed

1 file changed

+212
-0
lines changed

‎tools/decoder.py‎

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
#!/usr/bin/env python3
2+
3+
# Baseline code from https://github.com/me-no-dev/EspExceptionDecoder by Hristo Gochkov (@me-no-dev)
4+
# - https://github.com/me-no-dev/EspExceptionDecoder/blob/master/src/EspExceptionDecoder.java
5+
# Stack line detection from https://github.com/platformio/platform-espressif8266/ monitor exception filter by Vojtěch Boček (@Tasssadar)
6+
# - https://github.com/platformio/platform-espressif8266/commits?author=Tasssadar
7+
8+
importos
9+
importargparse
10+
importsys
11+
importre
12+
importsubprocess
13+
14+
# https://github.com/me-no-dev/EspExceptionDecoder/blob/349d17e4c9896306e2c00b4932be3ba510cad208/src/EspExceptionDecoder.java#L59-L90
15+
EXCEPTION_CODES= (
16+
"Illegal instruction",
17+
"SYSCALL instruction",
18+
"InstructionFetchError: Processor internal physical address or data error during "
19+
"instruction fetch",
20+
"LoadStoreError: Processor internal physical address or data error during load or store",
21+
"Level1Interrupt: Level-1 interrupt as indicated by set level-1 bits in "
22+
"the INTERRUPT register",
23+
"Alloca: MOVSP instruction, if caller's registers are not in the register file",
24+
"IntegerDivideByZero: QUOS, QUOU, REMS, or REMU divisor operand is zero",
25+
"reserved",
26+
"Privileged: Attempt to execute a privileged operation when CRING ? 0",
27+
"LoadStoreAlignmentCause: Load or store to an unaligned address",
28+
"reserved",
29+
"reserved",
30+
"InstrPIFDataError: PIF data error during instruction fetch",
31+
"LoadStorePIFDataError: Synchronous PIF data error during LoadStore access",
32+
"InstrPIFAddrError: PIF address error during instruction fetch",
33+
"LoadStorePIFAddrError: Synchronous PIF address error during LoadStore access",
34+
"InstTLBMiss: Error during Instruction TLB refill",
35+
"InstTLBMultiHit: Multiple instruction TLB entries matched",
36+
"InstFetchPrivilege: An instruction fetch referenced a virtual address at a ring level "
37+
"less than CRING",
38+
"reserved",
39+
"InstFetchProhibited: An instruction fetch referenced a page mapped with an attribute "
40+
"that does not permit instruction fetch",
41+
"reserved",
42+
"reserved",
43+
"reserved",
44+
"LoadStoreTLBMiss: Error during TLB refill for a load or store",
45+
"LoadStoreTLBMultiHit: Multiple TLB entries matched for a load or store",
46+
"LoadStorePrivilege: A load or store referenced a virtual address at a ring level "
47+
"less than CRING",
48+
"reserved",
49+
"LoadProhibited: A load referenced a page mapped with an attribute that does not "
50+
"permit loads",
51+
"StoreProhibited: A store referenced a page mapped with an attribute that does not "
52+
"permit stores",
53+
)
54+
55+
# similar to java version, which used `list` and re-formatted it
56+
# instead, simply use an already short-format `info line`
57+
# TODO `info symbol`? revert to `list`?
58+
defaddresses_gdb(gdb,elf,addresses):
59+
cmd= [gdb,"--batch"]
60+
foraddressinaddresses:
61+
ifnotaddress.startswith("0x"):
62+
address=f"0x{address}"
63+
cmd.extend(["--ex",f"info line *{address}"])
64+
cmd.append(elf)
65+
66+
withsubprocess.Popen(cmd,stdout=subprocess.PIPE,universal_newlines=True)asproc:
67+
forlineinproc.stdout.readlines():
68+
if"No line number"inline:
69+
continue
70+
yieldline.strip()
71+
72+
73+
# original approach using addr2line, which is pretty enough already
74+
defaddresses_addr2line(addr2line,elf,addresses):
75+
cmd= [
76+
addr2line,
77+
"--addresses",
78+
"--inlines",
79+
"--functions",
80+
"--pretty-print",
81+
"--demangle",
82+
"--exe",
83+
elf,
84+
]
85+
86+
foraddressinaddresses:
87+
ifnotaddress.startswith("0x"):
88+
address=f"0x{address}"
89+
cmd.append(address)
90+
91+
withsubprocess.Popen(cmd,stdout=subprocess.PIPE,universal_newlines=True)asproc:
92+
forlineinproc.stdout.readlines():
93+
if"??:0"inline:
94+
continue
95+
yieldline.strip()
96+
97+
98+
defdecode_lines(format_addresses,elf,lines):
99+
STACK_RE=re.compile(r"^[0-9a-f]{8}:\s+([0-9a-f]{8} ?)+ *$")
100+
101+
LAST_ALLOC_RE=re.compile(
102+
r"last failed alloc call: ([0-9a-fA-F]{8})\(([0-9]+)\).*"
103+
)
104+
LAST_ALLOC="last failed alloc"
105+
106+
CUT_HERE_STRING="CUT HERE FOR EXCEPTION DECODER"
107+
EXCEPTION_STRING="Exception ("
108+
EPC_STRING="epc1="
109+
110+
# either print everything as-is, or cache current string and dump after stack contents end
111+
last_stack=None
112+
stack_addresses= {}
113+
114+
in_stack=False
115+
116+
defprint_all_addresses(addresses):
117+
forctx,addrsinaddresses.items():
118+
print()
119+
print(ctx)
120+
forformattedinformat_addresses(elf,addrs):
121+
print(formatted)
122+
returndict()
123+
124+
defformat_address(address):
125+
return"\n".join(format_addresses(elf, [address]))
126+
127+
forlineinlines:
128+
# ctx could happen multiple times. for the 2nd one, reset list
129+
# ctx: bearssl *or* ctx: cont *or* ctx: sys *or* ctx: whatever
130+
ifin_stackand"ctx:"inline:
131+
stack_addresses=print_all_addresses(stack_addresses)
132+
last_stack=line.strip()
133+
# 3fffffb0: feefeffe feefeffe 3ffe85d8 401004ed
134+
elifin_stackandSTACK_RE.match(line):
135+
stack,addrs=line.split(":")
136+
addrs=addrs.strip()
137+
addrs=addrs.split(" ")
138+
stack_addresses.setdefault(last_stack, [])
139+
foraddrinaddrs:
140+
stack_addresses[last_stack].append(addr)
141+
# epc1=0xfffefefe epc2=0xfefefefe epc3=0xefefefef excvaddr=0xfefefefe depc=0xfefefefe
142+
elifEPC_STRINGinline:
143+
pairs=line.split()
144+
forpairinpairs:
145+
name,addr=pair.split("=")
146+
ifnamein ["epc1","excvaddr"]:
147+
output=format_address(addr)
148+
ifoutput:
149+
print(f"{name}={output}")
150+
# Exception (123):
151+
# Other reasons coming before the guard shown as-is
152+
elifEXCEPTION_STRINGinline:
153+
number=line.strip()[len(EXCEPTION_STRING) :-2]
154+
print(f"Exception ({number}) -{EXCEPTION_CODES[int(number)]}")
155+
# last failed alloc call: <ADDR>(<NUMBER>)[@<maybe file loc>]
156+
elifLAST_ALLOCinline:
157+
values=LAST_ALLOC_RE.match(line)
158+
ifvalues:
159+
addr,size=values.groups()
160+
print()
161+
print(f"Allocation of{size} bytes failed:{format_address(addr)}")
162+
# postmortem guards our actual stack dump values with these
163+
elif">>>stack>>>"inline:
164+
in_stack=True
165+
# ignore
166+
elif"<<<stack<<<"inline:
167+
continue
168+
elifCUT_HERE_STRINGinline:
169+
continue
170+
else:
171+
line=line.strip()
172+
ifline:
173+
print(line)
174+
175+
print_all_addresses(stack_addresses)
176+
177+
178+
TOOLS= {"gdb":addresses_gdb,"addr2line":addresses_addr2line}
179+
180+
181+
defselect_tool(toolchain_path,tool,func):
182+
path=f"xtensa-lx106-elf-{tool}"
183+
iftoolchain_path:
184+
path=os.path.join(toolchain_path,path)
185+
186+
defformatter(func,path):
187+
defwrapper(elf,addresses):
188+
returnfunc(path,elf,addresses)
189+
190+
returnwrapper
191+
192+
returnformatter(func,path)
193+
194+
195+
if__name__=="__main__":
196+
parser=argparse.ArgumentParser()
197+
parser.add_argument("--tool",choices=TOOLS,default="addr2line")
198+
parser.add_argument(
199+
"--toolchain-path",help="Sets path to Xtensa tools, when they are not in PATH"
200+
)
201+
202+
parser.add_argument("firmware_elf")
203+
parser.add_argument(
204+
"postmortem",nargs="?",type=argparse.FileType("r"),default=sys.stdin
205+
)
206+
207+
args=parser.parse_args()
208+
decode_lines(
209+
select_tool(args.toolchain_path,args.tool,TOOLS[args.tool]),
210+
args.firmware_elf,
211+
args.postmortem,
212+
)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp