like a /dev/null

いつかは捨てられる儚いモノたちの吹き溜まり

コマンドラインでgdb

コマンドラインからgdbを使ってRasPiに実行イメージをロードして実行してみた。

gdbはもっぱらeclipseから使っているけど、コマンドラインから使う方法を一応調べてみた。

mrubyをRaspberry Pi(bare metal)で動かす: Windows編にあった通りに環境を構築していて、主なツールは以下のとおり。

  • OpenOCD
  • YAGARTO

それぞれインストールしたディレクトリを$(OPENOCD), $(YAGARTO)とする。

ARM用のgdbはYAGARTOに含まれていて、これとJTAGツールを接続するためにOpenOCDがある。関係を図にすると以下のような感じ。

RasPiのSDカードにはmruby(略)のサイトにあったとおり、JTAGデバッグに必要なファイルをコピーしておく。

OpenOCDの起動

コマンドは以下の通り。

$(OPENOCD)/bin/openocd-0.7.0.exe -f $(OPENOCD)/scripts/interface/olimex-arm-usb-tiny-h.cfg -f ./raspi.cfg

なお、OpenOCDを起動する前にRasPiの電源を投入し、JTAGツールをUSBで接続しておく。

raspi.cfgはmruby(略)のサイトの手順通りに作業するとどこかのリポジトリから取得される。raspiプロジェクトを作成するところだったかな。

無事起動すると以下のようなメッセージがでる。

Open On-Chip Debugger 0.7.0 (2013-05-05-10:41)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.sourceforge.net/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'jtag'
adapter speed: 1000 kHz
none separate
raspi.arm
Info : max TCK change to: 30000 kHz
Info : clock speed 1000 kHz
Info : JTAG tap: raspi.arm tap/device found: 0x07b7617f (mfg: 0x0bf, part: 0x7b76, ver: 0x0)
Info : found ARM1176
Info : raspi.arm: hardware has 6 breakpoints, 2 watchpoints

OpenOCDは自分自身の制御のために4444ポートにtelnetで接続できる。

ほとんど使うことは無いと思ったが、実はgdbを接続したときにARMが動作しているとgdbが何もできないという状態になる。

ということで、telnetなり、他のツールを使ってlocalhost:4444に接続し、haltコマンドを実行しておく。

gdbの起動

起動の前に、実行したいプログラムのelfファイルをtarget.elfとして作業ディレクトリにコピーしておく。ここではv6piのgpioのそれをコピーした。うまく実行できればACT LEDが点滅する。

gdbの起動コマンドは以下の通り。

$(YAGARTO)/bin/arm-none-eabi-gdb.exe target.elf

続いて以下のコマンドを入力する。

target remote localhost:3333
load

後はnextとかstepとかlistとかでステップ実行できる。適当にこれらコマンドを実行したログは以下の通り。なお、nはnext, lはlistの略コマンド。

(gdb) target remote localhost:3333
Remote debugging using localhost:3333
vp_gpio_set_fsel (portnum=743516865, fsel=VP_GPIO_FSEL_INPUT) at vp_gpio.c:45
45        }else if (portnum < 54){
(gdb) load
Loading section .text, size 0x2f8 lma 0x8000
Start address 0x8000, load size 760
Transfer rate: 6080 bits in <1 sec, 760 bytes/write.
(gdb) n
Single stepping until exit from function _start,
which has no line number information.
stepi ignored. GDB will now fetch the register state from the target.

Program received signal SIGINT, Interrupt.
0x00008000 in _start ()
(gdb) n
Single stepping until exit from function _start,
which has no line number information.
0x00008040 in reset_handler ()
(gdb) n
Single stepping until exit from function reset_handler,
which has no line number information.
main () at main.c:21
21      int main(){
(gdb) n
24        vp_gpio_set_fsel(16, VP_GPIO_FSEL_OUTPUT);
(gdb) l
19      }
20
21      int main(){
22        u32_t n;
23        // ACT LEDのピンをoutputにする
24        vp_gpio_set_fsel(16, VP_GPIO_FSEL_OUTPUT);
25
26        while(1){
27          vp_gpio_clear_output(16);
28          delay();
(gdb) n
27          vp_gpio_clear_output(16);
(gdb) n
28          delay();
(gdb) n
29          vp_gpio_set_output(16);
(gdb)

ステップ実行じゃなくて、ブレークポイントに達するまで実行するのはcontinueコマンドである。ブレークポイントを指定してなかったら永遠に実行しつづける。

continueから抜ける方法を調べようとしたところで疲れたので終了。