前回までで、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コマンド
これは汎用レジスタの内容をダンプするコマンドだ。
‘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とのリンクを確立し、プログラムをダウンロードしてみる。
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
何にも詳細なログは出していないが、一応ダウンロードのための動作はできているようだ。 次は、いよいよシミュレーションさせたり、デバッグのための通信プロトコルを実装していこう。