home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / 3_1DOCS.DMS / in.adf / tutorials.lha / tutorials / Amiga_Debugging next >
Encoding:
Text File  |  1993-11-04  |  48.1 KB  |  1,035 lines

  1.  
  2.                       Using Amiga Debugging Tools
  3.                       ===========================
  4.  
  5.     (c) Copyright 1991-93 Commodore-Amiga, Inc. All Rights Reserved
  6.  
  7.  
  8. Have you ever experienced any of the following problems with software ?
  9.  
  10. The software runs well on your system but some others report it
  11.    has problems on their systems.
  12. The software runs well by itself but has problems running with
  13.    or after other software.
  14. The software runs well most of the time but occasionally crashes
  15.    or fails for no apparent reason.
  16.  
  17. You can find and eliminate many of these types of hidden software problems
  18. by running Amiga debugging and stressing tools while developing and
  19. testing your product.
  20. Hidden and obvious software problems are often caused by use of null
  21. pointers, uninitialized pointers, improperly initialized structures,
  22. improper use of IO requests, improper abort code, improper memory usage,
  23. or overwriting of memory allocations.
  24. By using Enforcer, Mungwall, IO_Torture, Scratch, Memoration, and other
  25. Amiga debugging and testing tools, you can catch most of these problems
  26. before you ship a product.
  27. In fact, many companies now require that all of their inhouse
  28. software pass at least Enforcer and Mungwall testing, and have also added
  29. this requirement to their contracts for outside development.
  30. Many other CATS tools such as Devmon, Owner, and LVO can help to pinpoint
  31. the causes of problems.  You have these tools.  Here are hints on how to
  32. use them, when to use them, and how to get the most from their output.
  33.  
  34.  
  35. Enforcer and Mungwall
  36. =====================
  37.  
  38. Enforcer and Mungwall are the top two bug finding and bug prevention tools.
  39. Enforcer is an MMU-based debugging tool by Michael Sinz, based on an earlier
  40. tool by Bryce Nesbitt.  An MMU is a memory management unit which can be
  41. configured to trap accesses to specified ranges of memory.  The 68030 and
  42. 68040 processors have a built-in MMU, and most 68020 boards contain a
  43. separate MMU.  Because it is MMU-based, Enforcer can trap reads and writes
  44. of low memory and non-existent memory the instant these accesses
  45. (also known as "Enforcer hits") occur.  This allows you to catch usage of
  46. null pointers and some uninitialized pointers in your program, and even
  47. accesses which would have trashed low memory or otherwise crashed the system.
  48.  
  49. Some of these accesses may seem harmless on your system (such as reads of
  50. address 0) but could cause your program to fail in the field.  If you are
  51. developing commercial software (or any software that you plan to distribute)
  52. it is extremely important that you invest in a MMU, or at the very least
  53. make sure that your software is tested on machines with an MMU, Enforcer,
  54. and Mungwall.  As more of the development community begins running these
  55. tools, software that is unusable in their presence will simply not be used.
  56.  
  57. The main differences between the new Enforcer and the previous Enforcers
  58. is that the new Enforcer also works with 68040 processors and has a wide
  59. variety of output options built in.  In addition, due to the variety of
  60. output options, the new Enforcer must be RUN.  The new Enforcer requires
  61. at least V37 OS, so if you need to run Enforcer on a 1.3 machine, you must
  62. use the older Enforcer 2.8b which we have renamed "Enforcer1.3".
  63. The current Enforcer comes with an important new tool called SegTracker.
  64. Enforcer and other debugging tools now take advantage of SegTracker
  65. to provide a way to report seglist name, hunk, and offset for addresses
  66. within ANY loaded code.  Full docs on Enforcer and SegTracker are provided
  67. in Enforcer.doc.
  68.  
  69. Enforcer is even more powerful when used in combination with Mungwall.
  70. Mungwall is a combination memory munging tool by Ewout Walraven which
  71. is based on Memmung by Bryce Nesbitt and Memwall by Randell Jesup.
  72. The "mung" part of Mungwall fills all of free memory (and all subsequently
  73. freed memory) with a nasty odd 32-bit values like $DEADF00D.  Such a values
  74. are almost guaranteed to cause serious problems for any program that uses
  75. uninitialized pointers or structures, or uses memory or allocations after
  76. they are freed.  Such usages can occur, for example, when allocations are
  77. not freed in the correct order.
  78.  
  79. Mungwall uses a few different nasty 32-bit values in its memory munging
  80. to help you diagnose any problems.
  81.  
  82.  - Except when Enforcer is running, location 0 is set to $C0DEDBAD
  83.    so that programs referencing location zero will not find a value.
  84.    Programs referencing location 0 as a string will get a string of
  85.    high ASCII characters rather than a null string, and programs
  86.    using null structure pointers should be irritated into crashing.
  87.    When Enforcer is running, this is not necessary because with location
  88.    0 containing 0, Enforcer can trap these low memory accesses by itself.
  89.  
  90.  - On startup all free memory is munged with $ABADCAFE. If this number
  91.    shows up, someone is referencing memory in the free list.
  92.  
  93.  - Except when MEMF_CLEAR is set, memory is pre-munged on allocation with
  94.    $DEADFOOD. When this is seen in an Enforcer report, the caller is
  95.    allocating memory and doesn't initialize it before using it.
  96.  
  97.  - Memory is filled with $DEADBEEF when it is deallocated, encouraging
  98.    programs reusing freed memory to crash or get Enforcer hits.
  99.  
  100.  
  101. The "wall" part of Mungwall allocates extra memory before and after
  102. every memory allocation and fills this "wall" with a fill pattern and
  103. other information.  On each de-allocation, Mungwall checks to make sure
  104. that the deallocation size matches the size of the allocation, and checks
  105. to make sure that the walls have not been overwritten.  Mungwall also
  106. watches for 0-size allocations, 0-size deallocations, and 0-address
  107. deallocations.
  108.  
  109. Mungwall checks for incorrect allocations (such as 0 size) during AllocMem,
  110. and checks for incorrect deallocations or trashing around allocations
  111. during FreeMem.  If trashing or incorrect deallocation is detected,
  112. Mungwall will both report it and refuse to free the memory.  These reports
  113. are all known as "Mungwall hits".
  114.  
  115. The latest Mungwall can also optionally report on failed allocations
  116. with the SHOWFAIL option.  In addition, Mungwall has an option
  117. to "snoop" and report on all memory allocations and deallocations
  118. for all tasks or specified tasks.  This can be useful when tracking
  119. down memory losses.  The sometimes voluminous snoop output can be run
  120. through the snoopstrip program which will throw away all matching
  121. allocation/deallocation pairs.
  122.  
  123. Another useful recently added Mungwall feature is the NAMETAG option.
  124. When this option is active, Mungwall will tag all memory allocations with
  125. the first 16 characters of the name of the task, process, or command
  126. that allocated the memory.  A program called Munglist can then
  127. do its best to show the names of the allocators of currently allocated
  128. pieces of memory.  This can be very useful in tracking down memory losses.
  129. However, keep in mind that some of an application's allocations
  130. may be done by a different system task (for example, if an application
  131. opens a file, a file handle or buffers may be allocated by the process
  132. for the disk volume).
  133.  
  134. The current Mungwall makes use of SegTracker, if running, to report
  135. the seglist, hunk, and offset of hit addresses in any loaded code.
  136. If neither possible PC (A: and C: PC) is within loaded code,
  137. Mungwall will check on the stack to see if it can find some address
  138. within loaded code.  For more information, see the MUNGWALL OUTPUT
  139. section later, and also Mungwall.doc.
  140.  
  141. Mungwall may be used without Enforcer and on non-MMU machines.
  142. If you don't have an MMU, at least test with Mungwall alone.
  143. If you are using uninitialized memory or memory after it is freed,
  144. Mungwall should help to crash you immediately (as you might crash on
  145. a user's machine when he runs other programs at the same time as yours).
  146. Mungwall is more pleasant when used with Enforcer however, since it will
  147. generally incite an Enforcer hit when memory is misused, rather than a crash.
  148.  
  149. It is generally not safe or recommended to turn Mungwall off and
  150. back on without rebooting.  This is because Mungwall recognizes
  151. its walled allocations by looking for a special value it has placed
  152. near the beginning of the allocation.  If a program allocates memory while
  153. Mungwall is running, then frees it while Mungwall is turned off,
  154. and another program reallocates the some of the same memory while Mungwall
  155. is turned off, and then tries to deallocate it with Mungwall turned
  156. back on, Mungwall may generate Mungwall hits due to incorrect data.
  157. Note that this can also occasionally happen on a soft-reboot if a task
  158. that starts up and allocates memory before Mungwall is run happens to
  159. receive a Mungwall-tagged piece of memory that was in use before reboot,
  160. and then frees the memory after Mungwall is running.  To identify
  161. such problems, turn your machine off for 15 seconds or so to clear
  162. memory, turn it back on, and retest.
  163.  
  164. A useful alternative to turning Mungwall off and on is the Mungwall
  165. UPDATE feature.  UPDATE allows you to turn on and off many of the
  166. options of another running copy of Mungwall.  For example, you
  167. could turn off the MEGASTACK option via Mungwall UPDATE NOMEGASTACK
  168. or turn on the SHOWFAIL option with Mungwall UPDATE SHOWFAIL.
  169.  
  170. The latest Mungwall has some additional options for hit display
  171. (SHOWHUNK, etc.) and also has a TIMESTAMP option for timestamping
  172. memory allocations.  The timestamps can be useful when using
  173. "MungList", the memory listing tool that comes with Mungwall.
  174.  
  175. MungList attempts to list ALL of the allocated pieces of memory
  176. in the system which have been allocated since Mungwall was started.
  177. If Mungwall was run with the NAMETAG option, MungList can show the
  178. name of the program that allocated each piece of memory.  If Mungwall
  179. was run with the TIMESTAMP option, the MungList SHOWTIME can also
  180. show the time each piece was allocated.  If SegTracker is running,
  181. MungList can also attempt to give some hunk and offset information.
  182. In addition, the new MungList can also REMUNGE and/or CHECK memory.
  183. In CHECK, MungList attempts to check for wall-trashing of memory
  184. that is currently allocated, and REMUNGE can re-fill free memory
  185. with nasty values (memory deallocated under a Forbid can not be
  186. post-filled by Mungwall at the time of deallocation).  Munglist
  187. can be told to stay running and REMUNGE and/or CHECK periodically.
  188.  
  189.  
  190. Debugging Terminals
  191. ===================
  192.  
  193. Enforcer and Mungwall both output their debugging information
  194. to the serial port at the baud rate your machine's serial
  195. hardware is set to.  At powerup, your serial hardware is set
  196. to 9600 baud, but you can modify this by bringing up a terminal
  197. package and setting a baud rate.  The optimal debugging setup
  198. is to connect your Amiga via a null modem serial cable to another
  199. Amiga or computer running a terminal package with ACSII capture
  200. capability.  Both Enforcer and Mungwall include CTRL-G's in their output
  201. to generate a beep with most terminal packages, and the ASCII capture
  202. capability will allow you to capture all serial debugging
  203. output to a file for examination.  This is especially useful when
  204. combined with serial kprintf() (debug.lib) debugging statements in
  205. your code such as kprintf("About to close window $%lx\n",win).
  206.  
  207. But some developers don't have a second machine to use as a debugging
  208. terminal, or may need to debug a serial application which would
  209. interfere with serial debugging output.
  210. So two other options exist.  One is to use the parallel
  211. versions of the debugging tools, and the parallel debugging "dprintf"
  212. command (from ddebug.lib) and connect a parallel printer for
  213. the output.  The benefit of serial and parallel debugging is that
  214. you can get some information out and capture it even if your
  215. machine is crashing, and even if your application has taken
  216. over the system.  The other option is "Sushi".
  217.  
  218.  
  219. Sushi
  220. =====
  221.  
  222. For most applications, an option now exists for debugging
  223. on a single machine.  It's called "Sushi" (a late-night name loosely
  224. based on the fact that it captures "raw" serial output).
  225. Sushi captures all raw serial debugging output (such as kprintf,
  226. new Enforcer with RAWIO option, Mungwall, IO_Torture, etc.)
  227. and has its AmigaDOS process send the debug information to stdout.
  228. This means you can redirect Sushi's output to a an AUTO/CON window
  229. (and the window will pop open if you have any hits), or to a multiserial
  230. port, etc.  Sushi can also be told to save its circular buffer
  231. (via CTRL-F signal or via a separate SUSHI SAVEAS FILENAME command),
  232. or to empty its buffer (CTRL-E signal or a separate SUSHI EMPTY command).
  233.  
  234. Sushi also can operate in quiet mode, just capturing debugging output,
  235. and provides a program task signalling interface which allows an external
  236. application to be written to display the captured debugging output
  237. (for those of you who want a fancier debugging display program).
  238. A benefit of Sushi is that fairly voluminous debugging output
  239. can be used even from within interrupt code or intense task code
  240. because Sushi only has to place the text bytes in a ram buffer,
  241. and the actual output is done by a separate process.
  242. See Sushi.doc for more information and a source for a sample
  243. external display program.
  244.  
  245. Sample user-startup:
  246.  
  247. run >NIL: Mungwall
  248. run >NIL: Enforcer RAWIO
  249. run >NIL: sushi <>"CON:0/20/640/100/Sushi CTRL-File CTRL-Empty/AUTO/CLOSE/WAIT" NOPROMPT
  250.  
  251.  
  252. Debugging printf's: kprintf and dprintf
  253. =======================================
  254. When using serial (or parallel) debugging and stress-testing tools,
  255. it is very useful to have your own program's debugging statements
  256. (such as "About to do xxx") mixed in with any potential hits
  257. from the debugging tools.
  258. In addition, it is very useful to have a printf-like command that
  259. can be used from within even the low level task or interrupt code.
  260. A clean way to add conditional debugging statements to a C program
  261. is to use a MACRO such a D(bug)) by including lines like the following
  262. in your program.  Set MYDEBUG to 1 to turn on debugging.
  263. Set bug to printf for printf debugging, or to kprintf (and link with
  264. debug.lib) for serial debugging, or to dprintf (and link with ddebug.lib)
  265. for parallel debugging.  The D(bug()) macro is neater in your code
  266. because it can be indented and you need not surround it with any
  267. #ifdef directives yourself.  Just be careful to remember to put two
  268. close paren's at the end of each D(bug()) statement, before the semicolon.
  269.  
  270. /**********    debug macros     ***********/
  271. #define MYDEBUG  1
  272. void kprintf(UBYTE *fmt,...);
  273. void dprintf(UBYTE *fmt,...);
  274. #define DEBTIME 0
  275. #define bug printf
  276. #if MYDEBUG
  277. #define D(x) (x); if(DEBTIME>0) Delay(DEBTIME);
  278. #else
  279. #define D(x) ;
  280. #endif /* MYDEBUG */
  281. /********** end of debug macros **********/
  282.  
  283. Example macro usage:
  284.     win = OpenWindow(&mynewwin);
  285.     D(bug("Opened window at $%lx\n", win));
  286.  
  287. Note that kprintf and dprintf debugging can be used inside even
  288. the lowest level task or interrupt code (although you better
  289. keep output down to a minimum during interrupts!).  The DEBTIME
  290. (Delay) in the macro above must be 0 however if you are doing
  291. output from anything other than a Process.
  292.  
  293.  
  294. Finding the Cause of Enforcer and Mungwall Hits
  295. ===============================================
  296. By using Enforcer and Mungwall while you are developing your software,
  297. you can catch problems as soon as they are introduced and greatly
  298. cut down your debugging time.  It is especially useful to place
  299. conditional remote debugging statements in your code as you write
  300. each routine so that they can easily be turned on when a problem occurs.
  301. You will easily be able to pinpoint the problem area when the kprintf
  302. (or dprintf) output is intermixed with the Enforcer or Mungwall output.
  303. The remote debugging commands kprintf and dprintf are avaiable in
  304. the linker libraries debug.lib (serial) and ddebug.lib (parallel)
  305. respectively.  These linker libs are supplied with some compilers
  306. and are also available on Commodore's Native Developer Update disks.
  307.  
  308. Some people prefer to use a source-level or single-stepping debugger
  309. in combination with Enforcer and Mungwall when tracking down a
  310. problem to single-step through their code until the hit occurs.
  311. A different low-level method of locating Enforcer or Mungwall hits is to
  312. disassemble program memory where the hit occurred.  If the hit occurred
  313. in ROM, first try using OWNER to determine ROM subsystem of that address.
  314. For example, OWNER 0x202442 might return the following on a soft-kicked
  315. A2500:
  316.  
  317. Address  - Owner
  318. --------   -----
  319. 00202442 - in resident module: exec 39.47 (28.8.92)
  320.  
  321.  
  322. Then use LVO to determine the probable function at that address within
  323. the subsystem:  LVO exec romaddress=0x202442
  324.  
  325. Closest to $202442 without going over:
  326. exec.library  LVO $fe0e -498  OpenResource() jumps to $202358 on this system
  327.  
  328. (See Owner and LVO section for more information on these tools)
  329.  
  330. If this does does not give enough clue, try disassembling just before
  331. other ROM and RAM addresses shown in the Enforcer stack dump line.
  332. If code is found, these may be application or ROM functions
  333. which called the routine that generated the hit.
  334.  
  335. If the hit occurs in RAM code, use various methods to match up the
  336. disassembly with your own code.  Assembly programmers can just compare
  337. the disassembly to their source.  Others may wish to take the hex values
  338. of a sequence of position-independent 68000 instructions near the hit
  339. (ie. no addresses except for offsets and branches) and do a search for
  340. this binary pattern in your object modules.  If you find the pattern,
  341. do a mixed source and object disassembly of that object module (for example,
  342. with SAS's OMD you could OMD >ram:dump mymodule.o mymodule.c) and then
  343. look in the output for instructions matching those where the hit occurred.
  344. NOte that when a hit occurs in a disk-loaded device or library, it is
  345. currently not possible to determine who owns the code where the hit occurred.
  346. This is because it is up to the device or library to store its
  347. seglist wherever it sees fit in its own library or device base.
  348. If you suspect that your hit is occuring in a disk-loaded library
  349. or device, you can try searching suspected disk libraries or devices
  350. for a match of the hex pattern of position-independent code near the hit.
  351.  
  352.  
  353. Deciphering Enforcer and Mungwall Output
  354. ========================================
  355. Enforcer and Mungwall provide lots of valuable information to help
  356. debug your hits.
  357.  
  358.  
  359. SAMPLE ENFORCER OUTPUT:
  360.  
  361. Here are two sample Enforcer hits caused by a program called "lawbreaker".
  362.  
  363. WORD-READ from 00000014                        PC: 0030801E
  364. USP:  00461990 SR: 0015 SW: 0769  (U0)(F)(D)  TCB: 004181A0
  365. Data: DDDD0041 DDDD1100 DDDD2200 DDDD3300 DDDD4400 DDDD5500 DDDD6600 DDDD7700
  366. Addr: AAAA0000 AAAA1100 AAAA2200 AAAA3300 AAAA4400 AAAA5500 00280804 --------
  367. Stck: 00000009 00000008 00000007 00000006 00000005 00000004 00000003 00000002
  368. Stck: 00000001 00216B98 00002710 00418B94 D5D5D5D5 D5D5D5D5 D5D5D5D5 D5D5D5D5
  369. ----> 0030801E - "lawbreaker"  Hunk 0000 Offset 00000096
  370. Name: "Shell Process"  CLI: "lawbreaker"  Hunk 0000 Offset 00000096
  371.  
  372. LONG-WRITE to  FEEDFACE        data=DDDD0041   PC: 00308030
  373. USP:  00461990 SR: 0018 SW: 0709  (U0)(F)(-)  TCB: 004181A0
  374. Data: DDDD0041 DDDD1100 DDDD2200 DDDD3300 DDDD4400 DDDD5500 DDDD6600 DDDD7700
  375. Addr: AAAA0000 AAAA1100 AAAA2200 AAAA3300 AAAA4400 AAAA5500 00280804 --------
  376. Stck: 00000009 00000008 00000007 00000006 00000005 00000004 00000003 00000002
  377. Stck: 00000001 00216B98 00002710 00418B94 D5D5D5D5 D5D5D5D5 D5D5D5D5 D5D5D5D5
  378. ----> 00308030 - "lawbreaker"  Hunk 0000 Offset 000000A8
  379. Name: "Shell Process"  CLI: "lawbreaker"  Hunk 0000 Offset 000000A8
  380.  
  381.  
  382. Here is an explanation of the some of the important information:
  383.  
  384. PC:
  385.  
  386. Program Counter.  This is the address in memory where the program was
  387. executing instructions when the hit occured.
  388. For some kinds of hits this will often be the address of the instruction
  389. after the hit.  Note that if your program passes a bad pointer
  390. or an improperly initialized structure to a system ROM routine,
  391. you may cause ROM code to read or write to an illegal address.
  392.  
  393.  
  394. TYPE-SIZE from or to (e.g. WORD-READ from 00000014):
  395.  
  396. This is the type of illegal access and the address where it occurred.
  397. In the first example, the illegal access occurred at address $14, and
  398. is specified as a WORD-READ access.
  399. This means the illegal memory access was an attempt to read a word (2 bytes)
  400. at address $14.  Low memory accesses are often caused by NULL
  401. pointers to structures.  If, for example, your code or a ROM routine
  402. references a structure member at offset $14,
  403. and what you provided or used a NULL structure pointer, Enforcer will
  404. pick up a hit at address $14.  Other illegal READ accesses are
  405. BYTE-READ (generally caused by a bad string pointer), and LONG-READ
  406. (generally caused by a bad pointer or a bad pointer within a structure).
  407. An Enforcer hit will ocuur whenever a program attempts to read low memory
  408. addresses (generally caused by a NULL pointer of some type) or non-existent
  409. memory addresses (generally caused by an uninitialized pointer).
  410. When Enforcer catches an illegal READ access, it reports the access
  411. and prevents the program from reading the address by returning data
  412. of zero.
  413.  
  414. On illegal WRITE accesses (i.e. attempts to write to ROM, low memory,
  415. or non-existent memory) Enforcer will report BYTE-WRITE, WORD-WRITE,
  416. or LONG-WRITE hits (such as in the second example).  These mean the access
  417. would have illegally and dangerously written to memory which should not
  418. be written to, quite possibly causing memory to be trashed.
  419. WRITE hits can be caused by bad pointers or bad code.
  420. Fortunately, Enforcer prevents the actual memory trashing
  421. from occurring, and instead just reports it.  This can allow debugging
  422. severe low memory trashing problems which would normally crash your
  423. machine.  In the second example above, the CLI program "lawbreaker"
  424. tried to write the long value $DDDD0041 to the address $FEEDFACE.
  425.  
  426. Occasionally you will see an INSTRUCTION access of illegal
  427. memory meaning the PC (Program Counter) is at an address it has no
  428. legal reason to be at.  Generally this is caused by trashed code, a trashed
  429. return address on your stack, or an invalid library base.
  430. Hint - when an INSTRUCTION Enforcer hit occurs at a negative address,
  431. it is most often caused by a JSR to an LVO (negative word offset)
  432. from a NULL library base.  Check the Stack dump lines for a possible
  433. return address to the code that made the bad library call.
  434.  
  435.  
  436. "data=xxxxxxxx":
  437.  
  438. On WRITE hits, Enforcer will show you the data that would have been
  439. written to the illegal address.
  440.  
  441.  
  442. Register Dump Lines:
  443.  
  444. All of the middle Enforcer lines show the contents of the program's
  445. registers and stack at the time of the hit.  The Data: line shows
  446. the D registers (D0 though D7).  The Addr: line shows the A registers
  447. (A0 though A6).  A7 (the Stack register) is shown as USP, and the contents
  448. of the top of the stack is shown in the Stck: lines (note - more Stck:
  449. lines are available via a command line option of the new Enforcer).
  450. The USP line also contains the contains of additional processor status
  451. registers, and also the address of the Task Control Block (TCB).
  452. On the same line are symbols which specify whether a Forbid (F) and/or
  453. a Disable (D) was in effect when the hit occurred.
  454.  
  455.  
  456. Name and Hunk/Offset:
  457.  
  458. Examples:
  459. ----> 00308030 - "lawbreaker"  Hunk 0000 Offset 000000A8
  460. Name: "Shell Process"  CLI: "lawbreaker"  Hunk 0000 Offset 000000A8
  461.  
  462. The firts line (---->), if present, is seglist name, hunk, and offset
  463. information found via Enforcer calling SegTracker (to possibly get this,
  464. you must have started SegTracker prior to the loading of the code where
  465. the hit occured).  SegTracker can find RAM hit addresses in ANY code
  466. that was loaded after SegTracker was started.  See Enforcer.doc
  467. for more information on SegTracker and its programmatic interface.
  468. Here the information is redundant because the hit occurred in
  469. the application process's own code.  However, if the hit had occurred,
  470. for example, inside a routine in a disk-loaded library or device
  471. called by the application process code, this SegTracker information
  472. would have been extremely important.
  473.  
  474. The next line (Name:) shows the task name, and CLI command name (if any)
  475. of the task or command on whose task context the hit occurred (i.e. the
  476. program that was executing the code where the hit occurred).
  477. Even if SegTracker is not running, Enforcer will attempt to provide
  478. hunk and offset information here if the hit address is within the loaded
  479. program's own code instructions.
  480.  
  481.  
  482.  
  483. SAMPLE MUNGWALL OUTPUT
  484. ======================
  485.  
  486. Here are sample Mungwall hits by a program called "mungwalltest".
  487. Additional explanation has been added in parentheses below each hit.
  488. For reference, the arguments for memory functions are AllocMem(size,type)
  489. and FreeMem(address,size).  The A: and C: addresses are Mungwall's
  490. guess at the address from which AllocMem was called.  The A: address
  491. is the address if the caller was assembler code.  The C: address is the
  492. probable address if the caller was C code, assuming a standard stub.
  493. Since Mungwall is wedged into the memory allocation functions, it can
  494. only guess the caller's address based on what is pushed on the stack.
  495. The "task" address on the first line of a Mungwall hit is the task address
  496. of the caller.  Mungwall checks for incorrect allocations (such as 0 size)
  497. during AllocMem, and checks for incorrect deallocations or trashing
  498. around allocations during FreeMem.  If trashing or incorrect deallocation
  499. is detected, Mungwall will both report it and refuse to free the memory.
  500.  
  501. Note that Mungwall has special code to prevent
  502. trapping the partial (wrong size) deallocations that are performed
  503. by some version of layers.library.  If any other debugging tools are
  504. also wedged into AllocMem and FreeMem, Mungwall's A: and C: addresses
  505. may be thrown off by additional information pushed on the stack, and
  506. Mungwall will also be unable to screen out any partial layers deallocations
  507. (which will show up as hits on your task's context).
  508.  
  509.  
  510. AllocMem(0x0,10000) attempted by `mungwalltest' (task 0x3E08F0)
  511.   from A:0x3EBB12 C:0x3EF552 SP:0x4559FC
  512. (means mungwalltest tried to allocate 0 bytes of memory)
  513.  
  514.  
  515. FreeMem(0x0,16) attempted by `mungwalltest' (task 0x3E08F0)
  516.   from A:0x3EBB40 C:0x3EF598 SP:0x4559F4
  517. (mungwalltest tried to free memory it never got - i.e. at address 0)
  518.  
  519.  
  520. FreeMem(0x2FE7C0,0) attempted by `mungwalltest' (task 0x3E08F0)
  521.   from A:0x3EBB40 C:0x3EF5A8 SP:0x4559EC
  522. (mungwalltest tried to free 0 bytes of memory)
  523.  
  524.  
  525. Mis-aligned FreeMem(0x2FE7C4,16) attempted by `mungwalltest' (task 0x3E08F0)
  526.   from A:0x3EBB40 C:0x3EF5B6 SP:0x4559E4
  527. (mungwalltest tried to free memory at an incorrect address)
  528.  
  529.  
  530. Mismatched FreeMem size 14!
  531. Original allocation: 16 bytes from A:0x3EBB12 C:0x3EF574 Task 0x3E08F0
  532. Testing with original size.
  533. (mungwalltest tried to free a different size from what it allocated)
  534.  
  535.  
  536. 19 byte(s) before allocation at 0x2FE7C0, size 16 were hit!
  537. >$: BBBBBBBB BBBBBBBB BB536572 6765616E 74277320 50657070 65722000
  538. (memory before this allocation was trashed; trash shown at right)
  539.  
  540.  
  541. 8 byte(s) after allocation at 0x2FE7C0, size 16 were hit!
  542. >$: 75622042 616E6400 BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB 
  543. (memory after this allocation was trashed; trash shown at left)
  544.  
  545.  
  546.   FreeMem(0x2FE7C0,14) attempted by `mungwalltest' (task 0x3E08F0)
  547.   from A:0x3EBB40 C:0x3EF5F4 SP:0x4559D0
  548. (deallocation refused due to trashing explained in last two reports)
  549.  
  550.  
  551. Failed memory allocation!
  552. AllocMem(0x500000000,1) attempted by `flush' (task 0x3E08F0)
  553.   from A:0x453E96 C:0x1 SP:0x4820F4
  554. (SHOWFAIL option shows flush tried to allocate memory and failed)
  555.  
  556.  
  557. As you can see, Mungwall alone can catch a large variety
  558. of memory-related software problems.  But one the most important
  559. benefits of Mungwall is that by filling freed memory with nasty
  560. 32-bit values, it can force subtle memory misuse problems
  561. into the open, by often causing the misuses to access addresses that
  562. can be trapped on by Enforcer.
  563.  
  564. Enforcer and Mungwall are required tools for the development of
  565. bug-free Amiga software.  If you don't have an MMU, get one.
  566. The investment in an A3000, 68030 card, or 68020+MMU card
  567. will quickly pay for itself by cutting down on your development
  568. and allowing you to catch and find software problems with Enforcer.  
  569. Enforcer and Mungwall are not just for developers and QA departments.
  570. Anyone who uses or reviews inhouse software or software for
  571. purchase or contract can benefit your company by catching hidden
  572. software problems during normal usage and examination of the programs.
  573. Many people at Commodore and other companies run Enforcer and Mungwall
  574. all of the time.  Keep that in mind if you are trying to impress a
  575. company with your software!
  576.  
  577.  
  578. Other Debugging and Testing Tools
  579. =================================
  580.  
  581. The next three tools, Memoration and Scratch by Bill Hawes, and IO_Torture
  582. by Bryce Nesbitt are important QA tools for testing the robustness of all
  583. application failure code, for uncovering illegal register usage in
  584. assembler code, and for detecting unsafe use of device IO requests.
  585. Following notes on these three are notes on some of the additional
  586. debugging and stresstest tools provided by CATS.
  587.  
  588.  
  589. Memoration
  590. ==========
  591. Memoration by Bill Hawes is a tool to selectively limit the ability of a
  592. task or module to allocate memory, thereby simulating the effects of a
  593. low-memory condition.  It provides the unique ability to selectively
  594. cause each individual memory allocation of a program, whether direct
  595. or indirect, to fail, thereby allowing you to test the failure path
  596. and abort code at every point in your application code.
  597.  
  598. Memoration works by SetFunctioning the Exec AllocMem and/or AllocVec
  599. entries and then screening the requests.  If a request from a particular
  600. task or range of addresses is received, memoration returns a zero instead
  601. of passing it through to AllocMem.
  602.  
  603. When a task or module is denied a memory request, memoration sends a
  604. message to the serial port identifying the client task ID, the address it
  605. was called from, and the size of the denied request.  If the software can't
  606. handle being denied its memory request, this message will typically be
  607. followed by a series of enforcer reports telling of how the software went
  608. ahead and wrote to location 0.
  609.  
  610.  
  611. Command-Line Parameters.
  612. Memoration accepts command-line parameters to specify the module or task
  613. name and the range of memory sizes to disallow.  The argument template is
  614.  
  615. MODULE,TASK/K,CLI/K/N,OFF/S,MIN/K/N,MAX/K/N,AFTER/K/N,EVERY/K/N,ALLADDR/S,
  616. ALLOCVEC/S,CHIP/S,FAST/S,BACKTRACE/K/N
  617.  
  618. and the specifications can be changed at any time by reissuing the command.
  619.  
  620.  
  621. MODULE is the name of a ROMTag or library.  The resident modules are
  622. searched first, followed by a search of the system library list.  When an
  623. entry is found, the range of addresses encompassing its code is determined
  624. using several methods.  For ROMTags the range extends from the ROMTag
  625. itself to the next higher module, or to RT_ENDSKIP if no higher module
  626. exists.  For libraries a certain amount of voodoo is required, as the
  627. location of the library ROMtag isn't stored in the (public) library
  628. structure. In this case memoration examines the LVOs to determine the
  629. lowest and highest addresses, and then searches for a ROMtag in the range
  630. (low-$2000,high+$2000).  If a ROMTag is found, memoration uses the smaller
  631. of the ROMTag addresss and the lowest LVO address as the low limit, and the
  632. larger of the RT_ENDSKIP address and the highest LVO address as the high
  633. limit.
  634.  
  635. TASK specifies the name of a task to trap.  The task must exist at the time
  636. memoration is run, and for best results should persist for the course of
  637. testing.  If you're using WShell (as you should be) you can define a name
  638. for a particular shell instance by using ``newwsh name sucker''.
  639.  
  640. CLI specifies a shell number as the task to trap.
  641.  
  642. MIN specifies the minimum memory request to trap.  The default is 0.
  643.  
  644. MAX specifies the maximum allocation to trap.  The default is 2000000.
  645.  
  646. OFF turns off memory trapping.  The code patch is left intact, but won't
  647. trap any requests until enabled again.  AllocMem and AllocVec traps
  648. can be turned on and off separately.
  649.  
  650. ALLOCVEC sets the trap for the AllocVec() entry, instead of AllocMem().
  651. Both functions can be trapped independently.
  652.  
  653. AFTER specifies the number of allocations (within other specifications) to
  654. pass before beginning the trap.
  655.  
  656. EVERY traps every Nth allocation meeting the specifications.
  657.  
  658. ALLADDR sets the address range to all memory.
  659.  
  660. CHIP limits the trap to CHIP memory specifications.
  661.  
  662. FAST limits the trap to FAST memory specifications.
  663.  
  664. BACKTRACE specifies the number of longwords of stack backtrace desired.
  665.  
  666.  
  667. Examples:
  668.   memoration myprog after 15  ; after 15th allocation, deny myprog any memory
  669.   memoration dos.library  ; disable all DOS allocations
  670.   memoration task DF0 min 400 ; disable larger allocations by DF0:
  671.   memoration icon.library task Workbench every 3
  672.   memoration console.device min 40 backtrace 8
  673.  
  674. Example test session to test failure of every allocation an application makes:
  675.  
  676. Open two shells - one for memoration (here 1>) and one for myprog (here 2>).
  677. Alternately, you could start myprog from Workbench.
  678. Run Enforcer and Mungwall.
  679. Have serial or Sushi debugging set up.
  680.  
  681. 1> memoration myprog after 0
  682. 2> myprog    ; a failure occurs but hopefully no hits or crashes
  683. 1> memoration off
  684. (exit myprog if it made it up)
  685.  
  686. 1> memoration myprog after 1
  687. 2> myprog    ; a failure occurs but hopefully no hits or crashes
  688. 1> memoration off
  689. (exit myprog if it made it up)
  690.  
  691. 1> memoration myprog after 2
  692. 2> myprog    ; a failure occurs but hopefully no hits or crashes
  693. 1> memoration off
  694. (exit myprog if it made it up)
  695.  
  696. etc.  Note - until you get up to a higher "after" number, myprog will likely
  697. fail during the startup code it is linked with - i.e. before even
  698. reaching your main() entry point.  
  699.  
  700. Further Notes.
  701. Memoration uses a seglist-split for its code patch, and so shouldn't be made
  702. resident, at least not on the first execution.  Memoration was written by
  703. William S. Hawes.
  704.  
  705.  
  706. Scratch
  707. =======
  708. Scratch by Bill Hawes purposely trashes the scratch registers (D1, A0, A1)
  709. on exit from library functions of any "scratched" library.
  710. This will point out assembler callers that accidentally or
  711. purposely depend upon getting "useful" values from those registers.  
  712. It is extrememly important that ALL assembler applications be tested with
  713. Scratch.  Even minor changes to the OS can change the values that happen to
  714. be left over in registers on exit from a system library function.
  715. Assembler code that is accidentally reusing a scratch register
  716. (for example A1) after a system call, or code that is looking at the
  717. wrong register for a result has the potential to break badly with
  718. even a minor change to the OS.  Scratch can catch these problems before
  719. you ship.  To use Scratch, see the script "SCRATCHALL.SCRIPT" which
  720. properly excepts certain system functions from scratching.
  721.  
  722.  
  723. IO_Torture
  724. ==========
  725. IO_torture is a tool which can be used to check for improper use
  726. or reuse of device IO requests.
  727.  
  728. IO_torture should be part of the standard test suite for all products.
  729.  
  730. Exec device IO usage is tracked by IO_torture.  If an IORequest is reused
  731. while still active, IO_torture will print a warning message on the serial
  732. port (parallel for IO_torture.par).
  733.  
  734. The current plan of IO_torture includes:
  735.  
  736.         SendIO() - Check that message is free.  Check for ReplyPort.
  737.         Be sure request is not linked into a list.
  738.  
  739.         BeginIO() - Check that message is free.  Check for ReplyPort.
  740.         Be sure request is not linked into a list.
  741.  
  742.         OpenDevice() - Mark message as free.  If error, trash IO_DEVICE,
  743.         IO_UNIT and LN_TYPE.
  744.         Be sure request is not linked into a list.
  745.  
  746.         CloseDevice() - Check that message is free.  Trash IO_DEVICE,
  747.         IO_UNIT.
  748.  
  749.  
  750. IO_torture does not currently check for another common mistake:
  751. After virtually all uses of AbortIO(IORequest), there should be a
  752. call to WaitIO(IORequest).  AbortIO() asks the device to finish
  753. the I/O as soon as possible; this may or may not happen instantly.
  754. AbortIO() does not wait for or remove the replied message.
  755.  
  756. Note regarding NT_MESSAGE:  NT_MESSAGE would seem to be the correct node
  757. type for an IO request which is newly initialized.  However, part of
  758. how IO_torture works is that it makes sure in-use requests are marked as
  759. NT_MESSAGE, and would normally complain if such an NT_MESSAGE came
  760. through BeginIO or SendIO (as it would signify reuse before ReplyMsg).
  761. So that IO_torture will not complain about a freshly initialized
  762. MT_MESSAGE IO request, IO_torture also checks to see if the message
  763. has ever been linked into a list.  If it has not, IO_torture will
  764. let the NT_MESSAAHE marked request by without complaining.  This
  765. is necessary because the amiga.lib CreateExtIO and CreateStdIO
  766. historically set a newly created IO request node type to NT_MESSAGE.
  767.  
  768.  
  769. SegTracker
  770. ==========
  771. SegTracker is an important new tool that comes with Enforcer.
  772. SegTracker should be called early in your startup sequence if possible,
  773. right after SetPatch (you should never call anything before SetPatch).
  774. SegTracker installs a routine which will keep track of the seglists
  775. of loaded code in the system, including disk-loaded programs, libraries,
  776. devices, and handlers.  SegTracker provides a function which may be
  777. called by other debugging tools to let them determine the seglist
  778. name, hunk, and offset of RAM addresses in any loadsegged code.
  779. Many of debugging tools now call SegTracker's function to provide
  780. name, hunk, and offset information for hits or other addresses.
  781. SegTracker makes it possible for the other tools (Mungwall, TNT,
  782. TStat, etc.) to provide this information even when the PC or hit is
  783. within disk-loaded code other than the process's own code.
  784. We would also like third-party debugging tools to use SegTracker's
  785. function to find hunk and offset debugging information.
  786. SegTracker can also be used as a command to dump a list of
  787. all loaded segments or to find the seglist containing a particular
  788. address.  See Enforcer.doc for more information and the programmatic
  789. interface for SegTracker.
  790.  
  791.  
  792. Devmon
  793. ======
  794. Devmon is a tool which allows you to monitor the activity of any
  795. exec device.  It is extremely useful for debugging both application
  796. use of a device and your own device drivers.  Devmon captures
  797. (or outputs to serial or Sushi) debugging information everytime
  798. any vector of a monitored device is entered.  Optionally, Devmon
  799. can also report on the entry to (and in some cases, exit from)
  800. the exec library functions which call the device.
  801.  
  802. USAGE: devmon name.device unitnum [remote] [hex] [allunits] [full]
  803.  
  804. remote        means serial debugging output
  805. hex        means show values in hex
  806. allunits    monitor regardless of unit pointer (required if device
  807.             gives a new unit pointer to every opener)
  808. full        means also monitor exec device-related library functions
  809.  
  810.  
  811. Some sample Devmon output as generated by:
  812.  
  813.     devmon clipboard.device 0 allunits hex full remote
  814.  
  815.  
  816. In the following regular devmon output lines, UPPERCASE: signifies
  817. entry to an actual device vector, while MixedCase: signifies entry to
  818. (or Rts from) an exec function.  The number preceded by "@" is the
  819. address of the IO request.  The single letters following are
  820. abbreviations for the fields of an IOStdRequest (C means io_Command,
  821. F means io_Flags, E means io_Error, etc.).  When Devmon is exited,
  822. it outputs a key to these fields.
  823.  
  824. Here we see C:ConClip executing DoIO of a request containing CMD_WRITE
  825. (C = 3, as defined in exec/io.h) of 8 bytes (L=$8) of data at $30BDF0.
  826. We see the same IO request make it to the BEGINIO vector of the
  827. device, and then we see the DoIO completing successfully with an
  828. io_Actual (A=) of 8.
  829.  
  830. DoIO : @$478294 C= 3 F=$81 E=0 A=$4 L=$8 D=$30BDF0 O=$0 (C:ConClip)
  831. BEGIN: @$478294 C= 3 F=$1 E=0 A=$4 L=$8 D=$30BDF0 O=$0 (C:ConClip)
  832. DoRts: @$478294 C= 3 F=$81 E=0 A=$8 L=$8 D=$30BDF0 O=$8 (C:ConClip)
  833.  
  834.  
  835. TNT
  836. ===
  837. TNT installs a trap handler that replaces Software Error requesters
  838. with a large requester containing informative debugging information.
  839. TNT can be called in your user-startup (it does not need to be run).
  840. But it does not get along well with trap-based single-stepping debuggers.
  841. So if you plan to run a debugger, turn off TNT with TNT OFF.
  842.  
  843. TNT requesters contain PC, task/command name, SP, SSP, register, and
  844. stack contents information similar to that displayed by Enforcer.
  845.  
  846.  
  847. Owner and LVO
  848. =============
  849. Owner and LVO are very useful for determining the owner of a memory address.
  850. This can help you determine the location and even the cause of an
  851. Enforcer or Mungwall hit.
  852.  
  853. LVO requires the Amiga FD files for your OS version in a directory
  854. assigned the logical name FD:.  The FD files are provided with 
  855. the includes and linker libs for the OS.
  856.  
  857. When you get a hit, use OWNER to determine if the address is in a ROM
  858. module (such as exec or intuition), or in the loaded code, stack, port,
  859. or other memory owned by a program.  Note that owner can not determine
  860. if an address is in the code of a disk-loaded device or library because
  861. there is no standard place for devcies and libraries to store their
  862. seglist.
  863.  
  864. Example:
  865.  
  866. 1> owner 0x202443
  867.  
  868. Address  - Owner
  869. --------   -----
  870. 00202442 - in resident module: exec 39.47 (28.8.92)
  871.  
  872.  
  873. Now use LVO to determine the probable function at that address within
  874. the subsystem:
  875.  
  876. 1> LVO exec romaddress=0x202442
  877.  
  878. Closest to $202442 without going over:
  879. exec.library  LVO $fe0e -498  OpenResource() jumps to $202358 on this system
  880.  
  881. LVO can also be used as a programming helper to list one function and
  882. its FD comment:
  883.  
  884. 1> LVO exec AllocMem
  885. exec.library  LVO $ff3a -198  AllocMem()
  886. AllocMem(byteSize,requirements)(d0/d1)
  887.  
  888. LVO will list all of a library's LVOs if no function name is provided.
  889. With the optional CONTAINS keyword, LVO will also list the addresses
  890. each function jumps to on YOUR system (different on different systems).
  891. Note that if you have debugging tools installed which use SetFunction
  892. (for example, Mungwall, Devmon, or Scratch), LVO will not be able to
  893. determine the ROM address of the SetFunctioned library functions
  894. because the LVOs of those functions will point to the SetFunctioned
  895. RAM code.
  896.  
  897. LVO can also create command lines for the "Wedge" program.
  898.  
  899. Note that LVO and Wedge can only interact with actual
  900. library functions, not for their various stub interfaces which
  901. only exist in linker libraries.  Actual library functions are the
  902. functions listed in the FD file for the libraries.
  903. Note also that under new versions of the OS, some older library
  904. functions become unused by the OS and newer functions are used
  905. in their place.
  906.  
  907.  
  908. Wedge
  909. =====
  910. Wedge is a tool for wedging into almost any system library function
  911. and monitoring calls to and results from the function, for any or
  912. all system tasks.  Sometimes it can be more efficient to quickly
  913. wedge and monitor a system function rather than ad debugging code
  914. and recompile.  It used to be very difficult to create command
  915. line arguments for wedge.  But LVO can generate a template command
  916. line to "wedge" into any system function.
  917.  
  918. Example: Creates a wedge command for wedging into OpenScreen
  919.  
  920. 1> LVO intuition CloseScreen wedgeline      
  921. run wedge intuition 0xffbe 0x8100 0x8100 opt r   "c=CloseScreen(screen)(a0)"
  922.  
  923. If you execute the WEDGE command line above, you will receive serial
  924. reports on every call to CloseScreen.  To turn off the wedge, type
  925. WEDGE KILLALL.  See Wedge.doc for more information.
  926.  
  927.  
  928. Tstat
  929. =====
  930. Tstat is a handy little tool for checking the signals, priority,
  931. state, and other Task control block variables of any task or command.
  932. Tstat also does its best to show the task registers as they were
  933. saved at task-switch time, and the stack usage of the task or command.
  934. Note however that Tstat is looking at provate exec Task context information
  935. and therefore often needs to be updated for each OS release, and may
  936. misinterpret the task context data in unusual conditions such as
  937. a task switch which occures in the middle of an FPU instruction. 
  938. But it is very useful when checking for lost signals, bad Forbid or
  939. Disable counts, and hung Waits.  Tstat can monitor once, or periodically.
  940. For example, tstat MyProg -4 would monitor MyProg every 4/50's of a second
  941. until CTRL-C is hit.  In a pinch, Tstat can be used as a poor-man's
  942. logic state analyzer to track another program stuck in a loop.
  943.  
  944.  
  945. Other Memory Tools
  946. ==================
  947. EatMem is an interactive tool for scaling back the apparent amount of memory
  948. available to the system.  It is useful for testing applications in a simulated
  949. low-memory situation, as well as for testing how an application deals with
  950. only chip memory or only fast memory.  EatMem requires at least V37 OS.
  951.  
  952. MemList displays all memory blocks (both free and in-use) in the system.
  953. It can be useful for debugging fragmentation/deallocation problems.
  954. See also the NAMETAG option of Mungwall, and Munglist.
  955.  
  956. Frags displays a chart of current systen memory fragmentation.
  957.  
  958. Memmon saves current free memory and a comment to a file on demand.
  959. It is useful for documenting memory usage while testing various
  960. program operations.
  961.  
  962. Flush does two large allocations designed to fail and thereby cause
  963. all disk-loaded devices, libraries, and fonts which are not currently
  964. in use to be flushed from the system.  Useful when doing memory-loss
  965. testing and device or library development.
  966.  
  967. Snoop can be used to snoop memory allocations, but has largely been
  968. replaced by the more flexible Mungwall SNOOP option.  SnoopStrip
  969. is used to discard allocation/deallocation pairs from captured Snoop
  970. or Mungwall SNOOP output.
  971.  
  972.  
  973. Report
  974. ======
  975. All bug reports, compatibility problem reports, and enhancement
  976. requests must be generated with the latest Amiga "Report" program
  977. (currently version 39.5), or must be compatible with the output
  978. of the Amiga Report program.  This makes automatic submission
  979. and routing of bug reports possible.  The Report program is
  980. included on most developer tool and Devcon disks.  Report HELP
  981. will output instructions and submissions addresses.
  982.  
  983. We STRONGLY REQUEST that you submit your reports electronically
  984. if possible.  PLEASE USE REPORT.  Only mail them on paper if you
  985. have no other method available.  
  986.  
  987. European ADSP users: Post in appropriate closed adsp bugs topic
  988.  
  989. BIX/CIX: Post bugs in the appropriate bugs topic of your closed conference.
  990.  
  991. UUCP: to uunet!cbmvax!bugs OR rutgers!cbmvax!bugs OR bugs@commodore.COM
  992.   (enhancement requests to cbmvax!suggestions instead of cbmvax!bugs)
  993.  
  994. Mail: Mail individual bug reports in Report format, on disk if possible.
  995.   European developers: Mail bug reports to your support manager
  996.   unless your support manager says to mail directly to West Chester.
  997.   U.S./others mail to: Amiga Software Engineering, ATTN: BUG REPORTS,
  998.   CBM, 1200 Wilson Drive, West Chester, PA., 19380, USA
  999.  
  1000. Please make sure the initial one-line bug description you provide
  1001. in each of your reports is as explicit as possible.  Engineering's bug
  1002. summary reports and bug processing tools often list only the one-line
  1003. description for each bug.  "Bug in intuition" is a useless title
  1004. for an intuition subsystem bug.  "Pixel trash when window dragged left"
  1005. is a much better title.
  1006.  
  1007. The latest Report program always includes a list of the currently
  1008. acceptable subsystems for bug reports and enhancement requests.
  1009. These allow reports to be properly routed.  A recent list includes:
  1010.  
  1011. A2024           amigavision     cia.resource   filesysres     input.device   
  1012. A2065           appshell        clipboard      filesystem     installer      
  1013. A2090.A2090A    arexx           commodities    fonts          intuition      
  1014. A2091.A590      art             con-handler    fountain       iprefs         
  1015. A2232           as225           console.device gadget.classes keyboard       
  1016. A2300           asl.library     creditcard     gadtools       keymap         
  1017. A2410           audio.device    crossdos       gameport       keymaps        
  1018. A2620           autoconfig      custom.chips   genlock        kickmenu       
  1019. A2630           battclock       datatypes      graphics       layers         
  1020. A3000           battmem         debug.lib      hardware       locale.library 
  1021. AmigaBasic      bootmenu        disk.resource  hdbackup       mathffp        
  1022. aa.chips        bridgeboard     diskfont       hdtoolbox      mathieee       
  1023. alink           bru             documentation  icon.library   mathieeedoub   
  1024. amiga.lib       bullet          dos.library    iconedit       mathieeesing   
  1025. amigaguide      cdos.command    exec           ide.device     microemacs     
  1026. amigaterm       cdtv            expansion      iffparse       monitors
  1027. multiview       printer.driver  scsi.device    timer.device   util.command   
  1028. narrator.device queue-handler   serial.device  toolkit        utility.library
  1029. new.look        ram-handler     setpatch       toolmaker      wack           
  1030. parallel.device ramdrive.device shell          tools          wbtag          
  1031. port-handler    ramlib          speak-handler  trackdisk      workbench      
  1032. potgo.resource  resource        startup        translations                  
  1033. preferences     sana2           strap          translator                    
  1034. printer.device  script          system.command unix
  1035.