home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD v1.2 / amidev_cd_12.iso / reference / amiga_mail_vol1 / program / troubleshooting_software < prev    next >
Text File  |  1990-01-25  |  21KB  |  506 lines

  1. (c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
  2. The information contained herein is subject to change without notice, and 
  3. is provided "as is" without warranty of any kind, either express or implied.  
  4. The entire risk as to the use of this information is assumed by the user.
  5.  
  6.  
  7.  
  8. Troubleshooting Your Software
  9.  
  10. by Carolyn Scheppner
  11.  
  12.  
  13. Many Amiga programming errors have classic symptoms.  This guide
  14. gives some tips to help you find and eliminate these problems in
  15. your software.
  16.  
  17.  
  18. CLI Error Messages
  19.  
  20. This is caused by calling exit(n) with an invalid or missing
  21. return value.  Assembler programmers using startup code should
  22. jump to the startup code's  _exit with a valid return value on
  23. the stack.  Programs without startup code should return with a
  24. valid value in D0.  Valid return values are defined in
  25. libraries/dos.h and i.  Other values (-1 for instance) can cause
  26. CLI error  messages such as "not an object module".  
  27.  
  28.  
  29. CLI Won't Close on RUN  
  30.  
  31. A CLI can't close if a program has a lock on the CLI input or
  32. output stream  ("*").  If your program is RUN >NIL: from a CLI,
  33. that CLI should be able to close unless your code or your
  34. compiler's startup code explicitly opens "*".
  35.  
  36.  
  37. Crashes and Memory Corruption at Run Time
  38.  
  39. Memory corruption, address errors, and illegal instruction errors
  40. are generally caused by wild pointers - pointers which are
  41. uninitialized,  incorrectly initialized, or point to memory
  42. oresources which have already been freed or closed.  You may be
  43. accidently modifying or incrementing a pointer later used to free
  44. memory or close a resource.  The pointer may be one that you use
  45. directly, or indirectly, such as in a structure which is  passed
  46. to a system routine. 
  47.  
  48. Amiga functions which open system resources or allocate memory
  49. typically return a pointer; if the open or allocate fails, zero
  50. is usually returned.   So you must test the return value of a
  51. system call for success before using  it as a pointer.
  52.  
  53. Test utilities such as MemWatch and MemMung can help catch the
  54. use of  uninitialized pointers or freed memory.  MemMung is a
  55. torture test which  sets freed memory areas and location $0 to
  56. odd values (if your program is  written correctly, this will have
  57. no effect; if not, your program is more likely to fail). 
  58. MemWatch is a watchdog utility which reports modification of low 
  59. memory (wild pointers often point to low memory, especially $0).
  60.  
  61. Memory corruption and crashes can also be caused by calling
  62. functions with  the wrong arguments or missing arguments (for
  63. example SetAPen(3) or  SetAPen(win,3), instead of SetAPen(rp,3)
  64. ).  Another possibility is that you might be overflowing  your
  65. stack.  The compiler's stack checking option may be able to catch
  66. this  (with Lattice, -v disables stack checking).  Cut stack
  67. usage by dynamically allocating large structures, buffers, and
  68. arrays if they are currently defined inside main() or your other
  69. functions.  If you are using short integers be sure to explicitly
  70. type any long constants (e.g. 42L).  For example, with short
  71. integers, the expression 1 << 17 may become zero.  If corruption
  72. is occurring during exit, use printf (or kprintf, etc.) with
  73. Delay(n) to slow down your cleanup and broadcast each step.
  74.  
  75. A bad pointer which causes a system crash will often be reported
  76. as a guru meditation 00000003 or 4.  Numbers in the range
  77. 00000006 - B may also indicate a problem with pointers.  These
  78. numbers correspond to the hardware defined CPU exceptions of
  79. Motorola's 68000-family of processors.  Generally these occur 
  80. when the CPU tries to access a non-existent memory location or
  81. execute an illegal instruction.  Other guru meditation numbers
  82. are Amiga-specific, but may be caused by wild pointers; for the
  83. meaning of these codes, refer to the include file exec/alerts.h.
  84.  
  85.  
  86. Crashes - After Exit  
  87.  
  88. If your program crashes after exiting only when your program is
  89. started from the Workbench, then you are probably UnLock()ing one
  90. of the WBStartup message  wa_Locks, or UnLock()ing the Lock
  91. returned from an initial CurrentDir() call.  If you call
  92. CurrentDir() in your application, you should save the first lock
  93. it returns and then call CurrentDir() on that lock before you
  94. exit.
  95.  
  96. If you are crashing from both Workbench and CLI and you are only
  97. crashing after exit, then you may be freeing or closing something
  98. twice.  Also, you may be freeing or closing something that you
  99. did not allocate or open.
  100.  
  101. A crash after your program exits can also be caused by leaving an
  102. outstanding device IO request or other wakeup request.  If you
  103. send an IO request and then exit, Exec, upon completion of that
  104. IO request, will send a reply message to a port that no longer
  105. exists.  You must abort and then WaitIO() on any pending IO
  106. requests before you free things and exit.  See the autodocs for 
  107. your device and for Exec AbortIO() and WaitIO().  Similar
  108. problems can be caused by deleting a subtask that is in a wait 
  109. loop such as WaitTOF().  Only delete subtasks when you are sure
  110. they are in a safe state such as Wait(0L).
  111.  
  112.  
  113. Crashes - Subtasks, Interrupts 
  114.  
  115. If part of your code runs on a different stack or on the system
  116. stack, you  must turn off compiler stack-checking options
  117. (Lattice uses the -v flag to  disable stack checking).  If part
  118. of your code is called directly by the system or by other tasks,
  119. you must use the large code / large data model, or use compiler
  120. functions or options to assure that the correct base registers
  121. are set up for  your subtask or interrupt code.
  122.  
  123.  
  124. Crashes - Window Related  
  125.  
  126. Be careful not to call CloseWindow() during a
  127. while(msg=GetMsg(...)) loop on that window's port because the
  128. next GetMsg() will be on a freed pointer.   Also, use
  129. ModifyIDCMP(NULL) with care, especially if you are using one port
  130. with multiple windows.  Be sure to ClearMenuStrip() any menus
  131. before closing a window, and do not free items such as
  132. dynamically allocated gadgets and menus while they are attached
  133. to a window.
  134.  
  135.  
  136. Crashes - Workbench Only  
  137.  
  138. If you are crashing near the first DOS call, either your stack is
  139. too small or your startup code does not GetMsg() the WBStartup
  140. message from the process message port.  If your program crashes
  141. only when started from Workbench and your startup code opens no
  142. stdio window or NIL: file handles for Workbench programs, then
  143. make  sure you are not writing anything to stdout (e.g. printf()
  144. ) when started  from Workbench (argc==0).  See also ``Crashes -
  145. After Exit'' above.
  146.  
  147.  
  148. Disk Icon Won't Go Away  
  149.  
  150. This occurs when a program leaves a lock on one or more of a
  151. disk's files or directories.  
  152.  
  153.  
  154. Fails Only On the 68020/30  
  155.  
  156. In general this occurs whenever an application inadvertently
  157. contains a CPU dependency.  The following programming practices
  158. will lead to programs which fail on the Motorola 68020/030 (but
  159. run OK on the 68000):
  160.  
  161.  o    Using the upper byte of addresses for flags.
  162.  o    Doing signed math on addresses.
  163.  o    Writing self-modifying code.
  164.  o    Using the MOVE SR assembler instruction (use Exec GetCC()
  165.     instead).
  166.  o    Using software delay or timing loops.
  167.  o    Making assumptions about the order in which asynchronous
  168.     tasks will finish.
  169.  
  170. Special features of the 68020/30 processors can also cause
  171. problems for  programs written on the 68000.  For example, an
  172. invalid cache entry due to DMA or other non-processor
  173. modification of data which has already been cached;  a different
  174. exception stack frame; interrupt auto-vectors moved by VBR; the 
  175. 68020/30 CLR instruction which does a single write access unlike
  176. the 68000 CLR instruction which does a separate read and write
  177. access (this might effect a read-triggered register in IO space -
  178. use MOVE instead).
  179.  
  180.  
  181. Fails Only On the 68000  
  182.  
  183. Again, a program which fails only on certain processors contains
  184. a CPU dependency.  The following programming practices can cause
  185. this problem:
  186.  
  187.  o    Software delay loops.
  188.  o    Word or longword access of an odd address (illegal on     the
  189.     68000).
  190.  o    Assumptions about the order in which asynchronous tasks will 
  191.     finish.
  192.  o    Using compiler flags which have generated inline 68881/68882
  193.     math coprocessor instructions or 68020/30 specific code.
  194.  o    Using the CLR instruction on a hardware register (it's
  195.     behavior on the 68000 differs from the 68020/030 (use
  196.     MOVE    instead) ).
  197.  
  198.  
  199. Fails Only on Older ROMs or Older Workbench  
  200.  
  201. This can be caused by calling functions or using structures which
  202. do not  exist in the older versions of the operating system.  Or
  203. you may be asking for a library version higher than you need. 
  204. Ask for the lowest version  which provides the functions your
  205. application 
  206.  
  207. requires (usually 33).  You should not use the #define
  208. LIBRARY_VERSION from the include files when you open a library. 
  209. Also make sure you check OpenLibrary() calls for  success (a
  210. non-zero return value).  If the library you request is not
  211. available, exit gracefully and informatively. 
  212.  
  213.  
  214. Fails only on Newer ROMs or Newer Workbench  
  215.  
  216. This should not happen with proper programming.  Possible causes
  217. are:
  218.  
  219.  o    Running too close to your stack limits or the memory limits
  220.     of a base machine (newer versions of the operating system
  221.     may use slightly more stack in system calls, and usually use
  222.     more free memory).
  223.  o    Using system functions improperly.
  224.  o    Not testing function return values.
  225.  o    Using improperly initialized pointers
  226.  o    Assuming that a system variable (such as a Flags field) is B
  227.     if it is not A.
  228.  o    Failing to initialize formerly reserved structure fields to
  229.     zero.
  230.  o    Violating Amiga programming guidelines (for example:
  231.     depending on or poking private  system structures, jumping
  232.     into ROM, depending on undocumented or unsupported 
  233.     behaviors).
  234.  o    Failing to read the function autodocs.
  235.  
  236.  
  237. Fails On CHIP-RAM-Only Machines  
  238.  
  239. This is caused by specifically asking for or requiring MEMF_FAST
  240. memory.   If you don't need chip memory, ask for memory type 0L,
  241. or MEMF_CLEAR, or  MEMF_PUBLIC|MEMF_CLEAR as applicable.  If
  242. there is fast memory available,  you will be given fast memory. 
  243. If not, you will get chip memory.
  244.  
  245.  
  246. Fails Only on Machines with FAST RAM  
  247.  
  248. Data and buffers which will be accessed directly by the custom
  249. chips must be in chip memory.  This includes bitplanes (use
  250. OpenScreen() or AllocRaster() ), audio samples, trackdisk
  251. buffers, and the graphic image data for sprites,  pointers, bobs,
  252. images, gadgets, etc.  Use compiler or linker flags to force chip
  253. memory loading of any initialized data that needs to be in chip
  254. memory.  You could also dynamically allocate chip memory and copy
  255. the initialized data there.
  256.  
  257.  
  258. Fails Only with Enhanced Chips  
  259.  
  260. This is usually caused by writing or reading addresses past the
  261. end of  register space on older custom chips, or writing a
  262. non-zero value to bits which are undefined in older chip
  263. registers, or failing to mask out undefined bits when
  264. interpreting the value read from a chip register.  
  265.  
  266.  
  267. Fireworks  
  268.  
  269. A dazzling pyrotechnic video display is caused by trashing or
  270. freeing a copper list which is in use, or trashing the pointers
  271. to the copper list.  If you aren't messing with copper lists, see
  272. ``Crashes and Memory Corruption''. 
  273.  
  274.  
  275. Graphics - Corrupted Images  
  276.  
  277. The bit data for graphic images such as sprites, pointers, bobs,
  278. and gadgets  must be in chip memory.  Check your compiler manual
  279. for directives or flags  which will place your graphic image data
  280. in chip memory.  Alternately you could allocate chip memory and
  281. copy the graphic image there.
  282.  
  283.  
  284. Hang - Single Program Only  
  285.  
  286. Program hangs are generally caused by Wait()ing on the wrong
  287. signal bits,  on the wrong port, on the wrong message, or on some
  288. other event that will  never occur.  They can also be caused by
  289. verify deadlocks.  Be sure to turn off all Intuition VERIFY
  290. messages (such as MENUVERIFY) before calling  AutoRequest() or
  291. doing disk access. 
  292.  
  293.  
  294. Hang - Whole System  
  295.  
  296. This is generally caused by a Disable() without a corresponding
  297. Enable(). It can also be caused by memory corruption, especially
  298. corruption of low memory.  See ``Crashes and Memory Corruption''
  299. above.
  300.  
  301.  
  302. Memory Loss  
  303.  
  304. First, make sure that your program is actually causing the memory
  305. loss.   Boot with a normal Workbench disk whose
  306. s:startup-sequence  LoadWB command line has been changed to
  307. LoadWB -debug.  It is important to  boot with a standard
  308. Workbench because some third party applications  such as
  309. background utilities, shells, and network handlers dynamically 
  310. allocate and free memory.  Arrange all windows so that part of
  311. the  Workbench backdrop window is accessible and so that no
  312. window rearrangement  will be needed to run your program.  Select
  313. flushlibs from the rightmost  Workbench menu.  Any disk-loaded
  314. fonts, libraries, devices, etc. that are  not currently open will
  315. be flushed from memory.  Wait a few seconds, then  click on the
  316. Workbench backdrop.  Write down the amount of free memory 
  317. displayed in the Workbench title bar.  Now without rearranging
  318. any windows,  run your program and use all of the program
  319. features.  Exit your program,  wait a few seconds, then click on
  320. the Workbench backdrop.  Now select  flushlibs, wait a few
  321. seconds and write down this final free amount.   If this matches
  322. the first value you wrote down, then your program is fine and is
  323. not causing a memory loss.
  324.  
  325. If memory was actually lost and your program can be run from CLI
  326. or Workbench, then try the above procedure with both methods of
  327. starting your program.  See ``Memory Loss - CLI Only'' and 
  328.  
  329. ``Memory Loss - Workbench Only'' as  appropriate.
  330.  
  331. If you lose memory from both Workbench and CLI, then make sure
  332. all calls to functions which open/allocate/create/lock have a
  333. matching call to the corresponding close/free/delete/unlock
  334. function  (there are a few  system calls that do not require a
  335. corresponding free - check the autodocs).   Generally, the
  336. close/free/delete/unlock calls should be in the opposite order of
  337. the allocations.
  338.  
  339. If you are losing a small, fixed amount of memory, look for a
  340. structure of that  size in the Structure Offsets listing in the
  341. Includes and Autodocs manual. For example, a loss of exactly 24
  342. bytes is probably a Lock which has not been UnLock()ed.  If you
  343. are using ScrollRaster(), be aware that ScrollRaster() left or
  344. right in a SUPERBITMAP window with no TmpRas will currently lose 
  345. memory (workaround - attach a TmpRas).  If you lose much more
  346. memory when  started from Workbench than from the CLI, make sure
  347. your program is not using  Exit(n).  This would bypass startup
  348. code cleanups and prevent a Workbench-loaded program from being
  349. unloaded. Use exit(n) instead.
  350.  
  351.  
  352. Memory Loss - CLI Only  
  353.  
  354. Some third-party shells dynamically allocate history buffers, or
  355. cause other  memory fluctuations.  Also, if your program executes
  356. different code when  started from CLI, check that code and its
  357. cleanup.  And check your startup.asm if you wrote your own.
  358.  
  359.  
  360. Memory Loss - Ctrl-C Exit Only  
  361.  
  362. This occurs when you have Amiga-specific resources allocated and
  363. you have not disabled your compiler's automatic Ctrl-C handling
  364. (causing all of  your program clean-ups to be skipped).  Disable
  365. the compiler's Ctrl-C  handling and handle Ctrl-C yourself.
  366.  
  367.  
  368. Memory Loss - During Execution  
  369.  
  370. A continuing memory loss during execution can be caused by
  371. failure to keep up with all of the IDCMP messages (such as
  372. MOUSEMOVE) that you request from Intuition.  Intuition can not
  373. reuse IDCMP message blocks until you call ReplyMsg() on  them. 
  374. If your window's allotted message blocks are all in use, new ones
  375. will be allocated and not freed until the window is closed. 
  376. Continuing  memory losses can also be caused by a program loop
  377. containing an  allocation/open type call without a corresponding
  378. free.
  379.  
  380.  
  381. Memory Loss - Workbench Only  
  382.  
  383. This is often caused by the failure of your code to unload after
  384. you exit.  Make sure that your code is being linked with a
  385. correct, standard startup module and do not use the Exit(n)
  386. function to exit your program.  The Exit(n) function will bypass
  387. your startup code's cleanup, including its ReplyMsg() of the
  388. WorkbenchStartup message (this signals Workbench to unload your 
  389. program from memory).  You should exit via exit(n) where n is a
  390. valid DOS  error code such as RETURN_OK (libraries/dos.h).  You
  391. may also exit with a final closing brace "}" or with the return
  392. statement.  Assembler  programmers using startup code can JMP to
  393. _exit with a long return value on the stack or use the RTS
  394. instruction.
  395.  
  396.  
  397. Menu Problems  
  398.  
  399. A flickering menu is caused by leaving a pixel or more space
  400. between menu subitems in your menu structures.  Crashing after
  401. browsing a menu (looking at menu without selecting any items) is
  402. caused by not properly handling MENUNULL select messages. 
  403. Multiple selection not working is caused by improper handling of
  404. the NextSelect field properly. See the Menus chapter from the
  405. Intuition  manual for more details.
  406.  
  407.  
  408. Out-of-Sync Response to Input  
  409.  
  410. This is caused by failing to handle all received signals or
  411. messages after waking up from a Wait() or WaitPort() call.  More
  412. than one event or message may have caused your program to be
  413. awakened.  Check the signals returned by Wait() and act on every
  414. one that is set.  At ports which may have more than one message
  415. (such as a window's IDCMP port) you must handle the messages in a
  416. while(msg=GetMsg(...)) loop.
  417.  
  418.  
  419. Performance Loss in Other Processes  
  420.  
  421. This is often caused by a program doing one of the following:
  422. Busy waiting or polling.
  423. Running at a higher priority.
  424. Doing lengthy Forbid()s, Disable()s, or interrupt handling.
  425.  
  426.  
  427. Sound Samples Won't Play Correctly
  428.  
  429. The data for audio samples must be in chip memory.  Check your
  430. compiler  manual for directives or flags which will place your
  431. audio sample data in chip memory.  Also, you can dynamically
  432. allocate chip memory and copy or load the audio sample there.
  433.  
  434.  
  435. Trackdisk Data Not Transferred  
  436.  
  437. This may occur if your trackdisk buffers are not in chip memory.
  438.  
  439.  
  440. Windows - Borders Flicker after Resize  
  441.  
  442. Set the NOCAREREFRESH flag.  Even SMART_REFRESH windows can
  443. generate refresh  events if there is a sizing gadget, so if you
  444. don't have specific code to handle this, you must set the
  445. NOCAREREFRESH flag.  If you do have refresh code, be sure to use
  446. the Begin/EndRefresh() calls.  Failure to do one or the other
  447. will leave Intuition in an intermediate state and slow down
  448. operation for all  windows on the screen.
  449.  
  450.  
  451.  
  452.  GENERAL DEBUGGING TECHNIQUES 
  453.  
  454. Isolate the problem by using printf() to find the section of code
  455. in which the problem occurs.  If you cannot display messages on
  456. the screen, use kprintf() to send messages to the serial port or
  457. dprintf() for the parallel port (see Linker Library
  458. documentation).  Check the initial values, allocation, use, and
  459. freeing of all pointers and structures used in the problem area. 
  460. Also make sure that all of your system and internal function
  461. calls pass correct initialized arguments and that all possible
  462. error returns are checked for and handled.
  463.  
  464.  
  465.  
  466. Use Debugging Tools  
  467.  
  468. A variety of debugging tools are available to help locate faulty
  469. code.  There are source level debuggers (such as Lattice's
  470. CodePRobe), crash interceptors (such as GOMF), memory watchdogs
  471. like MemWatch and WatchMem, and other helpful tools like MemMung,
  472. Avail, WBFrags, etc.  
  473.  
  474.  
  475. Test With Different Configurations
  476.  
  477. Test your program on a wide variety of systems and
  478. configurations.  Programs with coding errors may appear to work
  479. properly on one configuration but may fail or cause fatal
  480. problems on another.  Make sure that your code is tested on both
  481. the 68000 and the 68020/30, on machines with and without fast
  482. memory, and on machines with and without enhanced chips.  Test
  483. all of your program  functions on every machine.
  484.  
  485.  
  486. Test All Error and Abort Code
  487.  
  488. A program with missing error checks or unsafe cleanup might work
  489. fine when  all of the items it opens or allocates are available,
  490. but may fail fatally when an error or problem is encountered. 
  491. Try your code with missing files, filenames with spaces,
  492. incorrect filenames, cancelled requesters, Ctrl-C, missing
  493. libraries or devices, low memory, missing hardware, etc.
  494.  
  495. Test all of your text input functions with international ASCII
  496. characters (such as the character produced by pressing ALT-F then
  497. A).  Rawkey codes  produce different keyboard characters on the
  498. various national keyboards  (higher levels of keyboard input are
  499. automatically translated to the proper  characters).  If your
  500. program will be distributed internationally, support  and take
  501. advantage of the additional screen lines available on a PAL
  502. system.  On A2000s with the enhanced Agnus chip, a PAL display
  503. can be selected via  motherboard jumper J102.  Note that a base
  504. PAL machine will have less memory free due to the larger display
  505. size.
  506.