2009-11-23 13 views
16

mam ustawić punkty przerwania na wyjściu i _exit i mojego programu (wielowątkowych aplikacji, działa na Linux 2.6.16.46-0.12 sles10) jest jakoś nadal wychodzącego w sposób nie mogę zlokalizowaćustawienie przerwania wyjścia gdb nie działa?

 
(gdb) c 
... 
[New Thread 47513671297344 (LWP 15279)] 
[New Thread 47513667103040 (LWP 15280)] 
[New Thread 47513662908736 (LWP 15281)] 

Program exited with code 0177. 
(gdb) 

wyjście funkcje znajdują się w bibliotece libc, więc nie ma problemów z dzieloną biblioteką z odroczonym ładowaniem. Ktoś wie o jakimś tajemniczym spuście do wyjścia, którego nie można złapać?

EDYCJA: problem jest teraz tylko akademicki. Próbowałem debugowania binarnego wyszukiwania, wycofując podzbiór moich zmian (problem zniknął). Po ich ponownym zastosowaniu ponownie, nie mogę już repro problem, nawet z rzeczy przywrócone do pierwotnego stanu.

EDIT2: Ostatnio znalazłem jeden powód tego rodzaju błędu, który mógł być oryginalnym źródłem tego problemu. Z przyczyn historycznych nasz produkt wykorzystuje flagę zła linker -Bsymbolic. Jednym z efektów ubocznych tego jest to, że gdy symbol jest nieokreślony, ale wywoływany, linker środowiska wykonawczego GLIBC będzie bombardował dokładnie w ten sposób, a zobaczysz go w debugerze jako proces zakończony z 0177. Kiedy linker środowiska wykonawczego przerwie tę operację, 'zgadnij, że to sprawia, że ​​syscall _exit bezpośrednio (zamiast używać biblioteki wyjścia C() lub _exit()). Byłoby to zgodne z faktem, że nie byłem w stanie złapać tego z punktami przerwania wyjścia w debugerze.

Odpowiedz

22

Istnieją dwa powody, dla _exit przerwania dla „miss” - albo GDB nie ustawić punkt przerwania w odpowiednim miejscu, czy program wykonuje (moralnym odpowiednikiem) syscall(SYS_exit, ...)

Co zrobić info break i disassemble _exit powiedz?

Być może uda Ci się przekonać GDB do poprawnego ustawienia punktu przerwania za pomocą break *&_exit. Alternatywnie, GDB-7.0 obsługuje catch syscall. Coś jak to powinno działać (zakładając Linux/x86_64; pamiętać, że na ix86 numery będą inne) niezależnie od tego, w jaki sposób program wychodzi:

(gdb) catch syscall 60 
Catchpoint 3 (syscall 'exit' [60]) 
(gdb) catch syscall 231 
Catchpoint 4 (syscall 'exit_group' [231]) 
(gdb) c 

Catchpoint 4 (call to syscall 'exit_group'), 0x00007ffff7912f3d in _exit() from /lib/libc.so.6 

Aktualizacja:
Twój komentarz wskazuje, że _exit przerwania jest ustawiony prawidłowo, więc jest prawdopodobne, że twój proces po prostu nie działa _exit.

To pozostawia syscall(SYS_exit, ...) i jedną inną możliwość (której wcześniej brakowało): wszystkie wątki wykonujące pthread_exit. Możesz także ustawić punkt przerwania na pthread_exit (i wykonać info thread za każdym razem, gdy go klikniesz - ostatni wątek do wykonania pthread_exit spowoduje zakończenie procesu).

Edit:

Warto również zauważyć, że można użyć mnemonicznych nazw zamiast numerów syscall. Można również jednocześnie dodać wiele wywołań systemowych do listy catch tak:

(gdb) catch syscall exit exit_group 
Catchpoint 2 (syscalls 'exit' [1] 'exit_group' [252]) 
+0

Spróbuję zbudować gdb 7 i zobaczyć, co to pokazuje. i * i daje ten sam adres nauczania:

 (gdb) b _exit Breakpoint 2 at 0x2aeea040f250 (gdb) b *&_exit Note: breakpoint 2 also set at pc 0x2aeea040f250. Breakpoint 3 at 0x2aeea040f250 
 0x00002aeea040f250 <_exit+0>: mov %fs:0x0,%r9 ... 0x00002aeea040f275 <_exit+37>: syscall 
(wygląda dość standardowym syscall). Myślę, że przynajmniej wyizolowałem zmianę kodu prowadzącą do tego tajemniczego wyjścia, ale nie rozumiem jeszcze szczegółów. –

+2

Byłoby lepiej użyć 'catch syscall exit' i' catch syscall exit_group' zamiast wartości numerycznych. Na moim systemie na przykład 'exit' to' [1] 'not' [60]'. – Ruslan

+0

Dodatkowo, możesz ustawić obie jednocześnie: 'catch syscall exit exit_group'. W rzeczywistości, edytując go teraz ... –

1

Ustawienie punktu przerwania na _exit było dobrym pomysłem.

Możesz także spróbować linkować statycznie, aby złożyć stos potencjalnych powikłań gdb poza stołem.

0177 jest podejrzanie podobny status oczekiwaniawait(2) powraca do dziecka zatrzymany, ale gdb drukuje status wyjścia, która jest inna sprawa, więc to chyba prawdziwy zjazd argumentem.

+0

OP powiedział, że ma już punkty przerwania na _exit i exit. Ponadto, 0177 to 127. Jak na świecie dostałeś od 127 do SIGCHLD? –

+0

Och, nieodebrane wyjście. Ale mam rację co do statusu oczekiwania. Oczywiście nie mówię o numerze sygnału, ale status 'wait (2)' wraca do zatrzymanego procesu. Spójrz na to: $ grep IFSTOPPED /usr/include/bits/waitstatus.h '#define __WIFSTOPPED (status) (((status) i 0xff) == 0x7f)', AND, '0x7f == 0177'. Ale zgadzam się, że to nie jest to, co się tutaj dzieje. – DigitalRoss

1

Może być tak, że masz jakieś leniwe referencje nierozwiązane w jakiejś wspólnej biblioteki załadowane do procesu. Mam dokładnie taką samą sytuację, że "ktoś gdzieś" zakończył proces i wydawało się, że jest to nierozwiązane odniesienie.

Sprawdź swój proces za pomocą opcji "ldd -r".

Wygląda na to, że ld.so lub cokolwiek leniwy rozwiązuje niektóre symbole w celu uzyskania jednolitej funkcji wyjścia (która powinna być przerwana IMHO).

Moja sytuacja:

$ ldd ./program 
undefined symbol: XXXX (/usr/lib/libYYY.so) 

$./program 
program: started! 
... 
<program is running regardless of undefined references> 

Teraz wyjście pojawił kiedy już powoływać jakiś scenariusz, który funkcję, która była używana niezdefiniowane. Zawsze wychodziło z exitcode = 127, a gdb zgłosiło 0177.

+0

Nie wydaje się, aby tak było w tym przypadku. Nie dostaję niezdefiniowanych symboli w naszym pliku wykonywalnym (nie wychodzę ani nic innego). –

Powiązane problemy