2009-10-08 12 views
18

Chciałbym wiedzieć skąd wewnątrz aplikacji ogromna aplikacja drukowana jest pewna wiadomość. Aplikacja jest tak duża i stara, że ​​wykorzystuje wszystkie możliwe sposoby drukowania tekstu na terminalu; na przykład printf(), fprintf (stdout, ...) itp.jak mogę umieścić punkt przerwania na "coś jest drukowane na terminalu" w gdb?

Piszę, aby umieścić punkt przerwania w wywołaniu systemowym write(), ale potem jestem zalewany zbyt wieloma przerwaniami zatrzymania z powodu różnych plików I/O operacje, które używają również write().

W zasadzie chcę, aby gdb przestał za każdym razem, gdy program drukuje coś do terminalu, ale jednocześnie nie chcę, aby gdb przestał, kiedy program zapisuje coś do pliku.

+1

Zobacz również [Jak mogę monitorować co mogą być wprowadzane do standardowy bufor wyjściowy i przerwa, gdy konkretny ciąg jest zdeponowany w rurze?] (http://stackoverflow.com/questions/8235436/how-can-i-monitor-whats-being-put-into-the-standard- out-buffer-and-break-when-a) –

+0

Nie możesz po prostu "pobrać" źródło tego "czegoś", które pojawia się w terminalu, a następnie umieścić tam punkt przerwania? – Calmarius

Odpowiedz

18

Użyj warunkowego punktu przerwania, który sprawdza pierwszy parametr. W 64-bitowych systemach x86 warunek będzie:

(gdb) b zapisu jeśli 1 == $ RDI

na systemach 32-bitowych, jest bardziej złożona, ponieważ parametr jest na stosie, co oznacza, że musisz rzucić $ esp na int * i zindeksować parametr fd. Stos w tym miejscu ma adres zwrotny, długość, bufor i na końcu fd.

To znacznie różni się między platformami sprzętowymi.

+1

Mam trochę z tym problem i odkryłem, że numer FD jest dostępny jako "* (int) ($ esp + 4)", a długość ciągu jako "(int) * (int) ($ esp + 12)" i na koniec dane łańcucha jako "* (int) ($ esp + 8)". Więc dla STDOUT można zrobić coś takiego: przerwa zapisu jeśli 1 == * (int) ($ esp + 4) poleceń print (int) * (int) ($ esp + 12) x/s * (int) ($ esp + 8) koniec Ale kiedy próbowałem użyć tego w praktyce na wielkiej aplikacji, okazało się, że ta metoda nie jest niezawodna, ponieważ nie obsługuje przekierowań itp., więc jeśli aplikacja używa dup2() na stdout możesz pominąć pewne rzeczy drukowane na standardowe wyjście. – martin

+0

Oto nieco bardziej wyrafinowana próba:

 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

z gdb 7.0, można ustawić punkt przerwania warunkowego w zapisie syscall():

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

$ ebx zawiera pierwszy parametr syscall - numer FD tutaj

+0

Uwaga: 'printf' jest buforowany, więc może się zdarzyć, że zobaczysz' write' dla pierwszego 'printf' na drugim połączeniu' printf' połączonym w górę. –

Powiązane problemy