### 2-2　デバッグの実際

#### 2-2-1　プロジェクトの設定

今回使用するtankにはセッションファイルが添付されていません。

前項の手順を参考の上、お手元の環境に応じて［Project Setup］から環境を設定し、［File］メニューの［Session Save As］で、\katana\Shinobi\sample\tank\tank.ssnを作成してください。

#### 2-2-2　エラー発生からソースエディット

まず最初は、意図的にコンパイルエラーになるようなものを仕込んでみましょう。

ファイルの先頭に、このように不要な文字列を入れてみました。

これをmakeすると次のようになります。

このようにエラーになりました。

続いてこのエラーを取り除きましょう。 ［Editor Configuration］ウィンドウで指定したエディタが自動的に起動します 注10。

注10 この時、指定したエディタがタグジャンプ機能を持っていて、かつ［Editor Configuration］ウィンドウのEditor Argumentでその機能が指定されている場合、エラー行にカーソルが移動します。

問題のエラーは、不要な文字列が入っていることが原因ですのでこれを削除します。

変更後セーブし、再度［Project Build］ウィンドウからmakeします 注11。

注11 makeのショートカットキーは［Ctrl］＋［M］です。

エラーがないことを確認したら、続いてこの実行ファイルをロードします。 ［File］メニューの［Load Program File］をクリックすると、次のようなダイアログが表示されます 注12。

注12 ショートカットキーは［Ctrl］＋［Shift］＋［C］です。

一度ファイル名を指定して読み込んでおけば、以降はmake終了ごとに次のようなダイアログボックスが表示されますので、［はい］をクリックするだけで実行ファイルが自動的に再読み込みされます。

うまくコンパイルが終了していれば、次のいずれかの手順でDev.Box上で実行できます。

- ［Debug］メニューの［Execution］をクリックし、［Run］をクリック
- ［Debug］ツールバーから［Run］ボタンをクリック
- ［F9］キー 注13
- ［Editor］以外の適当なリージョンを右クリックし、［Execution］クリックして［Run］をクリック

注13 ［F9］キーは、RunとStopのトグルになっています。

以上が、基本的な修正から再makeへの流れです。

#### 2-2-3　Breakpointの設定

続いてBreakpointの設定を行ってみましょう。

tankでは、実際のメインコードはmain.c中のnjUserMain();ですので、その中にBreakpointを設定してみます。以下にその手順を示します。 ［Window］メニューの［New Window］をクリックして新しいリージョン（ウィンドウ）を開きます。

このように、未定義のリージョン（No type）が開きます。

今はBreakpointを設定するためにソースリストを表示させたいので、［Region Combo］ツールバーの［Source］をクリックします。

このリージョンのタイトルバーが［Source］に変わり、この［No type］リージョンは［Source］リージョンに設定されました 注14。

注14 本書では以降この一連の手順を、単に「〜リージョンを開く」と呼びます。

続いて、この［Source］リージョンで右クリックし、［Goto Source File］をクリックします。

すると次のようなウィンドウが開き、このプログラムで使用されているソースファイルの一覧がリストされます。

この中から開きたいソースファイルを選択します。

今開きたいソースはmain.cですから、この中からmain.cを選択します。

これで［Source］リージョンにmain.cが表示されました。

ではこの中にBreakpointを設定してみましょう。

#### 特定の行にBreakpointを設定する

画面上にスプライトを表示している行（107行目）にBreakpointを設定してみます。スクロールダウンし、その行をクリックします。

この状態で、次のいずれかの方法で設定できます。

- ［Debug］メニューの［Breakpoints］をクリックし、［Toggle Breakpoint］をクリック
- ［Breakpoint］ツールバーの［Toggle Breakpoint］ボタンをクリック
- ［F5］キー

または次の方法でも可能です。この場合、指定したい行をクリックする必要はありません（右クリックした時に、その時のカーソルの位置に設定されます）。

- マウスカーソルをその行で右クリックし、［Breakpoints］をクリックして［Toggle Breakpoint］をクリック

すると、行頭にBreakpointが設定されたことを示すマークがつきます 注15。

注15 これらはトグルですので、同じ行でこれらの操作を行うことでブレークポイントの解除が行えます。

これでこの行にBreakpointが設定されました。

それでは［F9］キーを押して実行してみましょう。

行頭のマークがSTOPに変わり、また［Target］ウィンドウも

と表示され、プロセッサがここで停止したことが分かります 注16。

注16 ここで［Register］リージョンを開くと、停止アドレス及び現在のレジスタの値などが確認できます。

#### 特定変数へのアクセスで停止

続いて、特定の変数にアクセスされた時に停止するような設定（Watch access breakpoint）を行ってみましょう。

