FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

GDBのプロトコルを読み解く(GDBのリンク確立とプログラムのダウンロード)

msyksphinz.hatenablog.com

前回までで、GDBのパケットの仕組みについて学んだ。今度は、GDBのリンク確立とプログラムのダウンロードだ。

まずは適当にGDBのフロンドエンドからパケットを受信して、どのような形式のパケットがやってくるか観察してみる。

GDBのパケットを観察し、内容を読み解く

Xコマンド、Mコマンド

どうやらGDBプロトコルの方針として、大文字の場合はフロントエンドからサーバへの書き込み、小文字の場合はフロントエンドへの情報の送信のようになっているみたいだ。 上記のXコマンドとMコマンドは、メモリに対する書き込みのコマンドになっている。

+Packet received X80000000,250:...

0x8000_0000から始まる250バイトを、メモリに書き込む。書き込む内容は、...の以下に示されている。 従って、このパケットがやってきたら、アドレスと書き込みバイト数を取得し、1バイトずつ書き込む処理を行っていく。

    case 'X' : {
        // Memory Download
        Addr_t mem_base = 0;
        Addr_t mem_size = 0;
        Byte_t mem_data = 0;
        int idx;
        for (idx = 1; packet_str[idx] != ','; idx++) {
            mem_base = (mem_base << 4) | Hex (packet_str[idx]);
        }
        idx++;
        for (idx = 1; packet_str[idx] != ':'; idx++) {
            mem_size = (mem_size << 4) | Hex (packet_str[idx]);
        }
        idx++;
        for (; idx < packet_str.length(); idx+=2) {
            if ((idx + 1) == packet_str.length()) {
                mem_data = (Hex (packet_str[idx]) << 4);
            } else {
                mem_data = (Hex (packet_str[idx]) << 4) | (Hex (packet_str[idx+1]));
            }
            m_env->StoreMemoryDebug (mem_base, mem_data, Size_Word);
            mem_base += 4;
        }
        PutPacket ("OK");
        break;

gコマンド

これは汎用レジスタの内容をダンプするコマンドだ。

sourceware.org

‘g’
Read general registers.

これは汎用レジスタの内容を全て返すようにする。この辺りは、プロセッサに対してAPIを定義しているので、これを読み出すだけでよい。

    case 'g' : {
        DumpGeneralRegisters ();
        break;
    }
...
void GdbEnv::DumpGeneralRegisters (void)
{
    std::stringstream str;
    for (Addr_t idx = 0; idx < 32; idx++) {
        Word_t reg_val = m_env->GRegRead<Word_t>(idx);
        str << std::hex << std::setw(8) << std::setfill('0') << reg_val;
    }
    SendPacketString (str.str().c_str());
}

mコマンド

これは、メモリの内容を読み出すコマンドだ。

‘m addr,length’
Read length addressable memory units starting at address addr (see addressable memory unit). Note that addr may not be aligned to any particular boundary.

従って、これもAPIを利用してメモリの内容を取得するようにする。

    case 'm' : {
        Addr_t base, length;
        sscanf (packet_str.c_str(), "m%d,%d", &base, &length);
        std::stringstream str;
        str << std::hex << std::setw(8) << std::setfill('0') << 0x0;
        SendPacketString (str.str());
        break;
    }

これらのプロトコルに従って、gdbとのリンクを確立し、プログラムをダウンロードしてみる。

github.com

GDBとの接続

  • GDBフロントエンド側
$ mips-img-elf-gdb

...

(gdb) target remote :2000
Remote debugging using :2000
0x00000000 in ?? ()
+PutPacket : $PacketSize=281#cb
+PutPacket : $OK#9a
+PutPacket : $#00
+PutPacket : $S05#b8
+PutPacket : $#00
+PutPacket : $#00
+PutPacket : $OK#9a
+PutPacket : $#00
+PutPacket : $#00
+PutPacket : $OK#9a
+PutPacket : $0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000#00
+PutPacket : $0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000#00
+PutPacket : $00000000#80
+PutPacket : $00000000#80
+PutPacket : $#00
+PutPacket : $00000000#80

プログラムのロード

  • GDBフロントエンド側
(gdb) load ~/benchmarks/releases/coremark_v1.0_mips64r6_img49_O2/coremark.bin
Loading section .data, size 0x10 lma 0x7f000000
Loading section .got, size 0x160 lma 0x7f000010
Loading section .data.rel.local, size 0x18 lma 0x7f000170
Loading section .data.rel.ro.local, size 0x80 lma 0x7f000188
Loading section .text, size 0x2810 lma 0x80000000
Loading section .text.startup, size 0x830 lma 0x80002810
Loading section .text.reset, size 0xe0 lma 0xbfc00000
Loading section .MIPS.options, size 0x140 lma 0xbfc000e0
Loading section .MIPS.abiflags, size 0x18 lma 0xbfc00220
Loading section .rodata.str1.8, size 0x670 lma 0xbfc00238
Loading section .rodata, size 0x4e0 lma 0xbfc008b0
Start address 0x80000000, load size 16336
Transfer rate: 409 KB/sec, 466 bytes/write.
  • ISS側 +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $OK#9a +PutPacket : $#00
何にも詳細なログは出していないが、一応ダウンロードのための動作はできているようだ。

次は、いよいよシミュレーションさせたり、デバッグのための通信プロトコルを実装していこう。