2010-12-09 3 views
0

Я планирую создать механизм журналирования/трассировки, который записывает адрес (const char*) строковых литералов в кольцевой буфер. Эти строки находятся в сегменте данных только для чтения и создаются препроцессором с __function__ или __file__.После Segfault: Есть ли способ проверить, сохраняется ли указатель?

Вопрос: Возможно ли проанализировать содержимое этого кольцевого буфера после Segfault, если все указатели действительны? С «valid» я имею в виду, что они указывают на отображаемую область памяти, а разыменование не приведет к сбою сегментации.

Я работаю с Linux 2.6.3x и GCC 4.4.x.

С наилучшими пожеланиями,

Charly

ответ

1

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

Предполагая, что, что нет никаких проблем со стеком или другой памяти, что вы полагаться на, и при условии, что вы не вызывает никаких функций, таких как malloc(), которые не являются async-signal safe, и при условии, что вы не пытаетесь вернуться из вашего сигнала обработчика, тогда не должно быть проблем с чтением или записью вашего буфера из вашего обработчика сигнала.

Если вы пытаетесь проверить, действителен ли конкретный адрес, вы можете использовать системный вызов, например mincore(), и проверить на предмет ошибки.

0

После того, как вы получили Segfault, все ставки выключены. Указатели могут быть действительными или могут быть повреждены. Ты просто не знаешь. Возможно, вы сможете сравнить их с допустимыми значениями или указатель на кольцевой буфер, возможно, был поврежден. В этом случае вы, вероятно, получите мусор.

2

Я думаю, что подход, который вы ищете, - это обработать сигнал SIGSEGV через sigaction.

void handler(int, siginfo_t *info, ucontext_t *uap) 
{ 
    /* Peek at parameters here... I'm not sure exactly what you want to do. */ 
} 

/* Set up the signal handler... */ 

struct sigaction sa, old_sa; 
memset(&sa, 0 sizeof(sa)); 

sa.sa_sigaction = handler; 
sa.sa_flags = SA_SIGINFO; 

if (sigaction(SIGSEGV, &sa, &old_sa)) 
{ 
    /* TODO: handle error */ 
} 

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

Если вы хотите, чтобы он был более стабильным, существует вызов sigaltstack, который позволяет указать альтернативный буфер стека, так что если вы полностью заблокировали свой стек, вы все равно сможете обрабатывать SIGSEGV. Для этого вам необходимо установить SA_ONSTACK в sa.sa_flags выше.

Если вы хотите, чтобы ответить на SEGV от безопасности другого процесса (тем самым изолируя себя от плохо ведет себя код segfaulting и сделать это так, чтобы вы не врезаться во время осмотра его), вы можете использовать ptrace. Этот интерфейс сложный, имеет много непереносимых частей и в основном используется для написания отладчиков. Но вы можете делать с ним большие дела, такие как чтение и запись памяти процесса и регистров, а также изменение ее исполнения.

2

Обычный способ проверки того, может ли разыменовать область памяти, приведет к тому, что segfault будет использовать read() или write().Например, чтобы проверить, если первые 128 байт, на который указывает ptr благополучно читаемым:

int fd[2]; 
if (pipe(fd) >= 0) { 
    if (write(fd[1], ptr, 128) > 0) 
     /* OK */ 
    else 
     /* not OK */ 
    close(fd[0]); 
    close(fd[1]); 
} 

(write() вернется EFAULT, а не поднимая сигнал, если область не читается).

Если вы хотите протестировать более PIPE_BUF байт за раз, вам нужно будет прочитать и выбросить со стороны чтения трубы.

+0

Хммм ... Я застрял, что запись в обычный файл или fifo отлично работает - при записи в/dev/null всегда записывается 128 байтов - независимо от правильности указателя ... – Charly 2011-02-17 12:26:25