Czy ktoś może wyjaśnić to zachowanie 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.
Dlaczego po wykonaniu linii 903 ponownie wykonuje to samo dla 905 908 910?
Kolejne rzeczy jest found
to bool
zmienna typu a, więc dlaczego to pokazuje value optimized out
? Nie jestem w stanie również ustawić wartości found
.
Wydaje się, że jest to optymalizacja kompilatora (w tym przypadku -O2
); jak mogę nadal ustawić wartość found
?
Odpowiedzi:
Aby debugować zoptymalizowany kod, naucz się języka asemblera / maszynowego.
Użyj trybu GDB TUI. Moja kopia GDB włącza to, kiedy wpisuję minus i Enter. Następnie wpisz Cx 2 (to znaczy przytrzymaj Control i naciśnij X, zwolnij oba, a następnie naciśnij 2). Spowoduje to wyświetlenie podzielonego źródła i demontażu. Następnie użyj
stepi
i,nexti
aby przesuwać jedną instrukcję maszynową na raz. Użyj Cx o, aby przełączać się między oknami TUI.Pobierz plik PDF o języku maszynowym procesora i konwencjach wywoływania funkcji. Szybko nauczysz się rozpoznawać, co się dzieje z argumentami funkcji i zwracanymi wartościami.
Możesz wyświetlić wartość rejestru za pomocą polecenia GDB, takiego jak
p $eax
źródło
Przekompiluj bez optymalizacji (-O0 na gcc).
źródło
Declare znaleźć jako „lotny”. Powinno to powiedzieć kompilatorowi, aby NIE optymalizował go.
volatile int found = 0;
źródło
Kompilator zacznie robić bardzo sprytne rzeczy z włączoną optymalizacją. Debugger pokaże kod przeskakujący dużo do przodu i do tyłu dzięki zoptymalizowanemu sposobowi przechowywania zmiennych w rejestrach. Jest to prawdopodobnie powód, dla którego nie możesz ustawić swojej zmiennej (lub w niektórych przypadkach zobaczyć jej wartości), ponieważ została sprytnie rozdzielona między rejestry dla szybkości, zamiast mieć bezpośrednią lokalizację w pamięci, do której debugger może uzyskać dostęp.
Skompilować bez optymalizacji?
źródło
Zwykle wartości logiczne, które są używane w gałęziach natychmiast po ich obliczeniu w ten sposób, nigdy nie są w rzeczywistości przechowywane w zmiennych. Zamiast tego kompilator po prostu rozgałęzia się bezpośrednio od kodów warunków, które zostały ustawione z poprzedniego porównania. Na przykład,
int a = SomeFunction(); bool result = --a >= 0; // use subtraction as example computation if ( result ) { foo(); } else { bar(); } return;
Zwykle kompiluje się do czegoś takiego:
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
Zwróć uwagę, że „bool” nigdy nie jest nigdzie przechowywany.
źródło
Prawie nie możesz ustawić wartości znalezionych. Debugowanie zoptymalizowanych programów rzadko jest warte zachodu, kompilator może zmienić kolejność kodu w taki sposób, że w żaden sposób nie będzie on odpowiadał kodowi źródłowemu (poza wytworzeniem tego samego wyniku), myląc w ten sposób debugery bez końca.
źródło
Podczas debugowania zoptymalizowanych programów (co może być konieczne, jeśli błąd nie pojawia się w kompilacjach debugowania), często trzeba zrozumieć wygenerowany kompilator asemblera.
W Twoim konkretnym przypadku wartość zwracana
cpnd_find_exact_ckptinfo
będzie przechowywana w rejestrze, który jest używany na Twojej platformie do zwracania wartości. Takix86
by było%eax
. Onx86_64
:%rax
itd. Może być konieczne wyszukanie w Google „konwencji wywoływania procedur [twój procesor]”, jeśli nie jest to żadna z powyższych.Możesz sprawdzić ten rejestr
GDB
i ustawić go. Np. Naix86
:(gdb) p $eax (gdb) set $eax = 0
źródło
Używam QtCreator z gdb.
Dodawanie
U mnie działa dobrze
źródło