このページは「24環境」の情報です

第10回 リモートgdb機能

海老原祐太郎
2002/11/1

CAT68701のROMモニターの g オプション使ったことありますか?
今回は リモートgdb機能を使ってみます。

準 備 

sh3-linux-binutils, sh3-linux-gcc, sh-linux-gdb をインストールしておいてください。

CAT68701と開発Linux機をシリアルケーブルでつなぎます。
Linuxの適当なシリアル端末プログラムをインストールしておきます。(minicom や cu)

debian woodyでは cu は uucpパッケージに入っていますので
# apt-get install uucp
でインストールできます。minicom は
# apt-get install minicom

プログラム

/*
* CAT68701 LED blink program
* STAT LED を点滅させるプログラム  (led.c)
*
* 2001.9.3 Yutaro Ebihara ebihara@si-linux.com
*
*/

#define P2_AREA (0xa0000000)
#define DSW (P2_AREA+0x14007000)     /* input port (DIP switch) */
#define LED (P2_AREA+0x14007400)     /* output port (LED) */

int main() {
  int i;
  while(1) {
    for(i=0; i<100000; i++) {
      *(volatile short*)LED =0x8000;
    }
    for(i=0; i<100000; i++) {
      *(volatile short*)LED =0x0000;
    }
  }
  return 0;
}

プログラムは超簡単なもので、基板上のSTAT LEDを点滅させるものです。
このプログラムを led.c として保存します。

メモリマップとリンカースクリプト

gdb_mem.gif

CAT68701は 0x8c00 0000〜0x8e00 0000 に32MバイトのSDRAMがあります。
そのうち 先頭付近はROMプログラムのワークエリアとなっていますので、
それ以降の部分をユーザープログラムで使用します。
今回は超大雑にプログラム領域、データ領域、スタック領域を各64Kバイトづつ使用します。
アドレス情報をリンカーに教えるために、リンカースクリプトを用意します。

OUTPUT_FORMAT("elf32-sh-linux")
OUTPUT_ARCH(sh)

ENTRY("main")

MEMORY
{
  ROM(rx): ORIGIN = 0x8c010000, LENGTH = 64k
  RAM(rw): ORIGIN = 0x8c020000, LENGTH = 64k
  STACK(rw): ORIGIN = 0x8c030000, LENGTH = 64k
}

SECTIONS
{
.text :
{
  *(.text)
  *(.strings)
  *(.rodata)
} > ROM

. = ALIGN(4);

.data :
{
  *(.data)
} > RAM

. = ALIGN(4);

.bss :
{
  *(.bss)
  *(COMMON)
} > RAM

. = ALIGN(4);

.stack :
{
  *(.stack)
} > STACK
}

上のファイルを cat68701gdb.x として保存します。

led.out: led.o cat68701gdb.x
        sh3-linux-ld -T cat68701gdb.x led.o -o led.out

led.o:led.c
        sh3-linux-gcc -g -c led.c

clean:
        rm led.o led.out

Makefileはこんな感じになります。
led.c をコンパイルしてオブジェクトファイル led.o が出来上がります。
このときはまだアドレスは確定していません。
次に led.o に対してリンカースクリプト cat68701gdb.x を指定して led.out を作ります。

実 行 

Linux機から端末プログラムを動かし、CAT68701の電源を入れます。
ROMモニターから g をタイプして端末プログラムを終了します。

~$ cu -l /dev/ttyS0 -s 115200
Connected.

> h
SH IPL+g version 0.11, Copyright (C) 2001 Free Software Foundation, Inc.
? --- Show this message (HELP)
b --- Boot the system
g --- Invoke GDB stub
l --- Show about license
w --- Show about (no)warranty

e --- Ether Boot
> g
$S05#b8$S05#b8~.        ← 『リターン』、『~』、『.』 の順に押してcuを終了

Disconnected.
~$

gdbを起動して led.out をロードします。

