1. ホーム
  2. c

[解決済み] GDBでスタックフレームが破壊された - デバッグするには?

2022-08-29 01:47:53

質問

次のようなスタックトレースがあります。ここからデバッグに役立つものを見つけ出すことは可能でしょうか。

Program received signal SIGSEGV, Segmentation fault.
0x00000002 in ?? ()
(gdb) bt
#0  0x00000002 in ?? ()
#1  0x00000001 in ?? ()
#2  0xbffff284 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) 

を得たとき、どこからコードを見ればいいのでしょうか? Segmentation fault が表示され、スタックトレースはあまり役に立ちません。

注:コードを投稿すれば、SOのエキスパートが答えを教えてくれるでしょう。私はSOの指導を受け、自分で答えを見つけたいので、ここにコードを投稿していません。申し訳ございません。

どのように解決するのですか?

これらの偽のアドレス (0x00000002 など) は、実際には SP 値ではなく PC 値です。 さて、偽の (非常に小さな) PC アドレスでこの種の SEGV が発生した場合、99% の場合、それは偽の関数ポインタを介して呼び出されたことが原因です。 C++の仮想呼び出しは関数ポインタを介して実装されているため、仮想呼び出しの問題はすべて同じ方法で現れる可能性があることに注意してください。

間接呼び出し命令は、呼び出し後の PC をスタックにプッシュし、PC をターゲット値 (この場合はインチキ) に設定するだけなので、もしこれが であれば、手動でスタックから PC をポップ オフすることで簡単に元に戻せます。 32 ビット x86 コードでは、ただそうするだけです。

(gdb) set $pc = *(void **)$esp
(gdb) set $esp = $esp + 4

64ビットx86のコードでは、以下のものが必要です。

(gdb) set $pc = *(void **)$rsp
(gdb) set $rsp = $rsp + 8

次に bt を実行して、実際にコードがどこにあるのかを把握します。

残りの1%は、スタックを上書きしたことによるエラーで、通常はスタックに格納された配列をオーバーフローさせることで発生します。 この場合、次のようなツールを使用することで、状況をより明確にすることができるかもしれません。 valgrind