Debugowanie Podstawy.doc

(71 KB) Pobierz

 

Debugowanie - podstawy

Wstęp

„Powstał kolejny kawałek kodu. Ja go pisałem, więc jest bezbłędny. Na pewno zadziała i nie trzeba go testować.” Oczywiście nic bardziej mylnego. Każdy wie, że nie ma nic bardziej irytującego w pracy nad projektem, niż członek zespołu, który myśli w taki sposób. Nawet najkrótszy program może mieć błędy a to, w jak krótkim czasie i jak sprawnie jesteśmy w stanie je odnaleźć i skorygować, często decyduje o sukcesie produktu. Pomocne okazują się narzędzia pozwalające na krokowe wykonywanie kodu, podgląd i zmianę zawartości zmiennych, pamięci, czy obserwowanie wywołań procedur.

Debugowanie można rozumieć dwojako: jako techniki wykonywania krokowego (wykorzystywanie debugera) lub jako strategię (całościowe podejście do fazy wyszukiwania błędów). Nie ulega wątpliwości, że sprawne posługiwanie się debugerem znakomicie ułatwia wyszukiwanie błędów. Jednakże podstawą fazy testów i usuwania błędów jest wypracowanie strategii, polityki i narzędzi testowania i usuwania błędów.

Co nowego

Microsoft Visual Studio .Net, do tego co znamy z wersji 6.0, dorzuca całą gamę nowych narzędzi pod nazwą „Integrated Visual Studio .Net Debugger”.

Pierwszym elementem, który jest konsekwencją wprowadzenia platformy .Net, to możliwość debugowania kodu i projektów, które powstały w różnych językach i środowiskach, takich jak Visual C# .Net, Visual Basic .Net, Visual C++ .Net, Managed Extensions for C++, skrypty i kod SQL.

Środowisko umożliwia także debugowanie aplikacji tworzonych dla środowiska Common Language Runtime (CLR) jak i tradycyjnych aplikacji Win32.

Spośród najważniejszych nowości, należy wymienić możliwość przyłączania debugera do działającego procesu, możliwość debugowania procesu serwera (np, ASP .Net), debugowanie wielu programów jednocześnie, możliwość wykrywania błędów typu „run-time error” w Visual C++, weryfikacja przepełnień bufora dla aplikacji Visual C++ (opcja kompilacji /GS), możliwość ustawienia pułapki w bibliotece DLL, która jeszcze nie została załadowana, przejścia z kodu klienta do kodu serwisu Web Services.

Znacznie łatwiej niż kiedyś można wykonywać debugowanie zdalne, debugowanie aplikacji wielowątkowych, rozbudowane zostały klasy ułatwiające diagnostykę i proces wyszukiwania błędów, pojawiły się dodatkowe narzędzia takie jak Visual Studio Analyzer.

Jednakże to bardziej jednolite środowisko będzie wymagało, szczególnie od pracujących w środowisku Visual Basic 6.0, drobnej zmiany przyzwyczajeń. „Edit and continue” nie jest już wspierane, nastąpiła zmiana skrótów klawiszowych dla debugowania czy zmiana znaczenia okien „Immediate” oraz „Command”.

Ustawienia debugera i przygotowania do procesu debugowania

Pierwszym krokiem do rozpoczęcia debugowania jest weryfikacja ustawień debugera. Decydują one o różnych zachowaniach debugera, wyświetlanych ostrzeżeniach, sposobie wyświetlania wartości zmiennych i innych elementach.

Opcje te znajdują się w oknie opcji debugera: Tools, Options, Debugging, General.

Wymagane uprawnienia

Proces debugowania wymaga odpowiednich uprawnień w systemie. Aby debugować programy na lokalnym systemie użytkownik musi być członkiem grupy „Users”. Debugowanie na systemie zdalnym wymaga od użytkownika członkostwa w grupie „Debugger Users”. Należy pamiętać, że dodanie użytkowników do tej grupy, daje im dostęp do systemu i zwiększa ryzyko związane z bezpieczeństwem. Debugowanie serwisów systemowych wymaga uprawnienia „Debug programs” zdefiniowanego w lokalnej polisie bezpieczeństwa (Programs, Administrative Tools, Local Security Policy, User Rights Assignment, Debug Programs) dla użytkownika.

