Что определяет, куда идет исключение на Cortex-M4? - PullRequest
1 голос
/ 09 апреля 2020

Я борюсь с записью фрейма стека исключений поверх моих локальных / автоматических / стековых переменных.

Я использую FreeRTOS 8.2.1 и Microchip ASF для SAM4L Разработка с Eclipse MCU 2018/09 и Segger J-Link 6.40.

[EDIT]
Первый раз в l oop, r7 имеет другое значение (0x200044D0), которое выглядит как правильное значение (то же, что и SP). Теперь я думаю, что r7 изменяется во время ожидания в очереди сообщений RTOS, что происходит в верхней части l oop (но не в первый раз!)

    for(;;){
        if(WaitTx(MSG_WAIT_TIME)){  calls xQueuePeek(...)
            do{
>> First time here, r7 has the value  0x200044D0
>> Subsequent times, r7 has the value 0x200044B0
                // Keep sending data until no more data 
                MsgBlock_t *tosend = BuildFrame(MSG_MAX_LEN);

                if(tosend){

[/ EDIT ]

У меня есть поток RTOS с верхним уровнем l oop. Две локальные переменные в функции потока становятся забитыми. Устанавливая точку наблюдения для одной из переменных, я вижу, как она запускается при выполнении второй инструкции обработчика прерываний. Дамп памяти показывает, что кадр стека исключений записан в 32 байтах стека потока. Самые низкие 5 суммированных значений соответствуют регистрам r0-r3, r12. Предположительно, остальные 3 соответствуют оригинальному lr, ​​p c и xpsr. Значения выглядят правильно. Код:

          TC02_Handler:
00013f84:   push    {r0, r1, r2, r4, r5, r6, r7, lr}
2141        tc_get_status(TC, BOARD_TC_CH_CMX);
00013f86:   movs    r1, #2            <<< Watchpoint triggers halt here
00013f88:   ldr     r0, [pc, #132]  ; 

Регистры:

r0 = 0x0             == Memory location 0x200044B0
r1 = 0x8             == Memory location 0x200044B4
r2 = 0x0             == Memory location 0x200044B8
r3 = 0x2000aab0      == Memory location 0x200044BC
r4 = 0x2000cd10
r5 = 0x0000cee3
r6 = 0x200044b0
r7 = 0x200044b0
r8-r11 all 0xa5a5a5a5  (RTOS fills stack with this value at startup)
r12= 0x6             == Memory location 0x200044C0
sp = 0x2000e3f8      (nowhere near where exception frame was stacked)
lr = 0xfffffffd

Память:

0x200044B0: 00000000 00000008 00000000 2000AAB0
0x200044C0: 00000006 0000CECB 0000CECC 01000000 
---
0x2000E3F8: 00000000 00000008 00000000 2000CD10
0x2000E408: 0000CEE3 200044B0 200044B0 FFFFFFFD

Я не понимаю, что когда точка наблюдения срабатывает при входе для обработчика указатель стека указывает на совершенно другое место. Кадр стека исключений записывается в местоположения с 0x200044B0 по 0x200044CF, но указатель стека (после того, как точка наблюдения останавливает микро) имеет значение 0x2000E3F8.

Первая инструкция обработчика исключений отправляет r0-r2, r4-r7 и лр. Эти значения помещаются в ячейку стека, на которую указывает sp в 0x2000E3F8 - 0x2000E417

Должен ли указатель стека указывать на нижнюю часть кадра стека исключений при входе в обработчик исключений?

Некоторые другие подсказки, которые могут иметь отношение

  • Отладчик ищет неправильный адрес для этих автоматических c переменных. Отладчик «думает», что мои переменные должны находиться в местах 200044E4 и 200044E8.

  • Когда код получает к ним доступ, они загружаются из местоположений 200044C0 и 200044C4. Доступ к ним осуществляется как смещение от r7.

ldr r0,[r7,#16]  (r7 is 0x200044B0).
and 
ldr r0,[r7,#20]  (r7 is 0x200044B0).

  • Во время выполнения поврежденного потока указатель стека имеет значение 0x200044d0, но r7 (который, я думаю, используется как «указатель кадра» ") имеет значение 0x200044b0. Кадр стека исключений размещен правильно в соответствии со значением sp.

Спасибо

1 Ответ

1 голос
/ 15 апреля 2020

Чтобы ответить на мой собственный вопрос, начальный кадр стека направляется непосредственно в стек текущего потока, а ОСРВ может переключиться на отдельный стек прерываний.

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

Я не уверен, было ли это пасхальным чудом, или если следовал совету всех ИТ-гуру решили это (вы пытались выключить и снова включить?). В любом случае, проблема волшебным образом исчезла после перезагрузки моего P C, и я не смог воспроизвести его. Мое единственное предположение, что отладчик оставил некоторый код в fla sh, о котором он «забыл». В любом случае, теперь все решено.

Спасибо за поиск.

...