Я пишу некоторый код для отладки стека сопрограмм, которые используют Boost.Context’s make_fcontext
а также jump_fcontext
и столкнулись с небольшой проблемой.
Обычно это невозможно backtrace
мимо записи стековой сопрограммы, поскольку она выполняется в своем собственном стеке. Это означает, что я не могу определить из отладчика, откуда была введена сопрограмма. Это, однако, не та проблема, о которой я спрашиваю. Я уже решил эту проблему, добавив некоторую встроенную сборку и байт-код DWARF в функцию, которую я передаю make_fcontext
:
__asm__ volatile (
"mov %[caller_fcontext_t] %[somewhere]\n\t"".cfi_escape /* DWARF bytecode to load caller_fcontext_t from "" * somewhere and use it to load all the registers saved "" * there by jump_fcontest */""call %[another_function]": /* stuff */ : /* stuff */ : /* stuff */)
Это действительно работает, и теперь я могу backtrace
до точки в вызывающей стороне, где он начинает или возобновляет внутреннюю сопрограмму — но только иногда.
Оказывается, у GDB есть «проверка работоспособности»: если указатель стека перемещается в «неправильном» направлении между кадрами вызова, GDB предполагает, что стек поврежден и останавливает трассировку с сообщением »Backtrace stopped: previous frame inner to this frame (corrupt stack?)
».
Это срабатывает, когда мои стеки распределены определенным образом, но не другими способами. У меня даже есть тест со статически распределенными стеками, который вызывает этот сбой при использовании в прямом порядке, но не при использовании в обратном порядке.
Я даже нашел часть исходного кода GDB, которая выполняет эту проверку здесь: https://github.com/bminor/binutils-gdb/blob/master/gdb/frame.c#L737-L816
Теперь вот мой актуальный вопрос: Как я могу это исправить?
Могу ли я написать какое-нибудь заклинание сборки, которое говорит GDB «поверь мне, я знаю, что делаю»?
Теперь вот мой актуальный вопрос: как я могу это исправить?
Могу ли я написать какое-нибудь заклинание сборки, которое говорит GDB «доверие
я знаю, что я делаю «?
Там в настоящее время нет способа сделать это. Это было бы хорошей идеей, но, вероятно, потребовало бы некоторого расширения DWARF. Таким образом, это может быть сложно реализовать.
Вы можете увидеть доказательства этого в источниках GDB: у GCC была похожая проблема, связанная с -fsplit-stack
, и это было обойдено путем простого кодирования имени вызывающей функции в gdb:
if (!morestack_name || strcmp (morestack_name, "__morestack") != 0)
Быстрый обходной путь для личного использования — просто закомментировать раннее возвращение сюда.
Других решений пока нет …