Как отладить ошибку сегментации, когда трассировка стека GDB полна '??'? - PullRequest
13 голосов
/ 10 марта 2010

Мой исполняемый файл содержит таблицу символов. Но похоже, что трассировка стека переписана.

Как получить больше информации из этого ядра, пожалуйста? Например, есть ли способ проверить кучу? Посмотрите экземпляры объектов, заполняющие кучу, чтобы получить некоторые подсказки. Как бы то ни было, любая идея ценится.

Ответы [ 8 ]

14 голосов
/ 10 марта 2010

Я зарабатываю на C ++ и сталкиваюсь с этой проблемой чаще, чем хочу признаться. Ваше приложение разбивает ОГРОМНУЮ часть стека. Скорее всего, функция, которая портит стек, также дает сбой при возврате. Причина в том, что адрес возврата был перезаписан, и именно поэтому трассировка стека GDB испорчена.

Вот как я отлаживаю эту проблему:

1) Пройдите через приложение, пока оно не выйдет из строя. (Ищите функцию, которая падает при возврате).

2) Как только вы определили функцию, объявите переменную в ОЧЕНЬ ПЕРВОЙ ЛИНИИ функции:

int canary=0;

(Причина, по которой это должна быть первая строка, заключается в том, что это значение должно быть в самой верхней части стека. Этот «канарейка» будет перезаписан до адреса возврата функции.)

3) Установите переменную watch на canary, шагните через функцию и когда canary! = 0, тогда вы обнаружили переполнение буфера! Еще одна возможность - установить переменную точку останова для canary! = 0 и просто запустить программу нормально, это немного проще, но не во всех точках останова переменных поддержки IDE.

РЕДАКТИРОВАТЬ: Я говорил со старшим программистом в моем офисе, и чтобы понять дамп ядра, вам нужно разрешить адреса памяти, которые у него есть. Один из способов выяснить эти адреса - посмотреть на двоичный файл MAP, который удобочитаем для человека. Вот пример создания файла MAP с использованием gcc:

gcc -o foo -Wl,-Map,foo.map foo.c

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

4 голосов
/ 11 марта 2010
  1. Вы должны использовать какой-то отладчик для обнаружения, с valgrind все в порядке
  2. пока вы компилируете свой код, убедитесь, что вы добавили опцию -Wall, это заставит компилятор сообщать вам, если есть какие-то ошибки или нет (убедитесь, что в вашем коде есть предупреждение).

напр .: gcc -Wall -g -c -o oke.o oke.c
3. Убедитесь, что у вас также есть опция -g для получения отладочной информации. Вы можете вызвать отладочную информацию с помощью некоторых макросов. Следующие макросы очень полезны для меня:

__LINE__: говорит вам строку

__FILE__: сообщает исходный файл

__func__: сообщает функцию

  1. Использование отладчика недостаточно, я думаю, вы должны привыкнуть к максимизации возможностей компилятора.

Надеюсь, это поможет

2 голосов
/ 13 июня 2012

TL; DR: в стеке размещаются очень большие объявления локальных переменных в функциях, которые при определенных сочетаниях платформы и компилятора могут переполнить и повредить стек.

Просто чтобы добавить еще одну потенциальную причину этой проблемы. Недавно я отлаживал очень похожую проблему. Запуск gdb с приложением и файлом ядра даст такие результаты, как:

Core was generated by `myExecutable myArguments'.
Program terminated with signal 6, Aborted.
#0  0x00002b075174ba45 in ?? ()
(gdb)

Это было крайне бесполезно и неутешительно. После нескольких часов поиска в Интернете я нашел форум, на котором говорилось о том, что используемый нами компилятор (компилятор Intel) имеет меньший размер стека по умолчанию, чем другие компиляторы, и что большие локальные переменные могут переполнить и повредить стек. Глядя на наш код, я нашел виновника:

void MyClass::MyMethod {
   ...
   char charBuffer[MAX_BUFFER_SIZE];
   ...

}

Бинго! Я обнаружил, что MAX_BUFFER_SIZE был установлен на 10000000, таким образом, локальная переменная размером 10 МБ выделялась в стеке! После изменения реализации на использование shared_ptr и динамического создания буфера, внезапно программа запустилась работает отлично.

1 голос
/ 10 марта 2010

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

Однако сам факт, что ваш стек поврежден, говорит о том, что вам нужно искать код, который записывает в стек.

  • Перезапись стекового массива. Это можно сделать очевидным способом или путем вызова функции или системного вызова с аргументами неверного размера или указателями неправильного типа.
  • Использование указателя или ссылки на локальные переменные стека функции после возврата этой функции.
  • Приведение указателя к значению стека к указателю неправильного размера и его использование.

Если у вас есть система Unix, «valgrind» является хорошим инструментом для поиска некоторых из этих проблем.

1 голос
/ 10 марта 2010

Для подтверждения, был ли ваш исполняемый файл скомпилирован в режиме выпуска, то есть без отладочных символов .... это может объяснить, почему есть ??Попробуйте перекомпилировать с ключом -g, который «включает в себя информацию отладки и встраивать ее в исполняемый файл». Кроме этого, у меня нет идей, почему у вас есть «??» ...

1 голос
/ 10 марта 2010

Попробуйте запустить с отладчиком памяти Valgrind.

0 голосов
/ 31 мая 2010

Похоже, вы не используете на своей машине ту же версию glibc, что и основной файл, когда он зависал на производстве. Получите вывод файлов с помощью «ldd ./appname» и загрузите их на свой компьютер, затем скажите gdb, где искать;

set solib-absolute-prefix /path/to/libs
0 голосов
/ 10 марта 2010

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

Мы можем только подтвердить это: строки -a | grep имя_функции_you_know_should_exist

Также попробуйте использовать pstack на ядре, и посмотрите, лучше ли справляется с захватом стека вызовов. В этом случае кажется, что ваш gdb устарел по сравнению с вашей версией gcc / g ++.

...