Debugowanie - Debugging

W programowania i rozwoju oprogramowania , debugowanie jest proces poszukiwania i rozwiązywania błędy (usterki i problemy, które uniemożliwiają prawidłowe funkcjonowanie) w ramach programów komputerowych , oprogramowania lub systemów .

Taktyka debugowanie może obejmować interaktywne debugowanie, kontrola przepływu analizy, testy jednostkowe , testy integracyjne , analizę pliku dziennika , monitorowanie w aplikacji lub systemu poziomie, zrzutów pamięci i profilowania . Wiele języków programowania i narzędzi programistycznych oferuje również programy ułatwiające debugowanie, znane jako debugery .

Etymologia

Wpis w dzienniku komputera z Mark II, z ćmą przyklejoną do strony

Terminy „błąd” i „debugowanie” są powszechnie przypisywane admirał Grace Hopper w latach 40. XX wieku. Kiedy pracowała na komputerze Mark II na Uniwersytecie Harvarda, jej współpracownicy odkryli ćmę utkwioną w przekaźniku, utrudniając w ten sposób działanie, po czym zauważyła, że ​​"debugują" system. Jednak termin „błąd” w znaczeniu „błąd techniczny” pochodzi z co najmniej 1878 roku i Thomasa Edisona ( pełne omówienie zawiera błąd oprogramowania ). Podobnie wydaje się, że termin „debugowanie” był używany jako termin w aeronautyce przed wejściem do świata komputerów. Rzeczywiście, w wywiadzie Grace Hopper zauważyła, że ​​nie ukuła tego terminu. Ćma pasowała do już istniejącej terminologii, więc została uratowana. List od Robert Oppenheimer (dyrektor II wojny światowej bomby atomowej projektu „Manhattan” w Los Alamos, NM) termin używany w liście do dr Ernest Lawrence w UC Berkeley, z dnia 27 października 1944, w odniesieniu do naboru dodatkowego personel techniczny.

Oxford English Dictionary wejście dla „debug” cytuje określenie „debugowania” użyte w odniesieniu do testowania silnika samolotu w 1945 roku artykuł w Journal of Royal Aeronautical Society. Artykuł w „Airforce” (czerwiec 1945 s. 50) również odnosi się do debugowania, tym razem kamer lotniczych. Błąd Hoppera został znaleziony 9 września 1947 roku. Programiści komputerowi przyjęli ten termin dopiero na początku lat pięćdziesiątych. Przełomowy artykuł Gilla z 1951 r. jest najwcześniejszą dogłębną dyskusją na temat błędów programowania, ale nie używa terminu „błąd” lub „debugowanie”. W cyfrowej bibliotece ACM termin „debugging” został po raz pierwszy użyty w trzech artykułach z 1952 National Meetings ACM. Dwóch z trzech używa tego terminu w cudzysłowie. W 1963 "debugowanie" było terminem na tyle powszechnym, że można go było wymieniać mimochodem bez wyjaśnienia na stronie 1 podręcznika CTSS .

Artykuł Peggy A. Kidwell Stalking the Elusive Computer Bug bardziej szczegółowo omawia etymologię „bugów” i „debugów”.

Zakres

Ponieważ oprogramowanie i systemy elektroniczne stały się ogólnie bardziej złożone, różne popularne techniki debugowania rozszerzyły się o więcej metod wykrywania anomalii, oceny wpływu i planowania poprawek oprogramowania lub pełnych aktualizacji systemu. Słowa „anomalia” i „rozbieżność” mogą być używane jako bardziej neutralne terminy , aby uniknąć słów „błąd” i „wada” lub „błąd”, w przypadku których może sugerować, że wszystkie tak zwane błędy , wady lub błędy musi zostać naprawiony (za wszelką cenę). Zamiast tego można przeprowadzić ocenę wpływu w celu ustalenia, czy zmiany mające na celu usunięcie anomalii (lub rozbieżności ) byłyby opłacalne dla systemu, czy też planowane nowe wydanie może sprawić, że zmiana(y) będzie niepotrzebna. Nie wszystkie problemy w systemie mają kluczowe znaczenie dla bezpieczeństwa lub misji . Ważne jest również, aby unikać sytuacji, w których zmiana może być bardziej przygnębiająca dla użytkowników w dłuższej perspektywie niż życie ze znanymi problemami (gdzie „lekarstwo byłoby gorsze niż choroba”). Opierając decyzje o dopuszczalności niektórych anomalii, można uniknąć kultury mandatu „zero defektów”, w którym ludzie mogą odczuwać pokusę zaprzeczania istnieniu problemów, tak aby wynik okazał się zerem defektów . Biorąc pod uwagę kwestie dodatkowe, takie jak ocena wpływu kosztów w stosunku do korzyści, szersze techniki debugowania zostaną rozszerzone w celu określenia częstotliwości anomalii (jak często występują te same „błędy”), aby pomóc ocenić ich wpływ na cały system.

