課題:Ubuntu 上にtinygo開発環境を構築して、gdb+OpenOCDを動くようにしたい
取り組み:Ubuntu 上にtinygoの開発環境をインストール、gdbの最新版をパッケージでインストールする
結論:gdb+OpenOCDによるシンボリックデバッグが可能となった
作業内容:
普段使ってるCygwinにtinygoの環境を入れようとしたが、パスの問題やら、gdbのバージョン不整合の問題が出た。標準的なUbuntu上で環境構築するのが無難ではと思い、Ubuntu に入れなおす
ビルド、gdbを起動してみる。
$ tinygo build -target pico blinky1.go $ tinygo gdb -target pico GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from /tmp/tinygo9732039/main... warning: Section .debug_aranges in /tmp/tinygo9732039/main entry at offset 0 debug_info_offset 0 does not exists, ignoring .debug_aranges. :3333: Connection timed out. "monitor" command not supported by this target. You can't do that when your target is `exec' "monitor" command not supported by this target. (gdb)
gdbが起動してOpenOCDと通信するところまで進んだ。エラーが出なかったのは、別件のためすでにgdbとOpenOCDがインストール済みだったため。gdbのバージョンは以下(9.2)
$ gdb-multiarch --version GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
"monitor" command not supported by this target. というエラーが気になるが、、この状態で、RPi上でOpenOCDを起動してgdbから接続してみる。
以下のコマンドでRPi上のOpenOCDを起動
$ /usr/local/bin/openocd -c 'bindto 0.0.0.0' -f /usr/local/share/openocd/scripts/interface/raspberrypi-swd.cfg -f /usr/local/share/openocd/scripts/target/rp2040.cfg Open On-Chip Debugger 0.11.0-g228ede4-dirty (2022-12-10-18:01) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html adapter speed: 1000 kHz Info : Hardware thread awareness created Info : Hardware thread awareness created Info : RP2040 Flash Bank Command Info : Listening on port 6666 for tcl connections Info : Listening on port 4444 for telnet connections Info : BCM2835 GPIO JTAG/SWD bitbang driver Info : clock speed 1001 kHz Info : SWD DPIDR 0x0bc12477 Info : SWD DLPIDR 0x00000001 Info : SWD DPIDR 0x0bc12477 Info : SWD DLPIDR 0x10000001 Info : rp2040.core0: hardware has 4 breakpoints, 2 watchpoints Info : rp2040.core1: hardware has 4 breakpoints, 2 watchpoints Info : starting gdb server for rp2040.core0 on 3333 Info : Listening on port 3333 for gdb connections Info : accepting 'gdb' connection on tcp/3333
3333ポートで待ち受けになっているので、Ubuntuのgdbから接続に行く。接続まではできてターゲットはHALTになった。リストコマンドを打つと、Drawf Errorになっている。なぜだろうか。
(gdb) target remote 192.168.10.100:3333 Remote debugging using 192.168.10.100:3333 0x10001a4c in runtime.scheduler () (gdb) b main Function "main" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (main) pending. (gdb) l Dwarf Error: DW_FORM_strx1 found in non-DWO CU [in module /tmp/tinygo9732039/main]
なお、OpenOCD側では以下の警告が出ている
Warn : Prefer GDB command "target extended-remote 3333" instead of "target remote 3333"
少しぐぐると、、Dwafのバージョンとgdbの整合性の問題のようで、Dwarf5を使っている場合はgdb10を使えということらしい。gdb9のままとする場合はdwaf4に落とせと。
Gdb < 10.1 can't read clang's DWARF v5 - Common Infrastructure - LLVM Discussion Forums
Ubuntu環境のgdbは特にこだわりないので、、最新版にあげてみる。
上げようとしたが、自分のUbuntuは20.04 LTSで、このLTSで入れられる最新版gdbは9.2のようであった。だから、、もっと新しいgdbを入れたかったらUbuntuのバージョンを上げないといけない様だ。あるいは、ソースからコンパイルか。
Ubuntuを24LTSにあげた。おおよそ以下の手順
1605 apt update 1606 apt upgrade 1607 apt full-upgrade 1608 apt autoremove -y 1609 apt autoclean -y 1610 reboot 1612 do-release-upgrade
参考にした記事
Ubuntu 20.04 LTS を 22.04 LTS にアップグレードする - Uzabase for Engineers
改めて、、RPi側は以下でOpenOCDを実行中
/usr/local/bin/openocd -c 'bindto 0.0.0.0' -f /usr/local/share/openocd/scripts/interface/raspberrypi-swd.cfg -f /usr/local/share/openocd/scripts/target/rp2040.cfg
RPiのIPが192.168.10.100なので、tinygo gdbでGDBを起動して、192.168.10.100:3333で接続する
$ tinygo gdb --target pico GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1 Copyright (C) 2022 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <https://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from /tmp/tinygo942108089/main... warning: Section .debug_aranges in /tmp/tinygo942108089/main entry at offset 0 debug_info_offset 0 does not exists, ignoring .debug_aranges. :3333: Connection timed out. "monitor" command not supported by this target. You can't do that when your target is `exec' "monitor" command not supported by this target. (gdb) target extended-remote 192.168.10.100:3333 Remote debugging using 192.168.10.100:3333 warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread 0x10001a4c in runtime[scheduler] ()
(gdb) info sources *略* /usr/local/lib/tinygo/src/runtime/scheduler_any.go, /usr/local/lib/tinygo/src/runtime/time.go, /usr/local/go/src/time/format.go, /usr/local/go/src/time/time.go, /usr/local/go/src/time/zoneinfo.go, /usr/local/go/src/time/zoneinfo_read.go, /usr/local/go/src/time/zoneinfo_unix.go, /mnt/c/cygwin64/home/<user_id>/lang/tgo/test/blinky1.go (gdb) info func *略* 0x10001c94 main.main
ソースの情報やシンボル情報は読み込めている。
HardwareBreadkpintを main.mainに設定する
(gdb) hb main.main Hardware assisted breakpoint 3 at 0x10001c96 (gdb) i b Num Type Disp Enb Address What 3 hw breakpoint keep y 0x10001c96 <main.main+2>
実行してみる。止まるには止まったが、ソースと一致しないようだ。
(再ビルドしたので番地が違っている?)
(gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /tmp/tinygo942108089/main target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x00000184 msp: 0x20041f00 [New Thread 1] [Switching to Thread 1] Thread 2 hit Breakpoint 3, 0x10001c96 in main.main () (gdb) l 1 <unknown>: No such file or directory.
適当に走らせてCtrl-Cで止めるとソースを参照できる
(gdb) l 171 // will be executed soon. 172 if sleepQueue != nil && now-sleepQueueBaseTime >= timeUnit(sleepQueue.Data) { 173 t := sleepQueue 174 scheduleLogTask(" awake:", t) 175 sleepQueueBaseTime += timeUnit(t.Data) 176 sleepQueue = t.Next 177 t.Next = nil 178 runqueue.Push(t) 179 } 180
想像するに、、main.mainで止めずに、main内の有効な行で止めないといけないのでは(スタックがまだ積まれていないから。。とか。。)
blinky1.goの12行目にhardware breakを設定してみる
(gdb) list blinky1.go:10 5 import ( 6 "machine" 7 "time" 8 ) 9 10 func main() { 11 //led := machine.LED 12 led := machine.GP15 13 led.Configure(machine.PinConfig{Mode: machine.PinOutput}) 14 for { Warning: the current language does not match this frame. (gdb) hb blinky1.go:12 Hardware assisted breakpoint 1 at 0x10001cb6: file /home/<user_id>/lang/tgo/test/blinky1.go, line 16. (gdb) i b Num Type Disp Enb Address What 1 hw breakpoint keep y 0x10001cb6 in main.main at /home/<user_id>/lang/tgo/test/blinky1.go:16 (gdb)
ソース行内のコードに対して、ブレークポイントを設定すると、停止してリスト表示も行えた。*1
(gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /tmp/tinygo3924727989/main target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x00000138 msp: 0x20041f00 [New Thread 2] Thread 1 hit Breakpoint 1, main.main () at /home/<user_id>/lang/tgo/test/blinky1.go:16 16 time.Sleep(time.Millisecond * 500) (gdb) l 11 //led := machine.LED 12 led := machine.GP15 13 led.Configure(machine.PinConfig{Mode: machine.PinOutput}) 14 for { 15 led.Low() 16 time.Sleep(time.Millisecond * 500) 17 18 led.High() 19 time.Sleep(time.Millisecond * 500) 20 } (gdb)
まとめ:RPi上でOpenOCDを走らせて、ノートPC上のWSL上のUbuntu でtinygoの開発環境を構築して、その中でgdbを走らせて、gdbからRPi上のOpenOCDとリモート接続することでシンボリックデバッグが可能となった。
[gdb on Ubuntu on WSL]
[Windows10] <--------------LAN----> [OpenOCD on RPi]<------SWD--->[Pico]
以下の写真はRPiとPicoをSWDで接続して動作確認しているところ
■追記
うまくいったといっても、Ubuntu上ではOpenOCDが起動された空振りしている状態なので、これはあくまでもWorkaroundのレベルだ。以下はプロセス一覧を確認したところ。ローカル環境でOpenOCDを走らせるのではなく、リモートのOpenOCDと接続できるように作込みが必要
$ ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 904 532 ? Sl 18:04 0:00 /init root 8 0.0 0.0 904 96 ? Ss 18:04 0:00 /init root 9 0.0 0.0 904 96 ? S 18:04 0:02 /init xxx 10 0.0 0.1 9276 5516 pts/0 Ss 18:04 0:00 -bash xxx 998 0.3 2.4 1014888 115516 pts/0 Tl 19:52 0:10 tinygo gdb --target pico xxx 1099 0.0 0.0 0 0 pts/0 Z 19:52 0:00 [openocd] <defunct> <<<< 無駄に走っているOpenOCDプロセス xxx 1100 0.0 0.9 395864 42404 pts/0 Tl 19:52 0:02 gdb-multiarch /tmp/tinygo3924727989/main -ex target ext xxx 1108 0.0 0.0 10456 3168 pts/0 R+ 20:48 0:00 ps aux
gdb起動オプション
gdb-multiarch /tmp/tinygo3924727989/main -ex target extended-remote :3333 -ex monitor halt -ex load -ex monitor reset halt
- ex target extended-remote :3333 で起動しているのを -ex target extended-remote
:3333 となればいいのだが、、リモートのOpenOCDのIPを指定するオプションがあればいいのだけど。。見つけられず。