課題: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を指定するオプションがあればいいのだけど。。見つけられず。