circuitpython/tools/safe_mode_finder.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

182 lines
5.6 KiB
Python
Raw Permalink Normal View History

# This uses pyocd to control a Cortex M core, set a breakpoint and dump the stack.
# It is expected that you modify it for your particular case.
from pyocd.core.helpers import ConnectHelper
from pyocd.core.target import Target
from pyocd.debug.elf.symbols import ELFSymbolProvider
from pyocd.flash.file_programmer import FileProgrammer
import logging
# logging.basicConfig(level=logging.DEBUG)
import sys
import time
board = sys.argv[1]
# Connect to the target.
with ConnectHelper.session_with_chosen_probe(target_override="nrf52840") as session:
target = session.target
# Set ELF file on target.
filename = f"build-{board}/firmware.elf"
target.elf = filename
e = target.elf._elf
# Look up address of reset_into_safe_mode().
provider = ELFSymbolProvider(target.elf)
addr = provider.get_symbol_value("reset_into_safe_mode")
print("reset_into_safe_mode() address: 0x%X" % addr)
for section in target.elf.sections:
print(section)
print()
print("loading", filename)
# FileProgrammer(session).program(filename, file_format="elf")
print("load done")
# Set breakpoint.
target.set_breakpoint(addr)
# target.set_watchpoint(0x20010558, 4, Target.WatchpointType.WRITE)
# Reset and run.
target.reset_and_halt()
for i in range(1):
target.resume()
print("resuming")
start = time.monotonic()
# Wait 10s until breakpoint is hit.
while target.get_state() != Target.State.HALTED and time.monotonic() - start < 10:
pass
# value = target.read_memory(0x20010558)
# print(f"{value:08x}")
# time.sleep(2)
target.halt()
# print("_sidata", hex(provider.get_symbol_value("_sidata")))
# flash_start = 0x000affe8
# ram_start = 0x20010000
# for i in range(0, 0x55c, 4):
# flash_value = target.read_memory(flash_start + i)
# value = target.read_memory(ram_start + i)
# diff = ""
# if flash_value != value:
# diff = "*"
# print(f"{ram_start + i:08x} {flash_value:08x} {value:08x} {diff}")
# Print PC.
pc = target.read_core_register("pc")
print("pc: 0x%X" % pc)
print(target.elf.symbol_decoder.get_symbol_for_address(pc))
sp = target.read_core_register("sp")
print("sp: 0x%X" % sp)
msp = target.read_core_register("msp")
print("msp: 0x%X" % msp)
psp = target.read_core_register("psp")
print("psp: 0x%X" % psp)
print(e.has_dwarf_info())
d = e.get_dwarf_info()
# print(dir(d))
aranges = d.get_aranges()
cu_offset = aranges.cu_offset_at_addr(pc)
if not cu_offset:
cu_offset = 0
main_cu = d.get_CU_at(cu_offset)
lines = d.line_program_for_CU(main_cu).get_entries()
lines_by_address = {}
for line in lines:
if not line.state:
# print(line)
continue
lines_by_address[line.state.address] = line.state
call_frames = None
# if d.has_CFI():
# print("CFI")
# call_frames = d.CFI_entries()
# if d.has_EH_CFI():
# print("EH CFI")
# call_frames = d.EH_CFI_entries()
all_frames = {}
# for frame in call_frames:
# decoded = frame.get_decoded()
# for entry in decoded.table:
# entry_pc = entry["pc"]
# all_frames[entry_pc] = decoded
# for r in d.range_lists().iter_range_lists():
# print(r)
if pc in all_frames:
print(all_frames[pc])
ad = target.elf.address_decoder
function = ad.get_function_for_address(pc)
if function:
print(" ", function)
line = ad.get_line_for_address(pc)
if line:
print(" ", line)
mm = target.get_memory_map()
ram = mm.get_region_for_address(sp)
if not ram:
sp_guess = 0x20013BCC
print("stack pointer bad using 0x{%08x}")
ram = mm.get_region_for_address(sp_guess)
stack_address = sp
offset = 0
while ram and sp + offset <= ram.end:
stack_address = sp + offset
value = target.read_memory(stack_address)
symbol = target.elf.symbol_decoder.get_symbol_for_address(value)
print(f"{stack_address:08x} {offset:04x} {value:08x} {symbol}")
function = ad.get_function_for_address(value)
if function:
print(" ", function)
line = ad.get_line_for_address(value)
if line:
print(" ", line)
# value -= 0x27000
# if value in all_frames:
# print(all_frames[value])
# if value in lines_by_address:
# print(lines_by_address[value])
offset += 4
top_symbol = target.elf.symbol_decoder.get_symbol_for_address(target.read_memory(sp))
if True or (top_symbol and top_symbol.name == "HardFault_Handler"):
lr = target.read_core_register("lr")
print("lr: 0x%08X" % lr)
cfsr = target.read_memory(0xE000ED28)
print("cfsr: 0x%08X" % cfsr)
hfsr = target.read_memory(0xE000ED2C)
print("hfsr: 0x%08X" % hfsr)
if hfsr & 0x4000_0000:
print("hard fault forced")
bfsr = (cfsr >> 8) & 0xFF
if bfsr & 0x80 != 0:
bad_address = target.read_memory(0xE000ED38)
print(f"bus fault with address 0x{bad_address:08x}")
bits = ["IBUSERR", "PRECISERR", "IMPRECISERR", "UNSTKERR", "STKERR", "LSPERR"]
for i, bit in enumerate(bits):
if bfsr & (1 << i):
print(bit)
for i in range(13):
reg = f"r{i}"
value = target.read_core_register(reg)
print(f"{reg} 0x{value:08x}")
# print(hex(target.read_memory(provider.get_symbol_value("prescaler"))))
# Remove breakpoint.
target.remove_breakpoint(addr)