У меня есть приложение C ++, скомпилированное для Linux, работающее на процессоре ARM CortexA9, которое аварийно завершает работу с исключением SIGFPE / Arithmetic. Сначала я думал, что это из-за некоторых оптимизаций, введенных флагом gcc -O3 , но затем я построил его в режиме отладки, и он все еще вылетает.
Я отладил приложение с помощью gdb, который перехватывает исключение, но, к сожалению, исключение, вызывающее операцию, похоже, также уничтожает стек, поэтому я не могу получить подробную информацию о месте в моем коде, которое вызывает это. Единственная деталь, которую я смог наконец получить, - это операция, вызывающая исключение (из следующего фрагмента стека):
3 raise() 0x402720ac
2 __aeabi_uldivmod() 0x400bb0b8
1 __divsi3() 0x400b9880
__aeabi_uldivmod () выполняет беззнаковое длинное длинное деление и напоминание, поэтому я попробовал подход грубой силы и искал в моем коде места, которые могли бы использовать эту операцию, но без особого успеха, поскольку это оказалось сложная задача. Также я попытался проверить потенциальные деления на ноль, но опять же кодовая база довольно большая, и проверка каждой операции деления - это громоздкий и несколько глупый подход. Таким образом, должен быть более разумный способ выяснить, что происходит.
Существуют ли какие-либо методы для отслеживания причин таких исключений, когда отладчик не может помочь?
ОБНОВЛЕНИЕ: После обработки шестнадцатеричных чисел, сброса памяти и анализа стеков (спасибо Crashworks) я наткнулся на этот камень в документации по компилятору ARM (хотя я не использую компилятор ARM Ltd. ):
Целочисленные ошибки деления на ноль могут быть перехвачены и идентифицированы
повторная реализация соответствующих вспомогательных функций библиотеки C.
Поведение по умолчанию при делении на ноль происходит, когда сигнал
функция используется, или
__rt_raise () или __aeabi_idiv0 () повторно реализованы, __aeabi_idiv0 ()
называется. В противном случае функция деления возвращает ноль.
__aeabi_idiv0 () вызывает SIGFPE с дополнительным аргументом, DIVBYZERO.
Поэтому я установил точку останова на __aeabi_idiv0 (_aeabi_ldiv0) и вуаля !, у меня была полная трассировка стека до того, как я был полностью уничтожен. Спасибо всем за их очень информативные ответы!
Отказ от ответственности: «победивший» ответ был выбран исключительно и субъективно с учетом веса его предложений в моих усилиях по отладке, потому что более одного было информативным и действительно полезным .