~$ sh-linux-gdb -b 115200 led.out
GNU gdb 2001-12-03-cvs
Copyright 2001 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "--host=i386-linux --target=sh-linux"...
(gdb) target remote /dev/ttyS0                         ←  ターゲットの指定
Remote debugging using /dev/ttyS0
0x80004756 in ?? ()
(gdb) load                                             ←  led.out プログラムのロード
Loading section .text, size 0x60 lma 0x8c010000
Start address 0x8c010000, load size 96
Transfer rate: 768 bits in <1 sec, 96 bytes/write.
(gdb) list                                             ←  ソースコードを表示
5 * 2001.9.3 Yutaro Ebihara ebihara@si-linux.com
6 *
7 */
8
9 #define P2_AREA (0xa0000000)
10 #define DSW (P2_AREA+0x14007000)
11 #define LED (P2_AREA+0x14007400)
12
13 int main() {
14   int i;
(gdb)                                                  ←  リターンキーで続き
15   while(1) {
16     for(i=0; i<100000; i++) {
17       *(volatile short*)LED =0x8000;
18     }
19
20     for(i=0; i<100000; i++) {
21       *(volatile short*)LED =0x0000;
22     }
23   }
24   return 0;
(gdb) b 17                                             ← ブレイクポイントを17行目に
Breakpoint 1 at 0x8c010020: file led.c, line 17.
(gdb) cont                                             ← 実行開始
Continuing.

Breakpoint 1, main () at led.c:17
17 *(volatile short*)LED =0x8000;                      ← ブレイクポイントで停止した!

てな感じでデバック開始です

Breakpoint 1, main () at led.c:17
17 *(volatile short*)LED =0x8000;
(gdb) p i                                              ← 変数 i の表示
$1 = 0
(gdb) p i=99998                                        ← 変数 i に 99998 を代入
$2 = 99998
(gdb) n                                                ← 続き実行
16 for(i=0; i<100000; i++) {
(gdb) p i                                              ← 変数 i の表示
$3 = 99998
(gdb) n                                                ← 続き実行

Breakpoint 1, main () at led.c:17
17 *(volatile short*)LED =0x8000;
(gdb) p i                                              ← 変数 i の表示 99999になってる!
$4 = 99999
(gdb) n                                                ← 続き実行
16 for(i=0; i<100000; i++) {
(gdb)                                                  ← リターンのみで続き実行
20 for(i=0; i<100000; i++) {
(gdb)
21 *(volatile short*)LED =0x0000;                      ← ここで LED が消灯するはず。やったね!
(gdb)

という雰囲気で実機でgdbでソースレベルデバックできます。

(gdb) disas                                            ← 逆アセンブルしてみたり
Dump of assembler code for function main:
0x8c010000 <main>: mov.l r14,@-r15
0x8c010002 <main+2>: sts.l pr,@-r15
0x8c010004 <main+4>: add #-4,r15
0x8c010006 <main+6>: mov r15,r14
0x8c010008 <main+8>: nop
0x8c01000a <main+10>: mov #0,r1
0x8c01000c <main+12>: mov.l r1,@r14
0x8c01000e <main+14>: mov.l @r14,r2
0x8c010010 <main+16>: mov.l 0x8c010054 <main+84>,r1 ! 0x1869f
0x8c010012 <main+18>: cmp/gt r1,r2
0x8c010014 <main+20>: bf 0x8c010020 <main+32>
0x8c010016 <main+22>: bra 0x8c010030 <main+48>
(gdb) reg                                              ← レジスタを表示させてみたり
PC=8c010020 SR=400000f0 PR=8000344c MACH=ffffffff MACHL=ffffffff
GBR=ffffffff VBR=80000000
R0-R7 00000000 0001869f 00000000 fffffe88 0000000a 8c0006e0 00000002 00000005
R8-R15 80006150 efffffff 80001000 80005f00 80003360 80005f60 8c000ed0 8c000ed0
(gdb) p *(short*)0xb4007400=0x8000                     ← LEDを直接点灯させたり
$10 = -81
(gdb) p *(short*)0xb4007400=0x0000                     ← LEDを直接消灯させたり

いやー。すばらしい。
あとはもうプログラム作るだけです。(^^