2016-08-02 1 views
-1

私のコードで特定の割り込みがどこで発生したのかを調べようとしています。この場合、それはstm32f4マイクロコントローラ上にあり、割り込みはSysTick_Handlerです。私が欲しいものcortex-m4で割り込みがどこで発生したのかを確認します

はのSysTick割り込みが起きた場所から把握することが基本的です。私は、バックトレースを見つけようとするアームなし-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見れ

、私がスタックポインタを読んで、そこからPCを得ることができる必要がありそうです。しかし、これはまさにGDBのアンワインダーがそれをやっているのですか?

+0

中断されたコードがメインスタックで実行されていましたか?プロセススタックで実行していた場合、間違ったものを巻き戻しています(Handlerモードは常にMSPを使用するため)。リンクしたドキュメントごとに、関連するスタックはEXC_RETURN値でエンコードされます。 – Notlikethat

+0

うん、私は今、私が前回の場所から正しいPCを実際に読み取るSysTick_Handlerのコードを持っていることに気づいた。それでも、GDBが正しく巻き戻してくれないことは悪いことです。 – Kristoffer

+0

これを行うには 'gdb'マクロを書くことができます。 MSPはcortex-m固有であり、GDBは多くの異なるプラットフォーム上で動作するように記述されており、主にユーザーアプリケーションに関係しています。それはオープンソースだと私は確信していると確信しています。 –

答えて

0

多くの人がコメントしたように、PCは2つのスタックに分かれています。私が解決したのは、実際にAssemblyでHardFault_Handlingコードを見つけてそこから必要なものを取り出すことでした。 PCの値を正しく取得するには、次のコードを使用しています。

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

を指すようになって死なをB
を指すようになったを知っていますより狭く離れたprintf()呼び出しで "C"と "D"の間のコードを飾ることで、これを下に向けることができます。

これは、初心者のための最善の方法です。多くの経験豊富な専門家は、デバッグのためにprintf()を使用します。デバッガは途中で邪魔になることがあります。

+4

これは私がprintfのを持っていない、と私は特に割り込みが、これはTI msp432ランチパッド内のCortex-M4です – Kristoffer

1

質問の最後に正しい軌道に乗っていました。 ARM Cortex-Mコアには、メインスタックポインタ(割り込み用に使用されるMSP)とプロセススタックポインタ(タスク用に使用されるPSP)の2つのスタックポインタがあります。

現在のレジスタ値(ほとんどのレジスタ)は現在のスタック(バックグラウンドアプリケーションを中断する場合はPSP)に、優先度の低い割り込みを中断した場合はMSPにプッシュされます。スタックがMSPに切り替えられます(まだ存在していない場合)。

あなたが最初の大部分はFのではなく、実際のリターンアドレスの値を持つことになり、割り込み、リンクレジスタ(LR、リターンアドレス)を入力します

。この値は、分岐したときに終了する方法をコアに伝えます。通常、バックグラウンドタスクが中断された場合は 0xFFFFFFFD、低い優先度の割り込みが中断された場合は 0xFFFFFFF1と表示されます。浮動小数点ユニットを使用している場合、これらの値は異なります。しかし、この値の魔法は、ビット2( 0x4)があなたのスタックフレームがPSPかMSPのどちらにあるかを知らせるということです。

あなたのフレームがオンになっているスタックを決定したら、あなたは適切なスタックポインタマイナス24(6、32ビット位置)を見てから実行されたアドレスを見つけることができます。あなたのリンクの図2.3を参照してください。これにより、中断されたPCが表示されます。私たちは、様々な形や人々にこの質問を見続ける

1

は、2つのスタックがあると言っておきます。だから、私はそれを自分で試してみた。

ドキュメントは、我々がリセットのうち、スレッドモードであることを述べている、とあなたはopenocdで停止した場合には、

​​

私はレジスタをダンプするためにいくつかのコードがあることを述べている:

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 . 

とハンドラで、私はストレートARMのドキュメントのうち、この場合には

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 

だから、見る、それはsp_mainを使用しているSP_processのを使用していません。それは、マニュアルが0x1000074である中断された/戻りアドレスを含むプッシュしていると言う項目を押しています。

ここで、SPSELビットを設定すると(PSPを最初に設定することに注意してください)、アプリケーション/スレッドモードのmov r0、spはMSPではないPSPを使用しているようです。しかし、その後、ハンドラは、したがって、この位置にあるように、MOV r0のためにMSPを使用して、SPが、ハンドラ内で、今

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がマーカーとして表示されますそれからカウントダウンしてリターンアドレスを確認してください。ハンドラに2つのスタックポインタを読み込ませ、gprsを見ることができます。 gnuアセンブラmrs rX、psp; mrs rX、msp;プロセススタックポインタとメインスタックポインタ。

+0

ノートから起こった場所を知りたい、私のプログラムありえないがクラッシュするので、 私を助けていません。私は他の人がいますが、これは二重スタックのことを必ずしも実証していないことを証明するのに十分です。 –

関連する問題