Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Odrobaczanie (debugging) programu Zasada van Tassela: Żaden program nie działa od razu. Bądź szczególnie podejrzliwy, jeżeli za pierwszym razem dostałeś

Podobne prezentacje


Prezentacja na temat: "Odrobaczanie (debugging) programu Zasada van Tassela: Żaden program nie działa od razu. Bądź szczególnie podejrzliwy, jeżeli za pierwszym razem dostałeś"— Zapis prezentacji:

1 Odrobaczanie (debugging) programu Zasada van Tassela: Żaden program nie działa od razu. Bądź szczególnie podejrzliwy, jeżeli za pierwszym razem dostałeś poprawną odpowiedź. Pojęcie robaka (bug) w elektronicznej technice obliczeniowej przypisuje się admirał U.S. Navy, Grace Murray Hopper, twórczyni COBOLu, która opowiadała historię o techniku, który naprawił komputer Harvard II usuwając ćmę z obwodów. Cała historia jest opisana w Annals of the History of Computing, (1981). Później uogólniono to pojęcie na złe funkcjonowanie programów. Jeszcze wcześniej mianem bug określano defekty urządzeń elektrycznych ("Hawkin's New Catechism of Electricity", T. Audel & Co., 1896) albo przyczyny szumu na liniach telefonicznych lub telegraficznych. Słowa bug w sensie nagłego rujnującego zdarzenia używano już w czasach Shakespearea. Samo słowo w tym znaczeniu prawdopodobnie pochodzi z walijskiego (zanglicyzowanego) bugbear, oznaczającego różne mityczne potwory.

2 Admirał Grace Murray Hopper ( ) Strona z dziennika komputera Harvard II z opisem usunięcia ćmy z obwodów wraz z przyklejonym owadem.