- ［Debug］メニューの［Breakpoints］をクリックし、［Configure Breakpoint（s）...］をクリック
- ［Breakpoint］ツールバーの［Configure breakpoint（s）］ボタンをクリック
- ［Ctrl］＋［F5］キー
- ［Editor］以外のリージョンを右クリックし、［Breakpoints］をクリックして［Configure Breakpoint（s）］をクリック

このようなダイアログが表示されました。

先ほど設定したBreakpointが有効なままですので、その情報が表示されています。

ここで［Add Watch］ボタンをクリックします。 ［Code Setting］タブが［Watch Settings］タブに変わります。

それでは、変数countのアクセスに対して停止するようにしてみましょう。 ［Local Expression］に「＆count」と入れ、またこれはC/C＋＋の表記方法ですので、下のオプションボックスで［C/C＋＋］を選択します。そして［OK］をクリックします。

これで、以降は変数countにアクセスが入るごとに停止するようになります 注17。

注17 これを読み込みまたは書き込みのいずれかのみに対して行いたい場合には、下の［Access Type］オプションボタンで［Both］ではなく［Read］または［Write］を選択します。

それでは［F9］キーを押して再実行してみましょう。

すぐに次のようなダイアログボックスが表示され、変数countがアクセスされたことが分かります。

［Source］リージョンを見ると、

ソース中に変数countが出てきている付近で停止しています。

このようにWatch access breakpointには注意しなければいけない点があります。

ここで［Disassemble］リージョンを開いてみます。

実際に変数countにアクセスが入ったのは、現在のPC値より3行前のようです。

このように、Watch access breakpointがトリガされる時PCはパイプライン中で、すでに数命令先を処理しています（よってズレが生じてしまいます）。

このことに気を付けてください。

このWatch access breakpointの解除は、上の［Configure breakpoint（s）］ダイアログで、下にリストされているBreakpointの一覧から解除したいものをクリックして選択し、［Remove］ボタンをクリックすることで行います。

これでWatch access breakpointが解除されました。

Breakpointには、ここで示した以外に、色々な条件を設定してのBreakpoint処理が可能です。詳細は『CodeScapeマニュアル』をご覧ください。

#### 2-2-4　値の内容チェック

実行中の変数の値を見てみましょう。

［Watch］リージョンを開きます。

では、ここでのカウンターである変数count（int count）の値を見ることにしましょう。

右クリックして［Insert］をクリックします。カーソルが点滅しますので、countと入力します。

変数countの、現在の値が表示されました。

先ほどのBreakpointの設定を解除していない場合、［F9］キーを押すごとにBreakpointで停止しますので、この値が1ずつカウントアップしていくことを確認してください。

続いてこの変数の値を変更してみましょう。 ［Watch］リージョンで変数countを左クリックで選択し、右クリックします。そして［Edit Watch Value］をクリックすると、次のようなウィンドウが表示されます。

この［Expression］に直接値を入力することで変数の内容を変更することができます 注18。

注18 ここには式を入れることも可能です。式を入れて［Evaluate］をクリックしてください。式が展開され、変数にその値が代入されます。

新しい値を設定して［OK］ボタンをクリックするとこのウィンドウが閉じ、［Watch］リージョンに新しい値が入っているはずです。確認してください。

この状態で再実行を行うと、新しい値で表示が始まります。

再実行は、次のいずれかの操作で行います。

- ［Debug］メニューの［Execution］をクリックし、［Run］をクリック
- ［Debug］ツールバーの［Run］ボタンをクリック
- ［F9］キー 注19
- ［Editor］以外の適当なリージョンを右クリックし、［Execution］をクリックして［Run］をクリック

注19 ［F9］キーは、RunとStopのトグルになっています。

ちなみに［Memory］リージョンから変数の値を見ることも可能です。

配列など、連続したアドレスの値を見るにはこちらが便利な場合もあるでしょう。 ［Memory］リージョンを開きます。

開いた直後の状態では、現在のプログラムカウンター（PC）値を先頭とする表示（メモリダンプ）を行っています。 ［Memory］リージョンで右クリックし、［Goto Address...］をクリックします。

ここで［Expression］に変数名を入れます。但し先頭にシンボル名であることを示す「＆」を付けることを忘れないでください。 ［OK］ボタンをクリックすると、変数countの、メモリ上のアドレス（変数countの内容が格納されているアドレス）を先頭とする表示に変わります。

この先頭アドレス（0x8C016E70）が、［Watch］リージョンで見た変数countのアドレスと同じであることを確認してください。

変数countの型はintつまり4バイト長ですから、このメモリダンプで先頭からの4バイト、ここでは“0A 00 00 00”がその値であることが分かります。

#### 2-2-5　プログラムの流れを調べる

デバッグ上、プログラムがどのような流れで実行されてきているのか調べたい時があります。このような時には［Call Stack］リージョンが役に立ちます。 ［Call Stack］リージョンを開きます。

