Most programmers are familiar with the process of debugging code. Many, however, will not be familiar with the issues of debugging programs in an entirely object-oriented, multithreaded system in which memory is often sharable by multiple programs. Because this type of system presents not only incredible power but also a new class of potential bugs, the GEOS tool kit provides a new class of symbolic debugger.
Swat is more than just a debugging program; it is an extensible debugging environment which you can tailor to your needs. Because all Swat commands are programmed in a special language called Tool Command Language (Tcl), you can write your own commands or extend existing commands. Tcl was originally developed by Professor John Ousterhout at the University of California in Berkeley, California. Swat itself was developed during a project headed by professor Ousterhout for a distributed multiprocessing operating system; Geoworks gained permission from the university to use and modify Swat. Since then, we have tailored it for use with GEOS; thus, it is the most appropriate debugger for any GEOS programmer.
Swat is essentially a system debugger, as opposed to an application debugger. This is an important distinction, due to the multithreaded nature of individual GEOS applications--each application may have more than one thread, and a system debugger greatly eases the debugging process for such applications. Swat also has many other features that make it preferable to other debuggers:
help
facility is available from the basic Swat command prompt, and you can use it either as an interactive help shell or to get help on one particular topic. Swat also offers many other features that both novices and experts will use. As you gain familiarity with Swat while using Swat with the sample applications and with your own programs, you will discover your own preferred methods of debugging.
1 DOS Command Line Options
2 Notation
3 Address Expressions
4 On-line Help
5 Essential Commands
5.1 Cycle of Development
5.2 Attaching and Detaching
5.3 Breakpoints and Code Stepping
5.4 Examining and Modifying Memory
5.5 Other Important Commands
6 Additional Features
To use Swat, you must have the
pccom
tool running on the target machine. You may then invoke Swat on the development machine. Swat takes the following command-line flags:
If you have set up your communications incorrectly, Swat will have problems. (Often these problems don't show up when sending or receiving files; Swat demands more from the communications programs than pcsend and pcget.)
One common problem arises when other devices are generating interrupts which are not being successfully masked out. If, for instance, you have a network card which is operating on IRQ 2, you must make sure that either the
pccom
tool or else Swat is called with the /i:a option. Swat will intercept IRQ level 5 by default. To determine what number to pass with the /i, take the IRQ level, add 8, and express the result in hexadecimal.
If Swat complains that it is "timing out" on some operation, you may have your communication speed set too high. Try changing the baud rate field in PTTY to a lower value.
Normally, Swat insists that any geodes it examines should have their symbolic information in the appropriate subdirectory of your root GEOSSDK development directory--the possible subdirectories are Appl, Library, Driver, and Loader. To ask Swat to look in different places for these sorts of files, change the SWAT.CFG file in your PCGEOS\BIN directory. You may also specify a fifth directory in which to look for geodes. You may specify absolute pathnames in this file; if you give relative paths, they will be assumed to start at the directory specified with your ROOT_DIR variable.
If you add a "default" line to your SWAT.CFG file, that tells Swat where to look for .SYM files as a last resort. To save hard disk space, some developers delete rarely-accessed .SYM files from their hard drive, leave their SDK CD in the CD-ROM drive, and specify the GEOSSDK directory as the default place to look for .SYM files:
default D:\GEOSSDK
The rest of this chapter is devoted to interacting with Swat once you have it running. Most of this is done by means of commands typed at a prompt. Some Swat commands may have subcommands, some may have flag options, and some combine the two. Others may have special options; all, however, are documented with the following conventions.
command (alternative1|alternative2|...|alternativeN)
The parentheses enclose a set of alternatives separated by vertical lines (in C, the bitwise OR operator character). For example, the expression
quit (cont|leave)
means that either
quit cont
or
quit leave
can be used.
command <type_of_argument>
The angled brackets enclose the type of an argument rather than the actual string to be typed. For example,
<addr>
indicates an address expression and
<argument>
indicates some sort of argument.
command [optional_argument]
The brackets enclose optional arguments to the command. For example, the command
alias [<word>[<command>]]
could have zero, one, or two arguments because the command and word arguments are optional. Another example would be the command
objwalk [<addr>]
, which may take zero arguments if it is meant to use the default address or one argument if the user gives it a particular address to look at.
* +
An asterisk following any of the previous constructs indicates zero or more repetitions of the construct may be typed. A plus sign indicates one or more repetitions of the construct may be used. For example,
unalias
<word>*
can be the
unalias
command by itself, or it can be followed by a list of words to be unaliased.
Address expressions are used as arguments to any Swat command that accesses memory. For example, the
pobject
command takes an address expression as an argument and prints out information about the object at that address. An address expression can be a symbol name, which is just the name of a pointer, or a
symbol path
. A symbol path has the following structure, where scope is the name of a patient, module, function, structure type, union type, enumerated type, or assembly record type:
(<scope>::)+<symbol>
Some of the more common symbol path formats are:
<module>::<symbol> <patient>::<symbol> <patient>::<module>::<symbol> <structure name>::<field name>
The symbol path is used when there is more than one symbol of a given name or if a symbol of a different application is needed. A symbol can be represented in a variety of ways: the name of an object, a field of a structure, a register/number combination, a number from the address history, an element of an array, nested Tcl commands, or a Tcl variable. Array indexing is used as follows:
<addr> [<n>]
which will return the zero-based element
n
from the given
addr
, even if
addr
is not an array.
Another important way of representing the symbol is as a
segment:offset
pair. In this, the segment is a constant, a register, a module, or a handle ID given as
^h<id>
where
id
is a constant or register.
There are several operators which are used to make memory examination and manipulation easier in Swat. These operators are shown below (in order of highest precedence to lowest):
^h
The
carat-h
is used to dereference a memory handle when representing an address as a
handle:offset
pair (this is also known as a "heap pointer" representation) or when accessing a particular block of memory. It is often used in the situation when a memory handle is in one register (such as BX) and the offset is in another register (such as SI). This is similar to the ^l operator (below), but it requires an offset into the block rather than a chunk handle. The
^h
operator is used thus:[hello3:0] 6 => print ^hdx:ALB_appRef
.
The
period
is used to access a field in a structure. For example, to get the top bound part of a rectangle structure stored as a global variable:[hello3:0] 8 => print theRect.R_top
+ -
The addition and subtraction operators are used to add and subtract symbols to and from other symbols and constants. If two symbols in the same segment are subtracted, a constant will be the result.
^l
The
carat-l
is used to dereference an optr, a pointer in the form
handle:chunk-handle
(this is also known as a "local memory pointer"). This is similar to the
^h
operator, but
^l
requires a chunk handle rather than an offset. If an optr is stored in CX:DX, for example, the ^l operator could be used to dereference it as follows:[hello3:0] 11 => pobj ^lCX:DX [hello3:0] 12 => pobj ^l0x43d0:0x022
:
The
colon
is the segment/offset operator, used to separate the segment and offset in a
segment:offset
pair.[hello3:0] 13 => pobj ^hCX:DX [hello3:0] 14 => pobj 0x43d0:0x022 [hello3:0] 15 => pobj INTERFACE:HelloView
*
The
asterisk
is a pointer-dereferencing operator, as in the C programming language:[hello3:0] 16 => print SubliminalTone @5: SubliminalTone = 7246h
[hello3:0] 17 => print *(&SubliminalTone)
@6: *(&SubliminalTone) = 7246h
^v
The
carat-v
is the virtual memory operator, used to get to the base of a block that is in a Virtual Memory file given the file handle and VM block handle. The correct usage of the
^v
operator is:^v<file>:<VM_block>
Much of the time the type of data stored at the address given by the address expression is implicit in the expression. Sometimes in ambiguous situations (using code as data), however, the type of data must be explicitly stated in the address expression. This is done by indicating the type of the data followed by a space and then a normal address expression. For example, in the expression
dword ds:14h
the data at
ds:14h
will be treated as a double word.
Swat provides on-line help, both for looking up Swat topics and GEOS reference material.
To get help on a specific Swat command, you simply type the following, where the command is the argument.
[hello3:0] 7 => help <cmd>
To use Swat's interactive, menu-based help system, simply type the following:
[hello3:0] 8 => help
The menu-based system provides a tree of help topics which are organized into subjects. If you are looking for Swat commands having to do with a subject not covered in the help tree, you might try using the
apropos
command.
To get information about a GEOS topic, use the doc functions.
apropos [<string>]
The
apropos
command searches the list of commands and command help for all entries containing <string>. It lists each command and its synopsis. The string may actually be a partial word.
help [<command>]
There are two different ways to use the help command. The first is to enter the
interactive help mode
using the
help
command with no arguments, and the second is to use the
help
command with a particular command as an argument.
(geos:0) 198 => help
top-most level of the help tree: 0 FINISH 6 memory... 12 step... 1 advanced... 7 object... 13 support... 2 breakpoint... 8 print... 14 swat_navigation... 3 crash... 9 running... 15 window... 4 file... 10 source... 5 heap... 11 stack...
Type "help" for help, "menu" to redisplay the menu, "0" to exit. Type a topic (or its number) to display it. help:top>
help
is typed with another command as an argument, information about that command is displayed (the same information as in the interactive help mode). This command is frequently used in order to get fast help on a particular command. (See The help Command
.)(geos:0) 200 => help help Help for help: Functions for manipulating/accessing the help tree ============================================================================== This is the user-level access to the on-line help facilities for Swat. If given a topic (e.g. "brk") as its argument, it will print all help strings defined for the given topic (there could be more than one if the same name is used for both a variable and a procedure, for instance). If invoked without arguments, it will enter a browsing mode, allowing the user to work his/her way up and down the documentation tree ============================================================================== (geos:0) 201 =>
This section covers the function and usage of some of the most important Swat commands. These commands fall into the following command groups:
A complete list of the Swat commands is contained in the Reference chapter.
Examining and Modifying Memory
send, run, exit, patient-default
These commands come in handy whenever you've edited and recompiled your application. You'll want to exit the application on the target machine. Use the
send
command to send down the new, compiled version of your application. Then use the
run
command to start up the program.
send [<geode-name>]
To send the latest compiled version of your program, type "send" followed by the application's patient name (the first part of the field on the "name" line of the .gp file).
run [<geode-name>]
To run your geode on the target machine, type "run" followed by the application's patient name (the first part of the field on the "name" line of the .gp file).
exit <geode-name>
To exit a running application, type "exit" followed by the application's patient name. The exit command won't work if your application has encountered a fatal error.
patient-default [<geode-name>]
Use this command to set a default patient to use with the
send
and
run
commands. The send and run commands will operate on this patient if they are not passed arguments.
attach, att, detach, quit, cont, Ctrl-C
This group of commands controls the state of the connection between Swat and GEOS when Swat is running. The
attach
and
att
commands are used to establish the connection while
detach
and
quit
are used to sever it. The most frequently used commands in this group are
att
with the
-r
flag and
detach
. Some related commands contained in the Reference are
go
,
istep
,
sstep
, and
next
.
The following is a typical but simplified debugging cycle using
detach
and
att
. It assumes you have already attached for the first time.
detach
.
att
command by typing Scrolllock-Shift-s on the target machine and typing
att
on the host machine.By themselves, the commands shown below can not do much except open and close the communication lines between GEOS and Swat. More commands to examine and modify the application's code as it runs are needed to start actual debugging.
Swat Display 3-3 Detaching and Attaching
(geos:0) 202 => det cont PC detached (loader:0) 203 => att Re-using patient geos Re-using patient ms4 Re-using patient vidmem Re-using patient swap Re-using patient xms Re-using patient disk Re-using patient kbd Re-using patient nimbus Re-using patient stream Re-using patient sound Re-using patient standard Re-using patient ui Re-using patient styles Re-using patient color Re-using patient ruler Re-using patient text Re-using patient motif Re-using patient vga Re-using patient spool Re-using patient serial Re-using patient msSer Re-using patient nonts Re-using patient welcome Re-using patient shell Re-using patient manager Re-using patient math Re-using patient borlandc Re-using patient mess1 Thread 1 created for patient geos Thread 2 created for patient geos Thread 0 created for patient ui Thread 0 created for patient spool Thread 0 created for patient welcome Thread 0 created for patient manager Thread 1 created for patient manager Thread 0 created for patient mess1 Attached to PC Stopped in 0070h:0005h, address 0070h:0005h DOS+773: JMP DOS+2963 (geos:0) 204 =>
In this example, we use the
det cont
command so that GEOS will keep running. We then re-attach with
att
. In the intervening time, the two machines are independent, and the serial line is unused. We could have taken advantage of this to send down a new copy of some application (as long as that application was not running on the target machine).
att
The
att
command is similar to the
attach
command, but has no bootstrap argument (as explained below).
attach [(+b|-b)]
This command is used to attach Swat to the target PC when the Swat stub is already invoked. The
-b
argument is to bootstrap and the
+b
argument is not to bootstrap. Bootstrapping means that Swat will search for the symbol files of all of the geodes and threads as they are encountered rather than all at the beginning. This saves some time if you've just detached and need to re-attach, using only a few geodes while debugging. If no argument is given, the most recent bootstrap setting is used. The default bootstrap setting is
+b
.
cont
The
cont
command continues the execution of GEOS after it has been stopped for some reason such as at a breakpoint or fatal error or by control-C. This command is often aliased as the letter
c
.
detach [(cont|leave)]
The
detach
command will detach Swat from the target PC. By itself, the
detach
command will detach Swat and exit GEOS. This command is usually used after a bug is encountered and the source code needs to be modified and recompiled (see Detaching and Attaching
).
cont
option will just detach Swat and allow GEOS to continue to run normally. This option is used when the debugging process is finished but GEOS is still needed to do other things (such as word processing) and you may need to re-attach later for further debugging.
leave
option will detach Swat but keep GEOS stopped wherever it was when the
detach leave
command was given. This command is useful for passing debugging control to someone remotely logged in to the workstation or when Swat can not continue for some reason.quit [(cont|leave)]
The
quit
command is only used when Swat needs to be exited for good. It will detach Swat (if necessary), exit from Swat on the development station, and exit from GEOS.
cont
option exits Swat on the development station but allows GEOS to continue running normally on the target PC. This option is used when the debugging process is finished but GEOS is still needed to do other things such as word processing.
leave
option will exit Swat but will keep GEOS stopped wherever it was when the
quit leave
command was given.Ctrl-C
The
Control-C
command is the command used to stop the execution of GEOS at any point. This command is executed by holding down the
Ctrl
key and pressing the
c
key. It is used to stop GEOS in order to set a breakpoint, examine memory, or to get a command line prompt.
The commands in this group are used to stop at specified breakpoints in an application's code and then step through the code line by line if necessary. These commands are often used with each other to examine critical areas in the application source code.
stop, brk, go, cbrk, spawn
The
stop
,
brk
and
cbrk
commands are used to set breakpoints. The breakpoint commands have many subcommands controlling the actions and attributes of a particular breakpoint.
The
cbrk
command sets breakpoints to be evaluated by the Swat stub;
brk
sets them to be evaluated by Swat. The Swat stub can evaluate the conditions much faster than Swat, but
cbrk
has certain limitations: only a limited number of breakpoints can be set using
cbrk
, and these breakpoints can only compare registers when the breakpoint is hit with a given set of criteria.
stop in <class>::<message> [if <expr>] stop in <procedure> [if <expr>] stop in <address-history-token> [if <expr>] stop at [<file:]<line> [if <expr>] stop <address> [if <expr>]
This is the main command to use when setting breakpoints in C programs. The "stop in" command will set a breakpoint at the beginning of a procedure, immediately after the procedure's stack frame has been set up. The "stop at" command will set a breakpoint at the first instruction of the given source line. If no <file> is specified, the source file for the current stack frame is used. If a condition is specified by means of an "if <expr>" clause, you should enclose the expression in curly braces to prevent any nested commands, such as a "value fetch" command, from being evaluated until the breakpoint is hit.
brk [<sub-command>]
The
brk
(breakpoint) command is used for setting nearly all breakpoints in an application's code. The simplest way to use it is to type
brk
with a single
addr
argument. The address is usually a routine name for a suspect procedure, and when the breakpoint is reached the code-stepping commands can be used to examine it carefully. The
brk
command can also create conditional breakpoints which will only be taken if certain conditions are satisfied. Once set, a breakpoint is given an integer number which can be obtained using the
list
subcommand (see Breakpoints
).
brk <addr> [<command>]
brk
command without any subcommands sets an unconditional breakpoint at the address specified in
addr
. If the
command
argument is passed, the given swat command will be carried out when the breakpoint is hit.
brk delete <break>*
clear
, above.
brk enable <break>*
brk disable <break>*
brk list [<addr>]
addr
is given, it returns the breakpoint numbers of all breakpoints set at the given address.
(geos:0) 4 => brk list Num S Address Patient Command/Condition 1 E loader::kcode::LoaderError all echo Loader death due to [penum LoaderStrings [read-reg ax]] expr 1 2 E kcode::FatalError all why assign kdata::errorFlag 0 expr 1 3 E kcode::WarningNotice all why-warning 4 E kcode::CWARNINGNOTICE all why-warning (geos:0) 5 => stop in Mess1Draw brk5 (geos:0) 6 => brk list Num S Address Patient Command/Condition 1 E loader::kcode::LoaderError all echo Loader death due to [penum LoaderStrings [read-reg ax]] expr 1 2 E kcode::FatalError all why assign kdata::errorFlag 0 expr 1 3 E kcode::WarningNotice all why-warning 4 E kcode::CWARNINGNOTICE all why-warning 5 E <ss1::MESS1_TEXT::Mess1Draw+10 all halt (geos:0) 7 => brk dis brk4 (geos:0) 8 => brk list Num S Address Patient Command/Condition 1 E loader::kcode::LoaderError all echo Loader death due to [penum LoaderStrings [read-reg ax]] expr 1 2 E kcode::FatalError all why assign kdata::errorFlag 0 expr 1 3 E kcode::WarningNotice all why-warning 4 D kcode::CWARNINGNOTICE all why-warning 5 E <ss1::MESS1_TEXT::Mess1Draw+10 all halt (geos:0) 9 =>
go [<address-expressions>]
The go command sets a one-time breakpoint and resumes execution on the target PC. The net effect of this is to let the target go until it hits a given address, then stop.
cbrk [<sub-command>]
The
cbrk
(conditional breakpoint) command is used to set fast conditional breakpoints. This command is very similar to the
brk
command above, except that the condition is evaluated by the Swat stub--this increases the speed of the evaluation. There are, however, certain restrictions on the
cbrk
command: only a limited number of breakpoints can be set (eight), and the scope of the evaluation is limited to comparing word registers (or a single word of memory) to a given set of values.
In the following descriptions,
criteria
stands for a series of one or more arguments of the form:
<register> <op> <value>
criteria
is given the breakpoint becomes a standard, unconditional breakpoint.spawn <patient-name> [<addr>]
The
spawn
command is used to set a temporary breakpoint in a process or thread which has not yet been created. The arguments are
patient-name
addr
This command is used to stop the geode before any of its code can be run, allowing breakpoints to be set in the desired routines. If you could not stop the machine in this manner, the application could hit a buggy routine before a breakpoint could be set in that routine. The
spawn
command can also be used to catch the spawning of new threads which is useful to keep track of the threads being used by an application (see The spawn Command
).
Swat Display 3-5 The spawn Command
(geos:1) 12 => spawn mess1 Mess1Draw Re-using patient math Re-using patient borlandc Re-using patient mess1 Thread 0 created for patient mess1 Interrupt 3: Breakpoint trap Stopped in Mess1Draw, line 211, "C:OMNIGO/Appl/SDK_C/MESS1/MESS1.GOC" Mess1Draw(GStateHandle gstate) /* GState to draw to */ (mess1:0) 13 =>
srcwin, istep, sstep
Once an application is stopped at a breakpoint and you want to examine the code line by line, you can use the commands
istep
(instruction step) and
sstep
(source step). These enter the
instruction step mode
or
source step mode
to examine and execute the application code line by line.
The subcommands for both
istep
and
sstep
are nearly the same and are used for actions including stepping to the next line, skipping the next instruction, or exiting the step mode and continuing the execution of the application. The
istep
and
sstep
commands are very similar except that
istep
is used when stepping through assembly source code (thus stepping through instructions), and
sstep
is used for stepping through C source code.
srcwin <numlines> [view]
The srcwin command will display the source code surrounding the presently executing code any time execution is stopped. The presently executing line will be highlighted. You may set breakpoints with the mouse by clicking on the line numbers which appear to the side. To scroll the srcwin buffer use the arrow keys, the <PgUp> key, and the <PgDn> key.
istep [<default subcommand>]
sstep [<default subcommand>]
These two commands are used to single-step through code, executing one or more instructions at a time. The
default subcommand
argument determines the action taken by Swat when the Return key is pressed. For example, the command
[hello3:0] 7 => istep n
will enter instruction step mode, and subsequently pressing the Return key will have the same effect as pressing
n
. If no default command is given, pressing Return has the same effect as pressing
s
.
The subcommands to the
istep
and
sstep
commands are
n
subcommand was given.
o
differs from
n
in that it executes all instructions in a macro without further interpretation and can only be used with
istep
. If a breakpoint other than for the next instruction is hit, it will take effect as long as the above conditions are met.
n
and
o
but will stop whenever a breakpoint is hit even if the frame is different.
O
will execute all instructions in a macro without further interpretation, and it can only be used with
istep
. If a breakpoint other than one for the next instruction is hit, it will take effect as long as the above conditions are met.
istep/sstep
and return to the command level. These subcommands are used when a point in the code is reached where another command needs to be used--to examine memory, for example.
istep
and continues the execution of the application. When GEOS next stops, Swat will return to the command prompt.
ObjMessage()
and
ObjCallInstanceNoLock()
assembly routines.The commands in this section all deal with the examination, manipulation, or modification of the memory used by an application. Memory from individual bytes to complex data structures such as objects can be displayed and examined. These commands fall into the following groups:
The commands in this section are often used with each other and with the code-stepping and breakpoint commands in order to pinpoint bugs in an application's code. Breakpoints can be set, code can be stepped through, and then the memory that the code uses can be examined.
Some related commands defined in the Reference chapter are
down
,
func
,
handles
,
hgwalk
,
impliedgrab
,
penum
,
phandle
,
pinst
,
piv
,
precord
,
skip
,
systemobj
,
up
, and
where
.
bytes, words, dwords, frame, backtrace, why, listi
The commands in this group are used to look at simple blocks of memory without modification. They are defined fully in the entries below.
bytes [<addr>] [<length>]
words [<addr>] [<length>]
dwords [<addr>] [<length>]
The
bytes
,
words
, and
dwords
commands are essentially the same except that each looks at a different sized piece of memory. These commands will display the memory as a pointer to a dump of bytes, words, or dwords using the given or most recent (if no address is given) address.
The
bytes
command additionally displays the dump as its ASCII character representation, if any. These three commands are used to examine memory on a very basic level and are useful only if the user knows what the bytes, words, or dwords should or should not be and so can spot any problems. For example, if a certain character string such as "Application" is supposed to be stored at the address given by
fileType
and the command
[hello3:0] 11 => bytes fileType
dumps the characters "noitacilppA", then there is most likely a problem.
These commands will automatically use the given
addr
as a pointer to the memory to be examined. If Return is hit many times in a row, the result will be to examine adjacent pieces of memory. (See The words Command
.)
Swat Display 3-6 The words Command
(mess1:0) 15 => words themeSongBuf Addr: +0 +2 +4 +6 +8 +a +c +e 0040h: 0004 0000 0049 0000 0004 0001 0083 0000 (mess1:0) 16 => words Addr: +0 +2 +4 +6 +8 +a +c +e 004eh: 0000 0006 0004 0028 0000 0001 020b b800 (mess1:0) 17 => !! words Addr: +0 +2 +4 +6 +8 +a +c +e 005ch: b800 000c 0020 0002 0001 0000 0001 020b (mess1:0) 18 => !! words Addr: +0 +2 +4 +6 +8 +a +c +e 006ah: 020b b800 000c 0010 0002 0001 000a 0010
Here the
words
command examines a buffer in memory. When this command is repeated without arguments, it will display memory continuing where the last command left off. Note the use of the
!!
command to repeat the previous command.
backtrace [<frames to list>]
frame <subcommand>
The
backtrace
and
frame
commands are used to examine data that has been pushed onto the stack. An application may crash in a routine that is correctly written but has been passed bad data.
The
backtrace
command prints out a list of all the active frames for the current patient. Then the user can choose a particular frame to examine using one of the
frame
subcommands. The
frame
command is used to access frames that have been pushed onto the stack, where a
frame
is the information for a routine that needs to be saved when it calls another routine.
The
frame
and
backtrace
commands can be used together to print the active frames with
backtrace
and then access data in these frames with
frame
. However, most of the
frame
subcommands expect a token for a frame, not the frame number given by the backtrace command. To get this token, the
top
,
cur
and
next
subcommands are used. Then the other
frame
subcommands can be used with the token to further examine the
frame
data. See also the reference information for the frame command.
Death due to SOUND_BAD_EVENT_COMMAND Execution died in patient sound: SoundHandleTimerEvent+63: MOV AX, 7 (0007h) *** No explanation available *** Interrupt 3: Breakpoint trap Stopped in FatalError, address 1844h:0163h SoundHandleTimerEvent+63: MOV AX, 7 (0007h) (mess1:0) 2 => backtrace 1: near FatalError(), 1844h:0163h 2: far AppFatalError(), 1844h:0163h * 3: far SoundHandleTimerEvent(), 2cb2h:003fh 4: far SoundLibDriverPlaySimpleFM(), 6247h:0062h 5: far ResourceCallInt(), 1844h:1492h 6: far SoundLibDriverStrategy(), 2cb2h:0ab2h 7: near SoundCallLibraryDriverRoutine(), 629ch:00feh 8: far SoundPlayMusic(), 629ch:0028h 9: far ResourceCallInt(), 1844h:1492h 10: far SOUNDPLAYMUSICNOTE(mh = ^h42b0h (at 753ch), priority = 1eh, tempo = 4h , flags = 80h), 62d6h:00f3h 11: far ResourceCallInt(), 1844h:1492h 12: far Mess1Draw(), MESS1.GOC:307 13: far MESS1PROCESSMETA_EXPOSED(win = 3a60h, message = 69 (invalid), oself = 3ee0h:0000h), MESS1.GOC:362 14: far ResourceCallInt(), 1844h:1492h MSG_META_EXPOSED (3a60h 0000h 0000h) sent to Mess1ProcessClass (^l20f0h:0h) 16: near ObjCallMethodTableSaveBXSI(), 1844h:9ea5h 17: far SendMessage(), 1844h:9d9bh 18: far ObjMessage(), 1844h:1d9ch 19: far MessageDispatchDefaultCallBack(), 1844h:1c72h 20: far MessageProcess(callBack = 1844h:1c68h (geos::kcode::MessageDispatchDef aultCallBack)), 1844h:1c15h 21: far MessageDispatch(), 1844h:1b31h 22: far ThreadAttachToQueue(), 1844h:bd2ch (mess1:0) 3 => frame 12 Mess1Draw+302: MOV AX, 100 (0064h)
print, hwalk, lhwalk, objwalk, pobject, gentree, vistree, vup, gup
The commands in this group are used to examine complex data structures in GEOS.
print <expression>
The
print
command is used to print out the value of the given
expression
argument. The
expression
argument is normally some sort of typed address. When there is no type for the
expression
, then its offset is printed.
The power of this command lies in its ability to print any type at any address; thus, it is used frequently to print out the values of important expressions such as registers or variables. The
print
command also takes many flags which control the way in which the value of the
expression
is displayed such as in decimal or hexadecimal. See the Reference chapter for more information on the flags for the
print
command.
hwalk [<patient>]
Use the
hwalk
(heap walk) command to display blocks on the global heap. Its output can be tailored in various ways according to how the
flags
are set. If a
patient
is given, then
hwalk
will only print the blocks owned by that patient. There are many fields in the listing such as the handle, address, and type of each block. By examining these fields, the user can get an overall sense of how the global heap is being managed, whether any block looks too big or too small, and what the handles of important blocks are. (See The hwalk Command
.)
Swat Display 3-8 The hwalk Command
(mess1:0) 6 => hwalk mess1 HANDLE ADDR SIZE FLAGS LOCK OWNER IDLE OINFO TYPE ---------------------------------------------------------------- 20f0h 41ebh 2272 FIXED n/a mess1 n/a 1h R#1 (dgroup) 4160h 58eah 448 sDS a 1 mess1 105eh 1h R#2 (MESS1_TEXT) 3a60h 59adh 784 s SL 0 mess1 0:03 1h WINDOW 4bb0h 6176h 560 s SL 0 mess1 0:05 1h WINDOW 3970h 6232h 336 s SL 0 mess1 0:03 1h GSTATE 3ee0h 633ch 160 s S a 0 mess1 0:05 49c0h Geode 4950h 63beh 1280 s SL 0 mess1 0:05 49c0h OBJ(mess1:0) 4340h 640eh 1328 SL 0 mess1 0:05 49c0h R#3 (INTERFACE) 42b0h 753ch 96 s S 4 mess1 1249h 1h 4bd0h 7542h 96 s S 0 mess1 0:01 1h 41b0h 89d4h 896 SL 0 mess1 0:05 49c0h R#4 (APPRESOURCE) 4270h 99e1h 32 s S 0 mess1 0:05 1h Total bytes allocated: 8288 (mess1:0) 7 =>
lhwalk [<addr>]
objwalk [<addr>]
The
lhwalk
(local heap walk) command is used to display information about a local memory heap, and the
objwalk
command is used to print out information about an object block. After using
hwalk
to locate a specific block,
lhwalk
or
objwalk
can be used to print out information about that particular block. These commands also print out fields of information which include the local handle, the address, size, and type of data or object. See the Reference chapter for more information on the fields printed by
lhwalk
and
objwalk
. (See The objwalk Command
.)
Swat Display 3-9 The objwalk Command
(mess1:0) 11 => objwalk ^h4340h Heap at 640eh:0 (^h4340h), Type = LMEM_TYPE_OBJ_BLOCK In use count = 3, Block size = 1328, Resource size = 59647 para (192 bytes) HANDLE ADDRESS SIZE FLAGS CLASS (NAME) ------ ------- ---- ----- ------------ 001ch 56h 1eh --- *flags* 001eh 76h c1h D RO GenPrimaryClass (Mess1Primary) 0020h 1aah ceh D RO GenViewClass (Mess1View) 0022h 166h 32h ID O OLGadgetAreaClass 0024h 19ah eh I 0026h 492h 6bh D O GenValueClass 0028h 2deh 6bh D O GenValueClass 002ah 37eh a6h ID O GenInteractionClass 002ch 44ah 46h ID O OLMenuBarClass 002eh 13ah bh ID 0030h 426h 22h ID O OLMenuButtonClass Free handles = 17, null handles = 0 Objects = 8, 4 of them marked ignoreDirty (mess1:0) 12 =>
pobject [<addr>] [<print level>]
The
pobject
(print object) command (often abbreviated
pobj
) is used to print out the entire instance data chunk of an object. You can use
gentree
,
vistree
, or
hwalk
and
objwalk
to get the handles for an object; once you have them, use
pobj
with the handles, as follows:
[hello3:0] 7 => pobj ^l0x43d0:0x0022
will print out the instance data chunk specified by that optr.
Any valid address expression, such as a dereferenced object name, may be used as an
addr
. Additionally, the print level can be changed to print just the headings to each of the master levels and an address history number. The
pobject
command is used to verify that the object is behaving correctly and that its instance variables (if any) are correct. (See The pobject Command
.)
Swat Display 3-10 The pobject Command
[lesink:0] 10 => pobj ^l4710h:0020h
*UpTextView::UpTextViewClass (@7, ^l4710h:0020h)
master part: Gen_offset(123) -- UpTextViewInstance
@8: {UpTextViewInstance (^h18192:622)+123} = {
MetaBase Gen = {
ClassStruct _far *MB_class = 360ah:162fh (motif::dgroup::OLPaneClass)
}
LinkPart GI_link = {
dword LP_next = 4710h:001fh
}
CompPart GI_comp = {
dword CP_firstChild = 4710h:002ah
}
word GI_visMoniker = 0h
word GI_kbdAccelerator = 0h
byte GI_attrs = 2h
byte GI_states = c0h
PointDWFixed GVI_origin = {
DWFixed PDF_x = {0.000000}
DWFixed PDF_y = {0.000000}
}
RectDWord GVI_docBounds = {
long RD_left = 0
long RD_top = 0
long RD_right = +480
long RD_bottom = +480
}
PointDWord GVI_increment = {
long PD_x = +20
long PD_y = +15
}
PointWWFixed GVI_scaleFactor = {
WWFixed PF_x = {1.000000}
WWFixed PF_y = {1.000000}
}
ColorQuad GVI_color = {
CQ_redOrIndex = fh, CQ_info = 0h, CQ_green = 0h, CQ_blue = 0h
}
word GVI_attrs = 10h
byte GVI_horizAttrs = 88h
byte GVI_vertAttrs = 88h
byte GVI_inkType = 0h
dword GVI_content = 4710h:0024h
dword GVI_horizLink = 0000h:0000h
dword GVI_vertLink = 0000h:0000h
}
Variable Data:
*** No Variable Data ***
[lesink:0] 11 =>
In addition to printing information about the object at a given address, pobject can print information about certain objects in the application if passed certain flags:
There are more flags available, and it is also possible to ask for more or less instance data information. See the full reference for this command for details.
gentree [<addr>] [<instance field>]
The
gentree
(generic tree) command prints out a generic tree from the given
addr
and
instance field
. The
addr
must be the address of an object in the generic tree, and the
instance field
must be the offset into the Generic master part of the instance chunk or any instance data within the Generic master level which is to be printed. This command is used primarily to ensure correct structure of a generic tree and its instance data and to find a particular object in the generic tree.
The
-i
(implied grab) option is used to find an object by placing the mouse over the window in which the object resides and typing the following:
[hello3:0] 7 => gentree -i
The default address that
gentree
examines is contained in *DS:SI. (See Gentree and Gup
.) To examine objects more closely, pass the handles displayed by
gentree
to the
pobject
command.
vistree [<addr>] [<instance field>]
The
vistree
(visual tree) command prints out a visual tree from the given
addr
and
instance field
. The
addr
must be the address of an object in the visual tree, and the
instance field
must be the offset into the Vis master part of the object's instance data which is to be printed. This command is primarily used to examine the on-screen layout of the application and to ensure correct structure of the visual tree and its instance data. The
vistree
command can use the
-i
option (implied grab), which will use the window that the mouse is over as the first visual object in the printed tree. The default address that
vistree
examines is contained in *DS:DI. To examine objects more closely, pass the handles displayed by
vistree
to the
pobject
command.
gup [<addr>] [<instance field>]
The
gup
(Generic UPward query) command is used to go up the generic tree from a particular object specified by the
addr
argument, the default *DS:SI, or the
-i
option. The
-i
option (implied grab) uses the windowed object under the mouse as the object from which to start the upward query. This command is used primarily to ensure correct generic class hierarchy and to determine the field of the given object.
Swat Display 3-11 Gentree and Gup
(mess1:0) 19 => gentree -i GenViewClass (@5, ^l4340h:0020h) GenValueClass (@6, ^l4340h:0026h) GenValueClass (@7, ^l4340h:0028h) (mess1:0) 20 => gup @5 GenViewClass (@11, ^l4340h:0020h) GenPrimaryClass (@12, ^l4340h:001eh) "MESS #1" GenApplicationClass (@13, ^l41b0h:0024h) *** Is Moniker List *** GenFieldClass (@14, ^l4080h:001eh) GenSystemClass (@15, ^l2460h:0020h) (mess1:0) 21 => gentree ^l4340h:001eh GenPrimaryClass (@16, ^l4340h:001eh) "MESS #1" GenViewClass (@17, ^l4340h:0020h) GenValueClass (@18, ^l4340h:0026h) GenValueClass (@19, ^l4340h:0028h)
vup [<addr>] [<instance field>]
The
vup
(Visual UPward query) command is used to examine the visual ancestors of a particular object given by the
addr
argument, the default *DS:SI, or the
-i
option. The
vup
command can be used with the
-i
option (implied grab) to use the windowed object under the mouse as the object from which to start the upward query. This command is used primarily to ensure correct visual class hierarchy and to determine the field of the given object.
assign, imem
The commands in this group are used to modify memory without detaching Swat and editing the application code. They are often used in conjunction with
istep
,
sstep
, and
pobject
to fix any small errors while the code is executing rather than detaching, modifying the actual code, and recompiling. These fixes are temporary, and you must change the source code to enact the real bug fixes.
assign <addr> <value>
The
assign
command will assign the given
value
to the given
addr
, which can only have type
byte
,
word
, or
dword
. Both memory locations and registers may be assigned new values. This command is used to correct minor mistakes or test differing values at run-time without having to recompile.
imem [<addr>] [<mode>]
The
imem
(inspect memory) command combines examination and modification of memory into one command. It can be used to search through areas of memory and modify problem areas selectively. The command is used to print out memory starting at either the given
addr
or at the default DS:SI in one of the following modes:
There are many subcommands to
imem
which are executed in the same manner as those for
istep
and
sstep
. These subcommands are as follows:
P
subcommand.
assign
command except for singly and doubly quoted strings. A singly quoted string such as `hello' will have its characters entered into memory starting at the current address with no null byte at the end. A doubly quoted string such as "good-bye" will be entered into memory at the current address with the addition of a null byte at the end of the string. This subcommand may not be used in instruction mode.
imem
mode and returns to the command level.alias, mwatch, objwatch, save, switch, sym-default, why
These commands are important to know but do not readily fall into any of the previous categories. This section will discuss each of these commands in relation to the debugging process.
alias [<name> [<body>]]
This command is normally used to abbreviate a long command or series of commands with one single, descriptive command. If no arguments are given, then
alias
will just give a list of all the aliases and the commands they alias. The
alias
command is a convenient shortcut for oft used commands or for commands that take a long time to type.
If only one argument is given, then
alias
will try to match that argument to the command it is aliased to. For example, if the
print
command is aliased to
p
, then
alias p
will return
print
as a result. If two arguments are given, then
alias
will cause argument1 to be allowed as an alternative to typing argument2. For example, if the command
print
were to be aliased as
p
, the
alias
command would be used as below:
[hello:0] 5 => alias p print
Typing
p
will now have the same effect in Swat as typing
print
.
mwatch [<message>+]
The
mwatch
(message watch) command watches a particular message and displays all deliveries of that message without stopping GEOS. This command can help to verify that a particular message is getting sent to all the right places and is not sent to any of the wrong places. Up to eight messages can be watched at once, and the
mwatch
command with no arguments clears all watched messages. Note that some message handlers will relay a message on to a superclass' handler; this may make it appear that the message is being delivered again, though this is not the case. (See The mwatch Command
.)
Swat Display 3-12 The mwatch Command
(ui:0) 30 => mwatch MSG_VIS_DRAW MSG_META_EXPOSED (ui:0) 31 => c MSG_VIS_DRAW, ^l2860h:001eh, GenInteractionClass cx = 3f80h, dx = 0000h, bp = 3950h MSG_VIS_DRAW, ^l2860h:001eh, GenInteractionClass cx = 3f80h, dx = 0000h, bp = 3950h MSG_VIS_DRAW, ^l2860h:001eh, GenInteractionClass cx = 3f80h, dx = 0016h, bp = 3950h MSG_VIS_DRAW, ^l2860h:001eh, GenInteractionClass cx = 3f80h, dx = 0016h, bp = 3950h MSG_VIS_DRAW, ^l2860h:002ch, OLGadgetAreaClass cx = 3f80h, dx = 3950h, bp = 3950h MSG_VIS_DRAW, ^l2860h:002ch, OLGadgetAreaClass cx = 3f80h, dx = 3950h, bp = 3950h MSG_VIS_DRAW, ^l2860h:002ch, OLGadgetAreaClass cx = 3f80h, dx = 007ch, bp = 3950h MSG_VIS_DRAW, ^l2860h:002ch, OLGadgetAreaClass cx = 3f80h, dx = 007ch, bp = 3950h MSG_VIS_DRAW, ^l2860h:0020h, GenTextClass cx = 3f80h, dx = 3950h, bp = 3950h MSG_VIS_DRAW, ^l2860h:0020h, GenTextClass cx = 3f80h, dx = 3950h, bp = 3950h MSG_VIS_DRAW, ^l2860h:0020h, GenTextClass cx = 3f80h, dx = 3950h, bp = 3950h
objwatch [<addr>]
The
objwatch
(object watch) command is used for displaying the messages that have reached a particular object. It is useful for verifying that messages are being sent to the object at addr. If no argument is given, then any current
objwatch
is turned off. (See The objwatch Command
.)
Swat Display 3-13 The objwatch Command
mess1:0) 2 => objwatch Mess1View brk5 (mess1:0) 3 => c MSG_META_MOUSE_PTR, ^l44a0h:0020h, GenViewClass cx = 00afh, dx = 0013h, bp = 0000h MSG_META_MOUSE_PTR, ^l44a0h:0020h, GenViewClass cx = 00afh, dx = 0013h, bp = 0000h MSG_META_WIN_UPDATE_COMPLETE, ^l44a0h:0020h, GenViewClass cx = 4b90h, dx = 0000h, bp = 0000h MSG_META_MOUSE_PTR, ^l44a0h:0020h, GenViewClass cx = 00b0h, dx = 0013h, bp = 0000h MSG_META_RAW_UNIV_LEAVE, ^l44a0h:0020h, GenViewClass cx = 44a0h, dx = 0020h, bp = 4b90h MSG_VIS_DRAW, ^l44a0h:0020h, GenViewClass cx = 4b80h, dx = 23c0h, bp = 23c0h MSG_VIS_COMP_GET_MARGINS, ^l44a0h:0020h, GenViewClass cx = 4b80h, dx = 23c0h, bp = 0000h MSG_VIS_DRAW, ^l44a0h:0020h, GenViewClass cx = 4b80h, dx = 0163h, bp = 23c0h MSG_META_WIN_UPDATE_COMPLETE, ^l44a0h:0020h, GenViewClass cx = 4b90h, dx = 0000h, bp = 0000h
save <filename>
The save command, when passed a file name, saves the contents of Swat's main buffer to that file. Thus this command dumps Swat output to a file.
showcalls -L showcalls
The
showcalls
command is, for the most part, only useful under rare circumstances. However,
showcalls
with the -L option is useful for a fairly common situation: a library is failing to load but you can't find which one.
To find out which libraries an application is trying to load, use
showcalls -L
. Swat will tell you whenever a library is sought. Whichever library is being sought when the "missing system file" error message appears is the library that's causing your problems: perhaps you need to re-install it.
Use the
showcalls
command without any arguments to turn off library-loading reporting.
switch [(<patient>:<thread-num>|<threadID>)]
The
switch
command is used to switch between applications or threads in Swat but does not physically change threads on the target PC. This allows the transfer of debugging control between threads of the same patient. If no argument is given, then
switch
will change to the thread executing when GEOS was halted. Another way to switch threads is to type the name of the patient on the command line. If a patient has more than one thread, type the name of the patient, a space, and then the thread number. To change thread numbers within a geode, type a colon followed by the thread number to change to (e.g. "
:1")
sym-default [<patient>]
The
sym-default
(symbol default) command is used to set the default patient to use when parsing an address expression which is not defined in the current patient. For example, if a breakpoint is hit in the kernel and an object in the application code needs to be examined, Swat will know to use the application as a patient and not the kernel. This command is useful when debugging a single patient, the most common way to debug. If no patient argument is given, then the name of the default patient will be displayed.
This command is normally aliased to
sd
.
why
The
why
command prints the error code for an occurrence of a fatal error. This command is useful because it can give a good idea of why GEOS crashed.
This section covers the features of Swat that make it easier to use when debugging an application.
brk list
if that was the most recent command that began with "b".Swat Display 3-14 Command Correction Using ^
(geos:0) 185 => wurds Error: invoked "wurds", which isn't a valid command name
(geos:0) 186 => ^u^o words Addr: +0 +2 +4 +6 +8 +a +c +e 4b4bh: e800 01b1 0e00 60f6 0016 9800 6e02 a900
(geos:0) 187 => ddwords Error: invoked "ddwords", which isn't a valid command name
(geos:0) 188 => ^d dwords Addr: +0 +4 +8 +c 4b59h: 1d0aa900 001c400d 294bd000 6c0a8000
print
or
pobj
. The elements in the history can be accessed by typing
@<number>
where the number argument is the number of the item in the history. These elements can replace a full address expression (except constants) and are often used when traversing through fields of a previously printed structure. The default history keeps track of the last 50 items. (See The Address History
.)Swat Display 3-15 The Address History
(geos:0) 8 => gentree -i
GenPrimaryClass (@1, ^l44a0h:001eh) "MESS #1"
GenViewClass (@2, ^l44a0h:0020h)
GenValueClass (@3, ^l44a0h:0026h)
GenValueClass (@4, ^l44a0h:0028h)
(geos:0) 9 => pinst @3
class = ui::dgroup::GenValueClass
master part: Gen_offset(53) -- ui::GenValueInstance
@5: {ui::GenValueInstance (^h17568:1170)+53} = {
GenInstance GenValue_metaInstance = {
MetaBase Gen_metaInstance = {
ClassStruct _far *MB_class = 3573h:1867h (motif::dgroup::OLScrollbarClass)
}
LinkPart GI_link = {
void _optr LP_next = ^l44a0h:0028h (ui::dgroup::GenValueClass@6244h:02deh)
}
CompPart GI_comp = {
void _optr CP_firstChild = null
}
void _lptr GI_visMoniker = null
KeyboardShortcut GI_kbdAccelerator = {
KS_PHYSICAL = 0
KS_ALT = 0
KS_CTRL = 0
KS_SHIFT = 0
KS_CHAR_SET = 0
KS_CHAR = C_NULL
}
GenAttrs GI_attrs = {}
GenStates GI_states = {GS_USABLE, GS_ENABLED}
}
WWFixed GVLI_value = {0.000000}
WWFixed GVLI_minimum = {0.000000}
WWFixed GVLI_maximum = {0.007324}
WWFixed GVLI_increment = {0.000229}
GenValueStateFlags GVLI_stateFlags = {GVSF_INDETERMINATE}
GenValueDisplayFormat GVLI_displayFormat = GVDF_INTEGER
void _optr GVLI_destination = ^l44a0h:0020h (ui::dgroup::GenViewClass@6244h:01aah)
word GVLI_applyMsg = 681ah
}
(geos:0) 10 =>
pobject
command can be specified
pobj
,
pob
, or even
po
, but not by just
p
because there are other commands (such as
print
) beginning with the letter
p
. To get a list of all commands with a given prefix, type the prefix at the Swat prompt, then type Ctrl-D. To automatically complete a command name use the
Escape key (if the prefix is unambiguous) or
Ctrl-] to scroll through the list of possible command completions.Swat Display 3-16 An Initialization File
srcwin 15 regwin save 500 patient-default mess1 run
This example shows a sample initialization file which sets up windows to display the source code and current register values, set the length of the save buffer to 500 lines, and continue running swat until the mess1 application has been loaded, at which point execution will automatically stop.