【ESP32】gaddr2lineを活用したバックトレース分析

この記事は約11分で読めます。

はじめに

ESP32を使ってネコ型おしゃべりロボットを開発中だが、デバイスを初回起動した時に下記エラーが発生するようになった。

C++
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)に読み書きしようとしたことを意味する。

バックトレース情報(クラッシュ時の関数呼び出しスタック)が記載されているので、クラッシュに至るまでにどの関数が呼び出されたかの経路を辿ることができる。

今回はバックトレースの分析を試みる。

バックトレースの取得

クラッシュ時にデバイスが生成するバックとレースを確認。今回の場合は下記のように記載されている。

C++
Backtrace: 0x400dd661:0x3ffd0080 0x400dd714:0x3ffd00a0 0x400d93fa:0x3ffd00c0 0x400d98f6:0x3ffd0230 0x400da273:0x3ffd02f0 0x402653fd:0x3ffd0350 0x400d369a:0x3ffd0370 0x400d3711:0x3ffd0390 0x400d9fe2:0x3ffd03b0 0x4013c20d:0x3ffd0400

シンボルの解決

バックトレースには関数のアドレスが含まれているが、これらのアドレスを人が読める関数名に変換する必要がある。このプロセスを、「シンボルの解決」と呼ぶ。

ESP32の場合、gaddr2lineツール(macOSの場合)を使用して、ELFファイルからアドレスをソースコードの行に変換できる。

ELFファイルとは・保存場所

ELFは「Executable and Linkable Format」の略称で、実行可能ファイル、オブジェクトコード、共有ライブラリ、コアダンプなどを格納するためのファイルフォーマットを指す。

ELFファイルは、プロジェクトのビルドプロセス中に生成される。PlatformIOを使用してESP32で開発している場合、ビルドされたファイル(ELFファイルを含む)は.pioディレクトリ内に格納される。

C++
<プロジェクトディレクトリ>/.pio/build/<環境>/firmware.elf

自分の場合は、下記ディレクトリにfirmware.elfファイルがあった。

gaddr2lineツールを使用して、ELFファイルをソースコードの行に変換

macOSの場合は、Homebrewを使用してGNU Binutilsをインストール。インストール後、gaddr2lineコマンドを使用してアドレスを解析できる。

LinuxディストリビューションやUnix系システムでは、gaddr2lineではなくaddr2lineをインストールする。また、Windows OSではMSYS2やCygwinなど、Unix系の環境を提供するツールをインストールする必要がある。

C++
brew install binutils

下記のコマンドを実行して、ELFファイルをソースコードの行に変換する。

C++
gaddr2line -e your_program.elf -a <アドレス>

ELFファイルが存在するディレクトリに移動

C++
cd /Users/ky/dev/clocky/clocky_platformio/.pio/build/upesy_wrover

次に、バックトレースに含まれる各アドレスに対してgaddr2lineコマンドを実行する。 これを、バックトレースに記載されている他のアドレスに対して繰り返す。

C++
gaddr2line -e firmware.elf -a 0x400dd661
gaddr2line -e firmware.elf -a 0x400dd714
gaddr2line -e firmware.elf -a 0x400d93fa
gaddr2line -e firmware.elf -a 0x400d98f6
gaddr2line -e firmware.elf -a 0x400da273
gaddr2line -e firmware.elf -a 0x402653fd
gaddr2line -e firmware.elf -a 0x400d369a
gaddr2line -e firmware.elf -a 0x400d3711
gaddr2line -e firmware.elf -a 0x400d9fe2
gaddr2line -e firmware.elf -a 0x4013c20d

プロジェクトのルートディレクトリからのfull pathだと下記。

C++
gaddr2line -e .pio/build/upesy_wrover/firmware.elf -a 0x400dd661

# 以下同様


実行したところ、下記のように結果でた。

C++
/Users/ky/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include/c++/8.4.0/ext/atomicity.h:53
0x400dd714
/Users/ky/dev/clocky/clocky_platformio/src/sync_device_shadow.cpp:11 (discriminator 1)
0x400d93fa
/Users/ky/dev/clocky/clocky_platformio/.pio/libdeps/upesy_wrover/expected/include/tl/expected.hpp:697
0x400d98f6
/Users/ky/dev/clocky/clocky_platformio/src/main.cpp:170
0x400da273
/Users/ky/dev/clocky/clocky_platformio/src/main.cpp:520
0x402653fd
/Users/ky/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src/WiFiClientSecure.cpp:194
0x400d369a
/Users/ky/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include/c++/8.4.0/bits/std_function.h:686
0x400d3711
/Users/ky/dev/clocky/clocky_platformio/src/ButtonManager.cpp:48 (discriminator 1)
0x400d9fe2
/Users/ky/dev/clocky/clocky_platformio/src/main.cpp:574 (discriminator 1)
0x4013c20d
/Users/ky/.platformio/packages/framework-arduinoespressif32/cores/esp32/esp32-hal-cpu.c:140

ソースコードの確認・デバッグ

gaddr2lineから得られたソースコードの行を確認し、問題が発生している可能性がある部分を特定する。

今回のケースだと、sync_device_shadow.cppの11行目、main.cppの170行目と520行目、ButtonManager.cppの48行目などが怪しいので、その行前後のポインタの使用、メモリアクセス、APIの呼び出し、nullチェックが適切に行われているかなどを重点的にチェックしていく。

コメント

タイトルとURLをコピーしました