在使用GDB调试程序时,是否有某种方法可以读取x86-64特定于模型的寄存器,特别是IA32_FS_BASE和IA32_GS_BASE?
不太可取的是使用像英特尔Pintool这样的动态仪器软件包的解决方案,但我们将不胜感激。
答案 0 :(得分:4)
从gdb 8开始,寄存器$fs_base
和$gs_base
也可用。这些也可以在代码转储中工作,而不仅仅是实时程序。
答案 1 :(得分:3)
可以使用MSRs指令读取x86 RDMSR,即privileged (Ring 0)。在Linux中,存在用户线程可以调用以读取FS_BASE和GS_BASE的系统调用。它们没有库包装器,所以你必须编写代码来自己调用它们。
这是在C ++中实现它的一种方法,您可以将这些全局函数定义添加到您的程序中:
#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调用这些函数并以十六进制格式打印它们的返回值,如下所示:
(gdb) p/x x86::fs_base()
$1 = 0x7ffff5e01780
(gdb) p/x x86::gs_base()
$2 = 0x0
(gdb)
答案 2 :(得分:2)
如果您不想更改代码(或者代码不可用),您可以通过以下方式执行类似于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