Вопрос

Я создаю программу, которая использует mprotect() для ограничения доступа к блоку памяти.Когда запрашивается память, генерируется SIGSEGV, который я прослушиваю с помощью вызова signal().

Как только SIGSEGV был обнаружен, мне нужно каким-то образом получить доступ к указателю на запрошенную память (который вызвал ошибку) и размеру запрошенного сегмента.Возможно ли это?

void fifoSigHandler(){

    // Needs to only remove protection from requested block of virtual memory
    mprotect(fifoVm,(size_t)fifoVm_size,PROT_WRITE);
    printf("Caught Seg Fault");
}

void fifo_init(void* vm, int vm_size, int n_frames, int page_size)
{
    fifoVm = vm;
    fifoVm_size = vm_size;
    fifoFrames = n_frames;
    fifoPageSize = page_size;

    mprotect(fifoVm,(size_t)fifoVm_size,PROT_NONE);

    signal(SIGSEGV, fifoSigHandler);
}

Кроме того, есть ли способ определить уровень mprotect(), которому в данный момент назначен блок памяти (PROT_NONE, PROT_READ и т.д.)?

Это было полезно?

Решение

Вы должны использовать sigaction с участием SA_SIGINFO вместо signal установить ваш обработчик, а затем вы получите обратно с полезной информацией в siginfo_t, включая si_addr.

si_addr, как объяснено в sigaction(2), будет содержать адрес. Что касается длины, ну, вам не повезло, если вы не готовы разбирать инструкции. Лучшее, что вы можете сделать, это принять меры для страницы, представленной в si_addr, А потом если этого недостаточно, вы получите еще один сигнал достаточно скоро. По крайней мере, вот как мы сделали вещи в ObjectStore.

Другие советы

Вы ищете libsigsegv http://libsigsegv.sourceforge.net/

Но остерегайтесь этого призвания mprotect безопасен для передачи сигналов только в Linux, другие системы POSIX могут не поддерживать это.

Я боюсь, что в Linux единственный способ получить биты защиты памяти - это прочитать в /proc/$pid/meminfo

На заметку (только для Linux):Если вы беспокоитесь о потреблении памяти и намерены включать страницы большего отображения одну за другой, я бы посоветовал создать свое отображение с помощью mmap с MAP_NORESERVE в этом случае вы получите сопоставление со страницами копирования при записи, заполненными нулем, которые будут выделять физическую оперативную память при первой записи. MAP_NORESERVE указывает ядру не создавать резервную копию вашей памяти с помощью пространства подкачки, позволяя вам выделить до 64 ТБ виртуального адресного пространства.Единственным недостатком является то, что если у вас действительно закончится память, могут произойти ужасные вещи (оом-убийца).

Шаг 1: Init a. sigaction:

struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
sigemptyset(&act.sa_mask);
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;

Шаг 2: Сделай это sigaction ручка SIGSEGV:

sigaction(SIGSEGV, &act, NULL);

(Необязательный) Шаг 3: Сделайте его обрабатывать другие сигналы памяти тоже:

sigaction(SIGBUS, &act, NULL);
sigaction(SIGTRAP, &act, NULL);

Добавить обработку ошибок по мере необходимости

Шаг 4.: Определите функцию обработчика:

void handler(int signal, siginfo_t* siginfo, void* uap) {
    printf("Attempt to access memory at address %p\n", 
           siginfo->si_addr);
    #ifdef LINUX_64BIT
    printf("Instruction pointer: %p\n",
           (((ucontext_t*)uap)->uc_mcontext.gregs[16]));
    #elif LINUX_32BIT
    printf("Instruction pointer: %p\n",
           (((ucontext_t*)uap)->uc_mcontext.gregs[14]));
    #endif
}

Вы можете обратиться к страницам человека для ucontext_t а также siginfo_t Для более интересных данных ваш обработчик может извлечь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top