GDB を使用してプログラムをデバッグしているときに、x86-64 モデル固有のレジスタ、具体的には IA32_FS_BASE および IA32_GS_BASE を読み取る方法はありますか?
Intel の Pintool のような動的インストルメンテーション パッケージを使用するソリューションはあまり好ましくありませんが、それでも同様に高く評価されます。
GDB を使用してプログラムをデバッグしているときに、x86-64 モデル固有のレジスタ、具体的には IA32_FS_BASE および IA32_GS_BASE を読み取る方法はありますか?
Intel の Pintool のような動的インストルメンテーション パッケージを使用するソリューションはあまり好ましくありませんが、それでも同様に高く評価されます。
x86 MSRは、特権 (リング 0)であるRDMSR命令で読み取ることができます。Linux には、FS_BASE と GS_BASE を読み取るためにユーザー スレッドが呼び出すことができるシステム コールがあります。それらのライブラリ ラッパーがないため、それらを呼び出すコードを自分で作成する必要があります。
これを C++ で行う 1 つの方法を次に示します。これらのグローバル関数定義をプログラムに追加します。
#include <cstdint>
#include <asm/prctl.h>
#include <sys/syscall.h>
namespace x86 {
uint64_t fs_base() {
uint64_t fs_base;
syscall(SYS_arch_prctl,ARCH_GET_FS,&fs_base);
return fs_base;
}
uint64_t gs_base() {
uint64_t gs_base;
syscall(SYS_arch_prctl,ARCH_GET_GS,&gs_base);
return gs_base;
}
}
これで、これらの関数を gdb から呼び出して、次のように戻り値を 16 進数で出力できます。
(gdb) p/x x86::fs_base()
$1 = 0x7ffff5e01780
(gdb) p/x x86::gs_base()
$2 = 0x0
(gdb)
コードを変更したくない場合 (またはコードが利用できない場合) は、次の方法で amdn の回答と同様のことを行うことができます。arch_prctl の呼び出しには、uint64_t へのポインターが必要です。これには、スタックの空の部分 (現在のスタック ポインターの 8 バイト下) へのアドレスを使用します。呼び出しが戻った後、その場所に格納されている 8 バイトの値を読み取ります。
使用される定数: ARCH_GET_FS = 0x1003、ARCH_GET_GS = 0x1004
(gdb) p $rsp
$1 = (void *)0x7fffffffe6f0
(gdb) call arch_prctl(0x1003, $rsp - 0x8)
$2 = 0
(gdb) x /gx $rsp - 0x8
0x7fffffffe6e8: 0x00007ffff7fe0700 => IA32_FS_BASE
(gdb) call arch_prctl(0x1004, $rsp - 0x8)
$3 = 0
(gdb) x /gx $rsp - 0x8
0x7fffffffe6e8: 0x0000000000000000 => IA32_GS_BASE