home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-11-04 | 48.1 KB | 1,035 lines |
-
- Using Amiga Debugging Tools
- ===========================
-
- (c) Copyright 1991-93 Commodore-Amiga, Inc. All Rights Reserved
-
-
- Have you ever experienced any of the following problems with software ?
-
- The software runs well on your system but some others report it
- has problems on their systems.
- The software runs well by itself but has problems running with
- or after other software.
- The software runs well most of the time but occasionally crashes
- or fails for no apparent reason.
-
- You can find and eliminate many of these types of hidden software problems
- by running Amiga debugging and stressing tools while developing and
- testing your product.
- Hidden and obvious software problems are often caused by use of null
- pointers, uninitialized pointers, improperly initialized structures,
- improper use of IO requests, improper abort code, improper memory usage,
- or overwriting of memory allocations.
- By using Enforcer, Mungwall, IO_Torture, Scratch, Memoration, and other
- Amiga debugging and testing tools, you can catch most of these problems
- before you ship a product.
- In fact, many companies now require that all of their inhouse
- software pass at least Enforcer and Mungwall testing, and have also added
- this requirement to their contracts for outside development.
- Many other CATS tools such as Devmon, Owner, and LVO can help to pinpoint
- the causes of problems. You have these tools. Here are hints on how to
- use them, when to use them, and how to get the most from their output.
-
-
- Enforcer and Mungwall
- =====================
-
- Enforcer and Mungwall are the top two bug finding and bug prevention tools.
- Enforcer is an MMU-based debugging tool by Michael Sinz, based on an earlier
- tool by Bryce Nesbitt. An MMU is a memory management unit which can be
- configured to trap accesses to specified ranges of memory. The 68030 and
- 68040 processors have a built-in MMU, and most 68020 boards contain a
- separate MMU. Because it is MMU-based, Enforcer can trap reads and writes
- of low memory and non-existent memory the instant these accesses
- (also known as "Enforcer hits") occur. This allows you to catch usage of
- null pointers and some uninitialized pointers in your program, and even
- accesses which would have trashed low memory or otherwise crashed the system.
-
- Some of these accesses may seem harmless on your system (such as reads of
- address 0) but could cause your program to fail in the field. If you are
- developing commercial software (or any software that you plan to distribute)
- it is extremely important that you invest in a MMU, or at the very least
- make sure that your software is tested on machines with an MMU, Enforcer,
- and Mungwall. As more of the development community begins running these
- tools, software that is unusable in their presence will simply not be used.
-
- The main differences between the new Enforcer and the previous Enforcers
- is that the new Enforcer also works with 68040 processors and has a wide
- variety of output options built in. In addition, due to the variety of
- output options, the new Enforcer must be RUN. The new Enforcer requires
- at least V37 OS, so if you need to run Enforcer on a 1.3 machine, you must
- use the older Enforcer 2.8b which we have renamed "Enforcer1.3".
- The current Enforcer comes with an important new tool called SegTracker.
- Enforcer and other debugging tools now take advantage of SegTracker
- to provide a way to report seglist name, hunk, and offset for addresses
- within ANY loaded code. Full docs on Enforcer and SegTracker are provided
- in Enforcer.doc.
-
- Enforcer is even more powerful when used in combination with Mungwall.
- Mungwall is a combination memory munging tool by Ewout Walraven which
- is based on Memmung by Bryce Nesbitt and Memwall by Randell Jesup.
- The "mung" part of Mungwall fills all of free memory (and all subsequently
- freed memory) with a nasty odd 32-bit values like $DEADF00D. Such a values
- are almost guaranteed to cause serious problems for any program that uses
- uninitialized pointers or structures, or uses memory or allocations after
- they are freed. Such usages can occur, for example, when allocations are
- not freed in the correct order.
-
- Mungwall uses a few different nasty 32-bit values in its memory munging
- to help you diagnose any problems.
-
- - Except when Enforcer is running, location 0 is set to $C0DEDBAD
- so that programs referencing location zero will not find a value.
- Programs referencing location 0 as a string will get a string of
- high ASCII characters rather than a null string, and programs
- using null structure pointers should be irritated into crashing.
- When Enforcer is running, this is not necessary because with location
- 0 containing 0, Enforcer can trap these low memory accesses by itself.
-
- - On startup all free memory is munged with $ABADCAFE. If this number
- shows up, someone is referencing memory in the free list.
-
- - Except when MEMF_CLEAR is set, memory is pre-munged on allocation with
- $DEADFOOD. When this is seen in an Enforcer report, the caller is
- allocating memory and doesn't initialize it before using it.
-
- - Memory is filled with $DEADBEEF when it is deallocated, encouraging
- programs reusing freed memory to crash or get Enforcer hits.
-
-
- The "wall" part of Mungwall allocates extra memory before and after
- every memory allocation and fills this "wall" with a fill pattern and
- other information. On each de-allocation, Mungwall checks to make sure
- that the deallocation size matches the size of the allocation, and checks
- to make sure that the walls have not been overwritten. Mungwall also
- watches for 0-size allocations, 0-size deallocations, and 0-address
- deallocations.
-
- Mungwall checks for incorrect allocations (such as 0 size) during AllocMem,
- and checks for incorrect deallocations or trashing around allocations
- during FreeMem. If trashing or incorrect deallocation is detected,
- Mungwall will both report it and refuse to free the memory. These reports
- are all known as "Mungwall hits".
-
- The latest Mungwall can also optionally report on failed allocations
- with the SHOWFAIL option. In addition, Mungwall has an option
- to "snoop" and report on all memory allocations and deallocations
- for all tasks or specified tasks. This can be useful when tracking
- down memory losses. The sometimes voluminous snoop output can be run
- through the snoopstrip program which will throw away all matching
- allocation/deallocation pairs.
-
- Another useful recently added Mungwall feature is the NAMETAG option.
- When this option is active, Mungwall will tag all memory allocations with
- the first 16 characters of the name of the task, process, or command
- that allocated the memory. A program called Munglist can then
- do its best to show the names of the allocators of currently allocated
- pieces of memory. This can be very useful in tracking down memory losses.
- However, keep in mind that some of an application's allocations
- may be done by a different system task (for example, if an application
- opens a file, a file handle or buffers may be allocated by the process
- for the disk volume).
-
- The current Mungwall makes use of SegTracker, if running, to report
- the seglist, hunk, and offset of hit addresses in any loaded code.
- If neither possible PC (A: and C: PC) is within loaded code,
- Mungwall will check on the stack to see if it can find some address
- within loaded code. For more information, see the MUNGWALL OUTPUT
- section later, and also Mungwall.doc.
-
- Mungwall may be used without Enforcer and on non-MMU machines.
- If you don't have an MMU, at least test with Mungwall alone.
- If you are using uninitialized memory or memory after it is freed,
- Mungwall should help to crash you immediately (as you might crash on
- a user's machine when he runs other programs at the same time as yours).
- Mungwall is more pleasant when used with Enforcer however, since it will
- generally incite an Enforcer hit when memory is misused, rather than a crash.
-
- It is generally not safe or recommended to turn Mungwall off and
- back on without rebooting. This is because Mungwall recognizes
- its walled allocations by looking for a special value it has placed
- near the beginning of the allocation. If a program allocates memory while
- Mungwall is running, then frees it while Mungwall is turned off,
- and another program reallocates the some of the same memory while Mungwall
- is turned off, and then tries to deallocate it with Mungwall turned
- back on, Mungwall may generate Mungwall hits due to incorrect data.
- Note that this can also occasionally happen on a soft-reboot if a task
- that starts up and allocates memory before Mungwall is run happens to
- receive a Mungwall-tagged piece of memory that was in use before reboot,
- and then frees the memory after Mungwall is running. To identify
- such problems, turn your machine off for 15 seconds or so to clear
- memory, turn it back on, and retest.
-
- A useful alternative to turning Mungwall off and on is the Mungwall
- UPDATE feature. UPDATE allows you to turn on and off many of the
- options of another running copy of Mungwall. For example, you
- could turn off the MEGASTACK option via Mungwall UPDATE NOMEGASTACK
- or turn on the SHOWFAIL option with Mungwall UPDATE SHOWFAIL.
-
- The latest Mungwall has some additional options for hit display
- (SHOWHUNK, etc.) and also has a TIMESTAMP option for timestamping
- memory allocations. The timestamps can be useful when using
- "MungList", the memory listing tool that comes with Mungwall.
-
- MungList attempts to list ALL of the allocated pieces of memory
- in the system which have been allocated since Mungwall was started.
- If Mungwall was run with the NAMETAG option, MungList can show the
- name of the program that allocated each piece of memory. If Mungwall
- was run with the TIMESTAMP option, the MungList SHOWTIME can also
- show the time each piece was allocated. If SegTracker is running,
- MungList can also attempt to give some hunk and offset information.
- In addition, the new MungList can also REMUNGE and/or CHECK memory.
- In CHECK, MungList attempts to check for wall-trashing of memory
- that is currently allocated, and REMUNGE can re-fill free memory
- with nasty values (memory deallocated under a Forbid can not be
- post-filled by Mungwall at the time of deallocation). Munglist
- can be told to stay running and REMUNGE and/or CHECK periodically.
-
-
- Debugging Terminals
- ===================
-
- Enforcer and Mungwall both output their debugging information
- to the serial port at the baud rate your machine's serial
- hardware is set to. At powerup, your serial hardware is set
- to 9600 baud, but you can modify this by bringing up a terminal
- package and setting a baud rate. The optimal debugging setup
- is to connect your Amiga via a null modem serial cable to another
- Amiga or computer running a terminal package with ACSII capture
- capability. Both Enforcer and Mungwall include CTRL-G's in their output
- to generate a beep with most terminal packages, and the ASCII capture
- capability will allow you to capture all serial debugging
- output to a file for examination. This is especially useful when
- combined with serial kprintf() (debug.lib) debugging statements in
- your code such as kprintf("About to close window $%lx\n",win).
-
- But some developers don't have a second machine to use as a debugging
- terminal, or may need to debug a serial application which would
- interfere with serial debugging output.
- So two other options exist. One is to use the parallel
- versions of the debugging tools, and the parallel debugging "dprintf"
- command (from ddebug.lib) and connect a parallel printer for
- the output. The benefit of serial and parallel debugging is that
- you can get some information out and capture it even if your
- machine is crashing, and even if your application has taken
- over the system. The other option is "Sushi".
-
-
- Sushi
- =====
-
- For most applications, an option now exists for debugging
- on a single machine. It's called "Sushi" (a late-night name loosely
- based on the fact that it captures "raw" serial output).
- Sushi captures all raw serial debugging output (such as kprintf,
- new Enforcer with RAWIO option, Mungwall, IO_Torture, etc.)
- and has its AmigaDOS process send the debug information to stdout.
- This means you can redirect Sushi's output to a an AUTO/CON window
- (and the window will pop open if you have any hits), or to a multiserial
- port, etc. Sushi can also be told to save its circular buffer
- (via CTRL-F signal or via a separate SUSHI SAVEAS FILENAME command),
- or to empty its buffer (CTRL-E signal or a separate SUSHI EMPTY command).
-
- Sushi also can operate in quiet mode, just capturing debugging output,
- and provides a program task signalling interface which allows an external
- application to be written to display the captured debugging output
- (for those of you who want a fancier debugging display program).
- A benefit of Sushi is that fairly voluminous debugging output
- can be used even from within interrupt code or intense task code
- because Sushi only has to place the text bytes in a ram buffer,
- and the actual output is done by a separate process.
- See Sushi.doc for more information and a source for a sample
- external display program.
-
- Sample user-startup:
-
- run >NIL: Mungwall
- run >NIL: Enforcer RAWIO
- run >NIL: sushi <>"CON:0/20/640/100/Sushi CTRL-File CTRL-Empty/AUTO/CLOSE/WAIT" NOPROMPT
-
-
- Debugging printf's: kprintf and dprintf
- =======================================
- When using serial (or parallel) debugging and stress-testing tools,
- it is very useful to have your own program's debugging statements
- (such as "About to do xxx") mixed in with any potential hits
- from the debugging tools.
- In addition, it is very useful to have a printf-like command that
- can be used from within even the low level task or interrupt code.
- A clean way to add conditional debugging statements to a C program
- is to use a MACRO such a D(bug)) by including lines like the following
- in your program. Set MYDEBUG to 1 to turn on debugging.
- Set bug to printf for printf debugging, or to kprintf (and link with
- debug.lib) for serial debugging, or to dprintf (and link with ddebug.lib)
- for parallel debugging. The D(bug()) macro is neater in your code
- because it can be indented and you need not surround it with any
- #ifdef directives yourself. Just be careful to remember to put two
- close paren's at the end of each D(bug()) statement, before the semicolon.
-
- /********** debug macros ***********/
- #define MYDEBUG 1
- void kprintf(UBYTE *fmt,...);
- void dprintf(UBYTE *fmt,...);
- #define DEBTIME 0
- #define bug printf
- #if MYDEBUG
- #define D(x) (x); if(DEBTIME>0) Delay(DEBTIME);
- #else
- #define D(x) ;
- #endif /* MYDEBUG */
- /********** end of debug macros **********/
-
- Example macro usage:
- win = OpenWindow(&mynewwin);
- D(bug("Opened window at $%lx\n", win));
-
- Note that kprintf and dprintf debugging can be used inside even
- the lowest level task or interrupt code (although you better
- keep output down to a minimum during interrupts!). The DEBTIME
- (Delay) in the macro above must be 0 however if you are doing
- output from anything other than a Process.
-
-
- Finding the Cause of Enforcer and Mungwall Hits
- ===============================================
- By using Enforcer and Mungwall while you are developing your software,
- you can catch problems as soon as they are introduced and greatly
- cut down your debugging time. It is especially useful to place
- conditional remote debugging statements in your code as you write
- each routine so that they can easily be turned on when a problem occurs.
- You will easily be able to pinpoint the problem area when the kprintf
- (or dprintf) output is intermixed with the Enforcer or Mungwall output.
- The remote debugging commands kprintf and dprintf are avaiable in
- the linker libraries debug.lib (serial) and ddebug.lib (parallel)
- respectively. These linker libs are supplied with some compilers
- and are also available on Commodore's Native Developer Update disks.
-
- Some people prefer to use a source-level or single-stepping debugger
- in combination with Enforcer and Mungwall when tracking down a
- problem to single-step through their code until the hit occurs.
- A different low-level method of locating Enforcer or Mungwall hits is to
- disassemble program memory where the hit occurred. If the hit occurred
- in ROM, first try using OWNER to determine ROM subsystem of that address.
- For example, OWNER 0x202442 might return the following on a soft-kicked
- A2500:
-
- Address - Owner
- -------- -----
- 00202442 - in resident module: exec 39.47 (28.8.92)
-
-
- Then use LVO to determine the probable function at that address within
- the subsystem: LVO exec romaddress=0x202442
-
- Closest to $202442 without going over:
- exec.library LVO $fe0e -498 OpenResource() jumps to $202358 on this system
-
- (See Owner and LVO section for more information on these tools)
-
- If this does does not give enough clue, try disassembling just before
- other ROM and RAM addresses shown in the Enforcer stack dump line.
- If code is found, these may be application or ROM functions
- which called the routine that generated the hit.
-
- If the hit occurs in RAM code, use various methods to match up the
- disassembly with your own code. Assembly programmers can just compare
- the disassembly to their source. Others may wish to take the hex values
- of a sequence of position-independent 68000 instructions near the hit
- (ie. no addresses except for offsets and branches) and do a search for
- this binary pattern in your object modules. If you find the pattern,
- do a mixed source and object disassembly of that object module (for example,
- with SAS's OMD you could OMD >ram:dump mymodule.o mymodule.c) and then
- look in the output for instructions matching those where the hit occurred.
- NOte that when a hit occurs in a disk-loaded device or library, it is
- currently not possible to determine who owns the code where the hit occurred.
- This is because it is up to the device or library to store its
- seglist wherever it sees fit in its own library or device base.
- If you suspect that your hit is occuring in a disk-loaded library
- or device, you can try searching suspected disk libraries or devices
- for a match of the hex pattern of position-independent code near the hit.
-
-
- Deciphering Enforcer and Mungwall Output
- ========================================
- Enforcer and Mungwall provide lots of valuable information to help
- debug your hits.
-
-
- SAMPLE ENFORCER OUTPUT:
-
- Here are two sample Enforcer hits caused by a program called "lawbreaker".
-
- WORD-READ from 00000014 PC: 0030801E
- USP: 00461990 SR: 0015 SW: 0769 (U0)(F)(D) TCB: 004181A0
- Data: DDDD0041 DDDD1100 DDDD2200 DDDD3300 DDDD4400 DDDD5500 DDDD6600 DDDD7700
- Addr: AAAA0000 AAAA1100 AAAA2200 AAAA3300 AAAA4400 AAAA5500 00280804 --------
- Stck: 00000009 00000008 00000007 00000006 00000005 00000004 00000003 00000002
- Stck: 00000001 00216B98 00002710 00418B94 D5D5D5D5 D5D5D5D5 D5D5D5D5 D5D5D5D5
- ----> 0030801E - "lawbreaker" Hunk 0000 Offset 00000096
- Name: "Shell Process" CLI: "lawbreaker" Hunk 0000 Offset 00000096
-
- LONG-WRITE to FEEDFACE data=DDDD0041 PC: 00308030
- USP: 00461990 SR: 0018 SW: 0709 (U0)(F)(-) TCB: 004181A0
- Data: DDDD0041 DDDD1100 DDDD2200 DDDD3300 DDDD4400 DDDD5500 DDDD6600 DDDD7700
- Addr: AAAA0000 AAAA1100 AAAA2200 AAAA3300 AAAA4400 AAAA5500 00280804 --------
- Stck: 00000009 00000008 00000007 00000006 00000005 00000004 00000003 00000002
- Stck: 00000001 00216B98 00002710 00418B94 D5D5D5D5 D5D5D5D5 D5D5D5D5 D5D5D5D5
- ----> 00308030 - "lawbreaker" Hunk 0000 Offset 000000A8
- Name: "Shell Process" CLI: "lawbreaker" Hunk 0000 Offset 000000A8
-
-
- Here is an explanation of the some of the important information:
-
- PC:
-
- Program Counter. This is the address in memory where the program was
- executing instructions when the hit occured.
- For some kinds of hits this will often be the address of the instruction
- after the hit. Note that if your program passes a bad pointer
- or an improperly initialized structure to a system ROM routine,
- you may cause ROM code to read or write to an illegal address.
-
-
- TYPE-SIZE from or to (e.g. WORD-READ from 00000014):
-
- This is the type of illegal access and the address where it occurred.
- In the first example, the illegal access occurred at address $14, and
- is specified as a WORD-READ access.
- This means the illegal memory access was an attempt to read a word (2 bytes)
- at address $14. Low memory accesses are often caused by NULL
- pointers to structures. If, for example, your code or a ROM routine
- references a structure member at offset $14,
- and what you provided or used a NULL structure pointer, Enforcer will
- pick up a hit at address $14. Other illegal READ accesses are
- BYTE-READ (generally caused by a bad string pointer), and LONG-READ
- (generally caused by a bad pointer or a bad pointer within a structure).
- An Enforcer hit will ocuur whenever a program attempts to read low memory
- addresses (generally caused by a NULL pointer of some type) or non-existent
- memory addresses (generally caused by an uninitialized pointer).
- When Enforcer catches an illegal READ access, it reports the access
- and prevents the program from reading the address by returning data
- of zero.
-
- On illegal WRITE accesses (i.e. attempts to write to ROM, low memory,
- or non-existent memory) Enforcer will report BYTE-WRITE, WORD-WRITE,
- or LONG-WRITE hits (such as in the second example). These mean the access
- would have illegally and dangerously written to memory which should not
- be written to, quite possibly causing memory to be trashed.
- WRITE hits can be caused by bad pointers or bad code.
- Fortunately, Enforcer prevents the actual memory trashing
- from occurring, and instead just reports it. This can allow debugging
- severe low memory trashing problems which would normally crash your
- machine. In the second example above, the CLI program "lawbreaker"
- tried to write the long value $DDDD0041 to the address $FEEDFACE.
-
- Occasionally you will see an INSTRUCTION access of illegal
- memory meaning the PC (Program Counter) is at an address it has no
- legal reason to be at. Generally this is caused by trashed code, a trashed
- return address on your stack, or an invalid library base.
- Hint - when an INSTRUCTION Enforcer hit occurs at a negative address,
- it is most often caused by a JSR to an LVO (negative word offset)
- from a NULL library base. Check the Stack dump lines for a possible
- return address to the code that made the bad library call.
-
-
- "data=xxxxxxxx":
-
- On WRITE hits, Enforcer will show you the data that would have been
- written to the illegal address.
-
-
- Register Dump Lines:
-
- All of the middle Enforcer lines show the contents of the program's
- registers and stack at the time of the hit. The Data: line shows
- the D registers (D0 though D7). The Addr: line shows the A registers
- (A0 though A6). A7 (the Stack register) is shown as USP, and the contents
- of the top of the stack is shown in the Stck: lines (note - more Stck:
- lines are available via a command line option of the new Enforcer).
- The USP line also contains the contains of additional processor status
- registers, and also the address of the Task Control Block (TCB).
- On the same line are symbols which specify whether a Forbid (F) and/or
- a Disable (D) was in effect when the hit occurred.
-
-
- Name and Hunk/Offset:
-
- Examples:
- ----> 00308030 - "lawbreaker" Hunk 0000 Offset 000000A8
- Name: "Shell Process" CLI: "lawbreaker" Hunk 0000 Offset 000000A8
-
- The firts line (---->), if present, is seglist name, hunk, and offset
- information found via Enforcer calling SegTracker (to possibly get this,
- you must have started SegTracker prior to the loading of the code where
- the hit occured). SegTracker can find RAM hit addresses in ANY code
- that was loaded after SegTracker was started. See Enforcer.doc
- for more information on SegTracker and its programmatic interface.
- Here the information is redundant because the hit occurred in
- the application process's own code. However, if the hit had occurred,
- for example, inside a routine in a disk-loaded library or device
- called by the application process code, this SegTracker information
- would have been extremely important.
-
- The next line (Name:) shows the task name, and CLI command name (if any)
- of the task or command on whose task context the hit occurred (i.e. the
- program that was executing the code where the hit occurred).
- Even if SegTracker is not running, Enforcer will attempt to provide
- hunk and offset information here if the hit address is within the loaded
- program's own code instructions.
-
-
-
- SAMPLE MUNGWALL OUTPUT
- ======================
-
- Here are sample Mungwall hits by a program called "mungwalltest".
- Additional explanation has been added in parentheses below each hit.
- For reference, the arguments for memory functions are AllocMem(size,type)
- and FreeMem(address,size). The A: and C: addresses are Mungwall's
- guess at the address from which AllocMem was called. The A: address
- is the address if the caller was assembler code. The C: address is the
- probable address if the caller was C code, assuming a standard stub.
- Since Mungwall is wedged into the memory allocation functions, it can
- only guess the caller's address based on what is pushed on the stack.
- The "task" address on the first line of a Mungwall hit is the task address
- of the caller. Mungwall checks for incorrect allocations (such as 0 size)
- during AllocMem, and checks for incorrect deallocations or trashing
- around allocations during FreeMem. If trashing or incorrect deallocation
- is detected, Mungwall will both report it and refuse to free the memory.
-
- Note that Mungwall has special code to prevent
- trapping the partial (wrong size) deallocations that are performed
- by some version of layers.library. If any other debugging tools are
- also wedged into AllocMem and FreeMem, Mungwall's A: and C: addresses
- may be thrown off by additional information pushed on the stack, and
- Mungwall will also be unable to screen out any partial layers deallocations
- (which will show up as hits on your task's context).
-
-
- AllocMem(0x0,10000) attempted by `mungwalltest' (task 0x3E08F0)
- from A:0x3EBB12 C:0x3EF552 SP:0x4559FC
- (means mungwalltest tried to allocate 0 bytes of memory)
-
-
- FreeMem(0x0,16) attempted by `mungwalltest' (task 0x3E08F0)
- from A:0x3EBB40 C:0x3EF598 SP:0x4559F4
- (mungwalltest tried to free memory it never got - i.e. at address 0)
-
-
- FreeMem(0x2FE7C0,0) attempted by `mungwalltest' (task 0x3E08F0)
- from A:0x3EBB40 C:0x3EF5A8 SP:0x4559EC
- (mungwalltest tried to free 0 bytes of memory)
-
-
- Mis-aligned FreeMem(0x2FE7C4,16) attempted by `mungwalltest' (task 0x3E08F0)
- from A:0x3EBB40 C:0x3EF5B6 SP:0x4559E4
- (mungwalltest tried to free memory at an incorrect address)
-
-
- Mismatched FreeMem size 14!
- Original allocation: 16 bytes from A:0x3EBB12 C:0x3EF574 Task 0x3E08F0
- Testing with original size.
- (mungwalltest tried to free a different size from what it allocated)
-
-
- 19 byte(s) before allocation at 0x2FE7C0, size 16 were hit!
- >$: BBBBBBBB BBBBBBBB BB536572 6765616E 74277320 50657070 65722000
- (memory before this allocation was trashed; trash shown at right)
-
-
- 8 byte(s) after allocation at 0x2FE7C0, size 16 were hit!
- >$: 75622042 616E6400 BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB
- (memory after this allocation was trashed; trash shown at left)
-
-
- FreeMem(0x2FE7C0,14) attempted by `mungwalltest' (task 0x3E08F0)
- from A:0x3EBB40 C:0x3EF5F4 SP:0x4559D0
- (deallocation refused due to trashing explained in last two reports)
-
-
- Failed memory allocation!
- AllocMem(0x500000000,1) attempted by `flush' (task 0x3E08F0)
- from A:0x453E96 C:0x1 SP:0x4820F4
- (SHOWFAIL option shows flush tried to allocate memory and failed)
-
-
- As you can see, Mungwall alone can catch a large variety
- of memory-related software problems. But one the most important
- benefits of Mungwall is that by filling freed memory with nasty
- 32-bit values, it can force subtle memory misuse problems
- into the open, by often causing the misuses to access addresses that
- can be trapped on by Enforcer.
-
- Enforcer and Mungwall are required tools for the development of
- bug-free Amiga software. If you don't have an MMU, get one.
- The investment in an A3000, 68030 card, or 68020+MMU card
- will quickly pay for itself by cutting down on your development
- and allowing you to catch and find software problems with Enforcer.
- Enforcer and Mungwall are not just for developers and QA departments.
- Anyone who uses or reviews inhouse software or software for
- purchase or contract can benefit your company by catching hidden
- software problems during normal usage and examination of the programs.
- Many people at Commodore and other companies run Enforcer and Mungwall
- all of the time. Keep that in mind if you are trying to impress a
- company with your software!
-
-
- Other Debugging and Testing Tools
- =================================
-
- The next three tools, Memoration and Scratch by Bill Hawes, and IO_Torture
- by Bryce Nesbitt are important QA tools for testing the robustness of all
- application failure code, for uncovering illegal register usage in
- assembler code, and for detecting unsafe use of device IO requests.
- Following notes on these three are notes on some of the additional
- debugging and stresstest tools provided by CATS.
-
-
- Memoration
- ==========
- Memoration by Bill Hawes is a tool to selectively limit the ability of a
- task or module to allocate memory, thereby simulating the effects of a
- low-memory condition. It provides the unique ability to selectively
- cause each individual memory allocation of a program, whether direct
- or indirect, to fail, thereby allowing you to test the failure path
- and abort code at every point in your application code.
-
- Memoration works by SetFunctioning the Exec AllocMem and/or AllocVec
- entries and then screening the requests. If a request from a particular
- task or range of addresses is received, memoration returns a zero instead
- of passing it through to AllocMem.
-
- When a task or module is denied a memory request, memoration sends a
- message to the serial port identifying the client task ID, the address it
- was called from, and the size of the denied request. If the software can't
- handle being denied its memory request, this message will typically be
- followed by a series of enforcer reports telling of how the software went
- ahead and wrote to location 0.
-
-
- Command-Line Parameters.
- Memoration accepts command-line parameters to specify the module or task
- name and the range of memory sizes to disallow. The argument template is
-
- MODULE,TASK/K,CLI/K/N,OFF/S,MIN/K/N,MAX/K/N,AFTER/K/N,EVERY/K/N,ALLADDR/S,
- ALLOCVEC/S,CHIP/S,FAST/S,BACKTRACE/K/N
-
- and the specifications can be changed at any time by reissuing the command.
-
-
- MODULE is the name of a ROMTag or library. The resident modules are
- searched first, followed by a search of the system library list. When an
- entry is found, the range of addresses encompassing its code is determined
- using several methods. For ROMTags the range extends from the ROMTag
- itself to the next higher module, or to RT_ENDSKIP if no higher module
- exists. For libraries a certain amount of voodoo is required, as the
- location of the library ROMtag isn't stored in the (public) library
- structure. In this case memoration examines the LVOs to determine the
- lowest and highest addresses, and then searches for a ROMtag in the range
- (low-$2000,high+$2000). If a ROMTag is found, memoration uses the smaller
- of the ROMTag addresss and the lowest LVO address as the low limit, and the
- larger of the RT_ENDSKIP address and the highest LVO address as the high
- limit.
-
- TASK specifies the name of a task to trap. The task must exist at the time
- memoration is run, and for best results should persist for the course of
- testing. If you're using WShell (as you should be) you can define a name
- for a particular shell instance by using ``newwsh name sucker''.
-
- CLI specifies a shell number as the task to trap.
-
- MIN specifies the minimum memory request to trap. The default is 0.
-
- MAX specifies the maximum allocation to trap. The default is 2000000.
-
- OFF turns off memory trapping. The code patch is left intact, but won't
- trap any requests until enabled again. AllocMem and AllocVec traps
- can be turned on and off separately.
-
- ALLOCVEC sets the trap for the AllocVec() entry, instead of AllocMem().
- Both functions can be trapped independently.
-
- AFTER specifies the number of allocations (within other specifications) to
- pass before beginning the trap.
-
- EVERY traps every Nth allocation meeting the specifications.
-
- ALLADDR sets the address range to all memory.
-
- CHIP limits the trap to CHIP memory specifications.
-
- FAST limits the trap to FAST memory specifications.
-
- BACKTRACE specifies the number of longwords of stack backtrace desired.
-
-
- Examples:
- memoration myprog after 15 ; after 15th allocation, deny myprog any memory
- memoration dos.library ; disable all DOS allocations
- memoration task DF0 min 400 ; disable larger allocations by DF0:
- memoration icon.library task Workbench every 3
- memoration console.device min 40 backtrace 8
-
- Example test session to test failure of every allocation an application makes:
-
- Open two shells - one for memoration (here 1>) and one for myprog (here 2>).
- Alternately, you could start myprog from Workbench.
- Run Enforcer and Mungwall.
- Have serial or Sushi debugging set up.
-
- 1> memoration myprog after 0
- 2> myprog ; a failure occurs but hopefully no hits or crashes
- 1> memoration off
- (exit myprog if it made it up)
-
- 1> memoration myprog after 1
- 2> myprog ; a failure occurs but hopefully no hits or crashes
- 1> memoration off
- (exit myprog if it made it up)
-
- 1> memoration myprog after 2
- 2> myprog ; a failure occurs but hopefully no hits or crashes
- 1> memoration off
- (exit myprog if it made it up)
-
- etc. Note - until you get up to a higher "after" number, myprog will likely
- fail during the startup code it is linked with - i.e. before even
- reaching your main() entry point.
-
- Further Notes.
- Memoration uses a seglist-split for its code patch, and so shouldn't be made
- resident, at least not on the first execution. Memoration was written by
- William S. Hawes.
-
-
- Scratch
- =======
- Scratch by Bill Hawes purposely trashes the scratch registers (D1, A0, A1)
- on exit from library functions of any "scratched" library.
- This will point out assembler callers that accidentally or
- purposely depend upon getting "useful" values from those registers.
- It is extrememly important that ALL assembler applications be tested with
- Scratch. Even minor changes to the OS can change the values that happen to
- be left over in registers on exit from a system library function.
- Assembler code that is accidentally reusing a scratch register
- (for example A1) after a system call, or code that is looking at the
- wrong register for a result has the potential to break badly with
- even a minor change to the OS. Scratch can catch these problems before
- you ship. To use Scratch, see the script "SCRATCHALL.SCRIPT" which
- properly excepts certain system functions from scratching.
-
-
- IO_Torture
- ==========
- IO_torture is a tool which can be used to check for improper use
- or reuse of device IO requests.
-
- IO_torture should be part of the standard test suite for all products.
-
- Exec device IO usage is tracked by IO_torture. If an IORequest is reused
- while still active, IO_torture will print a warning message on the serial
- port (parallel for IO_torture.par).
-
- The current plan of IO_torture includes:
-
- SendIO() - Check that message is free. Check for ReplyPort.
- Be sure request is not linked into a list.
-
- BeginIO() - Check that message is free. Check for ReplyPort.
- Be sure request is not linked into a list.
-
- OpenDevice() - Mark message as free. If error, trash IO_DEVICE,
- IO_UNIT and LN_TYPE.
- Be sure request is not linked into a list.
-
- CloseDevice() - Check that message is free. Trash IO_DEVICE,
- IO_UNIT.
-
-
- IO_torture does not currently check for another common mistake:
- After virtually all uses of AbortIO(IORequest), there should be a
- call to WaitIO(IORequest). AbortIO() asks the device to finish
- the I/O as soon as possible; this may or may not happen instantly.
- AbortIO() does not wait for or remove the replied message.
-
- Note regarding NT_MESSAGE: NT_MESSAGE would seem to be the correct node
- type for an IO request which is newly initialized. However, part of
- how IO_torture works is that it makes sure in-use requests are marked as
- NT_MESSAGE, and would normally complain if such an NT_MESSAGE came
- through BeginIO or SendIO (as it would signify reuse before ReplyMsg).
- So that IO_torture will not complain about a freshly initialized
- MT_MESSAGE IO request, IO_torture also checks to see if the message
- has ever been linked into a list. If it has not, IO_torture will
- let the NT_MESSAAHE marked request by without complaining. This
- is necessary because the amiga.lib CreateExtIO and CreateStdIO
- historically set a newly created IO request node type to NT_MESSAGE.
-
-
- SegTracker
- ==========
- SegTracker is an important new tool that comes with Enforcer.
- SegTracker should be called early in your startup sequence if possible,
- right after SetPatch (you should never call anything before SetPatch).
- SegTracker installs a routine which will keep track of the seglists
- of loaded code in the system, including disk-loaded programs, libraries,
- devices, and handlers. SegTracker provides a function which may be
- called by other debugging tools to let them determine the seglist
- name, hunk, and offset of RAM addresses in any loadsegged code.
- Many of debugging tools now call SegTracker's function to provide
- name, hunk, and offset information for hits or other addresses.
- SegTracker makes it possible for the other tools (Mungwall, TNT,
- TStat, etc.) to provide this information even when the PC or hit is
- within disk-loaded code other than the process's own code.
- We would also like third-party debugging tools to use SegTracker's
- function to find hunk and offset debugging information.
- SegTracker can also be used as a command to dump a list of
- all loaded segments or to find the seglist containing a particular
- address. See Enforcer.doc for more information and the programmatic
- interface for SegTracker.
-
-
- Devmon
- ======
- Devmon is a tool which allows you to monitor the activity of any
- exec device. It is extremely useful for debugging both application
- use of a device and your own device drivers. Devmon captures
- (or outputs to serial or Sushi) debugging information everytime
- any vector of a monitored device is entered. Optionally, Devmon
- can also report on the entry to (and in some cases, exit from)
- the exec library functions which call the device.
-
- USAGE: devmon name.device unitnum [remote] [hex] [allunits] [full]
-
- remote means serial debugging output
- hex means show values in hex
- allunits monitor regardless of unit pointer (required if device
- gives a new unit pointer to every opener)
- full means also monitor exec device-related library functions
-
-
- Some sample Devmon output as generated by:
-
- devmon clipboard.device 0 allunits hex full remote
-
-
- In the following regular devmon output lines, UPPERCASE: signifies
- entry to an actual device vector, while MixedCase: signifies entry to
- (or Rts from) an exec function. The number preceded by "@" is the
- address of the IO request. The single letters following are
- abbreviations for the fields of an IOStdRequest (C means io_Command,
- F means io_Flags, E means io_Error, etc.). When Devmon is exited,
- it outputs a key to these fields.
-
- Here we see C:ConClip executing DoIO of a request containing CMD_WRITE
- (C = 3, as defined in exec/io.h) of 8 bytes (L=$8) of data at $30BDF0.
- We see the same IO request make it to the BEGINIO vector of the
- device, and then we see the DoIO completing successfully with an
- io_Actual (A=) of 8.
-
- DoIO : @$478294 C= 3 F=$81 E=0 A=$4 L=$8 D=$30BDF0 O=$0 (C:ConClip)
- BEGIN: @$478294 C= 3 F=$1 E=0 A=$4 L=$8 D=$30BDF0 O=$0 (C:ConClip)
- DoRts: @$478294 C= 3 F=$81 E=0 A=$8 L=$8 D=$30BDF0 O=$8 (C:ConClip)
-
-
- TNT
- ===
- TNT installs a trap handler that replaces Software Error requesters
- with a large requester containing informative debugging information.
- TNT can be called in your user-startup (it does not need to be run).
- But it does not get along well with trap-based single-stepping debuggers.
- So if you plan to run a debugger, turn off TNT with TNT OFF.
-
- TNT requesters contain PC, task/command name, SP, SSP, register, and
- stack contents information similar to that displayed by Enforcer.
-
-
- Owner and LVO
- =============
- Owner and LVO are very useful for determining the owner of a memory address.
- This can help you determine the location and even the cause of an
- Enforcer or Mungwall hit.
-
- LVO requires the Amiga FD files for your OS version in a directory
- assigned the logical name FD:. The FD files are provided with
- the includes and linker libs for the OS.
-
- When you get a hit, use OWNER to determine if the address is in a ROM
- module (such as exec or intuition), or in the loaded code, stack, port,
- or other memory owned by a program. Note that owner can not determine
- if an address is in the code of a disk-loaded device or library because
- there is no standard place for devcies and libraries to store their
- seglist.
-
- Example:
-
- 1> owner 0x202443
-
- Address - Owner
- -------- -----
- 00202442 - in resident module: exec 39.47 (28.8.92)
-
-
- Now use LVO to determine the probable function at that address within
- the subsystem:
-
- 1> LVO exec romaddress=0x202442
-
- Closest to $202442 without going over:
- exec.library LVO $fe0e -498 OpenResource() jumps to $202358 on this system
-
- LVO can also be used as a programming helper to list one function and
- its FD comment:
-
- 1> LVO exec AllocMem
- exec.library LVO $ff3a -198 AllocMem()
- AllocMem(byteSize,requirements)(d0/d1)
-
- LVO will list all of a library's LVOs if no function name is provided.
- With the optional CONTAINS keyword, LVO will also list the addresses
- each function jumps to on YOUR system (different on different systems).
- Note that if you have debugging tools installed which use SetFunction
- (for example, Mungwall, Devmon, or Scratch), LVO will not be able to
- determine the ROM address of the SetFunctioned library functions
- because the LVOs of those functions will point to the SetFunctioned
- RAM code.
-
- LVO can also create command lines for the "Wedge" program.
-
- Note that LVO and Wedge can only interact with actual
- library functions, not for their various stub interfaces which
- only exist in linker libraries. Actual library functions are the
- functions listed in the FD file for the libraries.
- Note also that under new versions of the OS, some older library
- functions become unused by the OS and newer functions are used
- in their place.
-
-
- Wedge
- =====
- Wedge is a tool for wedging into almost any system library function
- and monitoring calls to and results from the function, for any or
- all system tasks. Sometimes it can be more efficient to quickly
- wedge and monitor a system function rather than ad debugging code
- and recompile. It used to be very difficult to create command
- line arguments for wedge. But LVO can generate a template command
- line to "wedge" into any system function.
-
- Example: Creates a wedge command for wedging into OpenScreen
-
- 1> LVO intuition CloseScreen wedgeline
- run wedge intuition 0xffbe 0x8100 0x8100 opt r "c=CloseScreen(screen)(a0)"
-
- If you execute the WEDGE command line above, you will receive serial
- reports on every call to CloseScreen. To turn off the wedge, type
- WEDGE KILLALL. See Wedge.doc for more information.
-
-
- Tstat
- =====
- Tstat is a handy little tool for checking the signals, priority,
- state, and other Task control block variables of any task or command.
- Tstat also does its best to show the task registers as they were
- saved at task-switch time, and the stack usage of the task or command.
- Note however that Tstat is looking at provate exec Task context information
- and therefore often needs to be updated for each OS release, and may
- misinterpret the task context data in unusual conditions such as
- a task switch which occures in the middle of an FPU instruction.
- But it is very useful when checking for lost signals, bad Forbid or
- Disable counts, and hung Waits. Tstat can monitor once, or periodically.
- For example, tstat MyProg -4 would monitor MyProg every 4/50's of a second
- until CTRL-C is hit. In a pinch, Tstat can be used as a poor-man's
- logic state analyzer to track another program stuck in a loop.
-
-
- Other Memory Tools
- ==================
- EatMem is an interactive tool for scaling back the apparent amount of memory
- available to the system. It is useful for testing applications in a simulated
- low-memory situation, as well as for testing how an application deals with
- only chip memory or only fast memory. EatMem requires at least V37 OS.
-
- MemList displays all memory blocks (both free and in-use) in the system.
- It can be useful for debugging fragmentation/deallocation problems.
- See also the NAMETAG option of Mungwall, and Munglist.
-
- Frags displays a chart of current systen memory fragmentation.
-
- Memmon saves current free memory and a comment to a file on demand.
- It is useful for documenting memory usage while testing various
- program operations.
-
- Flush does two large allocations designed to fail and thereby cause
- all disk-loaded devices, libraries, and fonts which are not currently
- in use to be flushed from the system. Useful when doing memory-loss
- testing and device or library development.
-
- Snoop can be used to snoop memory allocations, but has largely been
- replaced by the more flexible Mungwall SNOOP option. SnoopStrip
- is used to discard allocation/deallocation pairs from captured Snoop
- or Mungwall SNOOP output.
-
-
- Report
- ======
- All bug reports, compatibility problem reports, and enhancement
- requests must be generated with the latest Amiga "Report" program
- (currently version 39.5), or must be compatible with the output
- of the Amiga Report program. This makes automatic submission
- and routing of bug reports possible. The Report program is
- included on most developer tool and Devcon disks. Report HELP
- will output instructions and submissions addresses.
-
- We STRONGLY REQUEST that you submit your reports electronically
- if possible. PLEASE USE REPORT. Only mail them on paper if you
- have no other method available.
-
- European ADSP users: Post in appropriate closed adsp bugs topic
-
- BIX/CIX: Post bugs in the appropriate bugs topic of your closed conference.
-
- UUCP: to uunet!cbmvax!bugs OR rutgers!cbmvax!bugs OR bugs@commodore.COM
- (enhancement requests to cbmvax!suggestions instead of cbmvax!bugs)
-
- Mail: Mail individual bug reports in Report format, on disk if possible.
- European developers: Mail bug reports to your support manager
- unless your support manager says to mail directly to West Chester.
- U.S./others mail to: Amiga Software Engineering, ATTN: BUG REPORTS,
- CBM, 1200 Wilson Drive, West Chester, PA., 19380, USA
-
- Please make sure the initial one-line bug description you provide
- in each of your reports is as explicit as possible. Engineering's bug
- summary reports and bug processing tools often list only the one-line
- description for each bug. "Bug in intuition" is a useless title
- for an intuition subsystem bug. "Pixel trash when window dragged left"
- is a much better title.
-
- The latest Report program always includes a list of the currently
- acceptable subsystems for bug reports and enhancement requests.
- These allow reports to be properly routed. A recent list includes:
-
- A2024 amigavision cia.resource filesysres input.device
- A2065 appshell clipboard filesystem installer
- A2090.A2090A arexx commodities fonts intuition
- A2091.A590 art con-handler fountain iprefs
- A2232 as225 console.device gadget.classes keyboard
- A2300 asl.library creditcard gadtools keymap
- A2410 audio.device crossdos gameport keymaps
- A2620 autoconfig custom.chips genlock kickmenu
- A2630 battclock datatypes graphics layers
- A3000 battmem debug.lib hardware locale.library
- AmigaBasic bootmenu disk.resource hdbackup mathffp
- aa.chips bridgeboard diskfont hdtoolbox mathieee
- alink bru documentation icon.library mathieeedoub
- amiga.lib bullet dos.library iconedit mathieeesing
- amigaguide cdos.command exec ide.device microemacs
- amigaterm cdtv expansion iffparse monitors
- multiview printer.driver scsi.device timer.device util.command
- narrator.device queue-handler serial.device toolkit utility.library
- new.look ram-handler setpatch toolmaker wack
- parallel.device ramdrive.device shell tools wbtag
- port-handler ramlib speak-handler trackdisk workbench
- potgo.resource resource startup translations
- preferences sana2 strap translator
- printer.device script system.command unix
-