CrashCatcher
https://github.com/adamgreen/CrashCatcher
HardFaultに入ったときに素早く原因を突き止める
Windowsで扱う際の注意点
バックスラッシュを使うとだめになるのでパスはスラッシュで指定する
やったこと
なんとか動かせたのでやったことメモしておく
ファイルを追加する
サブモジュールにCrashCatcherをクローンする
ソースファイルにCrashCatcher.c
とCrashCatcher_armv7m.S
を追加する。拡張子.s
と.S
が別物扱いされたので.S
用のコンパイル設定を追加しておく。ヘッダファイルにフォルダを追加する
# C sources C_SOURCES = \ [...] \ # いろんなCソースファイル CrashCatcher/Core/src/CrashCatcher.c ASM_UPPER_SOURCES = \ CrashCatcher/Core/src/CrashCatcher_armv7m.S # C includes C_INCLUDES = \ [...] \ # いろんなインクルードディレクトリ -ICrashCatcher/include \ -ICrashCatcher/Core/src # .Sファイルのオブジェクトファイルを作るためのコマンドを追加しておく OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_UPPER_SOURCES:.S=.o))) vpath %.S $(sort $(dir $(ASM_UPPER_SOURCES)))
https://github.com/fouge/nrf_utils/blob/master/debug/log/crash_hexdump.c
を参考にクラッシュ時にダンプする出力関数の定義を行う。
以下の4つの関数はCrashCatcher.c
から呼び出されるので関数を定義する
/* 送信するためのペリフェラルの初期化などはここで実行する ダンプの送信開始をシリアルクライアントに知らせるため、###CRASH### を送信する */ void CrashCatcher_DumpStart(const CrashCatcherInfo* pInfo) /* ダンプするRAMの領域を定義する。RAMの出力をしない場合はNULLポインタを返すようにしておく。 */ const CrashCatcherMemoryRegion* CrashCatcher_GetMemoryRegions(void) /* 実際のダンプデータを1行ずつ出力する */ void CrashCatcher_DumpMemory(const void* pvMemory, CrashCatcherElementSizes elementSize, size_t elementCount) /* ダンプの送信終了をシリアルクライアントに知らせるため、###END### を送信する */ CrashCatcherReturnCodes CrashCatcher_DumpEnd(void)
自分のリポジトリにコピペして、1byteずつ送る関数の定義とかしておく。
CrashCatcher_GetMemoryRegions()
関数には注意が必要で、RAMの出力を行わないときはNULLポインタを返すようにコードを変更しておく。
CrashCatcherの中でHardFault_Handler()
が定義されているので、関数の重複でビルドエラーになる事があるから注意
実際にスタック分析してみる
Pythonでpyserial
を追加しておく
https://github.com/adamgreen/CrashDebugをクローンして実行ファイルを入手する
記事をもとにPythonのスクリプトを作る
今回はこんな感じのディレクトリ構成で進める
WorkSpace
├─CrashDebug
│ ├─bins
│ │ ├─lin64
│ │ ├─osx64
│ │ └─win32
│ ︙
└─CrashTest # <- ここで下のコマンドを実行する想定
├─build
│ ├─CrashTest.elf
︙ ︙
└─dump.py
COM6
と通信するものとする
path/to/WorkSpace$ python dump.py COM6 build/CrashTest.elf
こんな感じの出力が出た
Crash detected, retrieving crash info... arm-none-eabi-gdb -nx --batch --quiet build/CrashTest.elf -ex "set target-charset ASCII" -ex "target remote | ../CrashDebug/bins/win32/CrashDebug --elf build/CrashTest.elf --dump last_crash_dump.txt" -ex "set print pretty on" -ex "bt full" -ex "quit" Crash info retrieved. F:\gcc-arm-none-eabi-10.3-2021.10\bin\arm-none-eabi-gdb.exe: warning: Couldn't determine a path for the index cache directory. GotoCrash () at Core/Src/main.c:70 70 __builtin_trap(); #0 GotoCrash () at Core/Src/main.c:70 No locals. #1 0x080006d4 in main () at Core/Src/main.c:126 No locals. Backtrace stopped: Cannot access memory at address 0x2001fffc A debugging session is active. Inferior 1 [Remote target] will be killed. Quit anyway? (y or n) [answered Y; input not from terminal] ---------
これでHardFaultが発生したとき原因究明のスピードアップが期待できる