gdb: définit un point d’arrêt pour un gestionnaire SIGBUS

J’essaie de déboguer un simple ramasse-miettes stop-and-copy (écrit en C) à l’aide de GDB. Le GC fonctionne en traitant SIGBUS. J’ai défini un point d’arrêt en haut de mon gestionnaire de signal SIGBUS. J’ai dit à GDB de transmettre SIGBUS à mon programme. Cependant, cela ne semble pas fonctionner.

Le programme suivant (expliqué en ligne) montre l’essence de mon problème:

#include  #include  #include  #include  #define HEAP_SIZE 4096 unsigned long int *heap; void gc(int n) { signal(SIGBUS, SIG_DFL); // just for debugging printf("GC TIME\n"); } int main () { // Allocate twice the required heap size (two semi-spaces) heap = mmap(NULL, HEAP_SIZE * 2, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); assert (heap != MAP_FAILED); // 2nd semi-space is unreadable. Using "bump-pointer allocation", a SIGBUS // tells us we are out of space and need to GC. void *guard = mmap(heap + HEAP_SIZE, HEAP_SIZE, PROT_NONE, MAP_ANON | MAP_SHARED | MAP_FIXED, -1, 0); assert (guard != MAP_FAILED); signal(SIGBUS, gc); heap[HEAP_SIZE] = 90; // pretend we are out of heap space return 0; } 

Je comstack et exécute le programme sur Mac OS X 10.6 et obtient le résultat attendu:

 $ gcc debug.c $ ./a.out GC TIME Bus error 

Je veux exécuter et déboguer ce programme en utilisant GDB. En particulier, je veux définir un point d’arrêt à la fonction gc (en réalité, le gestionnaire de signal gc). Naturellement, je dois dire à GDB de ne pas s’arrêter également sur SIGBUS:

 $ gdb ./a.out GNU gdb 6.3.50-20050815 (Apple version gdb-1346) (Fri Sep 18 20:40:51 UTC 2009) ... snip ... (gdb) handle SIGSEGV SIGBUS nostop noprint Signal Stop Print Pass to program Description SIGBUS No No Yes Bus error SIGSEGV No No Yes Segmentation fault (gdb) break gc Breakpoint 1 at 0x100000d6f 

Cependant, nous n’atteignons jamais le point d’arrêt:

 (gdb) run Starting program: /snip/a.out Reading symbols for shared libraries +. done Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_PROTECTION_FAILURE at address: 0x0000000100029000 0x0000000100000e83 in main () (gdb) 

Apparemment, le gestionnaire de signal n’est pas appelé (GC TIME n’est pas imprimé). De plus, nous sums toujours dans main (), à la faute de mov:

 0x0000000100000e83 : movq $0x5a,(%rax) 

Des idées?

Merci.

Le même code (modifié pour gérer également SIGSEGV) fonctionne comme prévu dans GDB sous Linux; il peut s’agir d’un bogue dans le port d’OS X ou de GDB vers cette plate-forme.

Googler trouve un comportement cassé sous OS X exactement comme le vôtre depuis la version 10.1, avec une sorte de solution de contournement ( set inferior-bind-exception-port off avant d’exécuter le programme).

(Il y a un bogue similaire sur Windows .)

En interne, des access mémoire défectueux entraînent l’envoi de l’exception de machine EXC_BAD_ACCESS au programme. Normalement, cela est traduit en un signal SIGBUS UNIX. Cependant, gdb intercepte les exceptions Mach directement, avant la traduction du signal. La solution consiste à donner à gdb la commande set dont-handle-bad-access 1 avant d’exécuter votre programme. Ensuite, le mécanisme normal est utilisé et les points d’arrêt de votre gestionnaire de signal sont respectés.

Que diriez-vous de mettre un for( ;; ); après printf() , exécuter le programme normalement, puis se connecter au processus avec gdb après l’ gdb de GC TIME?

Pourquoi vous attendez-vous à obtenir un SIGBUS? SIGBUS signifie généralement une erreur d’alignement sur une architecture dans laquelle certains types de données sont soumis à des exigences d’alignement. On dirait que vous essayez simplement d’accéder à la mémoire en dehors de votre zone allouée, et je m’attendrais à ce que vous obteniez SIGSEGV à la place de SIGBUS.

Modifier:

Il semble que le nom Mac OS X pour ce que je pense que SIGSEGV est SIGBUS. Par conséquent, ignorez cette réponse.

Si vous avez besoin d’aide, le point d’arrêt fonctionne comme prévu (c’est-à-dire) lorsque j’essaie le programme sur un système Linux, SIGBUS étant remplacé par SIGSEGV.

Edit 2:

Pouvez-vous essayer d’attraper SIGSEGV dans votre programme aussi? Il semble que le type de signal puisse varier en fonction de l’emplacement de la mémoire dans Mac OS X (je viens de lire la discussion ici et ici ), et peut-être qu’un signal différent pourrait être émis lorsque vous exécutez le débogueur?