Как безопасно сбросить память рядом с попаданием в обработчик SIGSEGV.C, Linux - PullRequest
0 голосов
/ 03 июня 2018

Мне нужно напечатать память рядом с местом, где происходит сбой программы (SIGSEGV), но факт заключается в том, что когда я пытаюсь распечатать эту память, я снова могу вызвать SIGSEGV.

void handler_SIGSEGV(int signal, siginfo_t *data, void *extra_data) {

for (size_t* mem = (size_t*) (data->si_addr - 5); mem < (size_t*) (data->si_addr + 5); mem++){
    printf("%zx\n", *mem);   // call new SIGSEGV
   }

    exit(1);
}

Как я понял в обработчике, я могу использовать volatile sig_atomic_t переменные, чтобы указать, что сигнал уже сработал.

volatile sig_atomic_t isRecall = 0;

void handler_SIGSEGV(int signal, siginfo_t *data, void *extra_data) {

    if (isRecall == 1){
        //second call
    }

    printf("Call - %d\n", isRecall);
    isRecall = 1;
....

Но когда сигнал SIGSEGV вызывается снова, моя функция handler_SIGSEGV непозвонил по какой-то причине.

Почему это происходит?И как мне реализовать такой вывод памяти?

1 Ответ

0 голосов
/ 03 июня 2018

si_addr - это адрес памяти, вызвавший ошибку.Чтение содержимого может быть невозможно, если адрес выходит за пределы или процесс не имеет доступа для чтения.Например, это может быть 0, если нулевой указатель был разыменован.

По умолчанию во время обработки сигнала он блокируется, предотвращая вложенные вызовы.Генерация SIGSEGV, пока он заблокирован, приводит к неопределенному поведению (обычно к аварийному завершению).С sigprocmask :

Если SIGBUS, SIGFPE, SIGILL или SIGSEGV генерируются, когда они заблокированы, результат не определен, если только сигнал не был сгенерирован kill (2),sigqueue (3) или повышение (3).

Вы можете продолжить выполнение, установив пару sigsetjmp / siglongjmp или изменив состояние регистров (context->uc_mcontext.gregs), используемыхошибочная инструкция.

...