web-dev-qa-db-fra.com

Trouver quelle instruction d'assemblage a causé une erreur d'instruction illégale sans débogage

Lors de l'exécution d'un programme que j'ai écrit dans Assembly, l'erreur Illegal instruction est générée. Existe-t-il un moyen de savoir quelle instruction est à l'origine de l'erreur, sans le débogage, car la machine sur laquelle je cours d'exécution ne dispose pas de débogueur ni de système de développement. En d'autres termes, je compile dans une machine et fonctionne sur une autre. Je ne peux pas tester mon programme sur la machine que je compile car ils ne prennent pas en charge SSE4.2. La machine sur laquelle je lance le programme prend néanmoins en charge les instructions SSE4.2.

Je pense que c'est peut-être parce que je dois dire à l'assembleur (YASM) de reconnaître les instructions SSE4.2, comme nous le faisons avec gcc en lui passant le drapeau -msse4.2. Ou pensez-vous que ce n'est pas la raison? Une idée de comment dire à YASM de reconnaître les instructions SSE4.2?

Peut-être devrais-je piéger le signal SIGILL puis décoder le SA_SIGINFO pour voir le type d'opération illégale effectuée par le programme.

25
pythonic

En fait, vous obtenez souvent une erreur d’instruction illégale non pas parce que votre programme contient un opcode illégal, mais parce qu’il contient un bogue (par exemple, un débordement de mémoire tampon) qui fait que votre programme saute dans une adresse aléatoire avec des données en clair ou dans du code mais pas dans. le début de l'opcode.

30
ouah

Récemment, j'ai eu un crash dû à un code d'état de sortie 132 (128 + 4: programme interrompu par un signal + un signal d'instruction non conforme). Voici comment j'ai compris quelle instruction était à l'origine de l'accident.

Tout d'abord, j'ai activé les core dumps:

$ ulimit -c unlimited

Fait intéressant, le dossier à partir duquel j’exécutais le fichier binaire contenait un dossier nommé core. Je devais dire à Linux d'ajouter le PID au dump principal:

$ Sudo sysctl -w kernel.core_uses_pid=1

Ensuite, j'ai lancé mon programme et obtenu un noyau nommé core.23650. J'ai chargé le binaire et le noyau avec gdb.

$ gdb program core.23650

Une fois que je suis entré dans gdb, les informations suivantes sont apparues:

Program terminated with signal SIGILL, Illegal instruction.
#0  0x00007f58e9efd019 in ?? ()

Cela signifie que mon programme est tombé en panne en raison d'une instruction illégale dans la mémoire d'adresse 0x00007f58e9efd019. Puis je suis passé à asm layout pour vérifier la dernière instruction exécutée:

(gdb) layout asm
>|0x7f58e9efd019  vpmaskmovd (%r8),%ymm15,%ymm0
 |0x7f58e9efd01e  vpmaskmovd %ymm0,%ymm15,(%rdi)
 |0x7f58e9efd023  add    $0x4,%rdi
 |0x7f58e9efd027  add    $0x0,%rdi

C'est l'instruction vpmaskmovd qui a provoqué l'erreur. Apparemment, j'essayais de lancer un programme destiné à l'architecture AVX2 sur un système ne prenant pas en charge le jeu d'instructions AVX2.

$ cat /proc/cpuinfo | grep avx2

Enfin, j'ai confirmé vpmaskmovd est une instruction uniquement en AVX2 .

21
Diego Pino

Si vous pouvez activer les vidages principaux sur ce système, exécutez simplement le programme, laissez-le planter, puis extrayez le vidage principal de la machine cible sur votre machine de développement et chargez-le dans une GDB conçue pour déboguer l'architecture cible. où l'accident s'est produit. Utilisez simplement la commande core de GDB pour charger le fichier principal dans le débogueur.

  • Pour activer les vidages mémoire sur la cible:

    ulimit -c unlimited
    
  • pseudo-fichiers qui contrôlent comment le fichier principal sera nommé (classez-les pour voir la configuration actuelle, écrivez-leur pour changer la configuration):

    /proc/sys/kernel/core_pattern
    /proc/sys/kernel/core_uses_pid
    

Sur mon système, une fois le core dumps activé, un programme bloquant écrit un fichier simplement nommé "core" dans le répertoire de travail. C'est probablement suffisant pour vos besoins, mais modifier le nom du fichier de vidage principal vous permet de conserver un historique des vidages principaux si cela est nécessaire (peut-être pour un problème plus intermittent).

11
Michael Burr

Eh bien ... Vous pouvez bien sûr insérer des impressions de trace afin d'éliminer rapidement de larges zones du code. Une fois que vous avez fait cela, lancez par exemple.

$ objdump --disassemble my-crashing-program | less

Puis passez à par exemple la fonction que vous connaissez est à l'origine de l'erreur et lisez le code, en recherchant tout ce qui semble étrange.

Je ne suis pas tout à fait sûr de savoir comment objdump affiche des instructions illégales, mais elles devraient se démarquer.

4
unwind

Pour l’Assemblée manuscrite, je suspecterais un problème de gestion de la pile entraînant un retour nulle part. Rédigez une routine d’impression de débogage qui enregistre chaque registre et insérez-y un appel en haut de chaque fonction.

Ensuite, vous verrez à quelle distance vous allez ...

(BTW, un bon éditeur et une bonne compréhension de la syntaxe des macros de l’assembleur sont des sauveurs de vies lors de l’écriture de code machine.)

4
DigitalRoss

Cela peut être dû à l'absence d'une instruction return à la fin d'une fonction.

2
Gabriel