CHAPTER 4 - Symbolic Debugger
Well, we've almost completed this huge coverage of the Devpac system, which was typed in its entirety by the Animal House. Edited by Sewer Rat for use in Doc Disk Number 8. CHAPTER 4 SYMBOLIC DEBUGGER Introduction Programs written in assembly language are particularly error- prone because even a slight mistake can result in the entire machine crashing. There are various forms of bugs, ranging from the trivial (e.g. a missing CR in a printout), though the usual (e.g. an incorrect result_ to the very serious (e.g. the machine completely hanging, perhaps with a weird display). To help you find and correct all forms of bugs, DevpacST includes MonST. MonST is a symbolic debugger and disassembler which lets you examine programs and memory, execute programs an instruction at a time and trap processor exceptions caused by programmer error. As MonST is symbolic you can look at your program complete with all the original labels, making debugging very much easier than having to battle with 6-digit hex numbers. Although MonSt is a low-level debugger, displaying such things as 68000 instructions and bytes of memory, it can also be used for debugging programs written with any compiler that generates machine-code output. If the compiler has the option to dump the symbols into the binary code then you will see your procedure and function names within the code, and you can even view your original source code. We ourselves used MonST when debugging LinkST, which was written in a C compiler, MonST and GenST themselves were written entirely in assembly language. As MonST uses its own screen memory, the display of your program is not destroyed when you single-step or breakpoint, making it particularly useful for graphical-output programs such as GEM applications or games. It also uses it own screen drivers so it is possible to single-step into the operating system screen routines such as the AES or BIOS without affecting the debugger. There are three versions of MonST supplied on the disk. All are similar to use and are provided to make the debugging of different types of programs easy. the Exact differences are detailed later. 68000 Exceptions MonST uses the 68000 processor exceptions to stop runaway programs and to single-step, so at this point it would be useful to explain them and what normally happens when they occur on an ST. There are various types of exception that can occur, some deliberately, others accidentally. When one does occur the processor saves some information on the SSP, goes into Supervisor mode and jumps to an exception handler. When MonST is active it re-directs some of these exceptions so it can take control when they occur. The various forms of exceptions, their usual results, and what happens when they occur with MonST active is shown in the following table: Ex. No. Exception Usual effect MonST active 2 bus error bombs trapped 3 address error bombs trapped 4 illegal instruction bombs trapped 5 zero divide bombs trapped 6 CHK instruction bombs trapped 7 TRAPV instruction bombs trapped 8 privilege violation bombs trapped 9 trace bombs trapped 10 line 1010 emulator fast VDI interface fast VDI interface 11 line 1111 emulator internal TOS internal TOS 32 trap #0 bombs trapped 33 trap #1 GEMDOS call GEMDOS call 34 trap #2 AES/VDI call AES/VDI call 35-44 trap #3-#12 bombs trapped 45 trap #13 XBIOS call XBIOS call 46 trap #14 BIOS call BIOS call 47 trap #15 bombs trapped The exact causes of the above exceptions (and how best to recover from them) are detailed at the end of this section, but to summarise: Exceptions 2 to 8 are caused by a programmer error and are trapped by MonST. Exception 9 can remotely be caused by programmer error and is used by MonST for single stepping. Exceptions 10, 11, 33, 34, 45 and 46 are used by the system and left alone. The rest (i.e. the unused Trap exceptions) are diverted into MonST, but can subsequently be re-defined to be exploited by programs if required. The 'bombs' entry in the table above means that the ST will attempt to recover from the exception, but it is not always successful. When an exception occurs, the ST prints on the screen a number of bomb shapes or mushrooms on disk-loaded GEMDOS), the number being equal to the exception number. Having done this, it will abort the current program (losing any unsaved data from it) and attempt a return to Desktop. If the exception was caused by or resulted in important system variables being destroyed then the attempt may fail and the machine will not recover. Occasionally very nasty crashes can cause the whole screen to fill with bombs (or mushrooms) which looks very impressive, but is not very useful! Memory Layout The usual versions of MonSt co-reside with programs being debugged; that is, they are loaded, ask for a filename, and load that file in together with any labels. It is useful to examine the usual logical memory map (the physical layout in shown in Appendix C) both with and without MonST, shown in Figure 4.1 on the next page. high memory Free Free Program Program MonST System System low memory Without MonST With MonST Figure 4.1 - Logical Memory Map The actual code size of MonST is around 23k, but in addition it requires an additional 32k of workspace. This may seem large but it is required for the copy of the ST screen memory saved by MonSt; this is a most useful feature of the debugger. The three versions of MonST supplied are: MONST2.PRG GEM interactive version MONST2.TOS TOS interactive version AMONST2. PRG Auto-resident version For now the first two will be described; the auto-resident version is described later but is very similar in use to the others. Invoking MonST From the Desktop The two interactive versions of MonST are actually identical except for the filename extension. The GEM version should be used for GEM-based programs, which require use of the mouse and have initially a grey-pattern screen, while the TOS version should be used for TOS-based programs which require the flashing TOS cursor and have initially a white screen display. Both versions are invoked by double-clicking on their respective icons from the Desktop. Note: If you debug a TOS program with the GEM version of the debugger it will work fine but the screen display will probably be messy; however, debugging a GEM program with a TOS debugger will cause all sorts of nasty problems to occur and should be avoided. From the Editor When GenST is invoked it automatically looks for and loads the file MONST2.PRG into memory (unless this option is disabled in the Preferences option in the editor). The debugger is then instantly available at the press of a key from within the editor. Pressing Alt-M or clicking on MonST from the Program menu will then invoke it in a similar way to that described for the disk- based version only very much more quickly. Pressing Alt-D or clicking on Debug from the Program menu will invoke MonST but will also automatically prepare a program previously assembled to memory to be run, including any symbols within it. The type of initial screen mode used when invoked from the editor is determined by the Run with GEM menu item on the Program menu - if a check mark is present then GEM screen initialisation is done, otherwise TOS screen initialisation is used. The rules described above about using the wrong type of screen initialisation are also relevant to the in-memory debugger. Symbolic Debugging A major feature of MonST is its ability to use symbols taken from the original program whilst debugging. MonST supports two formats for debug information - the DRI standard, which allows up to 8 characters per symbol, and the HiSoft Extended Debug format, allowing up to 22 characters. Both GenST and LinkST can produce both formats, and many other vendors' compilers and linkers have an option to produce DRI-format debugging information. We are trying to establish the Hi-Soft Extended format as a second standard on the ST, but at the time of writing the only other products to support the format are HiSoft BASIC and FTL-Modula 2. MonST Dialogue and Alert Boxes MonST makes extensive use of dialogue and alert-boxes which are similar in concept to those in GEM programs but have several differences. MonST does not use genuine GEM-type boxes in order for it to remain robust - that is to avoid interaction when debugging programs that themselves use GEM calls. In addition the mouse is not available within the debugger itself which makes things like true GEM buttons impossible. A MonST dialogue box displays the prompt ESC to abort above the top left corner of the box together with a prompt, normally followed by a blank line with a cursor. At any time a dialogue box may be aborted by pressing Esc, or data may be entered by typing. The cursor keys, Backspace and Del keys may be used to edit entered text in the usual way and the whole line may be delted by pressing the Clr key - note that this is different to GEM dialogue boxes which use the Esc key to delete a whole line of text. An entered line is terminated by pressing the Return key, though if the line contains errors the screen will flash and the Return key will be ignored allowing correction of the data before pressing Return again. Another difference is that dialogue boxes that require more than one line of data to be entered do not allow the use of the cursor up and down keys to switch between different lines - in MonST the lines have to be entered in order. A MonST alert box is a small box displaying a message together with the prompt (Return) and is normally used to inform the user of some form of error. The box will disappear on pressing the Return or Esc keys, whichever is more convenient. Initial Display Unless you have chosen the Debug option within the editor you will be presented with a dialogue box prompting for an executable program name. If you wish to debug a program from disk you should enter the filename (which defaults to an extension of .PRG) then press Return, then you will be prompted for any command line. If you do not wish to debug a program from disk at this stage, for example you wish to investigate memory, press the Esc key or enter a blank filename. Low Res: Certain features work differently or are not available when using MonST in low resolution. They are shown with this icon. Front Panel Display The main display of MonST is via a Front Panel showing registers, memory and instructions. The name Front Panel stems from the type of panels that were mounted on mainframe and mini computers to provide information on the state of the machine at a particular moment, usually through the use of flashing lights. These lights represent whether or not particular flip-flops (electronic switches) within the computer are open or closed; the flip-flops that are chosen to be shown on this panel are normally those that make up the internal registers and flags of the computer thus enabling programmers and engineers to observe what the computer is doing when running a program. So these are hardware front panel displays; what MonST provides you with is a software front panel - the code within MonST works out the state of your computer and then displays this information on the screen. The initial MonSt display consists of four windows, similar to those shown in Figure 4.1. In low-resolution the arrangement of two of the windows is slightly different to allow efficient use of the smaller available screen space. 1. Registers D0:00000000 601E 0100 00FC 0020 D1:00000000 601E 0100 00FC 0020 D2:00000000 601E 0100 00FC 0020 D3:00000000 601E 0100 00FC 0020 D4:00000000 601E 0100 00FC 0020 D5:00000000 601E 0100 00FC 0020 D6:00000000 601E 0100 00FC 0020 D7:00000000 601E 0100 00FC 0020 SR:0000 U PC:00FC0020 MOVE,W #$2700,SR A0:00000000 601E 0100 00FC 0020 0003 9752 A1:00000000 601E 0100 00FC 0020 0003 9752 A2:00000000 601E 0100 00FC 0020 0003 9752 A3:00000000 601E 0100 00FC 0020 0003 9752 A4:00000000 601E 0100 00FC 0020 0003 9752 A5:00000000 601E 0100 00FC 0020 0003 9752 A6:00000000 601E 0100 00FC 0020 0003 9752 A7:00000000 601E 0100 00FC 0020 0003 9752 A7'00000000 601E 0100 00FC 0020 0003 9752 2. Disassembly PC 00FC0020 *MOVE, W #$2700,SR 00FC0024 RESET 00FC0026 CMPI.L #$FA52235F,$FA0000 00FC0030 BNE.S $FC003C 00FC0032 LEA $FC003C(PC),A6 00FC0036 JMP $FA0004 00FC003C LEA $FC0044(PC),A6 00FC0040 BRA $FC0508 00FC0044 BNE,S $FC0050 00FC0046 MOVE,B $424,$FFFF8001 00FC0050 SUBA.L A5,A5 00FC0052 CMPI.L #$31415926,$426(A5) 3. Memory 00000000 601E 0100 00000004 00FC 0020 00000008 0003 9752 0000000C 0003 9758 00000010 0003 97C0 00000014 0003 97C6 00000018 0003 97CC 0000001C 0003 97D2 00000020 0003 97D8 00000024 0003 97DE 00000028 0003 9C48 0000002C 0003 953E MonST 2.0 HiSoft 1988 Figure 4.1 MonSt Initial Display The top window (number 1) displays the values of the data and address registers, together with the memory pointed to by these registers. The next window (number 2) is the disassembly window which displays several lines of instructions, by default based around the program counter (PC), shown in the title area of the window. A => sign is used to denote the currant value of the PC Window number 3 is the memory window which displays a section of memory in word-aligned hex and ASCII. The final window at the bottom of the screen, which is un- numbered, is the smallest window and is used to display messages. One of the most powerful features of MonST is its flexibility with windows - up to 2 additional windows may be created, the font size can be changed, and windows may be locked to particular registers, these features are detailed later. Simple Window Handling MonST has the concept of a current window - this is denoted by displaying its title in black. The current window may be changed by pressing the Tab key to cycle between them, or by pressing the Alt key together with the window number, for example Alt-2 selects the disassembly window. (AZERTY keyboard users please note - the Shift key is not required when using Alt to select windows). Note that the lowest window can never may made the current window - it is used solely for displaying messages. Command Input MonST is controlled by single-key commands which creates a very fast user-interface, though this can take getting used to if you are familiar with a line-oriented command interface of another debugger. Users of HiSoft Devpac on other machines will find many commands are identical, particulary with the Spectrum and QL debuggers, though the window commands are unique to MonST. In general the Alt key is the window key - when used in conjunction with other keys it it acts on the current window. Commands may be entered in either upper or lower case. Those commands whose effects are potentially disastrous require the Ctrl key to be pressed in addition to a command key. The keys used where chosen to be easy to remember, wherever possible. Commands take effect immediately - there is no need to press Return and invalid commands are simply ignored. The relevant sections of the front panel display are updated after each command so any effects can be seen immediately. MonSt is a powerful and sometimes complex program and we realise that it is unlikely that many users will use every single command. For this reason the remainder of the MonST manual is divided into two sections - the former is an introduction to the basic commands of the program, while the latter is a full reference section. It is possible for new users and beginners to use the debugger effectively while having only read the Overview; don't be intimidated by the Reference section. MonST Overview To start with you will need to load a program to debug; if you have assembled a program to memory you can use the Debug option from the editor, else you will need to load a program from disk. When initially loaded you will be prompted for a file name, if you got an error or didn't specify a filename you can have another go by pressing Ctrl-L. A program's symbols will be used by the debugger, if found. A program will have symbols included if you used the Debug or Extended Debug options of the assembler. The extended debug option means you will get longer symbols, the normal option forces them to be truncated to 8 characters. The most common command in MonST is probably single-step, obtained by pressing Ctrl-Z (or Ctrl-Y if you find it more convenient). This will execute the instruction at the PC, the one shown in the Register window and, normally, also in the Disas� sembly window. After executing it the debugger re-displays the values of the registers and memory displayed, so you can watch the processor execute your program, step by step. Single-stepping is the best way of going through sections of code that are suspect and require deeper investigation, but it is also the slowest - you may only be interested in a section of code near the end of your program which could take ages to get to if you have to single-step all the way. There is, of course, an answer. A breakpoint is a special word placed into your program to stop it running and enter MonST. There are many types of breakpoint but we will restrict ourselves to the simplest for now. A breakpoint may be set by pressing Alt-B, then entering the address you wish to place the breakpoint. You can enter addresses in MonSt in hex (the default base), as a symbol, or as a complex expression. Examples of a valid address are 1A2B0, prog_start, 10+mydata. If you type in an invalid address the screen will flash and allow you to correct the expression. Having set a breakpoint you need some way of letting your program actually run, and Ctrl-R will do this. If will execute your program using the registers displayed and starting from the PC. MonST will be re-entered if a breakpoint has been hit, or if an exception occurs. MonST uses its own screen display which is independent from your own programs. If you press the v key you will see your current programs display, pressing another key switches you back to MonST. This allows you to debug programs without disturbing their output at all. MonST uses its own windows to, and any window may be zoomed to the full screen size by pressing Alt-Z. To return to the main display press Alt-Z or the Esc key. The Esc key is also the best way of getting out of anything you may have invoked by accident. The Zoom command, like all Alt- commands, works on the current window which you can change by pressing Tab. You can dump the current window to your printer by pressing Alt-P. To change the address from which a window displays its data, press Alt-A, then enter the new address. Note that the disassembly window will always re-display from the PC after you single-step, because it is locked to the PC. The locking of windows is detailed in the Reference section. To quit MonST press Ctrl-C. Strange as it may sound this will not always work - what Ctrl-C does is terminate the current program, which may be MonST or, more likely, the program you are debugging. You know when you have terminated the program under investigation because it will say so in the lower window. Once your program has been terminated, pressing Ctrl-C will terminate MonST. If you used the Debug option from the editor then Ctrl-C will always terminate MonST as well as your program. We hope this overview has given you a good idea of the most common features of MonST to let you get on with the complex process of writing and debugging assembly language programs. When you feel more confident you should try and read the Reference section, probably best taken, like all medicine, in small doses. MonST REFERENCE Numeric Expressions MonST has a full expression evaluator, based on that in GenST, including operator precedence. The main differences are that the default base is hexadecimal (decimal may be denoted with a \ sign), there is no concept of types of expressions (relative or absolute), ø is used only for multiplication and there is a not- equals operator, <>. Symbols may be referred to and are normally case-sensitive and significant to either 8 or 22 characters (depending on the form of debug used), though this can be changed with Preferences. Registers may be referred to simply by name, such as A3 or D7 (case insensitive), but this clashes with hex numbers. To obtain such hex numbers precede them with either a leading zero or a $ sign. A7 refers to the user stack pointer. There are several reserved symbols which are case insensitive, namely TEXT, DATA, BSS, END, SP, SR, and SSP. END refers to one byte past the end of the BSS section and SP refers to either the user- or supervisor-stack, depending on the current value of the status register. In addition there are 10 memories numbered M0 through M9, which are treated in a similar way to registers and can be assigned to using the Register Set command. Memories 2 through 5 inclusive refer to the current start address of the relevant window and assigning to them will change the start address of that window. The MonSt expression evaluator also supports indirection using the { and } symbols. Indirection may be performed on a byte word or long basis, by following the } with a period then the required size, which defaults to long. If the pointer is invalid, either because the memory is unreadable or even (if the word or longword indirection is used) then the expression will not be valid. For example, the expression {data_start+10},w will return the word contents of location data_start+10, assuming data_start is even. Indirection may be nested in a similar way to ordinary parenthesis. Window Types There are four window types and the exact contents of these windows and how they are displayed is detailed below. The allowed types of windows is shown in the table below. Window Allowed Types 1 Register 2 Disassembly 3 Memory 4 Disassembly, Memory or Source-code 5 Memory Register Window Display The data registers are shown in hex, together with the ASCII display of their low byte and then a hex display of the eight bytes they point to in memory. The address registers are also shown in hex, together with a hex display of 12 bytes. As with all hex displays in MonST this is word-aligned, with non-readable memory. The status register is shown in hex and in flag form, additionally with U or S denoting user- or supervisor-modes. A7' denotes the supervisor stack pointer, displayed in a similar way to the other address registers. The PC value is shown together with a disassembly of the current instruction. Where this involves one or more effective addresses these are shown in hex, together with a suitably-sized display of the memory they point to. For example, the display TST.W $12A(A3) ;00001FAE 0F01 signifies that the value of $12A plus register A3 is $1FAE, and that the word memory pointed to by this is $0F01. A more complex example is the display MOVE.W $12A(A3),-(SP) ;00001FAE 0F01 =>002AC08 FFFF The source addressing mode is as before but the destination address is $2AC08, presently containing $FFFF. Note that this display is always of a suitable size (MOVEM data being displayed as a quad-word) and when pre-decrement addressing is used this is included in the address calculations. Low Res: No hex data is shown for the data registers and the address register data area is reduced to 4 bytes. In addition the disassembly line may not be long enough to display complex addressing modes such as the second example above. Disassembly Window Display Disassembly windows display memory as disassembled instructions to the standard described below. On the left the hex address is shown, followed by any symbol, then the disassembly itself. The current value of the PC is denoted with =>. If the instruction has a breakpoint placed on it this is shown using square brackets ([ ]) afterwards, the contents of which depend on the type of breakpoint. For stop breakpoints this will be the number of times left for this instruction to execute, for conditional breakpoints this will be a ? followed by the beginning of the conditional expression, for count breakpoints this will be a = sign followed by the current count, and for permanent breakpoints a symbol resembling a small zero in superscript is shown. The exact format of the disassembled op-codes is Motorola standard, as GenST accepts. All output is upper-case (except lower-case labels) and all numeric output is hex, except Trap numbers. Leading zeroes are suppressed and the $ hex delimiter is not shown on numbers less than 10. Where relevant numerics are shown signed. the only deviation from Motorola standard is the register lists shown in MOVEM instructions - in order to save display space the type of the second register in a range is abbreviated, for example MOVEM.L d0-d3/a0-a2,-(sp) will be disassembled as MOVEM.L d0-3/a0-2,-(sp) Low Res: Any displayed symbols replace the hex address display, limited to a maximum of 8 characters Memory Window Display Memory windows display memory in the form of a hex address, word-aligned hex display and ASCII. Unreadable memory locations are denoted by (two zeros in superscript). The number of bytes shown is calculated from the window width, up to a maximum of 16 bytes per line. Source-code Window display The source code window displays ASCII files in a similar way to a screen editor. The default tab setting is 8 though this can be toggled to 4 with the Edit Window command. Window Commands The Alt key is generally used for controlling windows, and when used to apply to the current window. This is denoted by having an inverse title and can be changed by pressing the Tab or Alt plus the window number. Most window commands work in any window, zoomed or not, though when it does not make sense to do something the command is ignored. Alt-A Set Address This sets the starting address of a memory or disassembly window. Alt-B Set Breakpoint Allows the setting of any type of breakpoint, described later under Breakpoints. Alt-E Edit Window On a memory window this lets you edit memory in hex or ASCII. Hex editing can be accomplished using keys 1-9, A-F, together with the cursor keys. Pressing Tab switches between hex & ASCII, ASCII editing takes each keypress and writes it to memory. The cursor keys can be used to move about memory. To leave edit mode press the Esc key. On a register window this is the same as Alt-R, Register Set, described shortly. On a source code window this toggles the tab setting between 4 and 8. Alt-F Font size This changes the font size in a window. In high resolution 16 and 8 pixel high fonts are used, in colour 8 and 6 pixel high fonts are used. This allows a greater number of lines to be displayed, assuming your monitor can cope. Changing the font size on the register window causes the position of windows 2 and 3 to be re-calculated to fill the available space. Alt-L Lock Windows This allows disassembly and register windows to be locked to a particular register. After any exception the start address of the window is re-calculated, depending on the locked register. To unlock simply enter a blank string. By default window 2 is locked to the PC. You can lock windows to each other by specifying a lock to a memory window, ash as M2. Alt-O Show Other This prompts for an expression and displays it in hex, decimal and as a symbol if relevant. Alt-P Printer Dump Dumps the current window onto the printer. It can be aborted by pressing Esc. Alt-R Register Set Allows any register to be set to a value, by specifying the register, an equals sign, then its new value. It can also be used to set the value of memories. For example the line a3=a2+4 sets register A3 to be A2 plus 4. You can also use this to set the start address of windows when in zoom mode so that on exit from zoom mode the relevant window starts at the required address. Note: Do not assign M4 if window 4 is currently a source-code window. Alt-S Split windows This either splits windows 2 into 2 and 4, or splits window 3 into 3 and 5. Each new window is independent from its creator. Pressing Alt-S again will un-split the window. Low Res: This command has no effect. Alt-T Change Type This only works on window 4 (created either by splitting window 2 or by loading a source file). It changes the type of the window between disassembly, memory and source-code (if a file has been loaded). Alt-Z Zoom Window This zooms the current window to be full size. Other Alt commands are still available and normal size can be achieved by pressing Esc or Alt-Z again. Note: Zooming the register windows is unlikely to be useful. Cursor Keys The cursor keys can be used on the current window, the action of which depends on the window type. On a memory window all four cursor keys change the current address, and Shift Up Cursor and Shift Down Cursor move a page in either direction. On a disassembly window Up Cursor and Down Cursor change the start address on an instruction basis, Left Cursor and Right Cursor change the address on a word basis. On a source-code window Up Cursor and Down Cursor change the display on a line basis and Shift Up Cursor and Shift Down Cursor on a page basis. Screen Switching MonST uses its own screen display and drivers to prevent interference with a program's own screen output. To prevent flicker caused by excessive screen switching when single-stepping the screen display is only switched to the program's after 20 milliseconds, producing a flicker-free display while in the debugger. In addition the debugger display can have a different screen resolution to your program's if using a colour monitor. V View Other Screen This flips the screen to that of the programs, any key returns to the MonST display. Ctrl-O Other Screen Mode This changes the screen mode of MonST's display between low and medium resolution. It re-initialises window font sizes and positions to the initial display. This will not affect the screen mode of the program being debugged. This command is ignored on a monochrome monitor. As MonST has its own idea of where the screen is, what mode it is in and what palettes to use you can use MonST to actually look at the screen memory in use by your program, ideal for low-level graphics programs. Note: If your program changes screen position or resolution, via the XBIOS or the hardware registers, it is important that you temporarily disable screen switching using Preferences while executing such code else MonST will not notice the new attributes of your program's screen. When a disk is accessed, when loading or saving, the screen display will probably switch to the program's during the operation. This is in case a disk error occurs, such as write- protected or read errors, as it allows any GEM alert boxes to be seen and acted upon. Breaking into Programs Shift-Alt-Help Interrupt Program While a program is running it can be interrupted by pressing this key combination, which will cause a trace exception at the current value of the PC. With computationally-intense program sections this will be within the program itself but with a program making extensive use of the ROM, such as the BDOS or AES, the interruption will normally be in the ROm itself, or the line- F handler stored in low-memory. If this is the case it is recommended that a breakpoint be placed in your actual program area then a Return to Program command (Ctrl-R) issued. Pressing Alt-Help without the Shift key will normally produce a screen dump to the printer - if you press this accidentally it should be pressed again to cancel the dump. It is possible for this key combination to be ignored when pressed - if this occurs press it again when it should work. Pressing it when in MonST will produce no effect. Note: A program should never be terminated (using Ctrol-C) if it has just been interrupted in the middle of a ROM routine. This is likely to cause a system crash. Breakpoints Breakpoints allow you to stop the execution of your program at specified points within it. MonST allows up to eight simultaneous breakpoints, each of which may be one of five types. When a breakpoint is hit MonST is entered and then decides whether or not to halt execution of your program, entering the front panel display, or continue, this decision is based on the type of the breakpoint and the state of your program's variables. Simple Breakpoints These are one-off breakpoints which, when executed, are cleared and cause MonST to be entered. Stop Breakpoints These are breakpoints that cause program execution to stop after a particular instruction has been executed a particular number of times. In fact a simple breakpoint is really a stop breakpoint with a count of one. Count Breakpoints Merely counters; each time such a breakpoint is reached a counter associated with it is incremented, and the program will resume. Permanent Breakpoints These are similar to simple breakpoints except that they are never cleared - every time execution reaches a permanent breakpoint MonST will be entered. Conditional Breakpoints The most powerful type of breakpoint and these allow program execution to stop at a particular address, only if an arbitrarily complex set of conditions apply. Each conditional breakpoint has associated with it an expression (conforming to the rules already described). Every time the breakpoint is reached this expression is evaluated, and if it is non-zero (i.e. true) then the program will be stopped, otherwise it will resume. Alt-B Set Breakpoint This is a window command allowing the setting or clearing of breakpoints at any time. The line entered should be one of the following forms, depending on the type of breakpoint required. <address> will set a simple breakpoint. <address>,<expression> will set a stop breakpoint at the given address, after it has executed <expression> times. <address>,= will set a count breakpoint. The initial value of the count will be zero. <address>,(small zero in superscript) will set a permanent breakpoint. <address>,?<Expression> will set a conditional breakpoint, using the given expression. <address>,- will clear any breakpoint at the given address. Breakpoints cannot be set on addresses which are odd or unreadable, or in ROM though ROM breakpoints may be emulated using the Run Until command. Every time a breakpoint is reached, regardless of whether the program is interrupted or resumed, the program state is remembered in the History buffer, described later. Help Show Help and Breakpoints This displays the text, data and BSS segment addresses and lengths, together with every current breakpoint, Alt-commands are available within this display. Ctrl-B Set Breakpoint Included mainly for compatibility with MonST 1, this sets a simple breakpoint at the start address of the current window, so long as it is a disassembly window. If a breakpoint is already there then it will be cleared. U Go Until This prompts for an address, at which a simple breakpoint will be placed then program execution resumed. Ctrl-K Kill Breakpoints This clears all set breakpoints. Ctrl-A Set Breakpoint then Execute A command that places a simple breakpoint at the instruction after that at the PC and resumes execution from the PC. This is particularly for DBF-type loops if you don't want to go through the loop, but just want to see the result after the loop is over. Ctrl-D BDOS Breakpoint This allows a breakpoint to be set on specific BDOS calls. The required BDOS number should be entered, or a blank line if any existing BDOS breakpoint needs to be cleared. History MonST has a history buffer in which the machine status is remembered for later investigation. The most common way of entering data into the history buffer is when you single-step, but in addition every breakpoint reached and every exception caused enters the machine state into the buffer. Various forms of the Run command also cause entries to be made into this buffer. Note: The history buffer has room for five entries - when it fills the oldest entry is removed to make room for the newest entry. H Show History Buffer This opens a large window displaying the contents of the history buffer. All register values are shown including the PC as well as a disassembly of the next instruction to be executed. Note: If a disassembly in the History display includes an instruction which has a breakpoint placed on the [ ]s will show the current values for that breakpoint, not the values at the time of the entry into the history buffer. Quitting MonST Ctrl-C Terminate This will issue a terminate trap to the current GEMDOS task. If a program has been loaded from within MonST it will be terminated and the message Program Terminated appear in the lower window. Another program can be loaded, if required. If no program has been loaded into MonST it will itself terminate when this command is used. If the Debug option has been used from the GenSt editor then MonST will terminate automatically when the program it is debugging has terminated. Note: Terminating some GEM programs prematurely, before they have closed workstations window control properly can seriously confuse the AES and VDI. This may not be noticeable immediately but often causes crashes when a subsequent program is executed. Loading & Saving Ctrl-L Load Executable Program This will prompt for an executable filename then a command line and will attempt to load the file ready for execution. If MonST has already loaded a program it is not possible to load another until the former has terminated. The file to be loaded must be an executable file - attempting to load a non-executable file will normally result in TOS error 66 and further attempts to load executable files will normally fail as GEMDOS does not de-allocate the memory it allocated before trying to load the errant file. If this occurs terminate MonST then re-execute it and use the Load Binary File command. Note: This command in not available in the auto-resident version of MonST or in MonST invoked using Debug from the editor. B Load Binary File This will prompt for a filename and optional load address (separated by a comma) and will then load the file where specified. If no load address is given then memory will be allocated from GEMDOS and used. M0 will be set to the start address and M1 to the end address. S Save Binary File This will prompt for a filename, a start address and an (inclusive) end address. To re-save a file recently loaded with the above command <filename>,M0,M1 may be specified, assuming of course that M0 and M1 may be specified, assuming of course that M0 and M1 have not been re-assigned. A Load ASCII File This powerful command allows an ASCII file, normally of source code, to be loaded and viewed within MonST, Window 4 will be created if required then set up as a source code window. Memory for the source code is taken from GEMDOS so sufficient free memory must be available. It is recommended that source-code be loaded before an executable program to ensure enough memory. Low Res: Window 4 is not an ASCII file though may be loaded in low-res then viewed after switching to medium resolution using Ctrl-O and pressing Alt-S, Alt-T, Alt-T. Note: If an ASCII file is loaded after an executable program the memory used will be owned by the program itself, not MonST. when such a program terminates, any displayed source-code window will be closed. The auto-resident version of the debugger cannot detect this so care should be taken if loading source code into it. Executing Programs Ctrl-R Return to program/Run This runs the current program with the given register values at full speed and is the normal way to resume execution after entry via a breakpoint. Ctrl-Z Single-Step This single-steps the instruction at the PC with the current register values. Single-stepping a Trap, Line-A or Line-F opcode will, by default, be treated as a single instruction. This can be changed using Preferences. Ctrl-Y Single-Step Identical to Ctrl-Z above but included for the convenience of German users. Ctrl-T Interpret on Instruction (Trace) This interprets the instruction at the PC using the displayed register values. It is similar to Ctrl-Z but skips over BSRs, JSRs, Traps, Line-A and Line-F calls, re-entering the debugger on return from them to save stepping all the way through the routine or trap it works on instructions in ROM or RAM. R Run (various) This is a general Run command and prompts for the type of the Run to be done, selected by pressing a particular key. Run G Go This is identical to Ctrl-R, and resumes the program at full speed. Run S Slowly This will run the program at reduced speed, remembering every step in the history buffer. Run I Instruction This is similar to Run Slowly but allows a count to be entered, so that a particular number of instructions may be executed before MonST is entered. Run U Until You will be prompted for an expression which will be evaluated after every instruction. The program will then run, albeit at reduced speed, until the given expression evaluates to non-zero (true) when MonST will be entered. For example if single-stepping a DBF loop which used d6 in the ROM code you could say Run Until d6&ffff=ffff (waiting for the low word of d6 to be $FFFF) or, alternatively, PC=FC8B1A, or whatever. Note: This should not be confused with the Until command which takes an address, places a breakpoint there then resumes execution. With all of these commands (except Run Go) you will then be asked Watch Y/N? If Y is selected then the MonST display will be shown after every instruction and you can watch registers and memory as they change, or interrupt execution by pressing both Shift keys simultaneously. If N is selected then execution will occur while showing your program's display and execution may be interrupted by pressing Shift-Alt-Help. Note: Selection Watch mode with screen switching turned off is likely to result in a great deal of eye strain as the display will be flipped after each and every instruction, particularly alarming with colour monitors. With any of these Run modes (except Go) all information after every instruction will be remembered in the history buffer. In addition Traps will be treated as single-instructions, unless changed with Preferences, though see the warnings under that command about tracing all the way through ROM routines. When a program is running with one of the above modes a couple of pixels near the top left of the display will flicker, to denote that something is happening, as it is possible to think the machine has hung when in fact, it is simply taking a while to Run through the code an instruction at a time. Searching Memory G search memory (Get a sequence) This will prompt Search for B/W/L/T/I?, standing for Bytes, Words, Longs, Text and Instructions. If you select B, W or L you will then be prompted to enter the sequence of numbers you wish to search for, each separated by commas. MonST is not fussy about word-alignment when searching, so it can find longs on odd boundaries, for example. If you select T you may search for any given text string, which you will be prompted for. The search will be case-dependent. If you select I you can search for part or all of the mnemonic of an instruction, for example if you searched for $14 (A you would find an instruction like MOVE.L D2,$14(A0). The case of the string you enter is important (unlike MonST version 1), but you should bear in mind the format the disassembler produces, e.g. always use hex numbers, refer to A7 rather than SP and so on. Having selected the search type and parameters, the search begins, control passing to the Next command, described below. N find Next This can be used after the G command to find subsequent occuren� ces of the search data. With the B, W, L and T options you will always find at least one occurrence, which will be in the buffer within MonST that is used for storing the sequence. With the T option you may also find a copy in the system keyboard buffer. With these options, the Esc key is tested every 64k bytes and can be used to stop the search. With the be used to stop the search. With the I option, which is very much slower, the Esc key is tested every 2 bytes. The search area of memory goes from 0 to the end of RAM, then from $FA0000 to $FEFFFF (the cartridge and system ROM area), then back to 0. The search will start just past the start address of the current window (except register windows) and if an occurrence is found re-display the window at the given address. Searching Source-Code Windows If the G command is used on a source-code window the T sub- command is automatically chosen and if the text is found the window will re-display the line containing it. Miscellaneous Ctrl-P Preferences This permits control over various options within MonST. The first three require Y/N answers, pressing Esc aborts or Return leaves them alone. Screen Switching Defaulting to On, this causes the display to switch to your program's only after 20 milliseconds. It should be switched off when a program is about to change a screen address or resolution, then turned back on afterwards. Follow Traps By default single-stepping and the various forms of the run command treat Traps, Line A and Line F calls as single instructions. However by turning this option On the relevant routines will be entered allowing ROM code to be investigated. Note: Important: This option should be used with care. Certain time critical routines, such as the floppy- or hard-disk drivers have portions of code designed to be atomic, i.e. not interrup table, and being traced will cause malfunctions within such code and possible loss of data. On the other hand it can be fun to watch the AES as it draws pull-down menus or opens windows. If you have let ROM execute for a while you can interrupt it by pressing Shift-Alt-Help, then resume at normal speed by pressing Ctrl-R. However the AES and VDI both use Line-A and Line-F calls and it is very likely that there are pending stack frames left with the Trace bit set, so having resumed a traced program it is likely that seemingly spurious trace exceptions will be generated. Pressing Ctrl-R will resume at normal speed, though a few more such exceptions are likely until program flow reaches the lowest level, i.e. your program. There is a side effect of this that can cause machine to crash though: If you have traced through any AES event-type calls then stack frames can be created in desk accessories with the Trace bit set. If your program terminates before the accessory has a chance to respond to its own event call, a trace exception will occur after MonST terminates and returns to the Desktop or GenST, causing a system crash, unless an auto-resident MonST is installed or the NOTRACE.PRG program is used. NOTRACE Program This is a very small program intended to be added to the AUTO folder of your boot disk which causes trace exceptions to be ignored, instead of producing a large number of bombs as it will do by default. The source code is also supplied. Relative Offsets This option defaults to On and effects the disassembly of the address register indirect with offset addressing modes, i.e. xxx(An). With the option on the current value of the given address register is added to the offset then searched for in the symbol table. If found it is disassembled as symbol (An). This option is very useful for certain styles of assembly language programming as well as high level languages which use a base register as a major offset, such as HiSoft BASIC which uses A3 as a pointer to the run-time system. Symbols Option This allows control over the use of symbols in expressions in MonST. It will firstly ask whether the case of symbols should be ignored, pressing Y will cause case independent searching to be used. It will then prompt for the maximum length of symbols, which is normally 22 but may be reduced to as low as 8. I Intelligent Copy This copies a block of memory to another area. The addresses should be entered in the form <start>,<inclusive end>,<destination> The copy is intelligent in that the block of memory may be copied to a location which overlaps its previous location. NOTE: No checks at all are made on the validity of the move; copying to non-existent areas of memory is likely to crash MonST and corrupting system areas may well crash the machine. L List Lables This opens up a large window and displays all loaded symbols. Any key displays the next page, pressing Esc aborts. The symbols will be displayed in the order they were found on the disk (or in memory if using the Debug option from the editor). W Fill Memory With This fills a section of memory with a particular byte. The range should be entered in the form <start>,<inclusive_end>,<filbyte> The warning described previously about no checks applies equally to this command. P Disassemble to Printer/Disk This command allows the disassembly of an area of memory to printer or disk, complete with original labels and, optionally, an automatic list of labels created by MonST, based on cross- references. The first line should be entered as <buffer_start>,<buffer_end> Next is the prompt for data areas which will be disassembled as DC instructions, of the form <data_start>,<data_end>[,<size>] The optional size field should be B, W or L , defaulting to L, determining the size of the data. When all data areas have been defined, a blank line should be entered. Finally, a filename prompt will appear; if this is blank all output will be to the printer, else it will be assumed to be a disk file. If automatic labels were specified there may be a delay at this point while the table is generated. Automatic labels are of the form Lxxxxx where xxxxx is the actual hex address. Printer Output This is of the form of an 8 digit hex number, then up to 10 words of hex data, 12 characters of any symbol, then the disassembly itself. Printer output may be aborted by pressing Esc. Disk Output This is in a form directly loadable by GenST, consisting of any symbol, a tab, then the disassembly itself, with a tab separating any operand from the op-code. If you are disassembling an area of memory without loaded symbols then the XREF option should be used else no symbols will appear in the output file. Pressing Esc or a disk error will abort the disassembly. M Modify Address Included for compatibility with MonST 1, equivalent to Alt-A. O Show Other Bases Included for compatibility with MonST 1, equivalent to Alt-O. D Change Drive & Directory This allows the current drive and sub-directory to be changed. Auto-Residemt MonST The additional version of MonST called AMONST2.PRG will now be described. When placed in the AUTO folder on a boot disk, it will be loaded and initialised automatically on boot-up. Once booted, this version of MonSt lies dormant, ready to be invoked when any exception occurs in the machine, such as an address error. It is intended primarily for programmers writing and debugging desk accessories or other AUTO-type applications, as if there is a problem in the code which gets called as the machine boots, it hangs before you get a chance to use the normal MonST. If required you can deliberately put an illegal opcode, such as ILLEGAL, at the start of your auto program so that MonST will be invoked then use it to investigate any problems your code has. The auto-resident version may be double-clicked from the Desktop and will initialise itself in the same way as from the AUTO folder, unless a version of MonST is already resident. Once invoked the auto-resident version is very similar in use to the other versions except that programs or labels cannot be loaded and the base page variables are unknown and so set to 0. The other difference is that when the program being debugged exits or Ctrl-C is pressed within MonST, MonST itself stays active in memory. In addition any program may be interrupted by pressing the Shift- Alt-Help key combination when a resident version of MonST is installed. The resident version of MonST cannot be reclaimed from memory except by resetting the machine and booting with a disk which does not contain MonST in the AUTO folder. When an auto-resident version of MonST is loaded, the usual versions can still be used as normal, memory permitting, and the resident version will be ignored until the non-resident version exits, when it will become active once again. Note: Do not invoke an auto-resident MonST from within a program other than the Desktop, such as using Run Other from within GenST, as large areas of system memory will become locked away and unusable until a machine reset. If both shift keys are held down during the installation of the auto-resident MonST, the debugger is itself entered, allowing the editing of memory or setting of BDOS breakpoints. When entered via this method the debugger should be left using Ctrl-C when the debugger will remain resident. Command Summary Window Commands Alt-A ..................... Set Address Alt-B ..................... Set Breakpoint Alt-E ..................... Edit Window Alt-F ..................... Font Size Alt-L ..................... Lock Window Alt-O ..................... Show Other Alt-P ..................... Printer Dump Alt-R ..................... Register Set Alt-S ..................... Split Windows Alt-T ..................... Change Type Alt-Z ..................... Zoom Window Screen Switching V ......................... View Other Screen Ctrl-O .................... Other Screen Mode Breakpoints Alt-B ..................... Set Breakpoint Help ...................... Show Help and Breakpoints Ctrl-B .................... Set Breakpoint U ......................... Go Until Ctrl-K .................... Kill Breakpoints Ctrl-A .................... Set Breakpoint then Execute Ctrl-D .................... BDOS Breakpoint Loading and Saving Ctrl-L .................... Load Executable Program B ......................... Load Binary File S ......................... Save Binary File A ......................... Load ASCII File Executing Programs Ctrl-R .................... Return to program/Run Ctrl-Z .................... Single-Step Ctrl-Y .................... Single-Step Ctrl-T .................... Interpret an Instruction (Trace) R ......................... Run (various) Searching Memory G ......................... Search Memory (Get a sequence) N ......................... Find Next Miscellaneous Ctrl-C .................... Terminate Ctrl-P .................... Preferences I ......................... Intelligent Copy W ......................... Fill Memory With L ......................... List Labels P ......................... Disassemble to Printer/Disk M ......................... Modify Address O ......................... Show Other Bases D ......................... Change Drive & Directory Shift-Alt-Help ............ Interrupt Program H ......................... Show History Buffer Debugging Stratagem Hints & Tips If you have interrupted a program using Shift-Alt-Help or by a Run Until command and have found yourself in the middle of the ROM, there is a way of returning to the exact point in your program which called the ROM. Firstly ensure the Follow Traps option is on, then do Run Until with an expression of sp=a7. This will re-enter MonST the moment user mode is restored which will be in your program. If you are in a subrouting which doesn't interest you and want to let it run but return to MonST the easiest way is to use Until (not Run Until) then specify the expression (sp) - this sets a breakpoint at the return address. If the subroutine has placed something on the stack, or uses a local stack frame (normally the case for compiled programs) then try Run Until (pc).w=4e75 which will run slowly until the instruction RTS is reached. This won't work if the subroutine in question calls another, so it may require a further condition, such as ({pc}.w=4e75)&(sp>xxx) where xxx is one less than the current value. When using Run Until and you know it will take a quite a while for the condition to be satisfied, give MonST a hand by pre- computing as much of the expression as you can, for example (a3>(3A400-\100+M1)) could be reduced to a3>xxx where xxx has been calculated by you using the Alt-O command. MonST Command Line If you use a CLI-type program you can pass a command line to MonST, consisting of the program you wish to load and optionally, a command line to pass on to it. Bug Hunting There are probably as many strategies for finding bugs as there are programmers; there is really no substitute for learning the hard way, by experience. However, there are some hints which we have learnt, the hard way! Firstly, a very good way of finding bugs is to look at the source code and think. The disadvantage of reaching first for the debugger, then second for the source code, is that it gets you into bad habits. You may switch to a machine or programming environment that does not offer low-level debugging, or at least not one as powerful as you are used to. If a program fails in a very detectable way, such as causing an exception, debugging is normally easier than if, say, a program sometimes doesn't quite work exactly as it should. Many bugs are caused by a particular memory location being stepped on. Whether the offending memory location is detectable, by producing a bus error, for example, a conditional breakpoint placed at one or more main subroutines can help greatly. For example, suppose the global variable main_ptr is somehow becoming odd during execution, the conditional expression could be set up as {main_ptr]&1 If this method fails, and the global variable is being corrupted somewhere un-detectable, the remaining solution is to Run Until that expression, which could take a considerable time. Even then it may not find it, for example if the bug is caused by an interrupt happening at a certain time when the stack is in a particular place. Count breakpoints are a good way of tracking down bugs before they occur. For example, suppose a particular subroutine is known to eventually fail but you cannot see why, they you should set a count breakpoint on it, then let the program run. At the point where the program stops, because of an exception say, look at the value of the count breakpoint (using Help). Terminate the program, re-load it, then set a stop breakpoint on the subroutine for that particular value or one before it. Let it run, then you can follow through the sub-routine on the very call that it fails on, to try and work out why. Good luck! AUTO-folder programs If these crash during initialisation then use AMONST (which must be before your program in the directory) to catch the exception. Including a deliberate ILLEGAL instruction at its beginning will let you single step the initialisation. Desk Accessories If an accessory is mis-behaving during normal execution then use AMONST. To find a desk accessory in memory, enter the debugger by pressing Shift-Alt-Help then start looking from location 0 for the upper-cased name of your .ACC file, padded to eight characters with spaces. Ignore occurrences within directory buffers (these will be preceded by an ASCII T character). The correct occurrence will have a longword 12 bytes after the start of the name. This will point to the basepage of your accessory and $100 bytes after that will be the start of your program. From looking at this you should be able to find your main loop and set a suitable breakpoint. Normal execution should be resumed with Ctrl-R then MonST will be re-entered when your breakpoint is reached. If an accessory is misbehaving during its initialisation then you have to stop it at the very beginning before it has a chance to do anything. The recommended way is to re-assemble the accessory with an ILLEGAL instruction at the beginning and let AMONST catch it, but this is sometimes not possible. There follows a method that works on current ST ROMs to stop the AES just before it executes your program, but please note the method is complicated and not recommended for beginners. Firstly hold down both shift keys to enter AMONST during the boot sequence then set a BDOS Breakpoint on the Open call, $3D, then press Ctrl-C to let the boot sequence resume. MonST will be re-entered every time something tries to Open a file, so make window 3 the current window and after every BDOS breakpoint is hit set its address to (sp+2) - if the name is not your accessory then Ctrl-Z, to execute the Open call, set another BDOS breakpoint on $3D then Ctrl-R, and try again. If the name is your accessory then set a BDOS breakpoint on $4B, then Ctrl-R. MonST will then be entered just before it loads the accessory, so Ctr-Z to do the GEMDOS call, then Alt-B and enter d0+100 which sets a breakpoint on the very first instruction. Now Ctrl-R and the next time MonST appears it will be on the first instruction of the accessory. This method takes a while but it's often the only way of finding bugs in accessories. Exception Analysis When an unexpected exception occurs, it's very useful to be able to work out where and why it occurred and, possibly, to resume execution. Bus Error If the PC is in some non-existent area of memory then look at the relevant stack to try and find a return address to give a clue as to the cause, probably an unbalanced stack. If the PC is in a correct area of your program then the bus error must have been caused by a memory access to non-existent or protected memory. Recovering from bus errors and resuming execution is generally not possible. Address Error If the PC is somewhere strange the method above should be used, otherwise the error must have been caused by a program access to an odd address. Correcting a register value may be enough to resume execution, at least temporarily. Illegal Instruction If the PC is in very low memory, below around $30, it is probable that it was caused by a jump to location 0. If you use MonST to look here you will see a short branch together with normally, various ORI instructions (really longword pointers) and eventually an illegal instruction. Privilege Violation This is caused by executing a privileged instruction in user mode, normally meaning your program has gone horribly wrong. Bumping the PC past the offending instruction is unlikely to be much help in resuming the program.
Back to Devpac_Manual