2010-10-12 12 views
33

Jak działają punkty przerwania w kodzie C++? Czy są specjalne instrukcje wstawiane między niektórymi instrukcjami asemblera podczas kompilacji kodu? Czy jest tam coś jeszcze? W jaki sposób wdrażany jest krok po kroku? W taki sam sposób jak punkty przerwania ...?Jak działają punkty przerwania w kodzie C++?

+0

Punkty przerwania są wstrzykiwane dynamicznie przez debugger w czasie wykonywania procesu. I spodziewam się, że to również się liczy, by przejść przez kod. Jednak nie jestem w 100% ly pozytywny na ten temat. – Vinzenz

+0

@gablin, czy mógłbyś edytować pytanie, aby zapytać o "natywny" kod zamiast "C++"? To bardzo ten sam problem i lepiej odzwierciedla odpowiedzi, jakie masz. –

+0

@StevenFisher: Nie, proszę bardzo. =) – gablin

Odpowiedz

35

Jest to bardzo zależne od procesora i debuggera.

Na przykład, jednym z możliwych rozwiązań na x86 CPU:

  • Włóż jeden bajt instrukcji INT3 na wymaganym miejscu
  • Odczekać aż punktu przerwania wyjątku uderza
  • Porównaj adres wyjątku do listy punkt przerwania w celu określenia, który z nich ma być punktem końcowym.
  • Zamień INT3 na oryginalny bajt i przełącz debugowany proces w tryb śledzenia (krok po kroku wykonanie CPU i nstructions)
  • dalej debugowany procesowi
  • Natychmiast można złapać wyjątek śladowych - dyspozycja została wykonana
  • Put INT3 powrotem

Watchpoints mogą być realizowane w podobny sposób, ale zamiast INT3 umieścić pamięć strona, na której zmienna obserwowana jest w trybie tylko do odczytu lub w trybie bez dostępu i czekać na wyjątek segmentacji.

Krokowy montaż można również wykonać za pomocą trybu śledzenia. Przejście przez linie źródłowe można również wykonać umieszczając punkty przerwania na następnych instrukcjach, w oparciu o dane debugowania.

Również niektóre procesory obsługują punkt przerwania sprzętowego po załadowaniu adresu do pewnego rejestru.

+0

Nie rozumiem części "zamień INT3 na oryginalny bajt" ... Dlaczego musimy to zrobić? – gablin

+0

Po wznowieniu z punktu przerwania, musisz wykonać instrukcję CPU, w której zatrzymałeś się, ale ją uszkodziłeś - zastąpiłeś pierwszy bajt kodem INT3. Musisz go więc przywrócić, pozwolić, aby instrukcja została przetworzona przez procesor, a następnie ponownie wstawić INT3 - aby następnym razem wykonać tę instrukcję, znowu się zepsujesz – Xeor

+1

O, widzę. Tak więc to, w jaki sposób debugger "wstrzykuje" punkty przerwania w kodzie. Dzięki! – gablin

8

Według this blog entry na technochakra.com masz rację: Wartości graniczne

Oprogramowanie działa poprzez wstawienie specjalnej instrukcji w programie są pozbawione błędów. Ta specjalna instrukcja na platformie Intela to "int 3". Po uruchomieniu wywołuje procedurę obsługi wyjątku debuggera.

Nie jestem pewien, w jaki sposób wdrażane są kolejne instrukcje. Jednak artykuł dodaje:

Nierozsądnie jest prosić o rekompilację za każdym razem, gdy punkt przerwania zostanie dodany lub usunięty. Debuggerzy zmieniają załadowany obraz pliku wykonywalnego w pamięci i wstawiają instrukcję "int 3" w czasie wykonywania.

Jest to jednak używane tylko w przypadku opcji "Uruchom do bieżącej linii".

4

Pojedynczy krok zaimplementowano na poziomie kodu (asemblera), a nie na poziomie C++. Debugger wie, jak odwzorować linie kodu C++ na adresy kodowe.

Istnieją różne implementacje. Istnieją procesory obsługujące debugowanie za pomocą rejestrów punktów przerwania. Gdy wykonanie osiągnie adres w rejestrze punktu przerwania, CPU wykonuje wyjątek punktu przerwania.

Innym podejściem jest łatanie kodu na czas wykonania za pomocą specjalnej instrukcji, w najlepszym przypadku instrukcji jednobajtowej. W systemach x86, które zwykle mają 3.

Pierwsze podejście pozwala na wartości graniczne w pamięci ROM, drugie pozwala na więcej punktów przerwania w tym samym czasie.

1

AFAIK wszystkie debuggery (dla dowolnego języka kompilowanego), które pozwalają na nieograniczoną liczbę punktów przerwania, używają wariantu zastąpienia instrukcji, która ma zostać zerwana, specjalną wartością (jak opisano powyżej) i zachowaniem listy miejsc, w których te wartości zostały umieszczony.

Gdy procesor próbuje wykonać jedną z tych wartości specjalnych, wywoływany jest wyjątek, debugger przechwytuje go i sprawdza, czy adres wyjątku znajduje się na liście punktów przerwania. Jeśli tak jest, debugger jest wywoływany, a użytkownik ma możliwość interakcji. Jeśli NIE, to wyjątek jest spowodowany przez coś, co było w programie od samego początku, a debugger zezwala na wyjątek "przekazywać" do dowolnej procedury obsługi błędów.

Należy również zauważyć, że samodopasowujący się kod debugowania może się nie powieść, ponieważ debugger chwilowo modyfikuje sam kod. (Oczywiście, nikt nigdy nie pisz samemu, teraz?> ;-)

Z tych powodów ważne jest, aby debugger miał możliwość usunięcia wszystkich punktów zatrzymania, które ustawił przed zakończeniem sesji debugowania .

+0

"ważne jest, aby debugger miał możliwość usunięcia wszystkich punktów zatrzymania, które ustawił przed zakończeniem sesji debugowania." Nah - debugger modyfikuje tylko obraz w pamięci, a nie oryginalny plik na dysku. –

+0

Rzeczywiście, ale jeśli zakończysz debuggera i pozwolisz programowi kontynuować, musisz usunąć punkty przerwania w pamięci przed zezwoleniem na program – smirkingman

+0

Co zrobić, jeśli twój kod programu jest większy niż twoja pamięć? Może gdb używa mmap z MAP_PRIVATE, aby zatrzymać punkty przerwania na dysku ... –

Powiązane problemy