3 Jeden z najsławniejszych błędów w FORTRANie (historia opisana przez Freda Webba na alt.folklore.computers w roku 1990: I worked at Nasa during the summer of The group I was working in was doing preliminary work on the Mission Control Center computer systems and programs. My office mate had the job of testing out an orbit computation program which had been used during the Mercury flights. Running some test data with known answers through it, he was getting answers that were close, but not accurate enough. So, he started looking for numerical problems in the algorithm, checking to make sure his tests data was really correct, etc. After a couple of weeks with no results, he came across a DO statement, in the form: DO 10 I=1.10 This statement was interpreted by the compiler (correctly) as: DO10I = 1.10 The programmer had clearly intended: DO 10 I = 1, 10

4 Literówki w nazwach i nie tylko (np. JI zamiast IJ, 1 zamiast I lub O zamiast 0 jako indeks tablicy albo w wyrażeniach Rezygnacja z reguły pierwszej litery (zawsze dajemy IMPLICIT NONE). Używanie małych a nie dużych liter (trudno pomylić z cyframi) Pomyłkowe wstawienie zmiennych lub stałych całkowitych aby uzyskać wyrażenie rzeczywiste (np. X=1/6) Czasami pomaga wymóg deklarowania zmiennych Niewspółmierność bloków COMMON w różnych segmentach Bloki COMMON zapisać w plikach I używać instrukcji INCLUDE Niezgodność rozmiarów tablic w różnych segmentach Deklarować dyrektywą PARAMETER stałe używane w wymiarowaniu tablic i zapisać deklaracje w plikach włączanych do źródła przez INCLUDE Wyjście poza 72-gą kolumnęUżywać edytorów tekstów z licznikiem kolumn Użycie tablicy w kontekście zmiennej prostej lub odwrotnie Niezgodność listy parametrów formalnych i aktualnych Najczęstsze błędy podczas programowania w FORTRANie i sposoby zapobiegania im

5 Sposoby odrobaczania programu Analiza kodu źródłowego Analiza wyników działania programu Diagnostyka użytkownika (drukowanie wyników pośrednich) Użycie opcji kompilatora generujących informację diagnostyczną oraz sprawdzających przekroczenie granic tablic. Użycie odpowiednego programu narzędziowego, debuggera.

6 Sześć zasad odrobaczania. 1.Doprowadź do tego, żeby błąd był powtarzalny. 2.Zawęż problem do najprostszych przebiegów z najmniejszym zestawem danych, najlepiej takich gdzie wszystkie operacje możesz przeprowadzić na piechotę. 3.Zlokalizuj najmniejszą jednostkę programu, gdzie błąd występuje. 4.Przeprowadź odpowiednio zaplanowane eksperymenty (np., jeżeli program ma obliczyć kąt między trzema atomami rozsądnie jest wybrać najpierw współrzędne które dadzą kąt prosty, potem pełny, potem dowolny. 5.Używaj doświadczenia własnego i innych. 6.Nigdy nie dopuszczaj myśli, że problemu nie rozwiążesz albo że do jego rozwiązania jest potrzebna wiedza magiczna. Więcej w artykule Terence Parr Learn the Essentials of DebuggingLearn the Essentials of Debugging

7 gdb (Linux, darmowy) dbx (AIX i inne systemy; przychodzi z kompilatorem) xdb (AIX; okienkowy) totalview (AIX, UNICOS; okienkowy) Debuggery do kodów FORTRANowskich

8 Praca z debuggerem gdb Kompilacja z opcją –g (dodaje informację diagnostyczną do kodu wynikowego) Przykład: f77 –g program.f –o program Warto dodać sprawdzanie rozmiarów tablic (opcja fbounds-check), np: f77 –g –fbounds-check program.f –o program Tak skompilowany program można uruchomić z poziomu gdb: gdb program

9 Podstawowe komendy debuggera break plik.f:nr_liniiustawienie punktu zatrzymania w linii nr_linii pliku źródłowego plik.f clear plik.f:nr_liniiusunięcie danego punktu zatrzymania runwykonanie programu do końca lub pierwszego zatrzymania contwznowienie wykonywania programu po napotkaniu punktu zatrzymania next [liczba_linii]przejście do następnej linii lub wykonanie następnych liczba_linii kodu danego podprogramu bez wliczania linii wywoływanych popdrogramów lub funkcji. step [liczba_linii]przejście do następnej instrukcji lub wykonanie następnych liczba_linii instrukcji programu, włączając linie podprogramów lub funkcji wywoływanych print zmiennadrukowanie wartości danej zmiennej. quitwyjście z debuggera.

10 Trochę bardziej zaawansowane ale użyteczne komendy cd katalogzmiana katalogu roboczego na katalog pwdpokazuje katalog roboczy file progładowanie programu prog do debuggera set args argwprowadzanie argumentów arg do linii polecenia programu list [nr1,nr2]listowanie 10 linii kodu scentrowanych na danej linii (uwaga: kolejne list kontytuuje) albo od linii nr1 do linii nr2. list +[-]listowanie następnych (+) albo poprzednich (-) linii kodu źródłowego. list plik.f:linialistowanie kodu źródłowego z pliku plik.f począwszy od linii linia. info kategoriainformacja na temat danej kategorii; np. info break podaje informację o punktach zatrzymania wherepokazuje w którym miejscu programu się znajdujemy backtrace where fullpokazuje gdzie się znajdujemy oraz drukuje wartości wszystkich backtrace fullzmiennych w danym segmencie oraz segmentach wywołujących

11 set z=wartośćnadawanie nowej wartości zmiennej z występującej w aktualnie analizowanym module programu set env zm=wyrNadawanie wartości wyr zmiennej środowiskowej zm unset env zmanulowanie zmiennej środowiskowej zm show envpokazuje zmienne środowiskowe show pathpokazuje ścieżki dostępu where fullpokazuje gdzie się znajdujemy oraz drukuje wartości wszystkich zmiennych w danym segmencie oraz segmentach wywołujących watch wyrażeniezatrzymuje program jeżeli wartość wyrażenia wyrażenie zmienia się i drukuje nową wartość (wyrażenie może być nazwą zmiennej) awatch wyrażeniezatrzymuje program jeżeli wyrażenie jest pisane lub czytane rwatch wyrażeniezatrzymuje program, jeżeli wyrażenie jest czytane Pełen opis gdb:

12 Przykład użycia debuggera do śledzenia wykonywania programu titr obliczającego krzywą miareczkowania mocnego kwasu mocną zasadą Źródła FORTRANowskie titr.ftitr.f czyt_dane.f oblicz_krzywa.f oblicz_ph.f pisz_wyniki.f DIMENSIONSczyt_dane.foblicz_krzywa.foblicz_ph.f pisz_wyniki.fDIMENSIONS Dane krzywa_dane Wyniki krzywa_wyniki Plik Makefile Makefile

13 Przykład sesji debuggera etoh:~/FORTRAN/DEBUG> gdb titr (gdb) break titr.f:15 Breakpoint 1 at 0x804887b: file titr.f, line 15. (gdb) run Starting program: /big/staff/adam/FORTRAN/DEBUG/titr Breakpoint 1, MAIN__ () at titr.f:15 15 CALL OBLICZ_KRZYWA(IOUT,CKW,CZ,VKW) Current language: auto; currently fortran (gdb) print ckw $1 = (gdb) next 17 CALL PISZ_WYNIKI(IOUT) (gdb) step pisz_wyniki__ (wyjscie=0x804a050) at pisz_wyniki.f:7 7 OPEN(WYJSCIE,FILE='krzywa.wyniki',STATUS='UNKNOWN') (gdb) step 3 11 WRITE(WYJSCIE,'(I3,2x,F5.2,F8.3)') I,OBJZ(I),PH(I) (gdb) cont Continuing. Program exited normally. (gdb)

14 Zmieniamy w pliku DIMENSIONS maksymalną liczbę punktów ze 100 na 10 PARAMETER (MAXPUNKT=10) Kompilujemy bez debuggingu etoh:~/FORTRAN/DEBUG> make f77 -c titr.f f77 -c czyt_dane.f f77 -c oblicz_krzywa.f f77 -c oblicz_ph.f f77 -c pisz_wyniki.f f77 -o titr titr.o czyt_dane.o oblicz_krzywa.o oblicz_ph.o pisz_wyniki.o etoh:~/FORTRAN/DEBUG>./titr Program pozornie się wykonał ale plik krzywa.wyniki zawiera tylko nagłówek etoh:~/FORTRAN/DEBUG> more krzywa.wyniki Punkt VZ pH Sprawdzanie przekroczenia rozmiarów tablic

15 Teraz kompilujemy z –fbounds-check –g etoh:~/FORTRAN/DEBUG> make -f Makefile-debug f77 -c -fbounds-check -g titr.f f77 -c -fbounds-check -g czyt_dane.f f77 -c -fbounds-check -g oblicz_krzywa.f f77 -c -fbounds-check -g oblicz_ph.f f77 -c -fbounds-check -g pisz_wyniki.f f77 -o titr -fbounds-check -g titr.o czyt_dane.o oblicz_krzywa.o oblicz_ph.o pisz_wyniki.o Po uruchomieniu od razu widać, gdzie jest problem etoh:~/FORTRAN/DEBUG>./titr Subscript out of range on file line 12, procedure czyt. Attempt to access the 21-th element of variable vz. Abort

16 SUBROUTINE CZYT_DANE(WEJSCIE,STKW,STZ,OBJKW) C Czytanie danych wejsciowych IMPLICIT NONE INCLUDE 'DIMENSIONS' INTEGER WEJSCIE,I,NPUNKT REAL*8 STKW,STZ,OBJKW REAL*8 VZ(MAXPUNKT),PH(MAXPUNKT) COMMON /KRZYWA/ VZ,PH,NPUNKT OPEN(WEJSCIE,FILE='krzywa.dane',STATUS='OLD') READ(WEJSCIE,*) NPUNKT,STKW,STZ,OBJKW READ(WEJSCIE,*) (VZ(I),I=1,NPUNKT) CLOSE(WEJSCIE) RETURN END Zatrzymanie

17 Podobne informacje dostajemy uruchamiając program z poziomu debuggera etoh:~/FORTRAN/DEBUG> gdb titr (gdb) run Starting program: /big/staff/adam/FORTRAN/DEBUG/titr Subscript out of range on file line 12, procedure czyt. Attempt to access the 21-th element of variable vz. Program received signal SIGABRT, Aborted. 0x b in raise () from /lib/tls/libc.so.6 Możemy wtedy zapytać dokładnie gdzie błąd nastąpił (gdb) where #0 0x b in raise () from /lib/tls/libc.so.6 #1 0x40093fa2 in abort () from /lib/tls/libc.so.6 #2 0x f in sig_die () from /usr/lib/libg2c.so.0 #3 0x40027c94 in s_rnge () from /usr/lib/libg2c.so.0 #4 0x080489ea in czyt_dane__ (wejscie=0x804a04c, stkw=0xbffffc10, stz=0xbffffc08, objkw=0xbffffc00) at czyt_dane.f:12 #5 0x b in MAIN__ () at titr.f:12 #6 0x08048dd6 in main ()

18 Można też uzyskać pełną informację, łącznie z wartościami zmiennych (gdb) where full #0 0x b in raise () from /lib/tls/libc.so.6 No symbol table info available. #1 0x40093fa2 in abort () from /lib/tls/libc.so.6 No symbol table info available. #2 0x f in sig_die () from /usr/lib/libg2c.so.0 No symbol table info available. #3 0x40027c94 in s_rnge () from /usr/lib/libg2c.so.0 No symbol table info available. #4 0x080489ea in czyt_dane__ (wejscie=0x804a04c, stkw=0xbffffc10, stz=0xbffffc08, objkw=0xbffffc00) at czyt_dane.f:12 __g77_impdo_0 = 10 __g77_cilist_1 = {err = 0, unit = 1, end = 0, format = 0x0, rec = 0}

19 i = 21 npunkt = 31 vz = {1, 2, 3, 4, 5, 6, 7, 8, 9, , , , , , , , 10, 10.01, , 10.1} ph = {0 } #5 0x b in MAIN__ () at titr.f:12 n = 31 inp = 1 iout = 2 ckw = cz = vkw = 10 vz = {1, 2, 3, 4, 5, 6, 7, 8, 9, , , , , , , , 10, 10.01, , 10.1} ph = {0 } #6 0x08048dd6 in main () No symbol table info available.

20 Dlaczego błąd nie był sygnalizowany bez opcji –fbounds-check, natomiast program nie wydrukował wyników ? Kompilujemy tylko z opcją –g etoh:~/FORTRAN/DEBUG> make -f Makefile-debug1 f77 -c -g titr.f f77 -c -g czyt_dane.f f77 -c -g oblicz_krzywa.f f77 -c -g oblicz_ph.f f77 -c -g pisz_wyniki.f f77 -o titr -g titr.o czyt_dane.o oblicz_krzywa.o oblicz_ph.o pisz_wyniki.o

21 Kompilujemy tylko z opcją –g etoh:~/FORTRAN/DEBUG> make -f Makefile-debug1 f77 -c -g titr.f f77 -c -g czyt_dane.f f77 -c -g oblicz_krzywa.f f77 -c -g oblicz_ph.f f77 -c -g pisz_wyniki.f f77 -o titr -g titr.o czyt_dane.o oblicz_krzywa.o oblicz_ph.o pisz_wyniki.o Uruchamiamy z gdb ustawiając zatrzymanie w pisz_wyniki.f etoh:~/FORTRAN/DEBUG> gdb titr (gdb) break pisz_wyniki.f:1 Breakpoint 1 at 0x8048aec: file pisz_wyniki.f, line 1. (gdb) run Starting program: /big/staff/adam/FORTRAN/DEBUG/titr Breakpoint 1, pisz_wyniki__ (wyjscie=0x804864c) at pisz_wyniki.f:1 1 SUBROUTINE PISZ_WYNIKI(WYJSCIE) Current language: auto; currently fortran

22 Drukujemy pełną informację (gdb) where full #0 pisz_wyniki__ (wyjscie=0x804864c) at pisz_wyniki.f:1 i = npunkt = objz = (1, 2, 3, 4, 5, 6, 7, 8, 9, , , , , , , , 10, 10.01, , 10.1) ph = ( , , , , , , , , , , , , , , , , 7, , , )

23 #1 0x in MAIN__ () at titr.f:16 n = inp = 1 iout = 2 ckw = cz = vkw = 10 vz = (1, 2, 3, 4, 5, 6, 7, 8, 9, , , , , , , , 10, 10.01, , 10.1) ph = ( , , , , , , , , , , , , , , , , 7, , , ) #2 0x08048c76 in main () No symbol table info available.

24 Taka wartość zmiennej NPUNKT (w pisz_wyniki.f) lub N (w titr.f) jest wynikiem nadpisania jej przez pierwszy element tablicy PH wykraczający poza zadeklarowany rozmiar tablicy. Zmienna NPUNKT lub N sąsiadje z tablicą PH w obszarze wspólnym KRZYWA: REAL*8 VZ(MAXPUNKT),PH(MAXPUNKT) COMMON /KRZYWA/ VZ,PH,NPUNKT Błąd ten nastąpił w podprogramie oblicz_krzywa.f, gdzie jest wypełniana tablica PH. Jeżeli podejrzewamy, że problem jest ze zmienną NPUNKT, możemy wydrukować jej wartość bez zrzucania całego zestawu zmiennych w danym punkcie programu. (gdb) print npunkt $1 =

25 Zmianę wartości n możemy też śledzić przy pomocy komendy watch (gdb) break titr.f:1 Breakpoint 1 at 0x : file titr.f, line 1. (gdb) run Starting program: /big/staff/adam/FORTRAN/DEBUG/titr Breakpoint 1, MAIN__ () at titr.f:1 1 PROGRAM TITR Current language: auto; currently fortran

26 (gdb) watch n Hardware watchpoint 2: n (gdb) cont Continuing. Hardware watchpoint 2: n Old value = 0 New value = 31 0x4002ffc7 in l_read () from /usr/lib/libg2c.so.0 (gdb) cont Continuing. Hardware watchpoint 2: n Old value = 31 New value = oblicz_krzywa__ (wyjscie=0x , stkw=0xbffffc10, stz=0xbffffc08, objkw=0xbffffc00) at oblicz_krzywa.f:13 13 ENDDO

27 Użyteczne warianty wywoływania gdb Analiza zrzutu pamięci (coredump) programu który się wywalił Zwykle zrzut jest zapisany w pliku core. Przykładowo po wywołaniu gdb prog core gdb zachowa się tak, jakby program prog był uruchomiony z poziomu debuggera i zatrzymał się wskutek błędu, zatem można prowadzić analizę używając where, print, itp. Kolejność argumentów nie obowiązuje jeżeli prog poprzedzimu –e a core –c. Debugging już uruchomionego programu gdb prog nr_procesu Gdzie prog jest nazwą pliku wykonywalnego a nr_procesu numerem procesu odpowiadającego chodzącemu programowi. Specyfikowanie katalogów, gdzie znajdują się pliki źródłowe gdb –d katalog prog


Pobierz ppt "Odrobaczanie (debugging) programu Zasada van Tassela: Żaden program nie działa od razu. Bądź szczególnie podejrzliwy, jeżeli za pierwszym razem dostałeś"

Podobne prezentacje


Reklamy Google