Ustawienia dla projektów

Warto przyjrzeć się bliżej opcjom projektów, które są związane z debugowaniem. Poniższa lista ilustruje opcje projektów Visual Basic .Net i Visual C# .Net. Są one identyczne dla obu języków, jednakże okna i rozmieszczenie opcji są różne.

Opcje debugowania dla projektów:

Enable ASP Debugging  - pozwala na debugowanie aplikacji ASP

Enable ASP .Net Debugging – pozwala na debugowanie aplikacji ASP .Net

Enable Unmanaged Debugging – pozwala na śledzenie wywołań kodu Win32 z kodu typu „managed code”. Ustawienie to ma takie samo działanie, jak ustawienie opcji „Mixed” dla typu debugera (Debugger Type) dla projektów C++.

Enable SQL Debugging – pozwala na krokowe wykonywanie procedur składowanych SQL.

Debug Mode – określna sposób debugowania: projektu, wskazanej aplikacji nie będącej składową rozwiązania (solution) lub wskazanej aplikacji WWW.

Start Application – pozwala na wskazanie aplikacji, która jest debugowana.

Start URL – pozwala na wskazanie aplikacji ASP lub ASP .Net, która jest debugowana.

Start Page – pozwala na wskazanie strony startowej, od której ma się rozpocząć proces debugowania.

Command Line Arguments – pozwala na wyspecyfikowanie argumentów linii poleceń dla debugowanej aplikacji. Dla przypomnienia:

<file – czyta stdin z pliku

>file –zapisuje stdout do pliku

>>file – dołącza stdout do pliku

2>file – zapsuje stderr do pliku

2>>file – dołącza stderr do pliku

2>&1 – skierowuje zawartość stderr (2) do tej samej lokalizacji, co stdout (1)

1>&2 – skierowuje zawartość stdout (1) do tej samej lokalizacji, co stderr (2)

W większości przypadków argumenty linii poleceń będą dotyczyć aplikacji typu „console”.

Working Directory – wskazuje katalog roboczy debugowanej aplikacji

Always Use Internet Explorer – wymusza użycie Internet Explorer’a jako przglądarki dla debugowania aplikacji internetowych (w przeciwieństwie do domyślnej przeglądarki ustawionej dla Visual Studio).

Enable Remote Debugging – pozwala na debugowanie programów działających na zdalnym systemie.

Remote Debug Machine – wskazuje maszynę dla debugowania aplikacji zdalnej.

Opcje tworzenia kodu wynikowego projektów:

Conditional Compilation Constants – definiuje stałe dla kompilacji warunkowej. W tym miejscu definiowane są stałe np. TRACE i DEBUG.

Optimize Code – opcja ta umożliwia włączenie lub wyłączenie optymalizacji kodu. Standardowe ustawienie dla konfiguracji „Debug” projektów wyłącza optymalizację, co ułatwia debugowanie. Opcję tą należy włączyć w przypadku, gdy błąd ujawnia się wyłącznie w kodzie zoptymalizowanym. Należy jednak pamiętać, że debugowanie takiego kodu jest trudniejsze, ze względu bardziej zawiłe relacje pomiędzy kodem skompilowanym i źródłowym.

Generate Debugging Information – opcja powoduje utworzenie w czasie kompilacji informacji wymaganej dla debugowania projektu (pliki o rozszerzeniu .pdb). Informacja ta pozwala na prezentowanie zawartości i nazw zmiennych, stosu wywołań oraz innych danych w postaci przystępnej dla użytkownika.

Output Path – definiuje ścieżke, gdzie umieszczany jest wynik kompilacji.

Dla projektów tworzonych za pomocą kreatorów Visual Studio generuje dwie konfiguracje: Debug i Release. Konfiguracja Debug jest kompilowana z pełną informacją debugera w formacie Microsoft, a kod nie jest optymalizowany. Konfiguracja Release jest w pełni optymalizowana i nie zawiera informacji debugera. Osiągane to jest właśnie dzięki odpowiednim ustawieniom powyższych opcji.

Pliki .PDB

