2009-08-28 8 views
80

Qualcuno può spiegare questo comportamento di gdb?Perché GDB salta in modo imprevedibile tra le righe e stampa le variabili come "<valore ottimizzato>"?

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. 

Perché dopo l'esecuzione linea 903 si esegue di nuovo lo stesso per 905 908 910?

Un'altra cosa è found è una variabile di tipo bool, quindi perché sta mostrando value optimized out? Non riesco a impostare il valore di found.

Questo sembra essere un'ottimizzazione del compilatore (in questo caso il suo -O2); come posso ancora impostare il valore di found?

+7

quando il debug, è generalmente una buona idea di compilare con -O0 come ottimizzare porta a questo tipo di problemi. – LiraNuna

risposta

112

per eseguire il debug di codice ottimizzato, imparare il linguaggio assembly/macchina.

Utilizzare la modalità TUI GDB.La mia copia di GDB lo abilita quando digito il segno meno e Invio. Quindi digitare C-x 2 (tenere premuto Control e premere X, rilasciare entrambi e quindi premere 2). Questo lo metterà in visualizzazione split source e disassembly. Quindi utilizzare stepi e nexti per spostare un'istruzione macchina alla volta. Usa C-x o per spostarti tra le finestre TUI.

Scaricare un PDF sulla lingua della macchina della CPU e le convenzioni di chiamata della funzione. Imparerai rapidamente a riconoscere ciò che viene fatto con argomenti di funzione e valori di ritorno.

È possibile visualizzare il valore di un registro utilizzando un comando GDB come p $eax

+0

Ho ancora il problema "ottimizzato" e il valore della variabile non è mostrato nelle altre finestre, ma, comunque, è un'ottima informazione, grazie! –

+15

@ TomBrito: Ottimizzato significa che la variabile non è in memoria. Probabilmente è solo in un registro CPU, il che significa che è necessario leggere lo smontaggio e stampare i valori del registro per trovarlo. –

+0

@Zan Lynx: non sono sicuro di essere d'accordo con la tua analisi. I simboli DWARF hanno informazioni sufficienti per estrarre i valori dai registri. Forse ciò che si intende qui è che il compilatore ha determinato che la variabile può essere scartata in modo sicuro prima che l'esecuzione del tempo raggiunga la linea corrente. In quel caso la memoria in cui la variabile vive è stata probabilmente riutilizzata per qualcos'altro. Penso che tu abbia ragione nel dire che questo normalmente si verifica solo se la variabile è stata registrata, comunque. –

11

Il compilatore inizierà a fare cose molto intelligenti con le ottimizzazioni attivate. Il debugger mostrerà il codice che salta in avanti e indietro molto a causa del modo ottimizzato in cui le variabili sono memorizzate nei registri. Questo è probabilmente il motivo per cui non è possibile impostare la variabile (o in alcuni casi vederne il valore) poiché è stata abilmente distribuita tra i registri per la velocità, piuttosto che avere una posizione di memoria diretta a cui il debugger può accedere.

Compilare senza ottimizzazioni?

4

Quasi non è possibile impostare il valore di trovato. Il debug di programmi ottimizzati raramente vale la pena, il compilatore può riorganizzare il codice in modo che non corrisponda in alcun modo al codice sorgente (diverso dal produrre lo stesso risultato), confondendo così i debugger a non finire.

38

Declare ha trovato come "volatile". Questo dovrebbe dire al compilatore di NON ottimizzarlo.

volatile int found = 0; 
+0

Anche quando dichiaro alcune variabili "volatili" nel debugger gdb lo mostra come variabile ottimizzata! C'è più in questo? –

5

In genere, i valori booleani utilizzati nelle diramazioni immediatamente dopo essere stati calcolati in questo modo non vengono mai effettivamente memorizzati nelle variabili. Invece, il compilatore si dirama direttamente dallo condition codes impostato dal confronto precedente. Ad esempio,

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

compila solito a qualcosa di simile:

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 

Si noti come il "bool" non è mai in realtà memorizzati da nessuna parte.

4

Quando si esegue il debug di programmi ottimizzati (che possono essere necessari se il bug non viene visualizzato nelle build di debug), è spesso necessario comprendere il compilatore di assiemi generato.

Nel tuo caso particolare, il valore di ritorno di cpnd_find_exact_ckptinfo verrà memorizzato nel registro utilizzato sulla piattaforma per i valori di ritorno. Su ix86, sarebbe %eax. x86_64: %rax, ecc. Potrebbe essere necessario google per la convenzione di chiamata della procedura [del processore in uso] se non si verifica nulla di quanto sopra.

È possibile esaminare tale registro in GDB ed è possibile impostarlo. Per esempio. on ix86:

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

Ricompilate senza ottimizzazioni (-O0 su GCC).

+14

Anche -O0 può produrre codice ottimizzato (cercando di lottare con questo in questo momento), anche se non sono sicuro del perché. –

+0

@ChrisGregg Ho avuto lo stesso problema! Hai scoperto qual è il problema? –

+0

@paolom sembra che potrebbe essere un problema di clang, quindi sono stato compilando con g ++ invece per scopi di debug, purtroppo. –

0

Im utilizzando QtCreator con gdb.

Aggiunta

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

funziona bene per me