Linux でリモートデバッグを行うために gdbserver を使用する方法

最終更新: 14/01/2026
  • gdbserver は GDB のリモート エージェントとして機能し、TCP またはシリアル経由で別のマシン上のプロセスを制御します。
  • リモートデバッグするには、コンパイルすることが重要です シンボル適切な gdb を使用して、シンボルとフォントのパスを適切に構成します。
  • gdbserver はシングルプロセス モードとマルチプロセス モードを提供し、カーネル デバッグ用に WinDbg および QEMU と統合します。
  • --debug、sysroot、値のサイズ制限などのオプションは、問題の診断とセッションの安定化に役立ちます。

gdbserver によるリモートデバッグ

CまたはC++でプログラミングする場合 Linux gdbserverに触れたことがないサーバー、組み込みシステム、仮想マシン、WSLなど、リモートでプロセスをデバッグするための最も便利なツールの一つを見逃しています。gdbserverは、魔法のようなものでも専門家向けでもなく、gdbと通信して対象プロセスの実行を制御する小さなプログラムです。

重要な考え方は非常にシンプルです。: デバッグしたいバイナリが動作しているマシン( ターゲット)仕事用のコンピュータ( hostgdb または gdb プロトコルをサポートする WinDbg を起動します。どちらも TCP またはシリアルポート経由で接続し、そこからブレークポイントの設定、変数の検査、スタックの表示、あるいはまるで自分のマシンでプログラムを実行しているかのように実行をステップごとに追跡することができます。

gdbserver とは何ですか? また、いつ使用するのが適切ですか?

gdbserverとは

gdbserverはGNU gdbのリモートデバッグ「エージェント」です。その機能は非常に特殊です。分析対象のプログラムが実行されているマシン上で実行され、そのプロセス (またはプロセス群) を制御し、リモート接続を介して別のマシン (または同じマシン) にある gdb クライアントと通信します。

日常的な使用では、gdbserver は2つの典型的なシナリオで使用されます。組み込み環境(ルーター、簡素化された Linux を搭載したボード、デバイス)で実行されるソフトウェアのデバッグ IoTなど) や、すべてのライブラリとシンボルを備えた「ファット」 gdb を用意することが不便であったり、単純に不可能であったりするリモート Linux マシン上のプロセスをデバッグします。

実用レベルでは、gdbserverは次のようなタスクを処理します。 プロセスレジスタとメモリの読み書き、実行制御(継続、一時停止、ステップ実行)、ブレークポイントの管理、そしてこれらすべてのデータをGDBリモートプロトコルを使ってGDBに送信します。この考え方は、GDBと外部のOS間の橋渡しとして機能するOpenOCDなどのツールの考え方と非常に似ています。 ハードウェア 外部ですが、gdbserver はバイナリが実行されるのと同じシステムで実行されるという違いがあります。

あなたが環境から来た場合 Windows 知っておくと面白いのは WinDbg などのデバッガーは Linux 上の gdbserver と通信できるため、Microsoft が最近のバージョンに組み込んだ gdb プロトコル経由のリモート デバッグ サポートを使用して、WinDbg から Linux 上のユーザー プロセスをデバッグできます。

gdbとgdbserverを使ったデバッグの基本要件

gdbserver の使用要件

リモートでデバッグを開始する前に、ホストとターゲットの関係を理解する必要があります。。 ザ ターゲット デバッグ対象のプログラムが実行され、gdbserverが実行されるマシンです。 host これは、gdb (または WinDbg) を実行するマシンであり、ソース コードと、できればデバッグ シンボルが保存される場所です。