Pliki o rozszerzeniu .PDB (Program Database) zawiera informacje wymaganą do debugowania, a także informacje o stanie projektu wykorzystywaną do łączenia narastającego (incremental linking) wyników kompilacji. Pliki tworzone są, jeśli kompilacja jest wykonywana z opcją /ZI lub /Zi dla programów tworzonych za pomocą C/C++ lub /debug dla programów w Visual Basic/C# .Net.

Używanie debugera

Błędy popełniane w trakcie tworzenia programów można podzielić na trzy kategorie: błędy składni, błędy semantyczne i logiczne. Pierwszy rodzaj błędów jest wykrywany w czasie kompilacji programów. Błędy semantyczne to sytuacje kiedy kod poprawny syntaktycznie nie odzwierciedla tego, co autor miał na myśli. Takie błędy często powodują przerwanie egzekucji programu lub taki jego stan, który jest niepoprawny lub niestabilny. Błędy powodujące niepoprawne wyniki działania programu można określić jako błędy logiczne.

Jedyną możliwością wykrycia błędów semantycznych i logicznych jest przeprowadzenie testów i weryfikacja poprawności działania programu. Zintegrowany debuger Visual Studio ,Net jest potężnym narzędziem, które ułatwiając prowadzenie testów pozwala na obserwowanie zachowania programów w trakcie ich wykonywania (run-time). Debuger interpretuje elementy wbudowane w języki programowania, pozwala zatrzymać (zawiesić) wykonywanie programu, weryfikację kodu, ewaluację i zmianę wartości zmiennych, podgląd zawartości zmiennych rejestru, wgląd w skompilowany kod programu i pamięci. Dobra znajomość narzędzi debugera pozwala na sprawne i szybkie weryfikowanie poprawności semantycznej kodu i korektę błędów.

Kontrola wykonania programu

Debuger oferuje szereg narzędzi dla kontroli przebiegu wykonywania programu, co znakomicie ułatwia pracę nad wyszukiwaniem usterek. Debuger pozwala na rozpoczęcie działania programu, chwilowe zatrzymanie pracy programu, zatrzymanie programu, krokowe wykonywanie instrukcji programu. Wszystkie powyższe elementy można osiągnać na wiele sposobów korzystając z menu programu, skrótów klawiszowych lub menu kontekstowego.

Rozpoczęcie wykonania programu

W celu uruchomienia programu z wykorzystaniem debugera należy:

-          z menu Debug wybrac jedną z opcji Start (skrót klawiszowy F5), Step Into lub Step Over, lub

-          z menu kontekstowego dla kodu źródłowego wybrać opcję Run to Cursor, lub

-          z menu kontekstowego dla projektu w oknie Solution Explorer wybrać opcję Debug, a następnie Start new instance lub Step Into new instance.

Należy pamiętać, że w niektórych przypadkach dla grupy projektów (Solution) należy określić projekt startowy.

Zatrzymanie wykonania programu

W celu zatrzymania wykonywania programu należy:

-          z menu Debug wybrać opcję Stop debugging (sktót klawiszowy Shift+F5).

Chwilowe wstrzymanie wykonywania programu

W celu chwilowego zatrzymania wykonywania programu należy:

-          z menu Debug wybrać opcję Break All, lub

-          skorzystać ze skrótu klawiszowego Ctrl+Alt+Break, lub

-          w miejscu, gdzie debuger powinien wstrzymać wykonywanie programu ustawić pułapkę (breakpoint), lub

-          w przypadku konieczności warunkowego wstrzymania wykonywania programu skorzystać z metody Debug.Assert ().

Wykonywanie krokowe

Wykonywanie krokowe komend języka programowania możliwe jest przy pomocy następujących komend menu Debug:

-          Step Into (skrót klawiszowy F11) – wykonanie linii programu lub wejście do kodu procedury,

-          Step Over (skrót klawiszowy F10) – wykonanie linii programu (bez wejścia do kodu procedury),

-          Step Out (skrót klawiszowy Shift+F11) – wykonanie kodu procedury aż do momentu jej opuszczenia.

W trybie wykonywania krokowego programu możliwe jest podglądanie wszystkich elementów egzekucji i ich stanu na dany moment wykonywania programu, np. wartości zmiennych, stos wywołań.