最上段に現在のプログラムカウンタ（PC）、そしてその下に現在のプログラムスタックの状態がリストされています（リストは下に行くほど古いものになります）。

ここにはアドレスが、関数名、またその関数名からのオフセット値で示されています（今、先ほどのBreakpointが有効なままですので、その行で停止しています 注20）。

注20 Dev.Boxの実行中、［Call Stack］リージョンにはRUNNING...とだけ表示されます。

確認のため、この状態から［Disassemble］リージョンを開いて見てみましょう 注21。

注21 また［Disassemble］リージョンの表示から、SH4 CPUは2バイトを1命令の単位としていることも分かります。

開いた直後は、カーソル位置が現在のPCです。

確かに現在その位置（njUserMain()＋0x02）にいることが分かります。

その1つ下のスタックも確認してみましょう。

Call Stackリージョンの、“main() ＋ 0xa”の行をダブルクリックします。

このように表示が変わり、またこれに連動して［Disassemble］リージョンと［Source］リージョンのカーソル位置が、このnjUserMain();関数の呼び出しを行った個所に移ります。

ところで今現在、このように［Source］リージョンと［Disassemble］リージョンが同時に開いているはずですが、この2つは同期を取って、つまり片方の動きに合わせてもう片方を動かすことが可能です（具体的な方法については『CodeScapeマニュアル』を参照してください）。ソースレベルで取りきれないバグについては、この方法で調査することになります 注22。

注22 SH4 CPUについての知識と、コンパイラの動作の理解が必要になります。

#### 2-2-6　トレース

CoceScapeは幾つかのトレース実行機能を持っています。

これらの機能はデバッグツールバーから呼び出すことができます。

#### カーソル位置まで実行（Run to cursor）

現在のカーソル位置まで実行し、停止します。

ここでは、先ほどBreakpointを設定した行の位置まで、この機能で実行することにしましょう。［Source］リージョンを開きます。

以前のBreakpointが残っている場合には、その行で［F5］キーを押してこれを解除します。

続いて、カーソルを実行したい行の位置に持って行きます 注23。

注23 左クリックでも、カーソルキーでも構いません。

この状態で、次のいずれかの方法で現在のカーソル位置まで実行します。

- ［Debug］メニューの［Execution］をクリックし、［Run to Cursor］をクリック
- ［Debug］ツールバーの［Run to cursor］ボタンをクリック
- ［Alt］＋［F9］キー
- ［Source］リージョンを右クリックし、［Execution］をクリックして［Run to Cursor］をクリック

すると表示が次のように変わり、カーソル位置まで実行され、停止したことがわかります。

またこの時［Target］ウィンドウは

という表示になります。

#### 指定アドレスまで実行（Run to Address）

指定したアドレスまで実行し、停止します。

- ［Debug］メニューの［Execution］をクリックし、［Run to Address］をクリック
- ［Debug］ツールバーの［Run to address］ボタンをクリック
- ［Shift］＋［F9］キー
- ［Source］リージョンを右クリックし、［Execution］をクリックして［Run to Address］をクリック

次のようなダイアログボックスが表示されます。

ここで今表示されている値は、現在のPC値です。［Expression］に関数名であるnjUserMainと入力し、［Evaluate］ボタンをクリックして関数名をアドレスに展開させます。

関数名が式として評価され、下に値（アドレス）が表示されました 注24。

注24 ［Evaluate］をクリックせずに直接［OK］ボタンをクリックすると、すぐその関数まで実行（Run to Address）されます。

ここで［OK］ボタンをクリックすると、njUserMain();の先頭まで実行されます。

カーソルが上のような位置に移り、そこまで実行し停止したことが分かります。

#### 条件が満たされるまで実行（Run until）...

与えた式が満たされるまで実行します。

- ［Debug］メニューの［Execution］をクリックし、［Step Run Until］をクリック
- ［Debug］ツールバーの［Step run until］ボタンをクリック
- ［Alt］＋［F8］キー
- ［Edit］リージョン以外のリージョンを右クリックし、［Execution］をクリックして［Step Run Until］をクリック

［Expression］に条件式を入れます。

この式が満たされるまで実行されます。

しかしながらこの機能はかなり実行時間がかかります 注25。つまり実時間動作が行えません。このことが原因で期待したトレースが行えない場合があることも頭に入れて使用してください。またWatch access breakpointと同様、停止した時には既にアセンブラレベルで数命令先に進んでいることにも気を付けてください。

注25 しかし［Debug］−［Execution］−［Enable Animated Step Run］のチェックをオンにしておくことで、実行状況を刻々各リージョンに表示することができます。

#### ステップ実行

プログラムを1行単位で実行します。

ステップ実行には、以下の3種類の方法があります。

- 関数の中もトレース（Step into）
- 関数の中はトレースしない（Step over）
- この関数から抜け出る（Step Out）

