web-dev-qa-db-ja.com

GDBが行間で予期せずジャンプし、変数を「<value optimize out>」として出力するのはなぜですか?

誰でもgdbのこの動作を説明できますか?

900         memset(&new_ckpt_info,'\0',sizeof(CKPT_INFO));
(gdb)
**903         prev_offset   = cp_node->offset;**
(gdb)
**905         m_CPND_CKPTINFO_READ(ckpt_info,(char *)cb->shm_addr.ckpt_addr+sizeof(CKPT_** HDR),i_offset);
(gdb)
**903         prev_offset   = cp_node->offset;**
(gdb)
**905         m_CPND_CKPTINFO_READ(ckpt_info,(char *)cb->shm_addr.ckpt_addr+sizeof(CKPT_ HDR),i_offset);**
(gdb)
**908         bitmap_offset  = client_hdl/32;**
(gdb)
**910         bitmap_value = cpnd_client_bitmap_set(client_hdl%32);**
(gdb)
**908         bitmap_offset  = client_hdl/32;**
(gdb)
**910         bitmap_value = cpnd_client_bitmap_set(client_hdl%32);**
(gdb)
**908         bitmap_offset  = client_hdl/32;**
(gdb)
**910         bitmap_value = cpnd_client_bitmap_set(client_hdl%32);**
(gdb)
913         found = cpnd_find_exact_ckptinfo(cb , &ckpt_info , bitmap_offset , &offset , &prev_offset);
(gdb)
916         if(!found)
(gdb) p found
$1 = <value optimized out>
(gdb) set found=0
Left operand of assignment is not an lvalue.

なぜ903行目を実行した後、905 908 910でも同じことを再度実行するのですか?

もう1つは、foundbool型の変数であるため、なぜvalue optimized outを表示しているのでしょうか。 foundの値も設定できません。

これはコンパイラの最適化のようです(この場合は-O2)。 foundの値を設定するにはどうすればよいですか?

83
Arpit

最適化されたコードをデバッグするには、アセンブリ/マシン言語を学びます。

GDB TUIモードを使用します。 GDBのコピーは、マイナスを入力してEnterを押すと有効になります。次に、C-x 2と入力します(つまり、Controlを押しながらXを押し、両方を離してから2を押します)。これにより、ソースが分割表示され、逆アセンブリ表示されます。次に、stepinextiを使用して、一度に1つの機械語命令を移動します。 C-x oを使用して、TUIウィンドウを切り替えます。

CPUの機械語と関数呼び出し規約についてPDFをダウンロードしてください。関数の引数と戻り値で何が行われているかをすぐに理解できます。

p $eaxなどのGDBコマンドを使用して、レジスターの値を表示できます

113
Zan Lynx

最適化せずに再コンパイルします(gccの-O0)。

74
D'Nabre

foundを「volatile」として宣言します。これは、コンパイラーに最適化しないように指示する必要があります。

volatile int found = 0;
38
BenB

コンパイラーは、最適化を有効にして非常に賢いことを始めます。デバッガーは、変数がレジスターに格納される方法が最適化されているため、コードが前後にジャンプして表示されます。これはおそらく、デバッガーがアクセスできる直接メモリの場所を持つのではなく、速度を上げるためにレジスタ間で巧妙に分散されているため、変数を設定できない(または場合によってはその値を見る)ことができない理由です。

最適化せずにコンパイルしますか?

11
kjfletch

通常、このように計算された直後にブランチで使用されるブール値は、実際には変数に保存されません。代わりに、コンパイラは、直前の比較で設定された 条件コード から直接分岐します。例えば、

int a = SomeFunction();
bool result = --a >= 0; // use subtraction as example computation
if ( result ) 
{
   foo(); 
}
else
{
   bar();
}
return;

通常、次のようにコンパイルされます。

call .SomeFunction  ; calls to SomeFunction(), which stores its return value in eax
sub eax, 1 ; subtract 1 from eax and store in eax, set S (sign) flag if result is negative
jl ELSEBLOCK ; GOTO label "ELSEBLOCK" if S flag is set
call .foo ; this is the "if" black, call foo()
j FINISH ; GOTO FINISH; skip over the "else" block
ELSEBLOCK: ; label this location to the assembler
call .bar
FINISH: ; both paths end up here
ret ; return

「bool」が実際にどこにも保存されないことに注意してください。

6
Crashworks

最適化されたプログラム(デバッグビルドにバグが表示されない場合に必要になる可能性があります)をデバッグする場合、アセンブリコンパイラが生成することを理解する必要があります。

特定のケースでは、cpnd_find_exact_ckptinfoの戻り値は、戻り値のためにプラットフォームで使用されるレジスタに格納されます。 ix86では、%eaxになります。 x86_64%raxなど。上記のいずれでもない場合は、「[プロセッサ]プロシージャ呼び出し規約」をグーグルで検索する必要があります。

GDBでそのレジスタを調べて設定できます。例えば。 ix86

(gdb) p $eax
(gdb) set $eax = 0 
4

Foundの値を設定することはほとんどできません。最適化されたプログラムをデバッグすることはめったに価値がありません。コンパイラは、ソースコードにまったく対応しない方法でコードを再配置できます(同じ結果を生成する以外)。

4
nos

私はgdbでQtCreatorを使用しています。

追加中

QMAKE_CXXFLAGS += -O0
QMAKE_CXXFLAGS -= -O1
QMAKE_CXXFLAGS -= -O2
QMAKE_CXXFLAGS -= -O3

私にとってはうまくいく

0