2010-04-24 5 views
4

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

После обнаружения 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, и т.д ..)?

ответ

5

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

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

+2

Как мы ссылаемся на эту полезную информацию? В частности, указатель и размер запрашиваемой памяти – pws5068

1

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

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

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

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

0

Шаг 1: Init 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 для более интересных данных обработчика можно извлечь.