Narzędzia

Debugowanie na konsolach do gier wideo jest zwykle wykonywane przy użyciu specjalnego sprzętu, takiego jak ta jednostka debugowania konsoli Xbox przeznaczona dla programistów.

Debugowanie ma różną złożoność, od naprawiania prostych błędów po wykonywanie długotrwałych i męczących zadań związanych z gromadzeniem danych, analizą i planowaniem aktualizacji. Umiejętność debugowania programisty może być głównym czynnikiem umożliwiającym debugowanie problemu, ale trudność debugowania oprogramowania różni się znacznie w zależności od złożoności systemu, a także zależy, do pewnego stopnia, od użytego języka ( języków) programowania oraz dostępne narzędzia, takie jak debugery . Debugery to narzędzia programowe, które umożliwiają programiście monitorowanie wykonania programu, zatrzymanie go, ponowne uruchomienie, ustawienie punktów przerwania i zmianę wartości w pamięci. Termin debugger może również odnosić się do osoby, która wykonuje debugowanie.

Ogólnie rzecz biorąc, języki programowania wysokiego poziomu , takie jak Java , ułatwiają debugowanie, ponieważ mają funkcje, takie jak obsługa wyjątków i sprawdzanie typów, które ułatwiają wykrycie rzeczywistych źródeł nieprawidłowego zachowania. W językach programowania, takich jak C lub assembler , błędy mogą powodować ciche problemy, takie jak uszkodzenie pamięci i często trudno jest zobaczyć, gdzie wystąpił początkowy problem. W takich przypadkach mogą być potrzebne narzędzia do debugowania pamięci .

W niektórych sytuacjach narzędzia programowe ogólnego przeznaczenia, które są specyficzne dla języka, mogą być bardzo przydatne. Przybierają one formę statycznych narzędzi do analizy kodu . Narzędzia te szukają w kodzie źródłowym bardzo konkretnego zestawu znanych problemów, niektórych powszechnych, a niektórych rzadkich, koncentrując się bardziej na semantyce (np. przepływie danych) niż na składni, jak robią to kompilatory i interpretery.

Istnieją zarówno komercyjne, jak i bezpłatne narzędzia dla różnych języków; niektórzy twierdzą, że są w stanie wykryć setki różnych problemów. Narzędzia te mogą być niezwykle przydatne podczas sprawdzania bardzo dużych drzew źródłowych, gdzie niepraktyczne jest wykonywanie instrukcji kodu. Typowym przykładem wykrytego problemu może być wyłuskanie zmiennej, które ma miejsce przed przypisaniem zmiennej do wartości. Jako inny przykład, niektóre takie narzędzia wykonują silne sprawdzanie typu, gdy język tego nie wymaga. Dzięki temu lepiej lokalizują prawdopodobne błędy w kodzie, który jest poprawny składniowo. Ale te narzędzia mają reputację fałszywych alarmów, gdzie poprawny kod jest oznaczany jako wątpliwy. Wczesnym przykładem jest stary unixowy program lint .

Do debugowania sprzętu elektronicznego (na przykład sprzęt komputerowy ), jak również oprogramowanie niskopoziomowe (np BIOS-y , sterowniki ) i oprogramowania , takich instrumentów jak oscyloskopów , analizatorów logicznych , lub w obwodzie emulatory (ICES) są często używane, samodzielnie lub w połączeniu. ICE może wykonywać wiele typowych zadań debuggera oprogramowania na niskopoziomowym oprogramowaniu i oprogramowaniu układowym .

