Hacking  
  Wrzesień 26 2017 11:07:20  
 
Nawigacja
folder Portal
. Artykuły
. Download
. Forum
. Szukaj
. FAQ
. Regulamin
folder Hacking
. Gry Hakerskie
. Filmy
folder Delphi
. Kursy
. Faq
. Źródła
. Komponenty
. Artykuły
folderWebmaster
. JavaScripts
. Skrypty PHP
folderRóżne
. Kontakt
. Zlokalizuj ip
Aktualnie online
. Gości online: 5

. Użytkowników online: 0

. Łącznie użytkowników: 153,722
. Najnowszy użytkownik: ThomasRek
Ostatnie artykuły
. Metoda ataku symlin...
. Asembler x86 w pigułce
. Binder plików z komp...
. [Asembler/MASM] Pobi...
. Braifuck 4 fun
Nawigacja
Artykuły » Delphi artykuły » Debugowanie
Debugowanie
Debugowanie programów w Delphi






artykuł pochodzi z 4p





WSTĘP


    Artykuł został napisany na bazie Delphi 7 Enterprise, ale opisane narzędzia istnieją i działają tak samo (albo bardzo podobnie) także w innych wersjach tego środowiska.




    Jeśli masz już za sobą stworzenie większego kawałka kodu, to na pewno wiesz też, że jego pomyślne skompilowanie to dopiero początek walki o jego poprawne działanie. Na forum jest pełno tematów typu "co jest źle w tym kodzie", "czemu to nie działa" itp. Kod się kompiluje, uruchamia, często nawet nie wyskakują błędy - ale nie działa prawidłowo. Coś jest nie tak, właściwie to wszystko jest nie tak, ale co to powoduje i jak to sprawdzić?






