ブレークポイントとステップ実行が何となく動くようになったので、データの取得のためのレジスタ値取得コマンドとメモリ設定コマンドを調整していこう。
現在対象としているアーキテクチャはMIPS64のため、これに合うように、まずはレジスタのダンプコマンド(gコマンド)を修正するのと、メモリのバイトーオーダーを調整する。
Info Registerコマンドで取得されるレジスタ群
info registerコマンドにより、汎用レジスタの値を取得できる。
Breakpoint 1, main () at core_main.c:89 (gdb) info registers zero at v0 v1 R0 0000000000000000 ffffffff800025f8 0000000000000000 0000000000000000 a0 a1 a2 a3 R4 0000000000000000 0000000000000000 0000000000000000 0000000000000000 a4 a5 a6 a7 R8 0000000000000000 0000000000000000 0000000000000000 0000000000000000 t0 t1 t2 t3 R12 0000000000000000 0000000000000000 0000000000000000 0000000000000000 s0 s1 s2 s3 R16 0000000000000000 0000000000000000 0000000000000000 0000000000000000 s4 s5 s6 s7 R20 0000000000000000 0000000000000000 0000000000000000 0000000000000000 t8 t9 k0 k1 R24 ffffffff800025f8 0000000000000000 0000000000000000 0000000000000000 gp sp s8 ra R28 ffffffff7f000020 ffffffff7f004018 0000000000000000 ffffffffbfc000c4 sr lo hi bad 0000000000000000 0000000000000000 0000000000000000 0000000000000000 cause pc 0000000000000000 ffffffff800025f8 fsr fir 00000000 00000000 (gdb)
実際にはGDBクライアントとGDBサーバの間でgコマンドが発行されており、汎用レジスタの値を全て取得するようなコマンドが走っている。
void GdbEnv::DumpGeneralRegisters (void) { std::stringstream str; for (Addr_t idx = 0; idx < 32; idx++) { DWord_t val = m_env->GRegRead<DWord_t>(idx); DWord_t reversed_val = ReverseByte<DWord_t>(val); str << std::hex << std::setw(16) << std::setfill('0') << reversed_val; } SendPacketString (str.str().c_str()); }
気をつけなければならないのはバイトアラインだ。GDBの返答としては、バイト単位で返さなければらないらしく、そのままレジスタの表記で返してしまうとバイトが反転してしまう。 従って、ReverseByte関数を実装してバイト単位で反転し、その結果を返すようにしている。
template <class T> T GdbEnv::ReverseByte (T data) { T reversed_data = 0; const int byte_size = sizeof (T); for (int idx = 0; idx < byte_size; idx++) { Byte_t byte = data & 0x0FF; reversed_data = reversed_data << 8 | (byte & 0x0FF); data >>= 8; } return reversed_data; } template Word_t GdbEnv::ReverseByte (Word_t data); template DWord_t GdbEnv::ReverseByte (DWord_t data);
Killコマンドの実装
現在、GDBクライアント側を強制終了させると、GDBサーバ側(ISS)が強制終了されてしまう。これを防ぐために、GDBプロトコルの'k'コマンドをサポートしよう。
case 'k' : { return GDB_KILL; }
単純にStepExecutionをせずに、GDB_KILL通知をISSの制御部に返す。これによりGDBの通信チャネルを切断し、終了するように変更した。
if (FLAGS_gdb != -1) { #ifdef ARCH_MIPS64 Mips64Env *env = new Mips64Env (g_debug_fp, g_uart_fp, en_stop_sim, FLAGS_debug); #endif // ARCH_MIPS64 std::unique_ptr<GdbEnv> p_gdb = std::unique_ptr<GdbEnv>(new GdbEnv(env, FLAGS_gdb)); p_gdb->HandleGdb(); while (p_gdb->HandleClientRequest () == GDB_NORMAL); p_gdb->CloseRSPClient();
ポート番号をオプションで指定できるようにする
ついでに、--gdbオプションによりポート番号を指定できるようにした。
DEFINE_int32 (gdb, -1, "Wait GDB port");
- 以下のコマンドでポート番号を指定可能だ。
$ ./swimmer_mips64 -gdb 3000