Proces debugowania

Zwykle pierwszym krokiem debugowania jest próba odtworzenia problemu. Może to być nietrywialne zadanie, na przykład w przypadku procesów równoległych i niektórych błędów Heisenbug . Ponadto specyficzne środowisko użytkownika i historia użytkowania mogą utrudnić odtworzenie problemu.

Po odtworzeniu błędu może być konieczne uproszczenie danych wejściowych programu, aby ułatwić debugowanie. Na przykład błąd w kompilatorze może spowodować awarię podczas parsowania dużego pliku źródłowego. Jednak po uproszczeniu przypadku testowego tylko kilka wierszy z oryginalnego pliku źródłowego może wystarczyć do odtworzenia tej samej awarii. Takie uproszczenie można przeprowadzić ręcznie, stosując podejście dziel i zwyciężaj . Programista spróbuje usunąć niektóre części oryginalnego przypadku testowego i sprawdzić, czy problem nadal występuje. Podczas debugowania problemu w GUI programista może spróbować pominąć niektóre interakcje użytkownika z oryginalnego opisu problemu i sprawdzić, czy pozostałe działania są wystarczające, aby pojawiły się błędy.

Po wystarczającym uproszczeniu przypadku testowego programista może użyć narzędzia debugującego do zbadania stanów programu (wartości zmiennych oraz stosu wywołań ) i prześledzenia źródła problemu (problemów). Alternatywnie można użyć śledzenia . W prostych przypadkach śledzenie to tylko kilka instrukcji print, które wypisują wartości zmiennych w określonych punktach wykonywania programu.

Techniki

  • Interaktywne debugowanie
  • Debugowanie (lub śledzenie) drukowania jest czynnością polegającą na obserwowaniu (na żywo lub nagranych) instrukcji śledzenia lub instrukcji drukowania, które wskazują przebieg wykonywania procesu. Czasami nazywa się todebugowanie printf , ze względu na użyciefunkcjiprintfw C. Ten rodzaj debugowania był włączany komendą TRON w oryginalnych wersjach zorientowanego na nowicjuszyjęzykaprogramowaniaBASIC. TRON oznaczało „Trace On”. TRON powodował, że podczas działania programu drukowane były numery każdego wiersza poleceń BASIC.
  • Debugowanie zdalne to proces debugowania programu działającego w systemie innym niż debuger. Aby rozpocząć zdalne debugowanie, debuger łączy się ze zdalnym systemem przez łącze komunikacyjne, takie jak sieć lokalna. Debuger może wtedy sterować wykonywaniem programu w systemie zdalnym i pobierać informacje o jego stanie.
  • Debugowanie pośmiertne to debugowanie programu po jego awarii . Technik związanych często obejmują różne techniki Kalka jak sprawdzenie logów, wyprowadzanie stos wywołań na katastrofy i analiza zrzutu pamięci (lub zrzutu ) procesu rozbił. Zrzut procesu może zostać uzyskany automatycznie przez system (na przykład, gdy proces został zakończony z powodu nieobsłużonego wyjątku) lub przez instrukcję wstawioną przez programistę lub ręcznie przez interaktywnego użytkownika.
  • Algorytm „Wilczego ogrodzenia”: Edward Gauss opisał ten prosty, ale bardzo przydatny i obecnie znany algorytm w artykule Communications of the ACM z 1982 roku w następujący sposób: „Na Alasce jest jeden wilk; jak go znaleźć? Najpierw zbuduj ogrodzenie pośrodku stanu, poczekaj, aż wilk zawyje, ustal, po której stronie ogrodzenia się on znajduje. Powtarzaj proces tylko po tej stronie, aż dojdziesz do punktu, w którym zobaczysz wilka. Jest to zaimplementowane np. w systemie kontroli wersji Git jako polecenie git bisect , które wykorzystuje powyższy algorytm do określenia, który commit wprowadził konkretny błąd.
  • Debugowanie nagrywania i odtwarzania to technika tworzenia nagrania wykonania programu (np. za pomocą bezpłatnegonarzędzia do debugowania rr Mozilli; umożliwia odwracalne debugowanie/wykonanie), które można odtworzyć i interaktywnie debugować. Przydatne do zdalnego debugowania i debugowania sporadycznych, niedeterministycznych i innych trudnych do odtworzenia defektów.
  • Delta Debugging  – technika automatyzacji upraszczania przypadków testowych.
  • Saff Squeeze  – technika izolowania niepowodzeń w teście za pomocą progresywnego wstawiania części nieudanego testu.
  • Śledzenie przyczynowości : istnieją techniki śledzenia łańcuchów przyczynowo-skutkowych w obliczeniach. Techniki te można dostosować do określonych błędów, takich jak wyłuskiwanie wskaźnika zerowego.

