はじめに
ESP32を使ってネコ型おしゃべりロボットを開発中だが、デバイスを初回起動した時に下記エラーが発生するようになった。
Leaving...
Hard resetting via RTS pin...
--- Terminal on /dev/cu.wchusbserial1420 | 115200 8-N-1
--- Available filters and text transformations: colorize, debug, default, direct, esp32_exception_decoder, hexlify, log2file, nocontrol, printable, send_on_enter, time
--- More details at https://bit.ly/pio-monitor-filters
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H
E (1340) esp_core_dump_flash: No core �f~mp partition found!
E (1340) esp_core_dump_flash: No core dump partition found!
Starting
After Starting - Available heap size: 196328 bytes
{"device":{"id":"test_002","type":"prototype"},"mqtt":{"host":"a351w29x0awoaq-ats.iot.ap-northeast-1.amazonaws.com","port":8883,"credential":"/root.ca.pem","client_cert":"/device.cert.pem","private_key":"/device.private.key"},"resource":{"voices":"https://clocky-dev.s3.ap-northeast-1.amazonaws.com/voices"},"runtime":{}}
Connecting to WiFi with SSID and password from build flags...
Connecting to WiFi...
Connecting to WiFi...
Connecting to WiFi...
Connecting to WiFi...
Connecting to WiFi...
Not connected to WiFi
After Wi-Fi Connection - Available heap size: 146928 bytes
Initialise eye objects
Create display #0
Create display #1
Initialise Audio
After Setup Completed - Available heap size: 146436 bytes
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x400dd3c0 PS : 0x00060730 A0 : 0x800dd467 A1 : 0x3ffd0080
A2 : 0x3ffd0198 A3 : 0x00000090 A4 : 0x3ffdb674 A5 : 0x00000000
A6 : 0x00000000 A7 : 0x00000000 A8 : 0x8011cb3f A9 : 0x3ffd0190
A10 : 0x00000000 A11 : 0x400ef1dc A12 : 0x3ffdb774 A13 : 0x3ffec6cc
A14 : 0x00000000 A15 : 0x00000000 SAR : 0x00000015 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000100 LBEG : 0x400911fd LEND : 0x4009121f LCOUNT : 0xffffffff
Backtrace: 0x400dd3bd:0x3ffd0080 0x400dd464:0x3ffd00a0 0x400d9282:0x3ffd00c0 0x400d977e:0x3ffd0230 0x400da10b:0x3ffd02f0 0x40265035:0x3ffd0350 0x400d36a2:0x3ffd0370 0x400d3719:0x3ffd0390 0x400d9e6a:0x3ffd03b0 0x4013be45:0x3ffd0400
ELF file SHA256: dbc7e31d9cbb3c3c
E (6283) esp_core_dump_flash: Core dump flash config is corrupted! CRC=0x7bd5c66f instead of 0x0
Rebooting...
ets Jul 29 2019 12:21:46
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:1184
load:0x40078000,len:13192
load:0x40080400,len:3028
entry 0x400805e4
E (1340) esp_core_dump_flash: No core �f~mp partition found!
E (1340) esp_core_dump_flash: No core dump partition found!
Starting
After Starting - Available heap size: 196328 bytes
CPUが許可されていない方法でメモリにアクセスしようとしてLoadProhibited
エラーが発生。通常は、割り当てられていないメモリアドレス(0x00000110
)に読み書きしようとしたことを意味する。
バックトレース情報(クラッシュ時の関数呼び出しスタック)が記載されているので、クラッシュに至るまでにどの関数が呼び出されたかの経路を辿ることができる。
今回はバックトレースの分析を試みる。
バックトレースの取得
クラッシュ時にデバイスが生成するバックとレースを確認。今回の場合は下記のように記載されている。
Backtrace: 0x400dd661:0x3ffd0080 0x400dd714:0x3ffd00a0 0x400d93fa:0x3ffd00c0 0x400d98f6:0x3ffd0230 0x400da273:0x3ffd02f0 0x402653fd:0x3ffd0350 0x400d369a:0x3ffd0370 0x400d3711:0x3ffd0390 0x400d9fe2:0x3ffd03b0 0x4013c20d:0x3ffd0400
シンボルの解決
バックトレースには関数のアドレスが含まれているが、これらのアドレスを人が読める関数名に変換する必要がある。このプロセスを、「シンボルの解決」と呼ぶ。
ESP32の場合、addr2line
ツール(macOSの場合)を使用して、ELFファイルからアドレスをソースコードの行に変換できる。
ELFファイルとは・保存場所
ELFは「Executable and Linkable Format」の略称で、実行可能ファイル、オブジェクトコード、共有ライブラリ、コアダンプなどを格納するためのファイルフォーマットを指す。
ELFファイルは、プロジェクトのビルドプロセス中に生成される。PlatformIOを使用してESP32で開発している場合、ビルドされたファイル(ELFファイルを含む)は.pio
ディレクトリ内に格納される。
<プロジェクトディレクトリ>/.pio/build/<環境>/firmware.elf
自分の場合は、下記ディレクトリにfirmware.elfファイルがあった。
addr2lineツールを使用して、ELFファイルをソースコードの行に変換
macOSの場合は、Homebrewを使用してGNU Binutilsをインストール。インストール後、addr2line
コマンドを使用してアドレスを解析できる。Windows OSではMSYS2やCygwinなど、Unix系の環境を提供するツールをインストールする必要がある。
brew install binutils
環境変数の設定 (オプション)
# Bash
export PATH=$PATH:/usr/local/opt/binutils/bin
source ~/.bashrc
#Zsh
export PATH=$PATH:/usr/local/opt/binutils/bin
source ~/zshrc
下記のコマンドを実行して、ELFファイルをソースコードの行に変換する。
addr2line -e your_program.elf -a <アドレス>
ELFファイルが存在するディレクトリに移動
cd /Users/ky/dev/clocky/clocky_platformio/.pio/build/upesy_wrover
次に、バックトレースに含まれる各アドレスに対してaddr2line
コマンドを実行する。 これを、バックトレースに記載されている他のアドレスに対して繰り返す。一気に実行することもできる。
実行すると、エラーになっているコードのファイルと行番号が分かる形で出力された。
ソースコードの確認・デバッグ
gaddr2line
から得られたソースコードの行を確認し、問題が発生している可能性がある部分を特定する。
該当行前後のポインタの使用、メモリアクセス、APIの呼び出し、nullチェックが適切に行われているかなどを重点的にチェックしていく。
ちなみに、この記事を書いた後から知ったのだが、platform.iniファイルにverbose設定で実行すると、バックトレースをする必要なく、エラー行が出力されることがわかった。
CORE_DEBUG_LEVEL
はデバッグ出力のレベルを設定する定数で、5は最も詳細な出力を提供する。
; PlatformIO Project Configuration File
; https://docs.platformio.org/page/projectconf.html
[env]
platform = espressif32
framework = arduino
board = esp32dev
[env:debug]
build_flags =
${env.build_flags}
-DDEBUG_BUILD #こちらを設定
-DCORE_DEBUG_LEVEL=5
上記設定した後に、以下のコマンドでビルドとモニタリングを実行できる。
pio run -e debug -t upload
pio device monitor -e debug
これにより、下記のように、ESP32にプログラムが書き込まれ、シリアルモニターが起動して詳細なデバッグ情報をリアルタイムで確認できる。バックトレースを解析せずにエラー行も特定できる。
コメント