このようなジャンク バックトレースが発生した場合は、スタックがなんらかの形で破壊され、実際のリターン アドレスとスタック フレーム ポインターが上書きされたことをほぼ確実に意味します。
値0xbffff118
はほぼ確実にスタック内のアドレスです。多くの x86 Linux コンパイラーでは、コンパイラーは仮想アドレス0xc0000000
でスタックを開始し、そこから下に向かって成長するため、 で始まるアドレス0xbfff
はスタック アドレスである可能性が非常に高いと思います。
通常、命令ポインターはスタック内にあるべきではありません。通常、スタックを指している値がスタックに格納されている戻りアドレスを上書きし、現在の関数が戻ると、上書きされた値に戻ります。スタックが実行可能でない場合は、本来あるべきように、すぐにシグナルが発生します。どういうわけかスタックが実行可能である場合、悪意を持って悪用されていない限り、数命令後までクラッシュしない可能性があります。
あなたが知っているように、スタックが破壊backtrace
されると、コマンドは役に立たなくなります。そこから何が起こっているのかを把握する最善の方法は、スタックを手動で調べて、おそらくリターン アドレスとフレーム ポインターを検索することです。このコマンドを使用しx
てメモリ領域をダンプできます (詳細については実行help x
してください)。を使用してx/<NUMBER>wx
、4 バイトの 16 進値としてダンプするのが好きです。したがって、スタックポインタから始まる一連のデータをダンプする方法は次の$esp
とおりです。
(gdb) x/64wx $esp
0xbffff7c0: 0x00000073 0xbffff9e9 0x0000000b 0x00000012
0xbffff7d0: 0xbffff9e8 0x0be04aa0 0xbffff7f8 0x000018aa
0xbffff7e0: 0x0be04aa0 0xbffff9e8 0x00000000 0x00000002
0xbffff7f0: 0xbffff9e7 0x09a0bb10 0xbffff818 0x000018aa
0xbffff800: 0x09a0bb10 0xbffff9e7 0x00000002 0x0000000e
0xbffff810: 0xbffff9e6 0x015377f0 0xbffff838 0x000018aa
0xbffff820: 0x015377f0 0xbffff9e6 0x00000008 0x00000011
0xbffff830: 0xbffff9e5 0x01537860 0xbffff858 0x000018aa
0xbffff840: 0x01537860 0xbffff9e5 0x00000003 0x0000000f
0xbffff850: 0xbffff9e4 0x001ddbc0 0xbffff878 0x000018aa
0xbffff860: 0x001ddbc0 0xbffff9e4 0x00000018 0x00000017
0xbffff870: 0xbffff9e3 0x00177c50 0xbffff898 0x000018aa
0xbffff880: 0x00177c50 0xbffff9e3 0xbffff8b8 0x00000000
0xbffff890: 0xbffff9e2 0x00176050 0xbffff8b8 0x000018aa
0xbffff8a0: 0x00176050 0xbffff9e2 0xbffff9e1 0x0000000c
0xbffff8b0: 0xbffff9e1 0x00174920 0xbffffb08 0x00001b8a
ここでは、$esp
is 0xbffff7c0
、および$eip
is 0x00001870
(コマンドを使用して取得しましたが、すべてのレジスタを取得するためにp/x $eip
で確認することもできます)。info regs
したがって、すべてのスタック フレームは、スタック ( ) の上位にあるポインタであり、0xbfff....
その後に のようなアドレスが続きます0x00001870
。メモリ ダンプでこれらを探すと、これらがスタック フレームであることはほぼ確実です。
0xbffff7f8 0x000018aa
0xbffff818 0x000018aa
0xbffff838 0x000018aa
(etc.)
これは、私が横たわっていた非常に再帰的なプログラムから得た例です。そのため、戻りアドレスはすべて同じです。破壊されていない適切なスタック フレームをいくつか見つけたら、フレーム ポインターを自分でたどることができます。
(gdb) x/2wx 0xbffff7f8
0xbffff7f8: 0xbffff818 0x000018aa
(gdb) x/2wx 0xbffff818
0xbffff818: 0xbffff838 0x000018aa
(gdb) x/2wx 0xbffff838
0xbffff838: 0xbffff858 0x000018aa
(gdb) x/2wx 0xbffff858
0xbffff858: 0xbffff878 0x000018aa
...
そして、命令アドレスをシンボル名に変換したい場合は、再度x
コマンドを使用できます。デバッグ シンボルがある場合、gdb は問題なくシンボル名を出力します。
(gdb) x 0x000018aa
0x18aa <add_word+154>: 0x5d18c483
これは、スタックが破壊されたときに実際に役立つスタック トレースを取得する方法の簡単な入門書です。もちろん、最初からこれを避けるのが最善です。コードをコンパイルすることを強くお勧めします-Wall -Wextra -Werror
(-pedantic
可能であれば)。もちろん、本当に正当な理由が-fno-stack-protector
ない限り、使用しないでください。