重要な出発点は、シンボルを使ってバイナリをコンパイルすることですGCCやg++では、これはフラグで実現できる。 -gまた、通常は最適化も無効にすることをお勧めします(たとえば、 -O0これにより、デバッガは変数、マクロ、コード構造をより正確に表示できます。特定のマクロについては、次のようなより高いデバッグレベルを使用できます。 -g3.

ホスト側では互換性のあるバージョンのgdbが必要になります ターゲットアーキテクチャと互換性があります。MIPS、ARM、その他のアーキテクチャの組み込みシステムをデバッグするには、対応するクロスツールチェーンのgdbを使用する必要があります(例: arm-none-eabi-gdb o gdb-multiarch)そして必要に応じて、アーキテクチャとエンディアンを設定します。 コマンド として set arch y set endian.

接続に関しては、gdbserverは主に2つのタイプをサポートしています。シリアルリンク(組み込みハードウェアではUART経由が一般的)とTCP/IP。ターゲットが同一ネットワーク上にある場合、またはネットワーク経由でアクセス可能なLinuxマシンの場合に最も便利です。どちらの場合も、コマンドはgdbから使用します。 target remote gdbserver によって公開されるエンドポイントに接続します。

gdbserver の起動方法: シングルプロセスモードとマルチプロセスモード

gdbserver 実行モード

gdbserverは主に2つの方法で動作します ユーザー モードのデバッグについて言えば、単一のプロセスに直接関連付けられるか、またはさまざまなシステム プロセスの一覧表示とアタッチを可能にする「プロセス サーバー」として関連付けられます。

シングルプロセスモード gdbserverを起動し、ホスト:ポート番号と実行するプログラムを指定します。Linuxデスクトップマシンでの簡単な例では、次のように実行できます。

コマンド: gdbserver localhost:3333 foo

このコマンドにより、gdbserver はバイナリを起動します。 foo そして彼はポート3333で聞き続けているリモートGDBが接続するまでプログラムは停止したままです。GDBが接続すると target remote localhost:3333プロセスは、デスクリッパーによって制御され始めます。

マルチプロセスモード(プロセスサーバー)では、このオプションが使用されます --multiこの場合、gdbserver はプログラムを直接起動するのではなく、着信接続をリッスンし、クライアント (gdb または WinDbg) がどのプロセスを作成またはアタッチするかを管理できるようにします。

  Google が AI 搭載の無料プログラミング アシスタント「Gemini Code Assist」をリリース

コマンド: gdbserver --multi localhost:1234

Linux 上で WinDbg を使用する場合、このマルチモードは特に興味深いものです。WinDbg自体から、プロセスサーバーで行うのと同様の方法で、リモートシステム上のプロセスを一覧表示し、PID、ユーザー、コマンドラインを確認し、興味のあるプロセスにアタッチすることができます。 dbgsrv.exe Windowsの場合。

gdbserver と gdb を使ったリモートデバッグの手順

非常に典型的な例を使ってこれを現実的に考えてみましょう。: gdbserver を使用して、リモート シナリオをシミュレートし、同じマシン (ホストとターゲットが一致) 上で単純なアプリケーションをデバッグします。

まず小さなプログラムを書いてコンパイルしますたとえば、カウンターを出力する単純なループは次のようになります。

コマンド: gcc -g foo.c -o foo

ここで重要なのは旗だ -gこれにより、バイナリに必要なデバッグ情報が追加され、gdb がコード行、変数名、型などを表示できるようになります。「実際の」クロスコンパイル環境では、クロスツールチェーンを使用してこのコンパイルを実行し、バイナリとその依存関係の両方をターゲットにコピーします。

次のステップはターゲット上でgdbserverを起動することですホストとターゲットが同じマシンの場合:

コマンド: gdbserver localhost:3333 foo

次のようなメッセージが表示されます。 「プロセス foo が作成されました。pid = XXXX; ポート 3333 で待機しています。」これは、gdbserver がプロセスを作成し、gdb からの接続を待機していることを示しています。より多くの権限が必要なシステム(例えば、システムプロセスへのアタッチなど)の場合は、コマンドを次のように実行する必要があるかもしれません。 sudoしかし、許可を与えるときは常に注意することが賢明です。 ルート 脱硫装置へ。

ホスト上で、ローカル実行ファイルを指定してgdbを起動します。 (ターゲット上で実行されているものと同じもの、またはシンボルを含む同一のコピー):

コマンド: gdb foo

gdbに入ったら、リモート接続を確立します。:

コマンド: target remote localhost:3333

その時点で、gdb はローカルバイナリからシンボルをロードします。gdbserverと同期し、gdbserverの下で実際に実行されているプロセスを制御します。そこからの流れは通常のものです。次のようなコマンドを実行します。 break 限界点を設定するために、 continue, step, next, print 変数を検査するには、 backtrace バッテリーなどを確認するため

gdbserver を使用して実行中のプロセスに接続する

必ずしもプログラムを最初から起動する必要はありません。すでに実行中のプロセス(例えば、 httpd A ルータシステム デーモンまたは本番サービス)。

典型的なパターンは、オプションを使用することです --attach gdbserverから待ち受けるポートと対象プロセスのPIDを渡します。例えば、ルーターのアーキテクチャに合わせてコンパイルされたgdbserverをコピーした場合、次のように実行できます。

コマンド: gdbserver localhost:3333 --attach <pid_de_httpd>

ホスト側では、ルーターのアーキテクチャをサポートする gdb のバージョンを使用します。例えば gdb-multiarchアーキテクチャとエンディアンを事前に構成します。

コマンド: set arch mips
set endian big

次に、シンボルを含むローカル ファイルを指定します。 リモートバイナリの(例えば file httpd)そして、必要であれば、バイナリが実際にターゲット上でどこで実行されているかをgdbに伝えます。 set remote exec-file /usr/bin/httpd最後に、前と同じように、次のように接続します。

コマンド: target remote 192.168.0.1:3333

取り付けたら特定の関数にブレークポイントを設定できます(例: break checkFirmware)、実行を継続し、プログラムの通常のフロー(たとえば、Web インターフェイスからのファームウェアのアップロード)によってブレークポイントがトリガーされるようにします。

Linux で WinDbg と gdbserver を使用する

近年、マイクロソフトはWinDbgでLinuxプロセスのデバッグのサポートを追加しました。 gdbserver をバックエンドとして使用します。この機能は、Windows で作業しながら、コードは Linux(WSL を含む)で実行されるシナリオを想定しています。

gdbserverを使用してWinDbgで特定のLinuxプロセスをデバッグする流れは次のようになります。まず、Linuxマシン上のターゲットプロセスを次のようなコマンドで見つけます。 ps -A (例えば python3 実行中の場合)、ターゲット上で gdbserver を起動します。

コマンド: gdbserver localhost:1234 python3

環境によっては、 sudo gdbserver ...いつもと同じセキュリティ対策を講じてください。gdbserver が「ポート 1234 をリッスンしています」と表示したら、WinDbg で「ファイル / リモート デバッガーに接続」を選択し、以下の接続文字列を指定します。

コマンド: gdb:server=localhost,port=1234

WinDbgは小さなgdbプロトコル「ドライバー」を使用してgdbserverと通信します。 そして、接続が確立されると、その時点で停止したままになります。 ブーツ プロセスの。そこからスタックウィンドウ、モジュール、メモリ、ブレークポイント、そして以下のようなコマンドを使うことができます。 k バッテリーを確認するには lm モジュールを一覧表示します (一部のコマンドは ELF ではなく PE 形式を想定しているため、場合によっては奇妙なデータが表示される可能性があることに注意してください)。

gdbserver と WinDbg プロセス サーバー

単一プロセスの場合に加えて、WinDbgはプロセスサーバーとして機能するgdbserverに接続することができます。 リモートWindowsプロセスの動作に似た動作をします。このモードでは、gdbserverは次のように起動されます。 --multi 関連するプロセスがない場合:

  iPhoneで低電力モードを有効にする最良の方法

コマンド: sudo gdbserver --multi localhost:1234

WinDbgから「ファイル/プロセスサーバーに接続」を選択します。 そして接続文字列を再利用します gdb:server=localhost,port=1234接続がアクティブな場合、利用可能な Linux プロセスを一覧表示し、必要なプロセスに接続したり、新しいプロセスを起動したりすることもできます。

1 つの微妙な詳細を念頭に置く必要があります。WinDbgは、接続時にgdbserverが既にプロセスにアタッチされているかどうかに応じて、「プロセスサーバー」と「単一ターゲット」を区別します。gdbserverをプロセスにアタッチしたままWinDbgを終了し、再接続を試みた場合、プロセスサーバーとして検出されない可能性があり、gdbserverの再起動が必要になる場合があります。

プロセスサーバーセッションを終了するには通常、gdbserver が動作しているコンソールで Ctrl+D を押し、WinDbg からのデバッグを停止するだけで十分です。ただし、同期に問題がある場合は、極端なケースとしてデバッガーを完全に閉じて gdbserver を最初から再起動する必要があるかもしれません。

リモートデバッグにおけるシンボルとソースコードの管理

リモートデバッグを便利にするための鍵の1つは、シンボルとフォントの部分を適切に解決することです。シンボルがなければ、スタックをナビゲートしたり、特定の関数にブレークポイントを設定したりするのは苦痛になります。

従来の gdb + gdbserver シナリオでは、シンボルを含む実行可能ファイルのコピーをホスト上に保持することが理想的です。 (ストリップされていない)とソースツリー。gdbはリモートバイナリにシンボルが含まれていることを要求しません。 file オフセット レベルでリモート実行可能ファイルと一致します。

WinDbg と Linux デバッグの世界では、DebugInfoD のようなサービスも登場しています。HTTP経由でシンボルやフォントを公開する。WinDbgは次のような特別なパスを使用できる。 DebugInfoD*https://debuginfod.elfutils.org 両方 .sympath のように .srcpath オンデマンドの DWARF シンボルと Linux ELF バイナリ ソース コードをダウンロードします。

WSLの具体的な例では、ユーザーコードは C:\Users\Bob\WinDbg に次のように伝えることができます:

コマンド: .sympath C:\Users\Bob\
.srcpath C:\Users\Bob\

また、システムバイナリにもDebugInfoDを使用したい場合:

コマンド: .sympath+ DebugInfoD*https://debuginfod.elfutils.org
.srcpath+ DebugInfoD*https://debuginfod.elfutils.org

この設定では、スタックを調べたりlibc関数を入力したりするとWinDbg は対応する DWARF シンボルのダウンロードを試み、サーバーもコードを公開している場合はソースをかなり詳細に表示しますが、Windows ツールチェーンは内部的には ELF と DWARF を PE と PDB ほど「ネイティブに」処理しません。

実例: gdbserver と WinDbg を使用した C++ プログラムのデバッグ

分かりやすい例として、画面に挨拶を書き込む小さな C++ アプリケーションがあります。デバッグシンボル付きでWSLでコンパイルされたプログラム。 std::array<wchar_t, 50> 長いメッセージをコピーすると、テキストが切り捨てられ、文字が表示される。 ???? 最後に

次のようにコンパイルすると:

コマンド: g++ DisplayGreeting.cpp -g -o DisplayGreeting

そのバイナリに対してgdbserverを起動します:

コマンド: gdbserver localhost:1234 DisplayGreeting

WinDbgでは文字列で接続します gdb:server=localhost,port=1234 そして、セッションが確立され、シンボルとフォントのパスが設定されたら、 DisplayGreeting!main使用できます dx greeting ローカル配列を調べてそのサイズ (50 位置) を確認し、メモリ タブまたは変数ビューで挨拶がどのように切り取られているかを視覚的に確認します。

この例の素晴らしい点は、WinDbgですべてのELF/DWARF形式を完全にサポートしていなくても、gdbserver をリモート バックエンドとして使用すると、スタックをトラバースしたり、型を検査したり、関数名でブレークポイントを設定したり、C++ コードをかなり快適にナビゲートしたりできます。

qemuとgdbを使ったLinuxカーネルのデバッグ

gdbserver はユーザー モードで使用されるだけでなく、カーネル モードでも非常に強力なシナリオがあります。特にQEMUとデバッグサポートを組み合わせると、その効果が顕著になります。「gdbserver」の役割はQEMU独自のオプションによって担われますが、アプローチは同一です。片方の端末ではデバッグ対象のシステムを実行し、gdbポートを開きます。もう片方の端末では、gdbまたはリモートプロトコルに対応するデバッガーを使用します。

カーネルをデバッグするには、特定のデバッグ オプションを使用してコンパイルする必要があります。: デバッグ情報の生成を有効にする(CONFIG_DEBUG_INFO)、GDBカーネルスクリプト(CONFIG_GDB_SCRIPTS)とカーネル独自のデバッグモード(CONFIG_DEBUG_KERNEL「リンク中にアセンブラ生成シンボルを削除する」など、リンク中にシンボルを削除するオプションを無効にすることも重要です。

コンパイルするとバイナリファイルが得られます vmlinux 「剥奪されていない」これはgdbから使用するものです。また、基本的なinitramfsも必要です。これは以下のコマンドで生成できます。

コマンド: mkinitramfs -o ramdisk.img

次にデバッグパラメータを指定してQEMUを起動します典型的な例としては、 -gdb tcp::1234 gdb互換のリモートエンドポイントを開き、 -S 仮想マシンが最初から一時停止した状態で起動するようにします。また、カーネルも指定します。 -kernel vmlinux-initrd ramdisk.img、メモリと -m 512 そして通常はコンソールを ttyS0 すべてを管理するために ターミナル.

  Windows 11でEdgeを最新バージョンにアップデートする方法:完全なステップバイステップガイド

QEMUがgdbを待機中ホストマシンから、gdbを起動して以下を指定します。 vmlinux そしてあなたは target remote localhost:1234そこから、例えば、早期ブレークポイントを設定することができます。 hb start_kernel次のようなコマンドで実行を制御します。 c (続行)、Ctrl+C を押すと再度一時停止します。

gdbとgdbserverの最近の変更点とニュアンス

Red Hat Enterprise Linux 8 のような最新のディストリビューションでは、gdb と gdbserver に留意する価値のある変更が数多くあります。特に、以前のバージョンから移行する場合や、デバッガーの出力を分析するスクリプトがある場合はそうです。

一方、gdbserverはシェルを使って「下位」プロセスを開始するようになった。gdbと同様に、コマンドラインでの変数の拡張と置換が可能になります。何らかの理由でこの動作を無効にする必要がある場合は、RHEL 8に記載されている特定の設定で以前のモードに戻すことができます。

いくつかのものは削除または変更されました: Javaプログラムのデバッグサポート gcjHP-UX XDB互換モード、次のようなコマンド set remotebaud (置き換え set serial baud)または特定の古い形式との互換性 stabsさらに、スレッドの番号はグローバルではなく、「下位」スレッドによって付けられ、次のように表示されます。 inferior_num.thread_num、次のような新しい便利な変数が追加されました。 $_gthread グローバル識別子を参照します。

もう一つの重要な新機能は調整機能です max-value-sizeこれは、gdbが値の内容を表示するために割り当てることができるメモリ量を制限します。デフォルトは64KiBであるため、巨大な配列や巨大な構造体を出力しようとすると、利用可能なメモリのすべてが表示されるのではなく、「値が大きすぎます」という警告が表示される場合があります。

gdbの処理方法も調整されました。 sysrootデフォルト値は target:つまり、リモートプロセスの場合、まずターゲットシステム上のライブラリとシンボルを探します。ローカルシンボルを優先したい場合は、以下を実行してください。 set sysroot 興味のあるルートで target remote.

コマンド履歴に関しては、現在使用されている環境変数は GDBHISTSIZE 代わりに HISTSIZEこれにより、行読み取りライブラリを使用する他のアプリケーションの動作を妨げることなく、デバッグ セッションで入力したコマンドを保持する期間を微調整できます。

gdbserver を使用したワークフローのヒントとトラブルシューティング

快適なワークフローを実現するために、非常にうまく機能する傾向のあるパターンがいくつかあります。 組み込みシステムやリモートサーバー向けの開発では、まず最初に、シンボルのコンパイルとターゲットへのバイナリの展開を可能な限り自動化する必要があります。これにより、実行ファイルのどのバージョンが実行されているかを常に把握でき、シンボルのコピーをホスト上ですぐに利用できるようになります。

クラッシュ コアが多数ある環境では、gdb をバッチ モードで使用する方法を学ぶ価値があります。、次のような旗 --batch, --ex y -x コアのリストに対してコマンドを自動的に実行し、スクリプトからバックトレースを処理する(例えば、 Python これにより、繰り返し発生する問題をすばやく除外したり、スタック トレースごとに障害をグループ化したりすることが可能になります。

リモート接続に問題が発生した場合、オプション --debug gdbserverはあなたの親友ですたとえば、次のようにしてプロセス サーバーを開始するとします。

コマンド: gdbserver --debug --multi localhost:1234

gdbserverコンソールには何が起こっているかの詳細なトレースが表示されます。 リモート プロトコル レベルでは、着信パケット、フォーマット エラー、切断の問題などが含まれます。これは、gdb サーバーが突然切断された場合、ブレークポイントを設定するとすぐにプロセスがクラッシュした場合、またはデバッグ GUI が gdbserver が理解できない何かを送信した場合に非常に役立ちます。

TP-Linkルーターのような重要なプロセスにgdbserverを接続するような状況では、 httpd特定のブレークポイントでは、競合状態やウォッチドッグが発生し、デバッガ内でプロセスが長時間「スタック」するとプロセスが強制終了することがあります。このような状況では、どのシグナルをブロックするか、どのスレッドを制御するかを調整し、必要に応じてシステム構成(タイムアウト時間、ハードウェアウォッチドッグ)自体を変更して、デバッグセッションを長く実行できるようにする必要があるかもしれません。

gdbserverをうまく使うには、いくつかの部分を組み合わせる必要がある適切なシンボルでコンパイルし、アーキテクチャに適した gdb を選択し、シンボルとソース パスを構成し、gdbserver の 2 つの主なモード (シングル プロセスとマルチ プロセス) を理解し、モードからプルすることを恐れないでください。 --debug 接続が期待どおりに動作しない場合。この基盤があれば、リモートのLinuxシステム、ルーター、またはカスタムカーネルを搭載した仮想マシン上で実行されているアプリケーションのデバッグをPCから行うことが極めて日常的になり、何よりも非常に便利になります。