DEBUGER





    Dawno, dawno temu, za siedmioma górami i siedmioma lasami budowano olbrzymie komputery, lampowe pierwowzory malutkich pecetów. Owe komputery składały się z olbrzymiej ilości lamp (tranzystory nie były wtedy jeszcze w powszechnym użyciu), a lampy niestety miały (i mają) dwie wady: spore zyżycie mocy, i krótki czas życia. Krótki czas działania, skrócony jeszcze przez istnienie wielu lamp, powodował że dawne komputery częściej nie działały niż wykonywały obliczenia. Ponadto ich rozmiar powodował spore problemy z namierzeniem usterki. Któregoś razu okazało się, że kolejny błąd w działaniu systemu spowodował robak, którego smiertelnie popieścił prąd w trakcie wędrówki po płycie. Robak, konkretnie pluskwa, po angielsku bug, nadał nazwę całemu procesowi wyszukiwania i usuwania błędów w programie (poczucie humoru programistów...) - debuggowaniu, po polsku "odpluskwianiu".





    Początkujący programiści zanim nauczą się posługiwać debugerem, czasem korzystają z tricku polegającego na umieszczanie w kodzie programu linijki (bądź linijek) wypisujących dokąd to kod się wykonał zanim się wykrzaczył (ShowMessage - brzmi znajomo?...). To jednak wymaga wielu kompilacji programu, i celowania na chybił/trafił w podejrzane miejsca, a co za tym idzie jest to czaso- i pracochłonne. Dlatego Delphi od zarania dziejów zawiera pakiet narzędzi ułatwiających, czy też może raczej w ogóle umożliwiających wyłapywanie błędów w kodzie - debuger.





    Debuger (odpluskwiacz ;-)) Delphi umożliwia uruchomienie programu w trybie pracy krokowej, przejście do pracy ciągłej, zatrzymanie warunkowe bądź bezwarunkowe, sprawdzenie wartości zmiennych, rejestrów, pamięci, stosu, stanu wątków, a także umożliwia podgląd kodu programu z poziomu instrukcji procesora (czyli asemblera).





    JAK TEGO UŻYWAĆ





    Najważniejszym elementem debugera są tzw. breakpoints (punkty zatrzymania - tu lepiej chyba też jest używać angielskiego słowa). Breakpoint to specjalnie oznaczona linijka kodu, która spowoduje zatrzymanie PRZED NIĄ wykonywania programu - program przejdzie w tryb pracy krokowej, co pozwala na sprawdzenie rzeczy wymienionych akapit wyżej.



    No właśnie, a co to jest praca krokowa? Otóż jest to wykonywanie programu pod kontrolą debugera - uruchamianie np.: jednej linijki kodu, jednej instrukcji procesora, bloku kodu... W trakcie zatrzymania kodu (ale nie zamknięcia programu, zatrzymanie a zamknięcie to dwie różne rzeczy) masz do dyspozycji pewne fantastyczne narzędzie o nazwie Evaluate/Modify. Pozwala ono na podgląd wartości zmiennych i stałych, można nim także zmieniać wartości zmiennych, oraz sprawdzać wyniki wykonania funkcji (!). Inne narzędzia pozwalające testować zatrzymany program są w menu View->Debug Windows. Od razu mówię, że do skutecznego debugowania programu konieczne jest przekompilowanie, a jeszcze lepiej zbudowanie (Project->Build) całego projektu od nowa z odpowiednio ustawionymi opcjami kompilatora:



  • trzeba wyłączyć optymalizację kodu, bo inaczej nie będziesz mógł sprawdzić wartości większości zmiennnych (Project->Options->Compiler->Code generation->Optimization);




  • warto na wszelki wypadek włączyć wyłapywanie błędów przekroczenia wartości (Project->Options->Compiler->Runtime errors->Overflow checking)
    i zakresu (Project->Options->Compiler->Runtime errors->Range checking);




  • jeśli jakimś cudem nie są włączone, to trzeba je zaznaczyć - dodawanie do kodu informacji dla debugera (Project->Options->Compiler->Debugging->wszystko oprócz Use Debug DCUs).



    Całość powinna wyglądać mniej-więcej tak:







    Pamiętaj, żeby na koniec przekompilować cały program.



    PODSTAWOWE NARZĘDZIA




    W menu Run masz kilka interesujących pozycji:



    Step Over, Trace Into, Trace to Next Source Line, Run to Cursor, Evaluate/Modify, Add watch (w Delphi 7.0 i wyższych są jeszcze dodatkowe opcje, jednak raczej Ci się nie przydadzą, dlatego na razie nie omówię ich).
    Co robi Step over? Po pierwsze - skrót klawiszowy - F8 - zapamiętaj go. Po drugie - załaduj do Delphi jakiś program (chociażby File->New->Application) i wciśnij F8. Program został skompilowany (o ile wcześniej nie był), uruchomiony, a potem zatrzymany (ale nie zakończony). W edytorze jedna linijka kodu została podświetlona na niebiesko - w tym miejscu program został zapauzowany. Ponieważ plikiem, w którym zaczyna się wykonywanie kodu, jest plik dpr, masz przed swoim
    oczami najprawdopodobniej zawartość pliku Project1.dpr, i linijkę ze słowem begin







    Jeśli znowu wciśniesz F8, wykona się kod w tej linijce (tutaj Application.Initialize;), i zostanie podświetlona następna linijka. W ten sposób możesz wykonać cały program - to jest właśnie praca krokowa. W międzyczasie możesz obserwować, która część kodu jest wykonywana, a jeśli kod nie wykonuje się tak, jak według Ciebie powinien, to znaczy że namierzyłeś błąd (co nie znaczy, że łatwo znajdziesz jego powód i go usuniesz).



    Jeśli chcesz skończyć debugowanie, po prostu wciśnij F9 (skrót do Run) - program wykona się do końca tak, jakbyś go wcale nie debugował.



    Step Over wykonuje od razu całą zawartość linijki, nieważne, czy kryje się tam jedna instrukcja, kilka, przypisanie wartości do zmiennej, czy wywołanie Twojej funkcji albo procedury. Krótko mówiąc Step Over wykonuje operacje hurtowo - wszystko co stoi na drodze do następnej linijki. Jeśli program nigdy nie dotrze do kolejnej linijki (np.: zawiesi się wskutek źle skonstruowanej pętli), efekt będzie taki, jakbyś po prostu uruchomił program. Co zrobić, jeśli chcesz wykonać linijkę po linijcę wywoływaną funkcję/procedurę? Ano, po pierwsze musisz mieć do niej kod źródłowy, po drugie kod modułu, w którym znajduje się ta funkcja, musi być skompilowany wedle instrukcji podanych w części "Jak tego używać". Jeśli tak jest, zerknij na pozycję Run->Trace Into - skrót klawiszowy F7 (też go zapamiętaj).





    Trace Into pozwala na wykonanie kodu rzeczywiście linijka po linijce - z "wchodzeniem" do wnętrza wszystkich metod/funkcji/procedur. Jest to bardzo przydatne, aczkolwiek na dłuższą metę dość męczące (bo przeważnie nie interesuje nas wykonanie linijka po linijce wszystkich 153 funkcji siedzących w debugowanym kawałku programu, tylko kilka konkretnych, które są podejrzane o powodowanie błędów. Dlatego opcji Trace Into używa się przeważnie w kombinacji ze Step Over.



    Różnicę pomiędzy Trace Into a Step Over doskonale zauważysz po wykonaniu w trybie krokowym poniższego kodu (raz przejedź przez kod programu wciskając F8, a drugi raz - F7):




    program Project1;


    function a : integer;

    begin

    result := 1;

    end;


    var

    i : integer;

    begin

    i := a;

    end.





    Weź pod uwagę, że jest to zawartość pliku .dpr, a nie .pas.




    Jeżeli już masz dość wykonywania programu w trybie krokowym, ale nie chcesz, żeby się wykonał do końca, możesz go zresetować - służy do tego opcja Program reset (Run->Program reset) - skrót Ctrl+F2. Może ona zatrzymać program nie tylko w trybie pracy krokowej, ale także program uruchomiony poprzez Run, co bardzo przydaje się, gdy program się zawiesi (czyli wpadnie w nieskończoną pętlę).



    W trakcie szukania błędów przydaje się (o ile nie jest najważniejszy) podgląd wartości zmiennych - bo przecież to właśnie nieprawidłowe wartości tych zmiennych (albo nieprawidłowe przyjęcie założeń co do ich wartości) najczęściej powodują błędy. Do podglądu zawartości zmiennych tylko w trakcie pracy krokowej programu służy narzędzie Evaluate/Modify - skrót Ctrl+F7 (koniecznie zapamiętaj).



    Uruchom podany wyżej kod w trybie pracy krokowej, najedź kursorem klawiatury na zmienną "i" i wciśnij Ctrl+F7. Powinieneś zobaczyć coś takiego:








    Jeśli pole evaluate jest puste, wpisz tam nazwę zmiennej (w tym przypadku "i") i wciśnij enter. Jak widzisz, bezpośrednio po uruchomieniu programu zmienne globalne są zerowane - w polu result znajduje się liczba 0, tj. wartość zmiennej wpisanej w polu Expression. Zasad wpisywania zmiennych są takie, jak przy pisaniu kodu - jeśli "i" jest zmienną globalną, to będzie widoczna w każdym miejscu modułu, w którym została zdefiniowana (oraz w modułach używających tego z definicją); jeśli w funkcji/metodzie istnieje zmienna o nazwie takiej samej, jak zmienna globalna, to ta druga zostanie "przykryta" tą pierwszą - dlatego musisz się orientować co wpisujesz w pole Expression.



    Jeśli zamkniesz okno Evaluate/Modify i wykonasz linijkę i := a; i znowu otworzysz to okno, to przekonasz się, że wartość zmiennej i wynosi 1.



    Wartość zmiennej i możesz modyfikować - w polu New value możesz wpisać dowolną wartość (dowolną, ale prawidłową dla zmiennej - do np.: liczby nie przypiszesz stringa), zmiana zostanie zatwierdzona enterem.
    Narzędzie Evaluate/Modify posiada możliwość sprawdzania wartości nie tylko zmiennych (i stałych), ale także funkcji. Oczywiście funkcji nie można przypisać nowej wartości ;-) Pamiętaj, że jeśli funkcja wykonuje się długo, to i długo będziesz czekać na pokazanie wyniku, a jeśli funkcja się zapętli, to okno Evaluate/Modify
    się zawiesi (jednak Ctrl-F2 przywróci Delphi do stanu używalności, resetując wykonywanie programu).



    NARZĘDZIA TROCHE BARDZIEJ SKOMPLIKOWANE




    Dotarcie do interesującej nas linijki kodu za pomocą narzędzi Step Over/Trace Into może trwać wieki, zwłaszcza, jeśli interesuje Cię linijka o numerze 58624739 ;] Poza tym kod programów naspisanych w Delphi z użyciem VCL w zasadzie uniemożliwia dotarcie przez F7/F8 do kodu metody TForm1.Create. Więc co wtedy?



    Otóż masz do dyspozycji narzędzia, które powodują wykonanie kodu aż do momentu dotarcia do interesującej Cię linijki. Konkretnie Run to cursor (skrót F4) i breakpointy.



    Run to cursor działa następująco: ustawiasz się kursorem na interesującej Cię linijce, wciskasz F4, a program uruchomi się i będzie działać aż natrafi na zaznaczoną wcześniej linijkę - tam się zatrzyma, i będziesz mógł użyć wszystkich omówionych wyżej narzędzi - pojechać dalej po kodzie przez Step Over/Trace Into, sprawdzić/zmienić interesujące Cię zmienne przez Evaluate/Modify, albo znowu użyć Run to cursor (zakładając, że to ma sens, czyli np.: jesteś wewnątrz pętli, albo jesteś w kodzie obsługującym jakieś zdarzenie, choćby kliknięcie na TButton).
    W ramach ćwiczeń wstaw na formatkę przycisk, w jego zdarzeniu OnClick wklep jakiś kod (np.: exit) i wciśnij F4. Program będzie działać normalnie aż do momentu, gdy wciśniesz ten przycisk; po jego wciśnięciu zatrzyma się, i zostanie podświetlona linijka wczesniej wybrana przez F4. Jeśli ponownie wciśniesz F4, program znowu będzie działać normalnie aż do następnego naciśnięcia przycisku.



    Jeśli jednak musisz "pilnować" kodu w kilku odległych miejscach naraz, to ciągłe skakanie kursorem kilkadziesiąt linijek w górę lub w dół tylko po to, żeby wcisnąć F4, robi się męczące. Jeszcze gorzej jest, gdy debugujesz aplikację wielowątkową i nie masz pewności, który z fragmentów strategicznego kodu wykona się najpierw. Przydało by się mieć możliwość uruchomienia programu w trybie Run to cursor, ale żeby kursor stał w wielu miejscach naraz. Otóż da się coś takiego zrobić, nazywa się to breakpoint.



    Breakpoint stawia się albo poprzez Run->Add Breakpoint->Source breakpoint... albo przez kliknięcie myszą maksymalnie po lewej stronie kodu (zaznaczona w ten sposób linijka powinna się podświetlić na czerwono):







    W ten sposób możesz zaznaczyć dowolną ilość linijek; po uruchomieniu program zatrzyma się, gdy dotrze do któregokolwiek z postawionych breakpointów - możesz go uruchomić dalej (F9) - zatrzyma się wtedy na kolejnym breakpoincie, albo skorzystać z dowolnego ze wcześniej omówionych narzędzi.



    Jeśli okaże się, że błąd siedzi gdzieś w pętli, i wychodzi dopiero po jej 238107 iteracji, to zajedziesz się na śmierć stawiając w pętli breakpoint, a potem 238108 razy wciskając F9. I na to jest rada - na powyższym obrazku widzisz pole condition; możesz tam wpisać warunek, który musi zostać spełniony, żeby breakpoint zadziałał (np.: i = 238107).



    Breakpoint możesz skasować klikając na czerwonym znaczku z lewej strony kodu.
    Lista breakpointów dostępna jest w menu View->Debug Windows->Breakpoints.






    NARZĘDZIA ZAAWANSOWANE




    To jeszcze nie koniec narzędzi do debugowania oferowanych przez Delphi...



    PODGLĄD ZMIENNYCH




    Watches (Add watch... - Ctrl+F5) pozwala na śledzenie wielu zmiennych naraz. Używanie Evaluate/modify jest uciążliwe, gdy często musisz sprawdzać jak zmieniają się wartości zmiennych. W oknie Add watch możesz zdefiniować, które zmienne chcesz śledzić, zostaną one wyświetlone w okienku takim jak to dolne na poniższym obrazku:







    Nazwę zmiennej (albo także funkcji - o ile zaznaczony jest checkbox Allow Function Calls) wpisujesz do pola Expression. Jeśli śledzisz dane z tablicy, możesz w polu Repeat count podać ilość pól, która ma być wyświetlona; jeśli śledzisz zwykłe dane, ustawienie Repeat count spowoduje kilkukrotne wyświetlenie zawartości zmiennej (ciekaw jestem po co to komu ;]). Na sam koniec Enter, zmienna zostaje dodana do listy (Watch list) , i już. Oczywiście zawartość zmiennych można podglądać tylko w trakcie pracy krokowej (zasady takie same jak dla Evaluate/modify).
    Dostęp do Watches możliwy jest też poprzez View->Debug Windows->Watches.



    Stos (Call Stack)




    Call Stack (View->Debug Windows->Call Stack) pozwala na sprawdzenie, co zostało odłożone na stosie przy wywoływaniu funkcji (metody, procedury...) - a konkretnie pozwala sprawdzić, która funkcja wywołała funkcję, która wywołała funkcję (...), która wywołała naszą funkcję ;-) - czyli lista nazw funkcji, z których niższa wywołała wyższą.







    Run Until Return




    Run Until Return - Shift+F8 - wykonuje program aż do momentu, gdy skończy się bieżąca funkcja (procedura, metoda...). Przydatne zwłaszcza w połączeniu z breakpointami.



    Local Variables




    Narzędzie Local Variables (View->Debug Windows->Local Variables) wyświetla listę zawierającącą nazwy wszystkich dostępych zmiennych lokalnych.







    Thread Status




    Narzędzie Threads (View->Debug Windows->Threads) wyświetla listę procesów i wątków utworzonych przez Twój program. Po kliknięciu na procesie prawym przyciskiem myszy i wybraniu Process properties otwiera się okno Temporary Process Options For Process ..., w którym można ustawić opcje współpracy procesu z systemem i z IDE. Dodatkowo każdy z procesów programu można ręcznie zakończyc korzystając z polecenia Terminate Process, również dostępnego pod prawym przyciskiem myszy.







    Moduless




    Czasem przydaje się sprawdzić z jakich bibliotek pas/dcu i dll korzysta program - umożliwia to narzędzie Modules (View->Debug Windows->Modules). Dzięki niemu możesz też zobaczyć, jakie funkcje zawierają biblioteki, a nawet - za pośrednictwem narzędzia CPU - zobaczyć ich kod (oczywiście mowa o kodzie assemblerowym). Jednocześnie możesz zobaczyć, jak wygląda drzewko modułów, i otwierać kod źródłowy tych modułów (o ile go mają). Wszystkie opcje tego narzędzia dostępne są jedynie podczas pracy krokowej.







    CPU/FPU/MMX Window




    Na koniec najbardziej zaawansowane narzędzie, czyli okno z kodem assemblerowym Twojego programu - CPU Window (View->Debug Windows->CPU). Zawiera okna:



  • Disassembly z kodem programu (pokazane adresy komórek pamięci i ich zawartość, zarówno jako liczba, jak i jako instrukcja procesora);



  • CPU Registers z rejestrami - możesz podejrzeć i zmodyfikować zawartości wszystkich podstawowych rejestrów procesora (EAX..EDX, ESI..EFL, CS..GS); na czerwono zaznaczone są te rejestry, które w trakcie ostatniego kroku programu zmieniły wartość;



  • Flags z flagami procesora - każdą flagę możesz podejrzeć i przełączyć



  • Memory Dump z zawartością pamięci Twojego programu (możesz zmieniać jej zawartość);



  • Machine Stack - wyświetla zawartość stosu; na zielono zaznaczony jest wierzchołek stosu.



    Dla programów wielowątkowych możesz przełączyć kontekst (menu kontekstowe->Change Thread), aby zobaczyć stan procesora dla innych wątków. Oczywiście cały czas działają wszystkie omówione wyżej narzędzia - możesz sobie nawet otworzyć wszystkie okna z menu View->Debug Windows (o ile wystarczy Ci miejsca na ekranie :]) i wędrować po programie krok po kroku, i to z ustawionymi breakpointami. Okno CPU Window pozwala na wykonywanie kodu nie linijka po linijce, ale instrukcja po instrukcji - zarówno w trybie Trace Over, Step Into, jak i Run To Cursor; możesz nawet stawiać breakpointy na konkretne instrukcje procesora. Dla prostoty użytkowania skróty klawiszowe do wędrowania po instrukcjach są takie same, jak te do wędrowania po linijkach kodu źródłowego, a wielkość kroku, który się wykona, zależy od tego które okno jest aktywne (to z kodem źródłowym, czy CPU Window).







    Z menu podręcznego możesz wybrać narzędzie uzupełniające CPU Window, a mianowicie FPU Window. Dostępne jest ono także z menu View->Debug Windows->FPU. Pozwala ono na podgląd i edycję zawartości rejestrów jednostek FPU (menu podręczne->Show->Floating Point Registers) i MMX (menu podręczne->Show->MMX Registers) procesora.
    Polecam dość dokładne przebadanie zawartości menu kontekstowego zarówno CPU Window, jak i FPU Window - jest tam wiele opcji ułatwiających życie programiście. Opis wszystkich - F1 :-P





Logowanie
Nazwa użytkownika

Hasło



Nie masz jeszcze konta?
Zarejestruj się

Nie możesz się zalogować?
Poproś o nowe hasło
Shoutbox
Musisz zalogować się, aby móc dodać wiadomość.

05-09-2017 00:59
https://www.youtub
e.com/watch?v=fS0l
FNzl5uE

05-09-2017 00:58
https://www.youtub
e.com/watch?v=fS0l
FNzl5uE ZARABIANIE NA NECIE GRUBA FORSE BEZ INWESTYCIJ

30-08-2017 03:38
online payday loans direct lenders <a href="http://cashad
vances2017.com"
Chytry guaranteed payday loans</a> &lt;a href=&quot;http://c
ashadvances2017.co
m&quot;&gt; payda

07-08-2017 13:23

05-08-2017 00:33
forex trading online now blogspot search images http://anicinag.7m
.pl/qifyly/forex-m
ix-repinox-wikiped
ia-dictionary.html
forex omsk bird polandball philippines http://dandireli.7
m.pl/pylalyga

Licznik
30,422,082 unikalne wizyty