2010-09-03 16 views
14

En programmation en mode 32 bits, j'utilisais beaucoup int 3 dans mes programmes pour m'arrêter à un emplacement donné avec le débogueur (en incluant l'instruction dans la source). Maintenant, en 64 bits, il semble ne pas fonctionner, produisant un SIGSEGV très ordinaire sous gdb et détruisant le programme au-delà de l'espoir ("Programme terminé avec le signal SIGSEGV, erreur de segmentation Le programme n'existe plus."). Je me demande si le mode 64 bits a un autre mécanisme, ou si je devrais faire un peu de cache-flush (le int 3 est un opcode généré dynamiquement dans ce cas (0xcc), est un peu comme du code jit-like).Pourquoi int 3 génère un SIGSEGV en 64 bits au lieu d'arrêter le débogueur?

+0

Quel système d'exploitation/version? –

Répondre

7

La réponse de BarsMonster montre que __asm__("int3"); ne fonctionnera pas sur les plates-formes 64 bits. C'est - au moins aujourd'hui (2014) - pas vrai.

Le code suivant fonctionnera sur une plate-forme amd64:

point d'arrêt.c

int main() { 
    int i;  
    for(i=0; i<3;i++) { 
     __asm__("int3"); 
    } 
} 

Compile trivialement: gcc -c breakpoint.c et commencer gdb a.out:

(gdb) run 
Starting program: /tmp/a.out 

Program received signal SIGTRAP, Trace/breakpoint trap. 
0x00000000004004fb in main() 

Vous voyez, gdb arrêts au point d'arrêt.

+2

Vous devriez dire la version du noyau au lieu de juste la date :-) –

20

__debugbreak()

Aujourd'hui, un collègue est venu poser des questions sur comment obtenir la fonctionnalité "int 3" sur les plates-formes 64bit. Qu'est-ce que "int 3"? L'instruction d'assemblage est utilisée pour créer un point d'arrêt. Au moins c'est l'instruction pour le processeur x86 , et comme vous pouvez l'imaginer est très spécifique à la plate-forme.

Sur les plates-formes 64 bits, il n'y a pas d'assemblage en ligne , donc il y a "__asm ​​int 3". Que faire maintenant? Bien il y a une construction moins connue qui est en fait beaucoup mieux à utiliser dans le fait que cela fonctionne sur toutes les plates-formes (x64, Itanium, et x86), qui est __debugbreak(). Ceci est un compilateur Visual C++ intrinsèque (défini dans Visual C++ 2005 sous vc \ include \ intrin.h, avec des tonnes d'autres intrinsèques cool) qui agira effectivement "int 3" sur toutes les plates-formes.

DebugBreak, l'appel de fonction Win32 est toujours autour, mais en général en utilisant __debugbreak() est ma préférence, si pour aucune autre raison que ce n'est pas un appel de fonction (il est un compilateur intrinsèque), et vous n Pas besoin de déboguer les symboles pour obtenir une pile d'appels lisible.

Si vous écrivez C++ vous avez probablement ne voulez pas écrire ensemble non portable , ce qui est juste un de moins endroit où vous devez.

http://blogs.msdn.com/b/kangsu/archive/2005/09/07/462232.aspx

+9

Ceci est une réponse très informative, mais comme je l'ai spécifié dans ma question, je générais du code dynamiquement, ce qui exclut les intrinsèques du compilateur. Sans compter que mon compilateur habituel n'est pas Visual C++, ni ma plate-forme Windows. De plus, la réponse est inexacte car int 3 existe et au moins en 64 bits, linux se comporte comme d'habitude. En outre, selon le compilateur, vous avez un assemblage en ligne en mode 64 bits. – dsign

+0

ne fonctionne toujours que sur x86? – Damian

+0

C'est bien pour les IDE MS, mais que faire si j'utilise Eclipse et GCC? – Mawg

10

Ahh, je l'ai, désolé. J'ai dû déprotéger les pages pour l'exécution. Int 3 est toujours un piège de débogage valide.

+1

Détails? Les esprits curieux aimeraient savoir. – BeeOnRope

+0

Cette question était il y a sept ans, donc il est difficile de se souvenir des détails de ce que j'ai fait. Je me souviens que c'était très simple, je crois que j'appelais mmap (2) et que je viens d'ajouter le drapeau PROT_EXEC. Ou était-ce mprotect (2) ...? – dsign

+0

Probablement l'exécution n'atteignait jamais le 'int3' parce que le code était dans une page de lecture/écriture/non-exécution. Donc sauter simplement là a causé une erreur de ségrégation, quel que soit le contenu. Et oui, 'PROT_READ | PROT_EXEC | PROT_WRITE' pour mmap devrait être la bonne approche. Ou vous pouvez commencer avec une page en lecture/écriture, puis retournez-la en lecture/exec avec mprotect après avoir terminé, donc vous n'avez jamais mappé une page d'écriture + exec (pour des raisons de sécurité). –

0

Je vous recommande de ne jamais utiliser asm int 3 car il fonctionne pour tous les types de construction. Vous pourriez oublier une ligne quelque part dans votre code et cela peut signifier de gros problèmes. L'alternative est d'utiliser __debugbreak qui n'est valide qu'en mode debug.