誰でも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つは、found
がbool
型の変数であるため、なぜvalue optimized out
を表示しているのでしょうか。 found
の値も設定できません。
これはコンパイラの最適化のようです(この場合は-O2
)。 found
の値を設定するにはどうすればよいですか?
最適化されたコードをデバッグするには、アセンブリ/マシン言語を学びます。
GDB TUIモードを使用します。 GDBのコピーは、マイナスを入力してEnterを押すと有効になります。次に、C-x 2と入力します(つまり、Controlを押しながらXを押し、両方を離してから2を押します)。これにより、ソースが分割表示され、逆アセンブリ表示されます。次に、stepi
とnexti
を使用して、一度に1つの機械語命令を移動します。 C-x oを使用して、TUIウィンドウを切り替えます。
CPUの機械語と関数呼び出し規約についてPDFをダウンロードしてください。関数の引数と戻り値で何が行われているかをすぐに理解できます。
p $eax
などのGDBコマンドを使用して、レジスターの値を表示できます
最適化せずに再コンパイルします(gccの-O0)。
foundを「volatile」として宣言します。これは、コンパイラーに最適化しないように指示する必要があります。
volatile int found = 0;
コンパイラーは、最適化を有効にして非常に賢いことを始めます。デバッガーは、変数がレジスターに格納される方法が最適化されているため、コードが前後にジャンプして表示されます。これはおそらく、デバッガーがアクセスできる直接メモリの場所を持つのではなく、速度を上げるためにレジスタ間で巧妙に分散されているため、変数を設定できない(または場合によってはその値を見る)ことができない理由です。
最適化せずにコンパイルしますか?
通常、このように計算された直後にブランチで使用されるブール値は、実際には変数に保存されません。代わりに、コンパイラは、直前の比較で設定された 条件コード から直接分岐します。例えば、
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」が実際にどこにも保存されないことに注意してください。
最適化されたプログラム(デバッグビルドにバグが表示されない場合に必要になる可能性があります)をデバッグする場合、アセンブリコンパイラが生成することを理解する必要があります。
特定のケースでは、cpnd_find_exact_ckptinfo
の戻り値は、戻り値のためにプラットフォームで使用されるレジスタに格納されます。 ix86
では、%eax
になります。 x86_64
:%rax
など。上記のいずれでもない場合は、「[プロセッサ]プロシージャ呼び出し規約」をグーグルで検索する必要があります。
GDB
でそのレジスタを調べて設定できます。例えば。 ix86
:
(gdb) p $eax
(gdb) set $eax = 0
Foundの値を設定することはほとんどできません。最適化されたプログラムをデバッグすることはめったに価値がありません。コンパイラは、ソースコードにまったく対応しない方法でコードを再配置できます(同じ結果を生成する以外)。
私はgdbでQtCreatorを使用しています。
追加中
QMAKE_CXXFLAGS += -O0
QMAKE_CXXFLAGS -= -O1
QMAKE_CXXFLAGS -= -O2
QMAKE_CXXFLAGS -= -O3
私にとってはうまくいく