2010-09-03 3 views
14

W programowaniu w trybie 32-bitowym używałam w swoich programach int 3 do zatrzymywania się w danej lokalizacji za pomocą debuggera (osadzanie instrukcji w źródle). Teraz w 64 bitach wydaje się nie działać, tworząc bardzo zwykły SIGSEGV pod gdb i niszcząc program poza nadzieją ("Program zakończony sygnałem SIGSEGV, Usterka segmentacji Program już nie istnieje."). Zastanawiam się, czy tryb 64-bitowy ma inny mechanizm, czy też powinienem zrobić cache-flush (int 3 jest dynamicznie generowanym opodem w tym przypadku (0xcc), to jakiś kod podobny do jit-like).Dlaczego int 3 generuje SIGSEGV w wersji 64-bitowej, zamiast zatrzymywać debugger?

+0

Jaki system operacyjny/wersja? –

Odpowiedz

7

Odpowiedź BarsMonster pokazuje, że __asm__("int3"); nie działa na 64-bitowych platformach. To jest - przynajmniej dzisiaj (2014) - nieprawda.

Poniższy kod będzie działać na platformie amd64:

przerwania.c

int main() { 
    int i;  
    for(i=0; i<3;i++) { 
     __asm__("int3"); 
    } 
} 

skompilować trywialnie: gcc -c breakpoint.c i rozpocząć gdb a.out:

(gdb) run 
Starting program: /tmp/a.out 

Program received signal SIGTRAP, Trace/breakpoint trap. 
0x00000000004004fb in main() 

Widzisz, gdb zatrzymuje się przy zerwaniu.

+2

Powinieneś powiedzieć wersję jądra zamiast daty :-) –

20

__debugbreak()

Dzisiaj kolega przyszedł zapytać o jak dostać "int 3" funkcjonalność na platformach 64-bitowych się. Co to jest "int 3"? Jest to instrukcja montażu, która jest używana do tworzenia punktu przerwania. Co najmniej jest instrukcją dla procesora x86 , i jak można sobie wyobrazić, to jest bardzo specyficzna dla platformy.

Na platformach 64-bitowych nie ma żadnego wbudowanego zespołu , więc istnieje "__asm ​​int 3". Co zrobić teraz? No cóż, jest mniej znany konstrukt, który jest o wiele lepszy w użyciu w tym działa na wszystkich platformach (x64, Itanium i x86), który jest __debugbreak(). To jest wewnętrzny kompilator Visual C++ (zdefiniowany w Visual C++ 2005 pod vc \ include \ intrin.h, z tonami innych fajnych właściwości) , który skutecznie działa "int 3" na wszystkich platformach.

DebugBreak, wywołanie funkcji Win32 jest wciąż dokoła, ale ogólnie za pomocą __debugbreak() jest moje preferencje, jeśli nie z innego powodu niż to nie jest rozmowa funkcji (jest to kompilator wewnętrzna), a don Aby uzyskać czytelny stos wywołań, trzeba zdebugować symbole .

Jeśli piszesz C++ prawdopodobnie nie chcesz pisać non-przenośne zespół, a to jest tylko jeden mniej miejsce gdzie trzeba.

http://blogs.msdn.com/b/kangsu/archive/2005/09/07/462232.aspx

+9

To jest bardzo pouczająca odpowiedź, ale jak wskazałem w moim pytaniu, generowałem kod dynamicznie, a to wyklucza wewnętrzną kompilację. Nie wspominając o tym, że moim zwykłym kompilatorem nie jest Visual C++, ani moja platforma Windows. Co więcej, odpowiedź jest niedokładna, ponieważ int 3 istnieje i przynajmniej w 64 bitach linuks zachowuje się jak zwykle. Ponadto, w zależności od kompilatora, masz wbudowany zestaw w trybie 64-bitowym. – dsign

+0

nadal działa tylko na x86? – Damian

+0

To dobrze dla MS IDE, ale co, jeśli używam Eclipse i GCC? – Mawg

10

Ahh, mam go, przepraszam. Musiałem usunąć zabezpieczenia stron w celu wykonania. Int 3 nadal jest poprawną pułapką debugowania.

+1

Szczegóły? Dociekliwe umysły chcieliby wiedzieć. – BeeOnRope

+0

To pytanie było siedem lat temu, więc trudno jest zapamiętać szczegóły tego, co zrobiłem. Pamiętam, że było to dość proste, myślę, że dzwoniłem do mmap (2) i właśnie dodałem flagę PROT_EXEC. A może to mprotect (2) ...? – dsign

+0

Prawdopodobnie wykonanie nigdy nie osiągnęło "int3", ponieważ kod znajdował się na stronie odczytu/zapisu/braku wykonania. Więc tylko skoki spowodowały uszkodzenie, niezależnie od zawartości. I tak, 'PROT_READ | PROT_EXEC | PROT_WRITE' dla mmap powinno być właściwe. Możesz też zacząć od strony do odczytu/zapisu, a następnie odwrócić ją do read/exec z mprotect po zakończeniu, więc nigdy nie masz odwzorowanej strony write + exec (ze względów bezpieczeństwa). –

0

Zalecam, abyś nigdy nie używał asm int 3, ponieważ działa on dla wszystkich typów kompilacji. Możesz zapomnieć o linii gdzieś w kodzie i może to oznaczać duże problemy. Alternatywą jest użycie __debugbreak, która jest poprawna tylko w trybie debugowania.

Powiązane problemy