home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1997 #3 / amigamamagazinepolishissue03-1 / ma_1995 / 01 / ami012.txt < prev    next >
Text File  |  1997-04-06  |  18KB  |  359 lines

  1. Co to jest debugger (cz. 2.) 
  2. ----------------------------
  3.  
  4. ODPLUSKWIACZE 
  5.  
  6. <lead> W pierwszej czëôci opisaîem dwa najbardziej znane
  7. debuggery: Enforcera i Mungwalla. Dziô czas zajâê sië innymi, nie
  8. tak znanymi ani rozbudowanymi, co jednak wcale nie znaczy: mniej
  9. przydatnymi.
  10.  
  11. <a> Kamil Iskra
  12.  
  13. <txt> Na dysku 870 znanej wszystkim biblioteki Freda Fisha
  14. znalazîem program StackCheck 1.0 autorstwa Guenthera Roehricha. W
  15. niedîugi czas póúniej miaîem okazjë przekonaê sië o jego
  16. wartoôci, kiedy to robocza wersja jednego z moich programów z
  17. uporem maniaka zawieszaîa sië pod OS 3.0, podczas gdy pod OS 2.04
  18. dziaîaîa w zasadzie prawidîowo. Próbowaîem wykryê bîâd Mungwallem
  19. i innymi debuggerami i... nic -- kilkudniowe poszukiwania byîy
  20. bezowocne. W odruchu ostatniej rozpaczy uruchomiîem StackChecka.
  21. Program bez ûadnego ociâgania, krótko i dosadnie napisaî:
  22.  
  23. <l>
  24. StackCheck V1.0 by Guenther Roehrich
  25.  
  26. This program is Public Domain. Press CTRL-C to abort.
  27.  
  28.  
  29. Free stack area was cleared:
  30.  
  31. 0038519C: 00000000 00000000 00000000 00000000
  32.  
  33. Task stack overflowed:
  34.  
  35. 0038519C: BAD1BAD3 BEEFBEEF BEEFBEEF BEEFBEEF
  36.  
  37. Stacksize: 4096
  38.  
  39. <txt> Jednym sîowem, stwierdziî, ûe mój program po prostu
  40. przepeîniî stos procesora. Przepeînienie stosu polega na
  41. "wyjechaniu" poza jego granice -- zapisywany jest przypadkowy
  42. obszar pamiëci. Moûna w tym momencie zadaê sobie pytanie,
  43. dlaczego Mungwall tego bîëdu nie wykrywa, przecieû obkîada on
  44. kaûdy przydzielony obszar pamiëci "ôcianami". Powód jest prosty.
  45. Mungwall zgîasza bîâd tylko wtedy, gdy wykryje, ûe zwalniany
  46. obszar jest obîoûony ôcianami. Tymczasem przepeîniajâc stos o
  47. kilkaset bajtów czy kilobajt powodujemy, ûe ze ôcian ani
  48. poprzedzajâcego ich specjalnego nagîówka nie zostaje najmniejszy
  49. ôlad. Istnieje kilka innych programów sprawdzajâcych stan stosu,
  50. wedîug mnie jednak ûaden z nich (mówië o tych, które widziaîem:
  51. WatchStack, XOper) nie dorasta StackCheckowi do piët. Wynika to
  52. z róûnych zasad dziaîania.
  53.  
  54. StackCheck uruchamia sië z jednym parametrem: nazwâ procesu,
  55. który ma byê monitorowany (program ma teû kilka opcjonalnych
  56. parametrów, zwykle nieistotnych). Jeûeli proces o podanej nazwie
  57. nie istnieje, StackCheck czeka, aû sië pojawi (np. aû uruchomisz
  58. program). Wolny obszar monitorowanego stosu jest wstëpnie
  59. wypeîniany sekwencjami 0xBEEF, po czym pozostawia sië go "samemu
  60. sobie". Raz na jakiô czas StackCheck sprawdza, jaki obszar stosu
  61. byî w uûyciu -- rozpoznaje to po prostu po znikniëciu sekwencji
  62. 0xBEEF, które zostajâ zastâpione innymi wartoôciami,
  63. przechowywanymi przez program na stosie. Wiëkszoôê programów
  64. monitorujâcych stos dziaîa w taki sposób, ûe raz na jakiô czas
  65. sprawdzajâ one bieûâcâ wartoôê wskaúnika poczâtku stosu
  66. monitorowanego procesu: programy te nie sâ w stanie stwierdziê,
  67. jakie byîo uûycie stosu pomiëdzy dwoma sprawdzeniami: moûe na
  68. krótkâ chwilë zostaî uûyty bardzo duûy jego obszar? StackCheck
  69. jest tej wady caîkowicie pozbawiony -- sprawdza po prostu
  70. zawartoôê stosu, a nie bieûâcy wskaúnik jego poczâtku.
  71.  
  72. Chciaîbym w tym momencie ostrzec tych, którzy uwaûajâ, ûe ich
  73. programom przepeînienie stosu nie grozi, gdyû nie uûywajâ
  74. rekurencji (jak wiadomo, to ona jest gîównym "poûeraczem
  75. stosów"), a poza tym kompilujâ programy z opcjami powodujâcymi
  76. automatyczne sprawdzanie przepeînienia stosu przez program. Otóû
  77. ja... teû tak uwaûaîem, wîaônie do czasu opisanego powyûej
  78. incydentu: mój program (ciekawych informujë, ûe chodzi o
  79. "Konwersjë") NIE uûywaî rekurencji i BYΠskompilowany z
  80. doîâczeniem procedur testujâcych stos. Procedury te sâ niestety
  81. guzik warte, jeûeli przepeînienie stosu nastâpi w wywoîanej przez
  82. program funkcji z jakiejô biblioteki -- te procedury sprawdzajâ
  83. stos tylko na poczâtku kaûdej funkcji naleûâcej do programu. Stos
  84. zaô "udaîo mi sië" przepeîniê dziëki uûyciu duûych zmiennych
  85. lokalnych do obsîugi plików, no bo wypada daê 108 bajtów na nazwë
  86. pliku, 255 bajtów na caîâ nazwë (ze ôcieûkâ dostëpu), 260 bajtów
  87. to struktura FileInfoBlock (odkîadam jâ na stosie, uûywajâc
  88. "__aligned"), kolejnych 400 bajtów przeznaczam na tekst bîëdu
  89. ("Bîâd odczytu pliku..." itd.), poza tym file-requestery teû do
  90. oszczëdnych nie naleûâ (szczególnie w wypadku uûycia patternów:
  91. systemowe funkcje MatchPattern[NoCase]() potrafiâ zjeôê nawet 1,5
  92. KB stosu!).  Kiedy sië to wszystko zsumuje, to okazuje sië, ûe o
  93. przepeînienie stosu nietrudno. Najprostszym rozwiâzaniem problemu
  94. jest definiowanie duûych tablic jako zmiennych klasy "static".
  95. Powoduje to, co prawda, nieco wiëkszâ pamiëcioûernoôê programu,
  96. ale kogo w dzisiejszych czasach obchodzâ te 2, 3 KB... Zwróê teû
  97. uwagë na to, co powyûej napisaîem, ûe stos przepeîniaî sië pod OS
  98. 3.0, podczas gdy pod OS 2.04 nie (ôciôlej mówiâc: byî na granicy
  99. przepeînienia). Funkcje róûnych wersji systemu operacyjnego mogâ
  100. w róûnym stopniu "konsumowaê" stos, naleûy wiëc zawsze zapewniê
  101. spory "margines bezpieczeïstwa".
  102.  
  103. Wszystkie opisane dotychczas programy mogîeô znaleúê na
  104. stosunkowo îatwo dostëpnych dyskach Fisha. Z trzema pierwszymi
  105. spoôród opisanych poniûej nie jest juû tak wesoîo: tych programów
  106. firma Commodore nigdy u Fisha nie opublikowaîa. Ja znalazîem je
  107. na dyskach "DevCon93" (materiaîy dla zarejestrowanych
  108. developerów), które (przynajmniej w Krakowie) moûna zdobyê na
  109. gieîdzie. Ich zdobycie tâ drogâ nie jest chyba w ôwietle znanej i
  110. lubianej (?!) ustawy przestëpstwem, jako ûe w dokumentacji do
  111. ûadnego z tych programów nie jest napisane, ûe nie wolno ich
  112. rozpowszechniaê. Stosujâc zatem zasadë Zagîoby ("Bo widzisz,
  113. moôci Kowalski, ûeby to byîo nie wolno, to byô miaî rozkaz nie
  114. dawaê, a ûe nie masz rozkazu, wiëc dawaj" -- Henryk Sienkiewicz,
  115. "Potop", tom I), moûna je kopiowaê i uûywaê ich.
  116.  
  117. Zgodnie ze swoim zwyczajem w artykule tym zamieszczaîem
  118. dotychczas przykîadowe kody úródîowe napisane w jëzyku C. Co
  119. bardziej obraûalscy maniacy asemblera pewnie z tego powodu
  120. przestali juû ten artykuî czytaê (hej, jesteôcie tam?).
  121. Niesîusznie, zupeînie niesîusznie: wszystkie opisane wczeôniej
  122. debuggery przydajâ sië w takim samym stopniu przy programowaniu w
  123. asemblerze, co w C. A moûe nawet w wiëkszym w C, jako ûe praktyka
  124. wykazuje, ûe piszâc program w asemblerze popeînia sië wiëcej
  125. bîëdów, niû piszâc go w jëzyku wyûszego poziomu.
  126.  
  127. No, ale wracajâc do tematu, "na osîodë" bëdzie coô specjalnie dla
  128. maniaków asemblera: debugger, który programujâcym jedynie w
  129. jëzykach wyûszego poziomu na nic sië nie przyda: SCRATCH. Scratch
  130. zostaî napisany przez Billa Hawesa (skâd go znamy? Z ARexxa!).
  131. Debugger ten jest klasycznym przykîadem kata torturujâcego
  132. programiki.  Jak wszystkim piszâcym w asemblerze powinno byê
  133. wiadomo, funkcje biblioteczne majâ peîne prawo zmieniaê stan
  134. rejestrów D0, D1, A0, i A1 -- z tego powodu rejestry te okreôla
  135. sië mianem "scratch-registers".  Wszystkie pozostaîe rejestry
  136. adresowe i danych nie mogâ ulec zmianie (programy majâ
  137. zagwarantowane przez twórców systemu prawo korzystania z tej
  138. wîasnoôci). Potrzeba jednak sporo uwagi, aby program nie trzymaî
  139. ûadnych danych na scratch-registers przy wywoîywaniu funkcji z
  140. bibliotek. Popeîniony bîâd moûe sië np. nie ujawniaê na AMIDZE
  141. autora programu (bo akurat przypadkowo funkcja z biblioteki nie
  142. zmienia stanu jednego ze scratch-registers), a moûe powodowaê
  143. nawet zawieszenie systemu na innej maszynie (ze wzglëdu na inny
  144. system operacyjny, uruchomione inne programy itp). Scratch pomaga
  145. wykryê takie bîëdnie dziaîajâce programy: funkcje z bibliotek
  146. systemowych sâ "usprawniane" w taki sposób, ûe kaûda funkcja
  147. wstawia w rejestry D1, A0 i A1 jakieô ômiecie -- bîëdnie napisane
  148. programy zacznâ dziaîaê nieprawidîowo.  Rejestr D0 nie jest,
  149. niestety, zmieniany, jako ûe w wiëkszoôci funkcji systemu jest on
  150. uûywany do przekazywania wyniku od funkcji. Scratch jest, rzecz
  151. jasna, na tyle inteligentny, ûe pewne wyjâtkowe funkcje systemu,
  152. dla których udokumentowany jest stan scratch-registers (np.
  153. exec.library/ Forbid(), graphics.library/WaitBlit()), nie sâ
  154. "usprawniane".
  155.  
  156. Znajdujâcy sië poniûej Przykîad 1. to prosty programik, napisany
  157. w asemblerze, który bez Scratcha "dziaîa poprawnie" (przynajmniej
  158. pod OS 3.0), natomiast ze Scratchem sië zawiesza (przy
  159. uruchomieniu z Workbencha). Ja kompilowaîem go pakietem SAS/C 6.3
  160. -- asembler i debugger sâ doôê "czepialskie", stâd uûycie
  161. pewnych, normalnie niepotrzebnych, konstrukcji ("section", "END"
  162. itp.).
  163.  
  164. Bîâd w tym programie chyba doôê îatwo zauwaûyê. Nie jest brane
  165. pod uwagë, ûe po wykonaniu WaitPort() rejestr A0 moûe zawieraê
  166. coô innego niû MsgPort naszego procesu -- przypadkowo jest to
  167. prawda w obecnych systemach, dziëki czemu funkcja GetMsg()
  168. dostaje taki parametr, jaki dostawaê powinna, ale jak bëdzie w
  169. przyszîoôci (albo po uruchomieniu jakiegoô "patchera")?
  170.  
  171. Zazwyczaj najbardziej zawodnâ czëôciâ programu jest obsîuga
  172. sytuacji wyjâtkowych, w szczególnoôci braku pamiëci. Powód
  173. zawodnoôci tych procedur jest chyba doôê oczywisty:
  174. przetestowanie ich jest doôê skomplikowane. Programiôci majâ po
  175. prostu zwykle duûâ iloôê pamiëci i na ich Amigach w praktyce ich
  176. programom pamiëci nigdy nie brakuje. Bîëdy ujawniajâ sië dopiero
  177. u mniej zasobnych w pamiëê uûytkowników, którzy odchodzâ od
  178. zmysîów, zastanawiajâc sië, jak moûna byîo opublikowaê taki
  179. zawieszajâcy sië "na kaûdym kroku" program. Czësto zniechëcajâ
  180. sië nie tylko do programu, ale i do komputera. Znam takie
  181. przypadki: sprzedajâ Amigë, kupujâ peceta i juû tych problemów
  182. nie majâ. Pytajâ: dlaczego tak nie moûe byê na Amidze? Nie
  183. pomyôli jeden z drugim, ûe za peceta daî 30 baniek (bo trudno
  184. kupiê dziô coô taïszego), a Amiga kosztowaîa 10, ûe na AMIDZE
  185. miaî 1, 2 MB RAM, a na pececie ma 4 MB, a pod Windows jeszcze
  186. dodatkowe 8 MB (pamiëê wirtualna), wiëc jak na pececie ma
  187. brakowaê pamiëci?
  188.  
  189. No, wróêmy jednak do naszej szarej rzeczywistoôci: spójrz na
  190. Przykîad 2. Jest to prosty programik, otwierajâcy równie proste
  191. okienko.  Poniewaû nie chcemy, aby choê jeden amigowiec "zmieniî
  192. wiarë" po zawieszeniu sië naszego programu, wiëc mamy zamiar
  193. sprawdziê, czy program zachowa sië poprawnie w sytuacji, gdy nie
  194. starczy pamiëci na otwarcie okna.
  195.  
  196. Trzeba wiëc uruchomiê kupë róûnych pamiëcioûernych programów, w
  197. stylu Opusów czy jakichô graficznych Reali, ADPro itp. Trzeba
  198. przy tym byê subtelnym i pozostawiê wystarczajâco duûo pamiëci,
  199. aby program, który chcemy przetestowaê, zdoîaî sië wczytaê, ale
  200. aby okna juû otworzyê nie mógî. Wymaga to szeregu prób, jest
  201. trudne i czasochîonne.
  202.  
  203. Pewnym uîatwieniem moûe byê uûycie specjalnego programu,
  204. zajmujâcego sië "poûeraniem" ôciôle okreôlonej iloôci pamiëci.
  205. Takich programów jest sporo, ja uûywam zwykle "Zjadacza",
  206. autorstwa mojego kumpla Darka Ûbika. Ale i to nie jest tym, co
  207. "tygrysy lubiâ najbardziej", gdyû w bardziej skomplikowanych
  208. sytuacjach, np. w wypadku szeregu nastëpujâcych tuû po sobie
  209. ûâdaï przydzielenia pamiëci trudno jest wychwyciê to konkretne,
  210. które nas w danej chwili interesuje -- trzeba modyfikowaê kod,
  211. wstawiajâc pomocnicze printf()y i Delay()'e, jednym sîowem,
  212. koszmar.
  213.  
  214. Pierwszym powaûnym uîatwieniem, z którego moûna skorzystaê, jest
  215. uûycie source-level debuggera (wspomniaîem o tego typu programach
  216. w poprzedniej czëôci). Skompilujmy wiëc Przykîad 2., doîâczajâc
  217. informacje dla debuggera (np. "DEBUG=SYMBOLFLUSH" w SAS/C) i
  218. uruchommy debugger (np. "cpr przykîad2"). Otwiera sië ekran jak
  219. na rysunku 1. Ustawiamy breakpoint w linii 29. (tam, gdzie
  220. znajduje sië OpenWindow()) i puszczamy program "na ûywioî" (np.
  221. "go"). Program zatrzymuje sië w linii 29. W tym momencie moûemy
  222. "zeûreê" pamiëê w opisany powyûej sposób i sprawdziê, czy program
  223. zadziaîa poprawnie.
  224.  
  225. Jest to sposób niezîy, ma jednak pewnâ wadë: "zbyt dobrze"
  226. symuluje rzeczywistoôê. Po prostu brak pamiëci staje sië
  227. globalnym problemem wszystkich procesów, a my chcemy testowaê
  228. tylko nasz program, a nie sprawdzaê, jak zachowa sië w takiej
  229. sytuacji system czy np. CED. To jednak byîoby do wytrzymania,
  230. gdyby nie fakt, ûe pamiëci zacznie brakowaê równieû debuggerowi,
  231. który przecieû ma sprawowaê peînâ kontrolë nad naszym programem:
  232. czort wie, co moûe sië staê, gdy zabraknie mu pamiëci na jakieô
  233. waûne rzeczy? Tak wiëc przydaîby sië program "selektywnie
  234. wyîâczajâcy" pamiëê, tzn. powodujâcy, ûe jeden proces (ten
  235. testowany) pamiëci nie dostaje, a drugi (debugger) nie ma z tym
  236. problemów.
  237.  
  238. Takim programem jest MEMORATION autorstwa Billa Hewsa (skâd go
  239. znamy?  Ze Scratcha!). Program jest doôê rozbudowany, moûna mu
  240. podaê masë parametrów przy uruchomieniu, moim zdaniem jednak
  241. wiëkszoôê z nich to po prostu maîo przydatne w praktyce
  242. "wodotryski" (no bo na co, w gruncie rzeczy, moûe sië przydaê
  243. opcja powodujâca, ûe co n-te ûâdanie przydzielenia pamiëci
  244. zakoïczy sië niepowodzeniem?). Uwaûam, ûe najwygodniej korzysta
  245. sië z tego programu wîaônie w poîâczeniu z source-level
  246. debuggerem.
  247.  
  248. Tak wiëc w opisywanej sytuacji (kiedy nasz Przykîad 2. ma wîaônie
  249. wykonaê OpenWindow()) naleûy uruchomiê Memoration, podajâc nazwë
  250. procesu, który nie ma otrzymywaê pamiëci:
  251.  
  252. <l>memoration TASK=przykîad2
  253.  
  254. <txt> Powinien ukazaê sië komunikat w tym stylu:
  255.  
  256. <l>Rationing task 33E360 "przykîad2" addresses 0 to FFFFFFFF sizes 0 to 2000000
  257.  
  258. <txt> Jeûeli nic nie jest "podpiëte" do serial portu, to uruchom
  259. Sushi, gdyû Memoration wysyîa tam pewne komunikaty. Teraz moûna
  260. juû wykonaê linië 29. (np. naciskajâc Return w CPR). Zgodnie z
  261. naszym oczekiwaniem, okna nie udaîo sië otworzyê: program skacze
  262. do linii 31. -- procedury obsîugi bîëdu. Sushi natomiast wypisuje
  263. w okienku komunikat mniej wiëcej tej treôci:
  264.  
  265. <l>Rationed! Task 33E360 "przykîad2" from F81D00 denied AllocMem(238,10001)
  266.  
  267. <txt> Znaczenie komunikatu jest chyba oczywiste: wstrzymano
  268. przydziaî 238 bajtów pamiëci o atrybutach MEMF_PUBLIC (bit 0) i
  269. MEMF_CLEAR (bit 16 -- patrz definicje w "exec/memory.h"). Pamiëci
  270. zaûyczyî sobie kod znajdujâcy sië pod adresem 0xF81D00, a wiëc w
  271. pamiëci ROM (nic dziwnego -- "intuition.library" znajduje sië w
  272. ROM-ie, a OpenWindow() to przecieû funkcja z tej biblioteki).
  273.  
  274. Teraz moûna juû bez problemu sprawdziê, czy procedura obsîugi
  275. bîëdów wykonuje sië zgodnie z naszymi oczekiwaniami, po prostu
  276. pozwalajâc testowanemu programowi wykonywaê sië dalej. Naleûy
  277. przy tym pamiëtaê, ûe Memoration ciâgle dziaîa i nie pozwoli na
  278. ûadne przydziaîy pamiëci: jeûeli jest nam to nie na rëkë, to
  279. moûna ten program wyîâczyê:
  280.  
  281. <l>memoration OFF
  282.  
  283. <txt> Ostatniâ "grupâ" debuggerów, którâ chciaîbym w tym artykule
  284. omówiê, sâ róûnorakie monitory. Nie chodzi mi przy tym o uûywane
  285. przez róûnych kodero-hackerów programy umoûliwiajâce
  286. disasemblacjë pamiëci w celu odkrycia cudzych sekretów, tylko po
  287. prostu o programy, które na bieûâco informujâ o pewnych
  288. operacjach, stanie systemu itp.
  289.  
  290. Takim programem jest choêby DEVMON. Umoûliwia on monitorowanie
  291. aktywnoôci poszczególnych urzâdzeï (device'ów). Robi to
  292. wyrzucajâc na port Serial doôê szczegóîowy komunikat za kaûdym
  293. razem, gdy jakiô program stara sië wejôê z danym urzâdzeniem w
  294. kontakt -- wypisuje nazwë programu i poszczególne pola
  295. IORequesta.  Chcâc np. upewniê sië, czy nasz program po uûyciu w
  296. nim opcji Drukuj nie robi jakichô dziwnych rzeczy, wpisujemy:
  297.  
  298. <l>devmon printer.device 0 full remote hex
  299.  
  300. <txt> Pierwszy parametr to nazwa urzâdzenia, drugi to numer
  301. unita, trzeci (full) powoduje produkowanie peîniejszych
  302. informacji, "remote" powoduje wysyîanie informacji na port
  303. Serial, zamiast zapamiëtywania ich w buforze i póúniejszego
  304. zapisu do pliku (opcja warta uûywania -- dziëki niej otrzymujemy
  305. informacje na bieûâco), "hex" zaô powoduje wypisywanie danych
  306. liczbowych w kodzie szesnastkowym, a nie dziesiëtnym (teû warto
  307. uûywaê -- co mówi np. adres pamiëci w kodzie dziesiëtnym?).
  308.  
  309. Analizujâc szczegóîowo raport, uzyskany z DevMona moûna wykryê
  310. wiele nieprawidîowoôci, jak np. dwukrotne uûycie tego samego
  311. IORequesta w tym samym czasie, brak WaitIO() po AbortIO() itp.
  312.  
  313. Innymi programami monitorujâcymi sâ choêby DOSTrace czy IconTrace
  314. autorstwa Petera Stuera. Ich najnowsze znane mi wersje
  315. (odpowiednio: 2.20 i 2.02) znajdujâ sië na 25. dysku Shareware
  316. Magazynu AMIGA. Sâ one przydatne nie tylko do sprawdzania, z
  317. powodu braku jakich plików cudze programy nie chcâ sië
  318. uruchamiaê. Np. uwaûna analiza wyników uzyskanych przez DOSTrace
  319. umoûliwia czësto zoptymalizowanie programu, np. przez usuniëcie
  320. zbëdnych CurrentDir()ów, Lock()ów, CreateDir()ów itp. Umoûliwia
  321. takûe wykrycie pewnych bîëdów, jak np.  niezamykania (Close())
  322. otwartych (Open()) plików itp.
  323.  
  324. Ostatnim programem-monitorem wartym wspomnienia jest Amiga Real
  325. Time Monitor -- ARTM. Podstawowym zadaniem programu jest
  326. wyôwietlanie najwaûniejszych list systemowych, takich jak:
  327. procesy, biblioteki, okna, pamiëê itp. Umoûliwia to np.
  328. stwierdzenie, czy nasz program, nad którym straciliômy kontrolë
  329. (nie reaguje na naciskanie gadûetów), wszedî w nieskoïczonâ pëtlë
  330. (ARTM wyôwietli jego "State" jako "Ready"), czy teû czeka na coô
  331. (wtedy jego stanem bëdzie "Wait").  Umoûliwia on takûe pewne,
  332. niezupeînie legalne, ale w praktyce doôê przydatne, czynnoôci,
  333. jak np. zmiana priorytetu innych procesów, ich zatrzymanie czy
  334. usuniëcie, zamykanie okien i wiele, wiele innych.
  335.  
  336. Na koniec maîy apel:
  337.  
  338. Odpluskwiaczy MOÛNA uûywaê w charakterze straûy poûarnej, tzn.
  339. wîâczaê je dopiero wtedy, gdy uûytkownicy zgîoszâ bîëdy w naszych
  340. programach. Gorâco jednak polecam inne podejôcie, tzn.
  341. profilaktykë. Niektórzy np.  uruchamiajâ te najwaûniejsze
  342. debuggery -- Enforcera i Mungwalla -- na staîe, podczas startu
  343. systemu. Jest to dziaîanie mâdre, bo w ten sposób niewiele bîëdów
  344. im umknie. Ma to równieû wady, z których najwaûniejszymi sâ
  345. dostrzegalne spowolnienie pracy systemu i wiëksze zapotrzebowanie
  346. aplikacji na pamiëê. Jeûeli wiëc nie uruchamiasz tych debuggerów
  347. na staîe, to przynajmniej niech Ci "wejdzie w krew", ûe dokîadne
  348. przetestowanie programu z uûyciem debuggerów powinno stanowiê
  349. integralnâ czëôê tworzenia programu.  Lepszy jest program z
  350. mniejszâ liczbâ opcji, ale dziaîajâcy pewnie, niû rozbudowana
  351. kolubryna "wieszajâca sië" na kaûdym kroku. Tak wiëc KAÛDY
  352. program testuj Mungwallem, StackCheckiem i, jeûeli masz takâ
  353. moûliwoôê, Enforcerem, a i uûycie Memoration nie zaszkodzi (choê
  354. jest doôê czasochîonne). Jeûeli program jest choê w czëôci
  355. napisany w asemblerze, nie zapomnij o Scratchu. Jeûeli program
  356. uûywa device'owego I/O, uûyj DevMona.
  357.  
  358. Uûytkownicy Twoich programów podziëkujâ Ci za to.
  359.