2011-01-22 3 views

ответ

10

EDIT: Мой первоначальный ответ не будет печатать из произвольной нити. Я с тех пор написал надлежащую реализацию в моем проекте обработчика аварии: https://github.com/kstenerud/KSCrash

В частности, эти файлы:

С некоторой помощью:

Что вы делаете:

  • Сделать новый контекст машина структуру (_STRUCT_MCONTEXT)
  • Заполните в своем состоянии стека с помощью thread_get_state()
  • Получить счетчик программы (первая запись трассировки стека) и указатель кадра (все остальное)
  • Пройдите через стек стека, на который указывает указатель кадра, и сохраните всю инструкцию a ddresses в буфере для последующего использования.

Обратите внимание, что перед этим следует приостановить поток, иначе вы сможете получить непредсказуемые результаты.

кадр стека заполняется структуры, содержащие два указателя:

  • Указатель на следующий уровень в стеке
  • адрес команды

Таким образом, вы должны принять это во внимание при идя по кадру, чтобы заполнить трассировку стека. Также есть возможность испорченного стека, приводящего к плохой указатель, которая приведет к сбою вашей программы. Вы можете обойти это, скопировав память, используя vm_read_overwrite(), который сначала запрашивает ядро, если он имеет доступ к памяти, поэтому он не сбой.

Как только у вас есть трассировка стека, вы можете просто вызвать backtrace() на нем, как обычно (обработчик аварии должен быть асинхронным, поэтому он реализует свой собственный метод обратной линии, но в нормальных случаях backtrace() в порядке) ,

+0

Обратите внимание, что вы должны приостановить поток во время чтения его стека. – Albert

+0

Кроме того, вы уверены, что это работает? Он использует '__builtin_frame_address', который всегда находится в потоке ** current **. – Albert

+0

Так получилось, что это действительно не работает (он печатает трассировку стека, но я не понимал, что это была печать из текущего потока). У меня есть новый код, который работает по назначению, но он еще не готов к выпуску. Я опубликую обновление после его готовности. – Karl

3

Вот еще один более безопасный способ получить стоп-колл из другого потока: Implementation и some background information. Он использует обработку сигналов и порождает обработчик сигналов в целевом потоке. Преимущество заключается в том, что он является более кросс-платформенным, чем ваше решение, т. Е. Он должен работать где угодно, где у вас есть <signal.h> и <execinfo.h>.

Для печати вы можете использовать backtrace_symbols, как и в своем собственном предложении. Но вам может быть интересна расширенная версия, которая реализована как here.Он использует libbfd (от binutils; последняя версия также в основном работает на MacOSX, см. here для небольшого ограничения, которое может вам не подходит), чтобы прочитать информацию об отладке и добавить номер строки и другую информацию (она также возвращается к dladdr если все остальное терпит неудачу, то есть то, что делает backtrace_symbols).

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