web-dev-qa-db-fra.com

Pourquoi GDB saute-t-il de façon imprévisible entre les lignes et imprime les variables en tant que "<valeur optimisée>>"?

Quelqu'un peut-il expliquer ce comportement de 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.

Pourquoi après avoir exécuté la ligne 903, il exécute à nouveau la même chose pour 905 908 910?

Une autre chose est que found est une variable de type bool-, alors pourquoi affiche-t-il value optimized out? Je ne peux pas non plus définir la valeur de found.

Cela semble être une optimisation du compilateur (dans ce cas sa -O2); comment puis-je toujours définir la valeur de found?

83
Arpit

Pour déboguer un code optimisé, apprenez le langage assembleur/machine.

Utilisez le mode GDB TUI. Ma copie de GDB l’active lorsque je tape le moins et Entrée. Ensuite, tapez C-x 2 (maintenez enfoncée la touche Ctrl et appuyez sur X, relâchez les deux puis appuyez sur 2). Cela le mettra en source scindée et en affichage de désassemblage. Ensuite, utilisez stepi et nexti pour déplacer une instruction machine à la fois. Utilisez C-x o pour basculer entre les fenêtres TUI.

Téléchargez un PDF) sur le langage machine de votre CPU et sur les conventions d’appel des fonctions. Vous apprendrez rapidement à reconnaître ce que vous faites avec les arguments et les valeurs de fonction.

Vous pouvez afficher la valeur d’un registre à l’aide d’une commande GDB telle que p $eax

113
Zan Lynx

Recompiler sans optimisations (-O0 sur gcc).

74
D'Nabre

Déclarez trouvé comme "volatil". Cela devrait indiquer au compilateur de ne PAS l'optimiser.

volatile int found = 0;
38
BenB

Le compilateur commencera à faire des choses très intelligentes avec des optimisations activées. Le débogueur montrera le code sautant en avant et en arrière beaucoup en raison de la façon optimisée la façon dont les variables sont stockées dans les registres. C'est probablement la raison pour laquelle vous ne pouvez pas définir votre variable (ou dans certains cas voir sa valeur) car elle a été intelligemment répartie entre les registres pour la vitesse, plutôt que de disposer d'un emplacement de mémoire direct auquel le débogueur peut accéder.

Compiler sans optimisations?

11
kjfletch

En règle générale, les valeurs booléennes utilisées dans les branches immédiatement après leur calcul ne sont jamais stockées dans des variables. Au lieu de cela, le compilateur se branche directement sur les codes de condition qui ont été définis à partir de la comparaison précédente. Par exemple,

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

Compile habituellement à quelque chose comme:

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

Remarquez comment le "bool" n'est jamais stocké nulle part.

6
Crashworks

Lors du débogage de programmes optimisés (ce qui peut être nécessaire si le bogue n'apparaît pas dans les versions de débogage), vous devez souvent comprendre le compilateur Assembly généré.

Dans votre cas particulier, la valeur de retour de cpnd_find_exact_ckptinfo Sera stockée dans le registre qui est utilisé sur votre plate-forme pour les valeurs de retour. Sur ix86, Ce serait %eax. Sur x86_64: %rax, Etc. Vous aurez peut-être besoin de google pour la 'convention d'appel de la procédure [de votre processeur]' si ce n'est pas le cas.

Vous pouvez examiner ce registre dans GDB et vous pouvez le définir. Par exemple. sur ix86:

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

Vous ne pouvez pratiquement pas définir la valeur de found. Déboguer des programmes optimisés en vaut rarement la peine, le compilateur peut réorganiser le code de manière à ce qu'il ne corresponde en aucune manière au code source (autre que produire le même résultat), ce qui confond indéfiniment les débogueurs.

4
nos

J'utilise QtCreator avec gdb.

Ajouter

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

Fonctionne bien pour moi

0
Haselnussstrauch