2016-11-03 1 views
2

他の人が書いたコードでバグを修正しようとしていますが、何が起きているのか把握するためにgdbで実行しようとしています。しかし、私が打つ行の1つはlongjmp()の呼び出しで、その行の "next"を押すとgdbは実行されている次のソース行を壊すのではなく、通常の実行を続けます。 longjmp()行で「ステップ」を実行すると、同様の続きが発生します。 longjmp()の後に実行されている次のソース行でブレークするgdbコマンドはありますか?gdbでlongjmpを実行する方法

+0

あなたは 'break main'を実行してから' run'を実行し、 'step'をプログラムに入れておくことができます。それから、longjmp()の後の行を含むすべての行に入力を促します。 (それがあなたの質問に答えたなら私は答えに入れます) –

+0

"next"の代わりにその行の "step"を押すとどうなりますか?あなたができることの1つは、 'setjmp()'からのゼロ以外の戻り値を扱うコードにブレークポイントを追加することです。 –

+0

@MDXFは、 'next'コマンドの代わりに' step'コマンドを使うのがポイントですか? OPは彼が彼のために働かないと言います。私はあなたが特に 'main'で壊れていることを示唆しているのを見ていますが、' longjmp() 'の前に別の場所で壊れてしまうのはなぜなのでしょうか。 –

答えて

1

ゼロ以外の戻りコードに続く行にブレークポイントを設定する必要があります(setjmp)。例えば

#include <stdio.h> 
#include <setjmp.h> 

jmp_buf jb; 

void f1() 
{ 
    printf("jumping\n"); 
    longjmp(jb, 1); 
    printf("what???\n"); 
} 

int main() 
{ 
    if (!setjmp(jb)) { 
     printf("calling f1\n"); 
     f1(); 
    } else { 
     printf("jumped!!\n"); // line 19 
    } 
    return 0; 
} 

longjmpを呼び出した後、実行すべき次のラインは、ライン19(コメントを参照します)。したがってこの場合は、gdbプロンプトでbreak 19を実行し、longjmpの呼び出し後にその行で停止します。

gdbの出力:

(gdb) break 19 
Breakpoint 2 at 0x40056d: file /tmp/x1.c, line 19. 
(gdb) start 
Temporary breakpoint 3 at 0x400549: file /tmp/x1.c, line 15. 
Starting program: /tmp/x1 
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000 

Temporary breakpoint 3, main() at /tmp/x1.c:15 
15   if (!setjmp(jb)) { 
(gdb) step 
16    printf("calling f1\n"); 
(gdb) 
calling f1 
17    f1(); 
(gdb) 
f1() at /tmp/x1.c:8 
8   printf("jumping\n"); 
(gdb) 
jumping 
9   longjmp(jb, 1); 
(gdb) 

Breakpoint 2, main() at /tmp/x1.c:19 
19    printf("jumped!!\n"); 
(gdb) 
jumped!! 
21   return 0; 
(gdb) 
22  } 
(gdb) 
0x0000003fa441d9f4 in __libc_start_main() from /lib64/libc.so.6 
(gdb) 
+0

これは基本的に働いた。 setjmpが最後に呼び出されたものが何であるか把握するのに少し時間がかかりましたが、十分なsetjmpsが0以外の値に戻った後にブレークポイントを設定した後、プログラムがどこに行かれたかが分かりました。 –

1

は、私が)のlongjmp(後に実行されている次のソース行でブレークするために使用できる任意のGDBコマンドはありますか?

私が知る限りではありません。 jmp_bufの起源をトレースして、コールスタックをバックアップして、それが満たされたsetjmp()を見つけ出す必要があります。ソース内のsetjmp()コールが少ない場合、それぞれの後にブレークポイントを設定することを検討することができます。それ以外の場合は、プログラムをステップ実行し、各setjmp()がパスした後にブレークポイントを設定します。

対応するlongjmp()に達すると、コールスタック内の関数の1つに該当するsetjmp()が見つかるはずです。そうでない場合はjmp_bufが無効です。

btコマンドを使用してコールスタックを取得し、frameコマンドを使用してスタック上のフレームに切り替えて検査することができます。

4

gdbの動作はシステムによって異なることに注意してください。

Linuxの

nextあなたが期待するよう約働くlongjmp上またはthrow:非ローカルジャンプのターゲットがでたり、現在のフレームの上にある場合、実行が停止します。

これは、longjmpthrowの実装でデバッグフックを使用して実装されています。 throwの場合、これはヘルパー機能(旧アプローチ)といわゆるSystemTapプローブ(別名「sdtプローブ」)の両方で行われます。 longjmpの場合、これはglibcのsdtプローブでのみ行われます。

これを機能させるには、プローブサポートを問題のライブラリにコンパイルする必要があります。 readelf -nで確認できます。少なくともFedoraはこれを適切に行います。

gdbの他のプラットフォームではlongjmpのサポートを実装することは理論上可能です。しかし、それは自明ではないかもしれません。

他のコメントに記載されているように、jmp_bufのデコードを試みることができます。ただし、セキュリティ上の理由から、Linuxなどの一部のシステムでは、jmp_bufのターゲットPCがエンコードされています。だからあなたはそれを解読する方法を理解しなければならないでしょう。

これにアプローチするもう1つの方法は、longjmpを介して単純に1ステップ実行することです。ブレークポイントをbreak longjmpのように設定します。アセンブリを表示するにはdisassembleを使用してください。実行をターゲットに転送する命令をステップ実行するまで、siを実行します。

関連する問題