2012-04-05 20 views
5

Kontekst: Przydzielam własne konteksty i stosy maszyn z rodzinami funkcji getcontext(3)/().W jaki sposób GDB określa dno stosu?

Kiedy używam gdb (wersja 6.1.1) do zbadania stosu, gdy wątek znajduje się w jednym z tych kontekstów, które przydzieliłem, wygląda na to, że gdb nie wie, gdzie znajduje się koniec (logiczne dno) stosu jest. Na przykład, oto stos z x86 FreeBSD:

#0 0x2872d79f in poll() from /lib/libc.so.7 
#1 0x28646e23 in poll() from /lib/libthr.so.3 
#2 0x2869b267 in fdtask (task=0x28a3dc40, v=0x0) at fd.c:58 
#3 0x2869c8dc in taskstart (y=681827392, x=0) at task.c:58 
#4 0x00000000 in ??() 
#5 0x28a3dc40 in ??() 
#6 0x00000000 in ??() 
#7 0x00000000 in ??() 
… 
#65 0x00000000 in ??() 
… 

(Tak, to jest zbudowany na szczycie Russ Cox' libtask library).

wykonanie tym kontekście rozpoczyna się w funkcji taskstart, ale wydaje się, że GDB nie mogę zrozumieć że powinien przestać próbować odczytywać stos, nawet jeśli trafi on na adres zwrotny o wartości NULL w tej ramce.

Moje pytanie brzmi: czy jest coś, co mogę zrobić (formatując stos w jakiś sposób lub ustawiając rejestr, wszystko), aby pomóc GDB zrozumieć, gdzie znajduje się wierzchołek stosu? Dzięki.

Edit: Wnioski: Wydaje się, że jednym ze sposobów gdb 6.1.1 wykrywa końca stosu jest sprawdzenie, że rama jest przechowywany wskaźnik NULL; Naprawiłem problem z moim przypadkiem użycia, modyfikując funkcję x86 i amd64 makecontext(2), aby zresetować ebp lub rbp na zero podczas inicjowania nowego kontekstu. (W tym przypadku nie dbam o inne architektury.) Ten problem znika z gdb 7.1; przypuszczalnie gdb 7.1 jest w stanie wykryć koniec stosu za pomocą innych środków, takich jak debuginfo.

+1

to brzmi jak pytanie zadać na twórców gdb listy. –

Odpowiedz

2

Jeśli GDB używa wskaźników ramek do rozwinięcia stosu (metoda pre-DWARF2), zatrzymuje się, gdy dojdzie do zerowego wskaźnika ramki, jak sądzę. W przypadku DWARF2 rzeczy są znacznie bardziej skomplikowane, ponieważ "wskaźnik ramki" jest niejawnie określony przez wskaźnik stosu połączony ze wskaźnikiem błędu i informacja o przesunięciu ramki DWARF2 dla bieżącej instrukcji, ale zasadniczo efekt jest taki sam. Nie wiem, który FreeBSD używa tych dni.

+0

To jest dość starożytny FreeBSD (~ 7.2, jak sądzę). Dzięki! –

+0

Patrząc na demontaż 'taskstart', framepointer jest zapisywany przy wprowadzaniu. Dodałem kod, aby ustawić ebp utworzonego kontekstu na zero, a ślady stosów w gdb 6.1.1 wyglądają poprawnie. Dzięki jeszcze raz! –

0

Dokumentacja gdb mówi, że jednym ze sposobów zatrzymania wyświetlania ramek śledzenia jest następujący po adresie zwrotnym dla main().

Zobacz ftp://sourceware.org/pub/gdb/snapshots/current/gdb-7.4.50.20120405.tar.bz2 w gdb/doc/gdb.textinfo na @cindex backtrace beyond @code{main} function linii 6251.

+0

Oczywiście, ale nie jest to szczególnie pomocne w mojej sytuacji, ponieważ żaden z tych kontekstów nie zaczyna się od 'main'. –

+0

@ConradMeyer: Jak o nazwie funkcji, która nazywa 'taskstart' coś jak' main() ',' _main() 'lub' __main() '? – wallyk

+0

Nic nie wywołuje 'taskstart'. Program biblioteki libtask zamienia konteksty przestrzeni użytkownika na kontekst rozpoczynający się od 'taskstart'. Domyślam się, że 'taskstart' może być przemianowany na' main' lub '_main' lub cokolwiek innego, ale wydaje się, że to ogromny kludge. Inicjowanie wskaźnika ramki do zera wydaje się wystarczające, aby gdb6 wykrył koniec stosu i będzie działać bez względu na nazwę początkowej funkcji w kontekście. –

Powiązane problemy