これらの機能を1つずつ見て行ってみましょう。

#### 関数の中もトレース（Step into）

呼び出した関数や、サブルーチンの中もトレースします。

Step intoは以下のいずれかの操作で行い、これらを行うごとに1行ごと進みます。

- ［Debug］メニューの［Execution］をクリックし、［Single Step］をクリック
- ［Debug］ツールバーの［Single step （into）］ボタンをクリック
- ［F7］キー
- ［Edit］リージョン以外のリージョンを右クリックし、［Execution］をクリックして［Single Step］をクリック

たとえば上の状態で停止している場合、［F7］キーを1回押します。

1行分進みました（宣言文や空行は実行されません）。

この時点で現在のカーソル位置までは未だ実行されていないことに気を付けてください。

何度か［F7］キーを押し、進めてみます。

すると、あるところからソースが見えなくなってしまいました。

これはソースのない、ライブラリ内関数njDrawSprite2D();内部のトレースに入ったためです 注26。この場合、後に述べるStep Overを使用して、先ほどのソースまで進めることができます。またトレースの必要ない関数の場合、これも後に述べるStep Outを使用してスキップする（実行するが、トレース状況を表示しない）ことができます。

このStep intoを行った場合に限り、Unstepで1行づつプログラムを逆に戻ることができます。

注26 ソースのない関数のトレースが必要な場合、［Disassemble］リージョンと［Register］リージョンなどを使用します。

Unstepは以下のいずれかで行います。

- ［Debug］メニューの［Execution］をクリックし、［Unstep］をクリック
- ［Ctrl］＋［F7］キー
- ［Debug］ツールバーの［Unstep］ボタンをクリック
- ［Edit］リージョン以外で右クリックし、［Execution］をクリックして［Unstep］をクリック

#### 関数の中はトレースしない（Step over）

Step intoでは関数コールやJSR、BSRがあった場合には呼び出した関数またはサブルーチンの中までトレースしましたが、Step overではそれを行いません。

- ［Debug］メニューの［Execution］をクリックし、［Step Over］をクリック
- ［Debug］ツールバーの［Step over］ボタンをクリック
- ［F8］キー
- ［Edit］リージョン以外のリージョンを右クリックし、［Execution］をクリックして［Step Over］をクリック

まず既に説明したBreakpointの設定機能を使い、njDrawSprite2D();が呼ばれるところまで実行しましょう。

ここで［F8］キーを1回押します。

このように、Step intoと異なり関数njDrawSprite2D();の内部までのトレースは行いません。

ちなみに［Watch］リージョンで変数countの値を見ている場合、ここで変数countの値が変わることが分かります。

#### この関数から抜け出る（Step Out）

現在いる関数またはサブルーチンの終わりまで実行し、関数を抜けます。

- ［Debug］メニューの［Execution］をクリックし、［Step Run Out］をクリック
- ［Debug］ツールバーの［Step Out］ボタンをクリック
- ［Shift］＋［F8］キー
- ［Edit］リージョン以外のリージョンを右クリックし、［Execution］をクリックして［Step Out］をクリック

#### 2-2-7　ソースリスト中の、特定の範囲をチェックする

意図しない動作がある場合トレースなどを行うことになりますが、トレースを行う時、特定の怪しそうなところを重点的に見ておきたいことがあります。

そのような時には［Source］リージョンにLock Viewを行います。Lock Viewを行うことで、PC値によらず特定のソースファイルの特定の個所を常に表示させておくことができます。

まず［Source］リージョンを開きます。

をクリックします。

［File］をクリックすると、ソースファイルの一覧が表示されます。

常に表示させておきたい（ロックしたい）ファイルを指定します。

ここではmain.cをクリックします。

［Expression］にファイル名が入りました。ファイル名の後の:に続けてソースファイルの行指定を行うことで、特定の個所にLockをかける（特定の行からの表示を行う）ことができます。

Lockされたリージョンは、スクロールバーの操作なども無効になります。

解除するには再度 をクリックし、［Lock View］ダイアログで［OK］ボタンをクリックします。

#### 変数の内容を見る

続いて変数の内容を調べる場合、調べたい変数名を1つ1つ打ち込んでも良いのですが、［Local watch］リージョンを開くことで、その関数のローカル変数一覧を見ることができます。

停止している時に、［Local watch］リージョンを開きます。

停止している個所の関数で使用されているローカル変数の一覧とその内容が表示されます。

ここではnjUserMain();のローカル変数が表示されています。

ローカル変数が構造体の場合、その構造体名の上で右クリックし［Open/Close］を選ぶことで、構造体のメンバ一覧とその内容を見ることができます 注27。

注27 この動作はトグルになっていますので、今展開した構造体を再度Open/Closeすると閉じられます（構造体名のみの表示に戻ります）。

[←] | [INDEX] | [→]