Использование GDB для чтения MSR

Есть ли способ прочитать регистры, специфичные для модели x86-64, в частности IA32_FS_BASE и IA32_GS_BASE, при отладке программы с использованием GDB?

Менее предпочтительным было бы решение с использованием динамического пакета инструментов, такого как Pintool от Intel, но оно все равно будет оценено по достоинству.


person shigoel    schedule 15.04.2014    source источник


Ответы (3)


Если вы предпочитаете не менять свой код (или если код недоступен), вы можете сделать что-то похожее на ответ 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
person Soumava    schedule 16.04.2014

Начиная с gdb 8, также доступны регистры $fs_base и $gs_base. Они также работают в дампах кода, а не только в живых программах.

person Avi Kivity    schedule 01.12.2019
comment
просто как пример для не очень опытных людей с gdb (таких как я): pwndbg> i r $fs_base печатает fs_base 0x7f28edbd7540 139813764035904 - person KoKlA; 29.03.2020

MSR для x86 можно прочитать с помощью RDMSR, которая представляет собой привилегированный (кольцо 0). В Linux есть системные вызовы, которые пользовательский поток может вызывать для чтения FS_BASE и GS_BASE. Для них нет библиотечных оболочек, поэтому вам придется писать код для их вызова самостоятельно.

Вот один из способов сделать это на С++: вы добавляете эти глобальные определения функций в свою программу:

#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)
person amdn    schedule 16.04.2014
comment
В последнем аппаратном обеспечении x86 также есть RDFSBASE и WRFSBASE для чтения базовой файловой системы в пользовательском пространстве. Базовые правила GS. - person Peter Cordes; 01.12.2019