Code optimisé sur Unix?

Quelle est la meilleure méthode et la plus simple pour déboguer du code optimisé sur Unix écrit en C?

Parfois, nous n’avons pas non plus le code pour créer une bibliothèque non optimisée.

C’est une très bonne question. J’ai eu des difficultés similaires dans le passé où je devais intégrer des outils tiers dans mon application. D’après mon expérience, vous devez avoir au moins des stacks d’appels significatives dans les fichiers de symboles associés. Ceci est simplement une liste d’adresses et de noms de fonctions associés. Ceux-ci sont généralement supprimés et, du seul binary, vous ne les obtiendrez pas … Si vous avez ces fichiers de symboles, vous pouvez les charger tout en démarrant gdb ou après en les ajoutant. Sinon, vous êtes coincé au niveau de l’assemblage …

Un comportement bizarre: même si vous avez le code source, il sautera en avant et en arrière dans des endroits auxquels vous ne vous attendez pas (les instructions peuvent être réorganisées pour de meilleures performances) ou les variables n’existent plus (optimisées!), définir des points d’arrêt dans les fonctions intégrées est inutile (ils ne sont pas là mais font partie de l’endroit où ils sont insérés). Donc, même avec le code source, faites attention à ces pièges.

J’ai oublié de mentionner, les fichiers de symboles ont généralement l’extension .gdb, mais cela peut être différent …

Cette question n’est pas sans rappeler “quel est le meilleur moyen de réparer une voiture de tourisme?”

La meilleure façon de déboguer le code optimisé sous UNIX dépend exactement de votre UNIX, des outils dont vous disposez et du type de problème que vous essayez de déboguer.

Déboguer un crash dans malloc est très différent du débogage d’un unresolved symbol at runtime .

Pour les techniques générales de débogage, je recommande ce livre .

Plusieurs choses faciliteront le débogage au “niveau de l’assemblage”:

  • Vous devez connaître la convention d’appel de votre plate-forme, pour savoir quelles valeurs sont passées et renvoyées, où trouver le pointeur, quels registres sont “enregistrés par l’appelant” et lesquels sont “sauvegardés”, etc.
  • Vous devez connaître la “convention d’appel” de votre système d’exploitation – à quoi ressemble un appel système, à quel registre un numéro syscall va, au premier paramètre, etc.
  • Vous devez “maîsortingser” le débogueur: savoir comment trouver des threads, comment arrêter des threads individuels, comment définir un point d’arrêt conditionnel sur une instruction individuelle, une seule étape, entrer ou ignorer les appels de fonctions, etc.

Il est souvent utile de déboguer un programme de travail et un programme endommagé “en parallèle”. Si la version 1.1 fonctionne et que la version 1.2 ne fonctionne pas, où sont-elles divergentes par rapport à une API particulière? Démarrez les deux programmes sous le débogueur, définissez des points d’arrêt sur le même ensemble de fonctions, exécutez les deux programmes et observez les différences entre les points d’arrêt et les parameters transmis.

Ecrivez des exemples de code de petite taille par les mêmes interfaces (quelque chose dans son en-tête) et appelez vos échantillons au lieu de ce code optimisé, par exemple la simulation, pour limiter la scope du code que vous déboguez. De plus, vous pouvez effectuer des erreurs dans vos échantillons.