10

GDB を使用してプログラムをデバッグしているときに、x86-64 モデル固有のレジスタ、具体的には IA32_FS_BASE および IA32_GS_BASE を読み取る方法はありますか?

Intel の Pintool のような動的インストルメンテーション パッケージを使用するソリューションはあまり好ましくありませんが、それでも同様に高く評価されます。

4

3 に答える 3

6

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)
于 2014-04-16T20:53:05.373 に答える
5

コードを変更したくない場合 (またはコードが利用できない場合) は、次の方法で 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
于 2014-04-16T22:20:13.300 に答える