Debugowanie systemów wbudowanych

W przeciwieństwie do ogólnego środowiska projektowania oprogramowania komputerowego, podstawową cechą środowisk osadzonych jest sama liczba różnych platform dostępnych dla programistów (architektury procesorów, dostawcy, systemy operacyjne i ich warianty). Systemy wbudowane z definicji nie są projektami ogólnego przeznaczenia: są zazwyczaj opracowywane dla pojedynczego zadania (lub niewielkiego zakresu zadań), a platforma jest wybierana specjalnie w celu optymalizacji tej aplikacji. Fakt ten nie tylko utrudnia życie programistom systemów wbudowanych, ale także utrudnia debugowanie i testowanie tych systemów, ponieważ dla różnych platform potrzebne są różne narzędzia do debugowania.

Pomimo wspomnianego powyżej wyzwania związanego z heterogenicznością, niektóre debuggery zostały opracowane komercyjnie, a także jako prototypy badawcze. Przykłady rozwiązań komercyjnych pochodzą z Green Hills Software , Lauterbach GmbH i Microchip's MPLAB-ICD (dla debuggera w obwodzie). Dwa przykłady prototypowych narzędzi badawczych to Aveksha i Flocklab. Wszystkie one wykorzystują funkcjonalność dostępną w tanich procesorach wbudowanych, moduł debugowania na chipie (OCDM), którego sygnały są ujawniane przez standardowy interfejs JTAG . Są one porównywane w oparciu o to, ile zmian w aplikacji jest potrzebnych i ile zdarzeń jest w stanie nadążyć.

Oprócz typowego zadania identyfikacji błędów w systemie, debugowanie systemu wbudowanego ma również na celu zbieranie informacji o stanach operacyjnych systemu, które można następnie wykorzystać do analizy systemu: znalezienia sposobów na zwiększenie jego wydajności lub optymalizację innych ważnych charakterystyki (np. zużycie energii, niezawodność, reakcja w czasie rzeczywistym itp.).

Ochrona przed debugowaniem

Antydebugowanie to „wdrożenie jednej lub więcej technik w kodzie komputerowym, które utrudniają próby inżynierii wstecznej lub debugowania procesu docelowego”. Jest aktywnie wykorzystywany przez uznanych wydawców w schematach ochrony przed kopiowaniem , ale jest również wykorzystywany przez złośliwe oprogramowanie do komplikowania jego wykrywania i eliminacji. Techniki stosowane w zapobieganiu debugowaniu obejmują:

  • Oparte na API: sprawdź, czy istnieje debugger, korzystając z informacji o systemie
  • Oparte na wyjątkach: sprawdź, czy wyjątki są zakłócane
  • Bloki procesów i wątków: sprawdź, czy manipulowano blokami procesów i wątków
  • Zmodyfikowany kod: sprawdź modyfikacje kodu wprowadzone przez debugger obsługujący punkty przerwania oprogramowania
  • Oparte na sprzęcie i rejestrach: sprawdź sprzętowe punkty przerwania i rejestry procesora
  • Czas i opóźnienie: sprawdź czas potrzebny na wykonanie instrukcji
  • Wykrywanie i karanie debuggera

Wczesny przykład antydebugowania istniał we wczesnych wersjach Microsoft Word, które po wykryciu debuggera generowały komunikat „Drzewo zła rodzi gorzkie owoce. dysk twardy do emitowania alarmujących dźwięków z zamiarem odstraszenia użytkownika od ponownej próby.

Zobacz też

Bibliografia

Dalsza lektura

Zewnętrzne linki