aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/tools/safe_mode_finder.py
diff options
context:
space:
mode:
Diffstat (limited to 'circuitpython/tools/safe_mode_finder.py')
-rw-r--r--circuitpython/tools/safe_mode_finder.py181
1 files changed, 181 insertions, 0 deletions
diff --git a/circuitpython/tools/safe_mode_finder.py b/circuitpython/tools/safe_mode_finder.py
new file mode 100644
index 0000000..fece853
--- /dev/null
+++ b/circuitpython/tools/safe_mode_finder.py
@@ -0,0 +1,181 @@
+# 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)