2015-08-28 7 views
1

Итак, я отлаживаю программу, которая таинственно вылетает через SIGSEGV. Программа однопоточная.Интерпретация причины segfault с помощью GDB nexti

Я отлаживал много segfaults раньше - большинство из них приходят вниз, чтобы стека или куча коррупции. Обычно легко отлаживать проблемы с кучей коррупции с помощью valgrind. Повреждение стека более сложное, но обычно вы можете сказать, что повреждение стека является проблемой, когда GDB показывает, что ваш стек искажен.

Но здесь я столкнулся с очень странной проблемой, которую я никогда раньше не видел. Используя GDB, чтобы перейти к инструкции по инструкции, я вижу, что segfault происходит сразу после инструкции callq. Кроме этого callq адреса динамически не загружаются из регистра или из памяти - это просто статического адрес функции:

(gdb) ni 
0x00007ffff659c423  223   setPolicyDocumentLoader(docLoader); 
1: x/i $pc 
=> 0x7ffff659c423 <WebCore::FrameLoader::init()+351>: mov %rdx,%rsi 
(gdb) 
0x00007ffff659c426  223   setPolicyDocumentLoader(docLoader); 
1: x/i $pc 
=> 0x7ffff659c426 <WebCore::FrameLoader::init()+354>: mov %rax,%rdi 
(gdb) 
0x00007ffff659c429  223   setPolicyDocumentLoader(docLoader); 
1: x/i $pc 
=> 0x7ffff659c429 <WebCore::FrameLoader::init()+357>: 
    callq 0x7ffff53a2d50 <_ZN7WebC[email protected]plt> 
(gdb) ni 

Program received signal SIGSEGV, Segmentation fault. 
0x0000000000683670 in ??() 
1: x/i $pc 
=> 0x683670: add %al,(%rax) 
(gdb) 

Таким образом, как только он выполняет callq по адресу 0x7ffff53a2d50, он вдруг ошибка сегментации.

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

Но я все же думал, что стоит задать этот вопрос, потому что это принципиально даже не имеет для меня никакого смысла. Как это возможно возможно для ОС для доставки SIGSEGV, когда программа выполняет команду callq для законного статически определяется адрес функции?

+2

'ni' шагает по' call'. Ошибка в другом месте, глубже. Вместо этого вы должны использовать 'si' для входа в вызываемую функцию. – Jester

ответ

3

nexti выполнит следующую команду, но если инструкция является call, то она выполняется до тех пор, пока функция не вернется. Из GDB manual:

Nexti, Nexti ARG, щ

Выполнить одну машинную инструкцию, но если это вызов функции, продолжать до возврата. Аргумент - это количество повторов, как в следующем.

Когда вы делаете callq отладчик, называемый в этой функции, но затем падает где-то во время выполнения этой функции. Если вы хотите войти в вызов функции, я бы рекомендовал stepi, когда вы нажмете callq 0x7ffff53a2d50

0

, как только он выполняет callq по адресу 0x7ffff53a2d50, он внезапно исчезает.

Это обычно вызвано переполнением стека.

Ищите глубокую рекурсию (с использованием команды where). Также посмотрите на область вашего стека (содержащую текущее значение $rsp) на выходе от info proc map.

+0

Но не будет ли переполнение стека только инициировать segfault в команде 'push'?Команда вызова фактически не увеличивает размер стека или перемещает указатель стека – Siler

+0

Это определенно не переполнение стека через глубокую рекурсию (стек вызовов - всего 7 кадров), и это не переполнение стека из-за нехватки стека - простой эксперимент по размещению переменной в 'main', а затем вычисление размера стека в точке сбоя показывает, что стек меньше 1000 байтов – Siler

+2

@Siler A' CALL' инструкция 'PUSH'es возвращает адрес в стеке и * делает * фактически уменьшает указатель стека. –

Смежные вопросы