2016-08-02 6 views
-1

Я пытаюсь найти, где в моем коде произошло определенное прерывание. В этом случае он находится на микроконтроллере stm32f4, а прерывание - SysTick_Handler.найти, где прерывание произошло на cortex-m4

Что я хочу, это в основном выяснить, откуда произошло прерывание сигнала. Я использую рычажного ни-EABI-GDB, чтобы попытаться найти трассировку, но только информация, я получаю оттуда:

(gdb) bt 
#0 SysTick_Handler() at modules/profiling.c:66 
#1 <signal handler called> 
#2 0x55555554 in ??() Backtrace stopped: previous frame identical to this frame (corrupt stack?) 

Как я могу получить информацию о том, где программа была до выстрелил прерывания ?

Глядя на документацию на руку here, кажется, я должен быть в состоянии прочитать указатель стека и получить оттуда компьютер. Но тогда это именно то, что делает размотчик в GDB, не так ли?

+0

Был ли прерванный код запущен с основным стеком? Если он работает с стеком процессов, то вы разматываете неправильный (поскольку режим Handler всегда использует MSP). В соответствии с документами, которые вы связали, соответствующий стек закодирован в значение EXC_RETURN. – Notlikethat

+0

Да, я заметил, теперь у меня есть код в SysTick_Handler, который фактически считывает правильный ПК с того места, где я был в последний раз.Тем не менее, это плохо, что GDB не работает правильно. – Kristoffer

+0

Вы можете написать макросы 'gdb' для этого. MSP является специфичным для кортикации, и GDB написан для работы на разных платформах и в основном касается пользовательских приложений. Тем не менее, это открытый исходный код, и я уверен, что взносы приветствуются. –

ответ

0

Как многие из вас прокомментировали, ПК будет в двух разных стеках, так как я решил, что на самом деле нашел код HardFault_Handling в сборке и взял то, что мне нужно оттуда. Чтобы правильно получить значение ПК, я использую следующий код.

register int *r0 __asm("r0"); 

__asm( "TST lr, #4\n" 
     "ITE EQ\n" 
     "MRSEQ r0, MSP\n" 
     "MRSNE r0, PSP\n" // stack pointer now in r0 
     "ldr r0, [r0, #0x18]\n" // stored pc now in r0 
     //"add r0, r0, #6\n" // address to stored pc now in r0 
    ); 

Значение где happended прерывание теперь могут быть доступны

uint32_t PC = *r0; 

и теперь могут быть использованы для то, что я хочу. К сожалению, мне не удалось заставить GDB автоматически раскрутить стек. Но, по крайней мере, я узнал, где прерывается стрельба, что было целью.

-2

Это называется DEBUGGING. Самый простой способ начать - просто вставить кучу вызовов printf() здесь и там по всему коду. Запустите программу. Если он печатает:

получил в точку А
получил в точку Б
получил в точку С

и умирает, то вы знаете, что умер от «C» и «D» Теперь вы можете уточнить это, украсив код между «C» и «D» более близко расположенными вызовами printf().

Это лучший способ начинающего начинающего. Многие опытные эксперты также предпочитают printf() для отладки. Отладчики могут мешать.

+4

Это не помогает, так как моя программа не сбой, У меня нет printf, и я специально хочу знать, где произошло прерывание от – Kristoffer

1

Вы были на правильном пути в конце своего вопроса. В ядрах ARM Cortex-M есть два указателя стека, указатель главного стека (MSP, используемый для прерываний) и указатель стека процесса (PSP, используемый для задач).

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

Когда вы впервые вводите прерывание, регистр ссылок (LR, обратный адрес) будет иметь значение, которое в основном является F, а не фактическим адресом возврата. Это значение указывает ядру, как выйти с разветвленной. Как правило, вы увидите значение 0xFFFFFFFD, если фоновая задача была прервана, или 0xFFFFFFF1, если прерывание с более низким приоритетом было прервано. Эти значения будут отличаться, если вы используете блок с плавающей точкой. Магия в этом значении, однако, заключается в том, что бит 2 (0x4) сообщает вам, находится ли ваш стек стека на PSP или MSP.

Как только вы определяете, в какой стек включен ваш кадр, вы можете найти адрес, из которого вы выполняете, указав соответствующий указатель стека минус 24 (6 32-разрядных местоположений). См. Рисунок 2.3 в вашей ссылке. Это укажет вам на ПК, с которого вы были прерваны.

1

Мы продолжаем видеть этот вопрос в разных формах, и люди продолжают говорить, что есть два стека. Поэтому я попробовал это сам с помощью systick.

В документации сказано, что мы находимся в режиме потока из сброса, и если вы остановить с OpenOCD он говорит, что

target halted due to debug-request, current mode: Thread 