W celu wykonanie programu do wskazanego miejsca, należy:

-          w miejscu, gdzie debuger powinien wstrzymać wykonywanie programu ustawić pułapkę (breakpoint), lub

-          korzystając z menu kontekstowego dla okna kodu źródłowego w trybie przerwanej egzekucji programu należy wybrać opcję Run to cursor, lub

-          w przypadku konieczności warunkowego wstrzymania wykonywania programu skorzystać z metody Debug.Assert ().

Zmiana bieżącego miejsca wykonywania programu

Debuger umożliwia zmianę aktualnego miejsca wykonywania programu. W tym celu należy:

-          wskazać wybrane miejsce w kodzie źródłowym i skorzystać z opcji menu kontekstowego Set next statement.

Technika ta ma jednak kilka ograniczeń. W przypadku przesunięcia punktu od którego rozpoczyna się wykonywanie w przód instrukcje znajdujące się pomiędzy aktualnym i wskazanym punktem nie są wykonywane. W przypadku wskazania punktu wstecz, wykonane instrukcje nie są wycofywane. Przesunięcie punktu wykonywania do innej metody lub funkcji z reguły powoduje uszkodzenie informacji na stosie wywołań i powoduje wystąpienie wyjątku (ponadto nie jest to możliwe dla języka Visual Basic .Net).

Technika ta pozwala np. na pominięcie kawałka kodu, lub wykonanie operacji w metodzie lub funkcji ponownie, co pozwala przeanalizować zachowanie metody bez uruchamiania całego procesu raz jeszcze.

Debugowanie działających programów i wielu programów

Bardzo ciekawą możliwością jest debugowanie procesów uruchomionych poza środowiskiem Visual Studio .Net, wielu programów jednocześnie, programów działających na maszynach zdalnych, bibliotek DLL działających w odrębnych procesach i wystartowanie debugera automatycznie w przypadku wystąpienia błędu krytycznego (Just-In-Time debugging). Służy temu technika przyłączania debugera do działających procesów.

Przyłączenie do działającego procesu odbywa się przy pomocy okna dialogowego uruchamianego poprzez opcję menu Debug, Processes:

### OBRAZEK Rys_008_Debug_AttachWindow.bmp: Okno zarządzania debugowanymi procesami.

Przyłączenie debugera do procesu odbywa się poprzez wybranie procesu i użycie przycisku Attach.

W oknie tym znajduje się także lista procesów, do których debuger został przyłączony (Debugged Processes). Możliwe jest określenie akcji dla procesu, którego debugowanie jest zakańczane. Możliwe jest zatrzymanie procesu lub po prostu odłączenie debugera od procesu. Odbywa się to poprzez określenie odpowiedniej wartości dla wybranego debugowanego procesu w polu When debugging is stopped.

Inną możliwością debugowania wielu procesów w tej samej instancji środowiska jest uruchamianie kolejnych procesów przy wykorzystaniu opcji Debug menu kontekstowego projektu w oknie Solution Explorer.

W trakcie debugowania wielu procesów aktywna jest tak naprawdę tylko jedna konfiguracja. Aktywny program można wybrać przy pomocy opcji paska narzędzi Debug Location. Opcje tego paska narzędzi pozwalają także na wybór aktywnego wątku procesu oraz miejsca w stosie wywołań.

W trakcie przyłączania do procesów możliwe jest przyłączenie do procesu działającego na innej maszynie. W tym celu w oknie debugowanych procesów należy wybrać nazwę maszyny, na której działa proces oraz wskazać opcję warstwy komunikacji w polu Transport. Wartość Default będzie odpowiednia dla większości przypadków, natomiast wartość Native-only TCP/IP należy wskazać w przypadku debugowania programu typu Native oraz braku możliwości zastosowania mechanizmów DCOM.

Debugowanie zdalne wymaga zainstalowania komponentów Remote Components. Opis instalacji i konfiguracji debogowania zdalnego można odnaleźć w dokumentacji Visual Studio .Net w artykule pod tytułem „Remote Debugging Setup”.

Just-In-Time

