1. 概要GDB デバッグの 3 つの方法: 1. ターゲットボードは GDB を使用して直接デバッグされます。 2. ターゲット ボードは gdbserver を使用し、ホストはクライアントとして xxx-linux-gdb を使用します。 3. ターゲット ボードは ulimit -c unlimited を使用してコア ファイルを生成し、次にホストは xxx-linux-gdb ./test ./core を使用します。 2. gdbデバッグ次のように main.c と sum.c でテスト プログラムを構築します。 main.c: #include <stdio.h> #include <stdlib.h> 外部 int 合計(int 値); 構造体入出力{ int 値; int 結果; }; int main(int argc, char * argv[]) { 構造体 inout * io = (構造体 inout * ) malloc(sizeof(構造体 inout)); (NULL == io)の場合{ printf("Malloc に失敗しました。\n"); -1 を返します。 } (引数が2の場合){ printf("間違ったパラグラフです!\n"); -1 を返します。 } io->値 = *argv[1] - '0'; io->結果 = sum(io->値); printf("入力: %d、結果: %d\n", io->value, io->result); 0を返します。 } 合計.c: int 合計(int 値) { int 結果 = 0; 整数 i = 0; (i = 0; i < 値; i++) の場合 結果 += (i + 1); 結果を返します。 } 次に、gcc main.c sum.c -o main -g を実行して、メインの実行可能ファイルを取得します。 以下ではgdbのほとんどの機能を紹介します。1.1 ブレークポイントの設定と1.3 スタックフレームの表示はよく使われる機能です。デバッグ中には、1.6 シングルステップ実行、1.4 変数の表示、1.5 レジスタの表示、1.8 ウォッチポイント、および1.9 変数値の変更が必要になる場合があります。 プロセスがすでに実行されている場合は、1.11 でプロセスにアタッチするか、1.10 で分析用のダンプ ファイルを生成する必要があります。もちろん、効率を向上させるために、1.13 初期化ファイルをカスタマイズすることもできます。 2.1. ブレークポイントを設定するb または break を使用してブレークポイントを設定できます。ブレークポイントは、関数名、行番号、ファイル名 + 関数名、ファイル名 + 行番号、オフセット、アドレスなどで設定できます。 形式は次のとおりです。 ブレーク関数名 改行番号 ブレークファイル名: 関数名 ファイル名:行番号を区切る ブレーク + オフセット ブレーク - オフセット ブレーク *アドレス ブレークポイントを確認し、info break を通じてブレークポイント リストを表示します。 コマンドによるブレークポイントの削除には次のものがあります: delete <ブレークポイントID>: 指定されたブレークポイントを削除します 削除: すべてのブレークポイントを削除します クリア 関数名をクリアする クリアライン番号 ファイル名:行番号をクリア クリアファイル名: 関数名 ブレークポイントは条件付きで解除することもできる break breakpoint if condition; たとえば、break sum if value==9 の場合、入力値が 9 の場合にのみ実行が停止します。 条件ブレークポイント番号: 指定されたブレークポイントのトリガー条件を削除します 条件ブレークポイント番号条件: 指定されたブレークポイントにトリガー条件を追加します 下記のように、入力パラメータが 9 の場合は中断され、入力パラメータが 8 の場合は最後まで実行されます。 ブレークポイントは、disable/enable を使用して一時的に無効または有効にすることもできます。 無効にする ブレークポイント番号を無効にする 表示を無効にする 番号を表示する memメモリ領域を無効にする 有効にする ブレークポイント番号を有効にする ブレークポイント番号を 1 回有効にする: このブレークポイントは 1 回だけ有効になります。プログラムがこのブレークポイントまで実行されて一時停止すると、ブレークポイントは無効になります。 ブレークポイント番号の削除を有効にする 表示を有効にする 表示番号 メモリ領域を有効にする 2.1.1. ブレークポイントコマンドの高度な機能ほとんどの場合、ブレークポイントで一連のアクションを実行する必要があります。gdb は、ブレークポイントでコマンドを実行するためのコマンドと呼ばれる高度な機能を提供します。 #include <stdio.h> 整数合計 = 0; 整数平方(整数i) { 結果=0; 結果 = i*i; 結果を返します。 } int main(int argc, char **argv) { 整数 i; (i=0; i<10; i++) の場合 { 合計 += 平方(i); } 0を返します。 } たとえば、上記のプログラムで square パラメータ i が 5 のときにブレークポイントを設定し、この時点でのスタック、ローカル変数、合計の値を印刷する必要があります。 gdb.init を次のように記述します。 gdb.log にログを設定する i == 5 の場合、b の平方 コマンド btフル 地元の人々 p合計 「i == 5 のときにブレークする」と出力します。 終わり gdb シェルで、gdb.init をソースとして実行し、コマンド r を実行します。結果は次のようになります。 i==5 のときにブレークポイントが解除され、この時点で正しい値が出力されることがわかります。 2.2. 操作「gdb コマンド」の後に run を実行すると、gdb でコマンドを実行できます。コマンドにパラメータが必要な場合は、run にパラメータが続きます。 main() にブレークポイントが必要な場合は、start を直接実行してください。 2.3. スタックフレームを表示するブレークポイントに到達すると、実行が一時停止され、または coredump によってスタック フレームが表示されることがあります。 bt はスタック フレームを表示でき、bt full はローカル変数を表示できます。 コマンドの形式は次のとおりです。 ビット bt full: バックトレースだけでなく、ローカル変数も表示します bt N: 最初のN個のスタックフレームを表示する btフルN 2.4. 変数の表示「print variable」は変数の内容を表示できます。 1 行で複数の変数を監視する必要がある場合は、p {var1, var2, var3} を使用できます。 自動表示を追跡したい場合は、display {var1, var2, var3}を使用できます。 2.5. ディスプレイレジスタinfo reg はレジスタの内容を表示できます。 レジスタの内容を表示するには、レジスタ名の前に $ を追加します。 p $register: レジスタの内容を表示する p/x $register: レジスタの内容を16進数で表示します。 x コマンドを使用して、内容「x/format address」を表示します。 x $pc: プログラムポインタの内容を表示する x/i $pc: プログラムポインタアセンブリを表示します。 x/10i $pc: プログラムポインターの後の 10 個の命令を表示します。 x/128wx 0xfc207000: 0xfc20700 から始まる 16 進数で 128 語を出力します。 disassemble コマンドを使用して逆アセンブルすることもできます。 分解する プログラムカウンターを逆アセンブルします。pc が配置されている関数全体を逆アセンブルします。 disassemble addr-0x40,addr+0x40: 前後に 0x40 がある addr を逆アセンブルします。 2.6. シングルステップ実行シングルステップ実行には、next と step の 2 つのコマンドがあります。この 2 つの違いは、next は関数に遭遇してもその関数に入らないのに対し、step は関数内で実行されることです。 アセンブリ命令を 1 つずつ実行する必要がある場合は、それぞれ nexti と stepi を使用できます。 2.7. 実行を継続するデバッグ時は、continue コマンドを使用してプログラムの実行を続行します。停電後、プログラムは再び一時停止します。ブレークポイントがない場合、最後まで実行を続けます。 続行: 実行を続行する 継続回数: 指定回数実行を継続します。 2.8. 監視ポイント変数がどこで変更されたかを確認するには、watch コマンドを使用してウォッチポイントを設定します。 <式> を見る: 式が変わったら一時停止する awatch<expression>: 式にアクセスし、変更を一時停止します rwatch<式>: 式にアクセスしたときに実行を一時停止する その他のバリエーションには、watch expr [thread thread-id] [mask maskvalue] などがあります。ここで、mask にはアーキテクチャ サポートが必要です。 GDB は定数を監視できません。たとえば、watch 0x600850 はエラーを報告します。 ただし、*(int *)0x600850 は監視できます。 2.9. 変数の値を変更する「set variable <variable>=<expression>」で変数の値を変更します。 set $r0=xxx: レジスタ r0 の値を xxx に設定します。 2.10. カーネルダンプファイルを生成する「generate-core-file」を使用して core.xxxx ダンプ ファイルを生成します。 次に、gdb ./main ./core.xxxx を使用して、復元されたシーンを表示します。 別のコマンド gcore を使用すると、コマンド ラインから直接コア ダンプ ファイルを生成できます。 gcore `pidof コマンド`: 実行中のプログラムを停止せずにダンプ ファイルを取得します。 2.11. プロセスにアタッチするプログラムがすでに実行中の場合、またはデバッグが無限ループに陥ってコンソール プロセスに戻れない場合は、attach コマンドを使用できます。
ps aux を使用してプロセスの pid を表示し、bt を使用してスタック フレームを表示できます。 top を例にとると、操作手順は次のようになります。 1. ps -aux を実行してプロセス pid (16974) を表示します。 2. sudo gdb attach 16974 を実行し、gdb を使用して top コマンドにアタッチします。 3. bt full を使用して現在のスタック フレームを表示します。このとき、印刷などを利用して情報を閲覧してください。 4. info proc を使用してプロセス情報を表示することもできます。 2.12. 繰り返し実行continue、step、stepi、next、nexti はすべて繰り返し実行の回数を指定できます。 ブレークポイントを指定した回数無視: 指定した数のブレークポイントを無視できます。 2.13. 初期化ファイルLinux 環境での初期化ファイルは .gdbinit です。 .gdbinit ファイルが存在する場合、gdb は起動前にそれをコマンド ファイルとして実行します。 初期化ファイルとコマンド ファイルの実行順序は、HOME/.gdbinit > コマンドライン オプションの実行 > ./.gdbinit > -x でコマンド ファイルを指定します。 2.14. ソースディレクトリを設定するデバッグ中にソースコードに関連付ける必要がある場合は、より詳細な情報を表示します。 ソース ディレクトリは、directory または set substitute-path で指定できます。 2.15 TUIデバッグTUI (TextUserInterface) は、GDB デバッグ用のテキスト ユーザー インターフェイスであり、ソース コード、アセンブリ、レジスタ テキスト ウィンドウを便利に表示できます。 ソース コード ウィンドウとアセンブリ ウィンドウでは、プログラムの実行場所が強調表示され、「>」記号でマークされます。ブレークポイントを識別するために使用される特別なタグが 2 つあります。最初のタグはブレークポイントの種類を識別します。
2 番目のフラグは、ブレークポイントが有効かどうかを示すために使用されます。 プログラムをデバッグすると、ソース コード ウィンドウ、アセンブリ ウィンドウ、レジスタ ウィンドウの内容が自動的に更新されます。 2.16 キャッチポイントCatch は、特定の種類のイベントに基づいてプログラムの実行を停止できます。 システム コール close が生成されたときにプログラムの実行を停止するには、catch syscall close を使用できます。 その他のキャッチ イベントには、throw、syscall、assert、exception などがあります。 2.17 カスタムスクリプトコマンドラインの入力パラメータは、argc および *argv を通じて取得できます。 2.17.0、注釈、割り当て、表示# - スクリプトにコメントを追加します。 set - gdb 変数とデバッガー変数を区別するために $ で始まる変数に値を割り当てます。 例えば: $x = 1 と設定する 変数の表示は echo と printf を通じて行うことができます。 2.17.1 カスタムコマンドdefine コマンドを使用して独自のコマンドを定義したり、document コマンドを使用してカスタム コマンドに説明を追加したりすることもできます。 加算器を定義する $argc == 2の場合 $arg0 + $arg1 を印刷する 終わり $argc == 3の場合 $arg0 + $arg1 + $arg2 を印刷します 終わり 終わり ドキュメント追加 2 つまたは 3 つの変数を合計します。 終わり bfカスタムコマンドを実行すると、結果は次のようになります。 行パラメータ宣言はありませんが、$arg0、$arg1、$argcを使用して直接参照できます。$argcは仮パラメータの数です。 2.17.2 条件文条件付きコマンド: 2.17.3 ループ文ループコマンド: set logged on overwrite gdb.log------------表示されたログを gdb.log に保存します。 set pagination off--------------------------ページング表示機能をオフにします。 tar jtag jtag://localhost:1025--------------JTAGに接続します。 d------------------------------------------------既存のブレークポイントを削除します。 b func_a------------------------------------func_a にブレークポイントを追加します。 コマンド------------------------------------ブレークポイントの後、以下のコマンドを実行します。 b func_b----------------------------------func_a のブレークポイントの後に、func_b にブレークポイントを追加します。 コマンド bt full-------------------------------func_b のスタック フレームを出力します。 c-------------------------------------実行を続行します。 終わり b file.c:555------------------------------file.c の 555 行目にブレークポイント コマンドを追加します while 1-------------------------------次のコマンドを無限に実行します。 次 終わり 終わり c----------------------------------------- 実行を続行して、func_b および file.c:555 ブレークポイントをトリガーします。 終わり c-------------------------------------------------------- はプログラムが実行を継続することを意味します。 また、コマンドラインで gdb -x gdb.init bin; または gdb bin を実行してからコマンドラインで gdb.init をソースとして実行して、スクリプトを更新することもできます。 2.18. 指定したファイルにメモリをダンプするgdb のデバッグ中に、メモリのセクションをファイルにエクスポートする必要がある場合があります。これは、dump コマンドを使用して実行できます。 コマンド形式: バイナリメモリをダンプ FILE START STOP たとえば、dump binary memory ./dump.bin 0x0 0x008000000 は、0x0 から 0x00800000 までのメモリ範囲を dump.bin にエクスポートします。 3. gdb+gdbserver リモートデバッグターゲット ボード gdbserver + ホスト gdb リモート デバッグ方式は、パフォーマンスが制限され、gdbserver 機能のみを提供できるターゲット ボードに適しています。 リモート デバッグのためにホスト コンピューターで gdb を実行します。テスト手順は以下のとおりです。 #include <stdio.h> void C(int *p) { *p = 0x12; } void B(int *p) { C(p); } void A(int *p) { B(p); } void A2(int *p) { C(p); } int main(int argc, char **argv) { 整数a; int *p = NULL; A2(&a); // A2 > C printf("a = 0x%x\n", a); A(p); // A > B > C 0を返します。 } ターゲット ボードは次のように設定されます: ポート 2345 を gdbserver 銅ポートとして開きます。
ホスト上で gdb test_debug を実行し、次に tar remote 192.168.2.84.2345 を実行してリモート gdbserver に接続します。 ターゲット ボードは、「ホスト 192.168.33.77 からのリモート デバッグ」というメッセージを受信し、2 つの間の接続が成功したことを示します。 ホスト上でリモートデバッグを実行できます。続行すると、両端で取得される結果は次のとおりです。 ターゲットボードは「a=0x12」を出力した後、実行を停止します。 ホストは SIGSEGV を受信し、バックトレース情報を表示できます。問題はポインタ p が NULL を指していること、および 0 ポインタの割り当てが間違っていることにあることがわかります。 4. core+gdbによるオフライン解析ターゲット ボード上で ulimit -c unlimited を実行し、アプリケーションを実行します。 プログラム エラーが発生すると、現在のディレクトリにコア ファイルが生成されます。 コアファイルをコピーした後、PC上でxxx-linux-gdb ./test ./coreを実行して解析します。 4.1、ライブラリファイルの読み込みxxx-linux-gdb ./test ./core を実行した後、ライブラリ ファイルが関連付けられていない可能性があります。 ライブラリの読み込みステータスを表示するには、info sharedlibrary を使用します。 Syms 共有オブジェクトライブラリの読み取り xxx.soはありません /lib/libdl.so.2 なし /lib/libpthread.so.0 なし 0x2ab6ec00 0x2ac09ba4 はい xxx/lib/libstdc++.so.6 /lib/libm.so.6 なし 0x2acec460 0x2acf626c はい xxx/lib/libgcc_s.so.1 /lib/libc.so.6 なし /lib/ld.so.1 がありません これは、ライブラリが配置されているパスに対応する set solib-search-path および set solib-absolute-prefix によって設定できます。 Syms 共有オブジェクトライブラリの読み取り 0x2aaca050 0x2aacc8d0 はい xxx.so 0x2aad0ad0 0x2aad17ac はい (*) xxx/lib/libdl.so.2 0x2aad8a50 0x2aae7434 はい (*) xxx/lib/libpthread.so.0 0x2ab6ec00 0x2ac09ba4 はい xxx/lib/libstdc++.so.6 0x2ac4b3d0 0x2acb1988 はい xxx/lib/libm.so.6 0x2acec460 0x2acf626c はい xxx/lib/libgcc_s.so.1 0x2ad17b80 0x2adf699e はい xxx/lib/libc.so.6 0x2aaa89e0 0x2aabf66c はい (*) xxx/lib/ld.so.1 (*): 共有ライブラリにデバッグ情報がありません。 関連するライブラリ ファイルがロードされていることがわかりますが、一部のライブラリ ファイルにはデバッグ情報がありません。 4.2. バックトレースの表示コアダンプのバックトレースを表示するには、ビット t を使用します。より完全な情報を表示するには、ビット t full を使用します。 関数呼び出しスタックを生成するいくつかの関数 bt: すべての関数呼び出しスタック フレームに関する情報を、フレームごとに 1 行表示します。 bt n: スタック内の n フレームの情報を表示します。 bt -n: スタックの一番下に n フレームの情報を表示します。 bt full: 関数パラメータやローカル変数など、スタック内のすべてのフレームの完全な情報を表示します。 bt full n: 上記と同じ使用法です。 btフル-n (gdb) うーん #0 xxx/lib/libc.so.6 からの memcpy() の 0x2ad71f1e #1 xxx/lib/libc.so.6 からの memmove() で 0x2ad71ac0 #2 0x0011f36c in std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m<unsigned char> (__first=0x34dfb008 "\377\330\377", <不完全なシーケンス \340>, __last=0x34eeea2c "", ... #3 0x0011ee22 in std::__copy_move_a<false, unsigned char*, unsigned char*> (__first=0x34dfb008 "\377\330\377", <不完全なシーケンス \340>, __last=0x34eeea2c "", __result=0x2b2013c0 "\377\330\377", <不完全なシーケンス \340>) xxxinclude/c++/6.3.0/bits/stl_algobase.h:386 で #4 0x0011e7e2 in std::__copy_move_a2<false, __gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char> >, unsigned char*> (__first=..., __last=..., __result=0x2b2013c0 "\377\330\377", <不完全なシーケンス \340>) xxx/bits/stl_algobase.h:424 で #5 std::copy<__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char> >, unsigned char*> 内の 0x0011dfd2 (__first=...、__last=...、__result=0x2b2013c0 "\377\330\377"、<不完全なシーケンス \340>) xxx/6.3.0/bits/stl_algobase.h:456 で #6 xxx の 0x0011c948 #7 xxx の 0x00133e08 #8 xxx/libc/lib/libpthread.so.0 からの start_thread() の 0x2aada31e #9 0x005a11b4 ??() 内 4.3 コアダンプ保存ファイルのディレクトリと命名規則デフォルトでは、コア ファイルは現在のアプリケーション パスに保存され、区別するために設定できます。 コアは主に /proc/sys/kernel/core_uses_pid と /proc/sys/kernel/core_pattern によって区別されます。 /proc/sys/kernel/core_uses_pid: 生成されたコア ファイルのファイル名に拡張子として pid を追加するかどうかを制御できます。追加される場合、ファイルの内容は 1 になり、追加されない場合は 0 になります。 proc/sys/kernel/core_pattern: フォーマットされたコアファイルの保存場所またはファイル名を設定できます。たとえば、元のファイルの内容は core-%e です。
生成されたコアファイルは/corefileディレクトリに保存されます。生成されたファイル名はcore-コマンド名-pid-タイムスタンプです。 パラメータのリストは次のとおりです。 %p - ファイル名にPIDを挿入 もちろん、次の方法でこれを行うこともできます。
4.4 ulimitの使用関数の説明: シェル プログラムのリソースを制御します。 構文: ulimit [-aHS][-c <コアファイルの上限>][-d <データセクションのサイズ>][-f <ファイルサイズ>][-m <メモリサイズ>][-n <ファイル数>][-p <バッファサイズ>][-s <スタックサイズ>][-t <CPU時間>][-u <プログラム数>][-v <仮想メモリサイズ>] 追加情報: ulimit は、シェル実行プログラムのリソースを制御するために使用できる組み込みシェル コマンドです。 パラメータ: -a 現在のリソース制限設定を表示します。 5. GDBのヒント5.1. 閉じる続行するには<return>、終了するにはq<return>と入力してください--- 表示内容が大きい場合、GDB はページングを強制し、表示が中断されます。ただし、これは必要ない場合があり、ページ区切りをオフに設定することで無効にすることができます。 5.2. 実行中のカーネルに接続する実行中の Linux でクラッシュやその他の問題が発生した場合、JTAG 接続を使用して問題を特定する必要があります。 接続方法は次のとおりです。
その後、実行ステータスをオンラインで確認できます。 上記は Linux デバッガー GDB の基本的な使用方法の詳細な内容です。Linux デバッガー GDB の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
>>: CSSポジショニングによる階層関係の問題の詳細な説明
概要プロジェクトは正常に作成され、正常にデプロイされましたが、以下に示すように、Tomcat サーバ...
水平線<hr /> タグを使用して、現在の位置に水平の分割線を描画します。例: XML/...
目次1. Vueの概要Vue公式サイトMVVM アーキテクチャ パターンVue の紹介2. Vueを...
Mysql マスタースレーブ同期の Last_IO_Errno:1236 エラーの原因は何ですか? ...
背景すべての会社の Web サイトは HTTPS プロトコルをサポートする必要があります。Aliba...
私たち、特に Linux エンジニアは毎日 Linux サーバーを扱っています。サーバーのセキュリテ...
Ubuntu に jdk をインストールする: [リンク] UbuntuにEclipseをインストー...
コアはmysqldumpとランタイムです操作は実際にはそれほど難しくありません。バックアップ操作を実...
注意: この方法は、Webkit ベースのブラウザにのみ適用されます。ブラウザのスクロールバーが広す...
概要データベースでは、ツリー ディレクトリと同様に、インデックスを使用してデータ検索を高速化します。...
目次効果ドキュメント最初のステップステップ2ステップ3ソースコード効果ドキュメント最初のステップta...
1. セットアップを始める次のコード関数を簡単に紹介します。 ref 関数を使用して変数の変更を監視...
まず、Docker がインストールされたサーバーが必要です。 (私はすでにこれをサーバーにインストー...
目次1. usrディレクトリにHadoopディレクトリを作成し、インストールパッケージをそのディレク...
解決すべき問題主にコンポーネント間のクロスレベル通信用なぜディスパッチとブロードキャストを自分で実装...