У меня есть некоторый код, чтобы вывести регистры:

20000000 APSR 
00000000 IPSR 
00000000 EPSR 
00000000 CONTROL 
00000000 SP_PROCESS 
20000D00 SP_PROCESS after I modified it 
20000FF0 SP_MAIN 
20000FF0 mov r0,sp 
then I dump the stack up to 0x20001000 which is where I know my stack started 
20000FF0 00000000 
20000FF4 00000000 
20000FF8 00000000 
20000FFC 0100005F 

I установки и дождитесь прерывания systick, обработчик выгружает регистры и RAM, а затем переходит в бесконечный цикл. плохая практика в целом, но просто отладка/обучение здесь. Перед прерыванием я приготовительному некоторые регистры:

.thumb_func 
.globl iwait 
iwait: 
    mov r0,#1 
    mov r1,#2 
    mov r2,#3 
    mov r3,#4 
    mov r4,#13 
    mov r12,r4 
    mov r4,#15 
    mov r14,r4 
    b . 

и в обработчике я вижу

20000000 APSR 
0000000F IPSR 
00000000 EPSR 
00000000 CONTROL 
20000D00 SP_PROCESS 
20000FC0 SP_MAIN 
20000FC0 mov r0,sp 
20000FC0 0000000F 
20000FC4 20000FFF 
20000FC8 00000000 
20000FCC FFFFFFF9 this is our special lr (not one rjp mentioned) 
20000FD0 00000001 this is r0 
20000FD4 00000002 this is r1 
20000FD8 00000003 this is r2 
20000FDC 00000004 this is r3 
20000FE0 0000000D this is r12 
20000FE4 0000000F this is r14/lr 
20000FE8 01000074 and this is where we were interrupted from 
20000FEC 21000000 this is probably the xpsr mentioned 
20000FF0 00000000 stuff that was there before 
20000FF4 00000000 
20000FF8 00000000 
20000FFC 0100005F 


01000064 <iwait>: 
1000064: 2001  movs r0, #1 
1000066: 2102  movs r1, #2 
1000068: 2203  movs r2, #3 
100006a: 2304  movs r3, #4 
100006c: 240d  movs r4, #13 
100006e: 46a4  mov ip, r4 
1000070: 240f  movs r4, #15 
1000072: 46a6  mov lr, r4 
1000074: e7fe  b.n 1000074 <iwait+0x10> 
1000076: bf00  nop 

Таким образом, в этом случае, прямо из документации ARM, она не использует sp_process он использует sp_main , Он толкает элементы, о которых говорится в руководстве, в том числе о прерванном/обратном адресе, который равен 0x1000074.

Теперь, если я устанавливаю бит SPSEL (прежде всего, сначала установите PSP), кажется, что mov r0, sp в режиме приложения/потока использует PSP, а не MSP. Но тогда обработчик использует ПМП для мов r0, зр, но, как представляется, поставить

ранее в потоке/переднего плана

20000000 APSR 
00000000 IPSR 
00000000 EPSR 
00000000 SP_PROCESS 
20000D00 SP_PROCESS modified 
00000000 CONTROL 
00000002 CONTROL modified 
20000FF0 SP_MAIN 
20000D00 mov r0,sp 

сейчас в обработчике

20000000 APSR 
0000000F IPSR 
00000000 EPSR 
00000000 CONTROL (interesting!) 
20000CE0 SP_PROCESS 
20000FE0 SP_MAIN 
20000FE0 mov r0,sp 
dump of that stack 
20000FE0 0000000F 
20000FE4 20000CFF 
20000FE8 00000000 
20000FEC FFFFFFFD 
20000FF0 00000000 
20000FF4 00000000 
20000FF8 00000000 
20000FFC 0100005F 
dump of sp_process stack 
20000CE0 00000001 
20000CE4 00000002 
20000CE8 00000003 
20000CEC 00000004 
20000CF0 0000000D 
20000CF4 0000000F 
20000CF8 01000074 our return value 
20000CFC 21000000 

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

Я не использую gdb, но вам нужно заставить его сбросить все регистры sp_process и sp_main, тогда в зависимости от того, что вы найдете, а затем выгрузите дюжину слов в каждом, и там вы должны увидеть 0xFFFFFFFx как маркер затем обратный отсчет от этого, чтобы увидеть обратный адрес. Вы можете заставить обработчик прочитать два указателя стека, а затем вы можете посмотреть на gprs. С ассемблером gnu mrs rX, psp; mrs rX, msp; Для указателей процесса и основного стека.

+0

. Обратите внимание, что это cortex-m4 в стартовой панели ti msp432. У меня есть другие, но это было достаточно хорошо, чтобы продемонстрировать, что вы, возможно, не обязательно имеете дело с двойным стеке, esp, если вы не создали альтернативный стек. –