2009-10-08 21 views
18

Je voudrais savoir d'où un énorme demande un certain message est imprimé. L'application est tellement grande et ancienne qu'elle utilise toutes les manières imaginables d'imprimer du texte sur le terminal; par exemple printf(), fprintf (stdout, ...) etc.comment puis-je mettre un point d'arrêt sur "quelque chose est imprimé sur le terminal" dans gdb?

J'écris pour mettre un point d'arrêt sur l'appel système write(), mais je suis inondé de trop de points d'arrêt en raison de divers fichiers I/O opérations qui utilisent write() aussi bien. Donc, fondamentalement, je veux que gdb s'arrête chaque fois que le programme imprime quelque chose au terminal mais en même temps je ne veux pas que gdb s'arrête quand le programme écrit quelque chose dans un fichier.

+1

Voir aussi [Comment puis-je surveiller ce qui est mis en le tampon de sortie standard et casse quand une chaîne spécifique est déposée dans le tuyau?] (http://stackoverflow.com/questions/8235436/how-can-i-monitor-whats-being-put-into-the-standard- out-buffer-and-break-when-a) –

+0

Vous ne pouvez pas simplement "grep" la source de ce "quelque chose" qui apparaît dans le terminal, puis y placer un point d'arrêt? – Calmarius

Répondre

18

Utilisez un point d'arrêt conditionnel qui vérifie le premier paramètre. Sur les systèmes 64 bits x86 la condition serait:

(gdb) b écriture si 1 == $ rdi

Sur les systèmes 32 bits, il est plus complexe, car le paramètre est sur la pile, ce qui signifie que vous devez lancer $ esp dans un int * et indexer le paramètre fd. La pile à ce point a l'adresse de retour, la longueur, le tampon et enfin fd.

Cela varie considérablement entre les plates-formes matérielles.

+1

Je mélange un peu avec ceci et ai trouvé que le nombre de FD est availabe comme "* (int) ($ esp + 4)" et la longueur de chaîne comme "(int) * (int) ($ esp + 12)" et enfin les données de chaîne comme "* (int) ($ esp + 8)". Donc, pour STDOUT que vous pouvez faire quelque chose comme: break écriture si 1 == * (int) print ($ esp + 4) commandes (int) * (int) ($ esp + 12) x/s * (int) ($ esp + 8) fin Mais quand j'ai essayé de l'utiliser en pratique sur une application _huge_ il s'est avéré que cette méthode n'est pas infaillible car elle ne gère pas les redirections, donc si l'application utilise dup2() sur stdout, vous risquez de manquer des éléments imprimés sur stdout. – martin

+0

Voici une tentative légèrement plus raffinée:

 break write commands silent if !isatty(*(int)($esp + 4)) c end echo \ntty write(), size: x/d (int)($esp + 12) echo tty write(), data: x/s *(int)($esp + 8) end 
martin

11

Avec gdb 7.0, vous pouvez définir point d'arrêt conditionnel à l'écriture() syscall:

(gdb) catch syscall write 
Catchpoint 1 (syscall 'write' [4]) 
(gdb) condition 1 $ebx==1 

EBX $ contient premier paramètre syscall - Numéro FD ici

+0

Note: 'printf' est tamponné, il peut donc arriver que vous ne voyiez que' write' pour le premier 'printf' sur un second appel' printf' concaténé. –