なんとかなるさね

マイコンをネタにブログを始めてみました


RZマイコン基板(CEV-RZ/A1L)|Interface誌のシリアルGDBスタブをKPIT GNUARM対応に改造(暫定) 

KPIT GNUARM-NONE-EABI v14.01でInterface誌2014年4月号記事(pp.163-167,村井和夫氏執筆)と同6月号
記事(pp.161-165,同上)のシリアルGDBスタブを使えるように改造してみました。(もっとも、シリアルGDB
スタブのソースコードのCPU例外/Linuxシグナル変換テーブルとリンカスクリプトを書き換えた程度ですが。)
なお、シリアルGDBスタブをビルドする時は、6つ前のエントリの手順でe2studio上でビルドしました。(この
時のリンカスクリプトも流用しました。) また、シリアルGDBスタブを動かす時は、4つ前のエントリの手順で
e2studio上で動かしました。(ソースコードに同梱されたものではなく自分でビルドしたものを使いました。)
ただ、GDBのコマンドラインからの操作と比べると、さすがにe2studioのGUIからの操作には重さを感じます。
やはり基板上のFT232RLとRZ/A1Lマイコンの間の通信速度を上げてみるとか試してみたいです。ちなみに、
トラ技ARMライタ(トラ技CMSIS-DAP)がどのくらいサクサク動くか気になるところです。(J-Link EDUはOK)

リンカスクリプトファイル: memory.x
変更内容: 以下の赤字の箇所を変更(紫字の箇所は以前に変更済みの箇所)

変更前

MEMORY {
/*A9    ram (w) : ORIGIN = 0x20000000, LENGTH = 0x300000 */
    ram (rxw) : ORIGIN = 0x20200000, LENGTH = 8k
}
途中省略
    .text :
    {
        vect.o(.rodata)
        *(.text*)
        *(.rodata*)
        etext = .;
    }

変更後

MEMORY {
/*A9    ram (w) : ORIGIN = 0x20000000, LENGTH = 0x300000 */
    ram (rxw) : ORIGIN = 0x20200000, LENGTH = 9k/*8k-->9k kari by mon80*/
}
    .text :
    {
        ./src/vect.o(.rodata)
        *(.text*)
        *(.rodata*)
        etext = .;
    }

Cソースファイル: main.c
変更内容: 以下の赤字の箇所を変更

変更前

int
computeSignal (int exceptionVector)
{
    static int signal[] = {
        SIGINT, /* Reset    */  
        SIGILL, /* Undefined Instruction    */
        SIGTRAP,    /* Software Interrupt   */
        SIGSEGV,    /* Prefetch Abort   */
        SIGBUS,     /* Data Abort   */
        0,  /* Reserved */
        SIGINT, /* IRQ      */
        SIGINT, /* FIQ      */
    };

    return (signal[exceptionVector]);
}

変更後

int
computeSignal (int exceptionVector)
{
    static int signal[] = {
        SIGINT, /* Reset    */  
        SIGTRAP,    /*SIGILL-->SIGTRAP kari by mon80*/  /* Undefined Instruction    */
        SIGTRAP,    /* Software Interrupt   */
        SIGSEGV,    /* Prefetch Abort   */
        SIGBUS,     /* Data Abort   */
        0,  /* Reserved */
        SIGINT, /* IRQ      */
        SIGINT, /* FIQ      */
    };

    return (signal[exceptionVector]);
}

今までの問題は以下の2つでした。それぞれ原因は以下の通り(のよう)でした。

(1) 自分でビルドしたシリアルGDBスタブが起動しない

 →Interface誌のコンパイル環境(コンパイラ/コンパイルオプション/ライブラリ)と比べると自分の環境
  (KPIT GNUARM + e2studio)ではコードサイズが大きくなっており、それが巡り巡って初期値なし
  変数領域とスタック領域で重なり合う部分が出来てしまい、いわゆる'変数内容が勝手に変化する'問題が
  発生して、プログラムが誤動作していました。

 →リンカスクリプトを変更して重なり合う部分が出来ないようにしてみました。

(2) ソースステップ実行するとシグナル'SIGILL'を受け取りましたと表示され1命令ステップ実行になる

 →Interface誌のGDBと比べてKPIT GNUARMのGDBではステップ実行時の異常動作の検出機能が強化(?)
  されていて、このシリアルGDBスタブのステップ実行の実装に使われている不正命令例外の発生(たぶん
  JTAG-ICEでは発生しない?)も異常動作として検出されてしまっている(のではないか)と思います。その
  一方で、ソフトウェアブレークも同じ不正命令例外を使って実装されているのですが、こちらはGDBに
  不正命令例外を正常動作として扱っても良いかどうかチェックする機構がある(のではないか)と思います。
  (たぶんJTAG-ICEでも同じ実装になるから?)

  追記 : 6月号記事のGDBの小さな画面コピーを見直したところ、結局、同じ動作をしているようでした。
  記事も読み直したところ、執筆された人は'妙な動作'と'デバッガの内部動作'を混同されているような、、、

 →やっつけでCPU例外/Linuxシグナル変換テーブルを書き換えて不正命令例外を別の例外にしてみました。

その結果、何事もなく起動して期待した動作をするようになりました。

変更前

呼び出し元で関数をステップイン実行すると呼び出し元の命令が1つだけ実行されて0x2010029cで停止


変更後

呼び出し元で関数をステップイン実行すると呼び出し先の関数の前処理も実行されて0x201002a4で停止


比較対象としてJ-Link GDB Server + J-Link EDUで実行すると、期待していた動作と同じ動作になりました。

呼び出し元で関数をステップイン実行すると呼び出し先の関数の前処理も実行されて0x201002a4で停止


追記 : 補足

シリアルGDBスタブのソースコードに同梱されていたSample4というプログラムはスタックポインタを設定
していないことに注意する必要があります。Sample2やSample3からコピペするのが良いかもしれません。

追記 : 雑感

このシリアルGDBスタブですが、ステップ実行時に割り込みや意図しない例外が発生したらどうなるかとか、
キャッシュを使うようになったらどうなるかとか、ちょっと気になるところもあるにはあります、、、

あと、PC(プログラムカウンタ)以外のレジスタをGDBなり(e2studioなり)から書き換えたつもりでも無視
されるという制限になっていますが、後日、解除出来ないかどうか試しに修正してみたいです。

ちなみに、ステップ実行の問題をやっつけではない修正にするなら、不正命令例外のアドレスがステップ
実行の実装に使用した不正命令のアドレスだった場合のみLinuxシグナルを偽装するという修正になります。
後日、これも試しに修正してみたいです。

追記 : 雑感その2

ソフトウェアブレークの場合、J-Link GDB Server + J-Link EDUでも同じ不正命令コードをソフトウェア
ブレーク命令として使っているのかな?

関連記事

2014/11/26   blog-entry-522   category: RZ /* 32bit RISC */

go page top