Debugowanie Just-In-Time pozwala na uruchomienie i przyłączenie debugera do procesu, który wykona nieprawidłową operację. Aktywacja debugowania just-in-time wykonywana jest w opcjach tego trybu dla całego środowiska Visual Studio .Net (menu Tools, Options, Debugging, Just-In-Time).

Możliwe jest aktywowanie tej opcji debugera dla debugowania na maszynach zdalnych lub z wykorzystaniem warstwy DCOM w przypadku Windows 9x/Me.

Aktywowanie opcji dla aplikacji typu Windows Forms wymaga ustawienia opcji jitDebugging w machine.config lub application.exe.config (sekcja system.windows.forms):

<configuration>

    <system.windows.forms jitDebugging="true" />

</configuration>

Edit and Continue

Faktem, który zasmuci byłych użytkowników Visual Basic jest brak funkcji Edit and Continue. Funkcjonalność ta jest dostępna jedynie w Visual C/C++ i to pod pewnymi warunkami. W językach Visual Basic i Visual C# środowisko jedynie ostrzega o wykonaniu zmian i zezwala na kontynuację działania programu.

Debugowanie SQL

Debuger Visual Studio .Net umożliwia wykonywanie krokowe procedur składowanych SQL, funkcji i triggerów w taki sam sposób jak innego kodu.

Debugowanie kodu SQL jest możliwe na dwa sposoby. Pierwszym z nich jest utworzenie odpowiedniego połączenia w oknie Server Explorer środowiska Visual Studio .Net. Następnie należy odnaleźć żądaną procedurę składowaną, funkcję lub trigger:

### OBRAZEK Rys_011_Debug_SQL.bmp: Procedura składowana z ustawioną pułapką.

Tak wybraną procedurę można wykonywać krokowo przez wykorzystanie menu kontekstowego okna Server Explorer dla procedury składowanej lub funkcji i wybranie opcji Step Into Stored Procdure lub Run Stored Procedure. W przypadku, gdy kod SQL wymaga parametrów wyświetlone zostanie okno dialogowe z parametrami dla procedury umożliwiające ustawienie ich wartości. Pozwala to na wielokrotne wykonywanie procedury z tymi samymi wartościami parametrów.

Innym sposobem jest ustawienie pułapki w kodzie procedury składowanej, funkcji lub triggera i ustawienie opcji Enable SQL Debugging dla projektu. Wtedy wywołanie kodu SQL zostanie zatrzymane w miejscu ustawienia pułapki i umożliwi wykonywanie krokowe.

Debugowanie kodu SQL ma wiele ograniczeń. Są to między innymi:

-          brak możliwości wykorzystania opcji Set Next Statement

-          brak działania Edit and Continue

-          brak możliwości Step Into pomiędzy kodem SQL i kodem programu

-          brak możliwości przerwania działania programu w trakcie wykonywania kodu SQL poprzez wykorzystanie komendy Break

-          brak możliwości debugowania triggerów bezpośrednio; kod SQL triggerów musi być wywołany w celu debugowania poprzez odpowiednią akcję; jeśli tak się dzieje w przypadku operacji w innej procedurze składowanej, możliwe jest wykonanie operacji Step Into.

Dodając do debugowania SQL możliwości edycji obiektów baz danych MS SQL Server’a Visual Studio .Net staje się potężnym i wygodnym narzędziem do pracy nad aplikacjami baz danych.

Załączony przykład pod nazwą SQLDebugTestApplication zawiera wywołanie procedury składowanej bazy danych Northwind i zakłada, że w procedurze jest ustawiona pułapka.

Podsumowanie

Środowisko Visual Studio .Net oferuje potężne możliwości w zakresie wykonywania krokowego aplikacji. Wiele nowych cech i możliwości wynika z ujednolicenia środowiska wykonywania programów (Common Language Runtime) i ujednolicenia środowiska programistycznego dla wielu języków. Artykuł ten porusza tylko niektóre z tych możliwości.

W jego kontynuacji opisane zostaną w szerokim zakresie pułapki (breakpoints) debugera, narzędzia służące do diagnostyki stanu programów oraz rekomendacje dotyczące debugowania różnych typów projektów.

Cezary Nolewajko

 

Zgłoś jeśli naruszono regulamin