Rust Embedded panic уничтожает стек

Я использую Rust на Cortex-M4 и использую gdb с openocd для его отладки.

Из C (++) я привык смотреть на стек вызовов, когда происходит исключение (например, аппаратный сбой). Очень полезно увидеть, какая строка вызвала исключение.

Однако в Rust, когда случается паника, стек вызовов почти пуст. Почему это происходит?

Есть ли способ заставить Rust сохранять стек (только для отладчика, мне не нужно его распечатывать)? Или я могу вставить точку останова где-нибудь, где стек вызовов еще не был уничтожен?

Прямо сейчас у меня есть где-то разворачивание, которое вызывает панику, но я не могу найти где, если не прохожу через весь код.


РЕДАКТИРОВАТЬ: это трассировка стека, которую я получаю в обработчике паники:

i stack
#0  rust_begin_unwind (info=0x2001f810) at src\main.rs:122
#1  0x080219dc in cortex_m::itm::write_fmt (port=0x2001f820, args=...) at C:\Users\d.dokter\.cargo\registry\src\github.com-1ecc6299db9ec823\cortex-m-0.6.1\src/itm.rs:128
#2  0x2001f894 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

Также странно, что функция write_fmt находится в стеке, поскольку она вызывается внутри обработчика для регистрации паники. Я также считаю, что адрес 0x2001f894 очень подозрительный, потому что это адрес ОЗУ.


person Geoxion    schedule 04.12.2019    source источник
comment
Вы используете параллелизм / многопоточность? Когда вы это сделаете, обработчик исключений переключится на системный стек, поэтому стек прерванного потока больше не будет виден. Это верно и для C и C ++, но, возможно, в этом случае вы не использовали потоки? Разработчик . arm.com/docs/dui0553/a/the-cortex-m4-processor/   -  person Clifford    schedule 04.12.2019
comment
@Clifford Нет, используется только msp, а psp всегда остается на 0   -  person Geoxion    schedule 04.12.2019
comment
Я исправил проблему, которая вызвала панику, но поиск места, где это произошло, занял намного больше времени, чем следовало бы ... Оказывается, я где-то забыл чек   -  person Geoxion    schedule 04.12.2019


Ответы (1)


Самое простое решение - настроить обработчик паники на вызов abort() вместо раскручивания стека. Это можно сделать, добавив это в свой Cargo.toml

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"

С этой настройкой обработчик паники немедленно вызовет abort(), поэтому gdb все еще может видеть всю трассировку.

Если вы просто хотите распечатать трассировку стека, вы также можете установить переменную среды RUST_BACKTRACE=1.

person Sven Marnach    schedule 04.12.2019
comment
Я вижу, как это поможет в нормальной обстановке. Но я использую это встроенное ПО, и оно компилируется только при наличии специального обработчика паники. К сожалению, эти настройки не действуют. rust-embedded.github.io/book/start/panicking.html - person Geoxion; 04.12.2019
comment
@Geoxion В этом случае вы должны установить точку останова в начале вашего пользовательского обработчика паники. Gdb может показать вам трассировку только в том случае, если вы позволите ему посмотреть до того, как стек будет размотан. - person Sven Marnach; 04.12.2019
comment
Ну в том-то и дело. Если я сломаю обработчик, будь то в начале или в конце, я не получу хороший стек. Что-то случилось с ним до вызова обработчика. - person Geoxion; 04.12.2019
comment
@Geoxion На странице, которую вы связали, говорится, что вы должны установить точку останова на rust_begin_unwind. Это то, что ты сделал? - person Sven Marnach; 04.12.2019
comment
да. Хотя, если я сделаю это через cli, у меня будет другой стек вызовов. Сверху находится rust_begin_unwind, а после этого бесконечное количество core::panicking::panic_fmt. Немного покопавшись в этом, я теперь знаю, что если я поставлю точку останова на core::result::unwrap_failed, я все равно получу полный стек вызовов. Теперь заглянем в исходный код, чтобы увидеть, что происходит между ними. - person Geoxion; 04.12.2019