Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ debug(8) — AOS 4.3

Media Vault

Software Library

Restoration Projects

Artifacts Sought

DEBUG(8)  —  

NAME

debug − debugger for the IBM RT PC

SYNOPSIS

/sys/standca/debug [ −w ]  [ mem [ vmunix ] ] [ −n ]  [−b# ] [ −d ]

DESCRIPTION

The IBM RT PC debugger is designed to be used in standalone mode -- when it is linked with the program being debugged -- or for online kernel debugging, in which case it is linked separately, then loaded with the kernel, and for post-mortem kernel debugging, in which case it is a separate program called debug. 

The kernel version, however, sets some global variables to change the environment and provide the symbol table. 

The options have the following meanings:

−wOpens mem for writing to allow changes to be made to the mem contents. 

−dInternal debugging flag. 

−nDon’t pause for certain commands to read response (useful when debug is initiated from shell scripts). 

−b#Turns on buffering of data from mem.  # sets the buffer size.  A negative buffer size turns buffering off. 

memThe file or device that corresponds to a memory image.  It defaults to /dev/mem.  It can be in the format described in a.out(5). 

vmunix
Contains the kernel namelist and defaults to /vmunix. 

Entering the Debugger

Kernels compiled with a debugger can access the debugger using the {FN_DEBUG} function assigned to the <PAUSE> key.  This function can be redefined to any key using the pf(1) command.  (See pf and kbdemul(4).)  The debugger can also be entered using the <Ctrl> <Alt> <Scroll Lock> sequence. 

The debugger will be invoked during boot and after panics. 

Standalone utilities compiled with the debugger can access the debugger with the “∗” command described below, or by generating a level 0 interrupt from the keyboard. It is possible to generate a standalone program with a debugger by making it with a dbg suffix, as the standalone makefile has a rule for this suffix. 

Debugger Commands

Commands may be given from either the debug command mode (after a DEBUG> prompt) or at the standalone command level (after S/A % ) with a leading “∗”.  Commands may be abbreviated, but take care to avoid ambiguity. 

A “null” command is taken as the previous command (with default operands),
 so it is possible to display consecutive segments of memory by typing display, followed by pressing the <Enter> key several times, or to single-step through a program by typing step and then pressing the <Enter> key several times.  The commands are given in alphabetical order, except that the command with the shorter abbreviation is given first.  The following commands are available:

$ prints out the current status.  It prints the reason for the current entry to the debugger, along with the IAR, ICS and CS at the time of the interrupt, and a symbolic printout of the MCPCS.  These are followed by the general registers and the System Control Registers (SCRs).  Any “watchpoints” tripped (see “Break and Watchpoints”, below) are also printed. 

? [cmd]
is a synonym for help. 

/half [addr [count] ]
opens the given address for halfword modification.  Each location is opened, the current contents displayed, and a new value read to replace the previous contents.  The new value may be a debugger expression.  Negative and zero values for count have special meanings discussed below.  A total of count locations will be opened (unless terminated by an end replacement value; see below for more details). 

/byte [addr [count] ]
opens the given address for byte modification.

/word [addr [count] ]
opens the given address for word modification.

= [addr [format] ]
prints out the given address in the given format.  The format is a printf format string and defaults to %x.  This is a quick way of printing out the contents of a given register (e.g. “= r1”). 

ascii [addr]
displays memory at the specified address in ASCII characters. One common use of this command is to display the kernel console message buffer by the command "ascii msgbufp!4+8". 

break [addr]
sets a breakpoint at the given address or, if no address is specified, lists the current breakpoints.

call addr [arg ...]
calls the C routine at the given address with up to three provided arguments. This is done on the debugger stack if the debugger has control ( DEBUG> prompt), otherwise the normal stack is used. 

clear [addr]
clears the breakpoint or watchpoint at addr.  If no addr is specified, all the current breakpoints and watchpoints are cleared. 

cls clears the screen. 

define symbol addr
defines (or redefines) the value of the symbol symbol to given address value addr. 

display [addr [count] ]
displays the contents of the given address in hexadecimal and ASCII. Count lines of output will be produced (with lines that are all zero-suppressed, except for the first).  Addr defaults to the next address (from the previous command) and count defaults to 10.  Since the default command is the previous command, one may use a display command to display memory and then press the <Enter> key to display following memory locations. 

dump [addr [count] [incr] ]
displays count words at the address addr in various formats. The increment value incr (which defaults to 1) specifies how many words to increase addr by. 

go [addr]
resumes execution after an interrupt (trap).  It inserts the breakpoints into the code and transfers control either to the IAR at the time of the interrupt or to addr if it was specified.  The ICS will have whatever value it had at the time of the interrupt (unless changed with a scr 14 value command). 

hatipt [page [count] ]
displays count entries in the hatipt (Hash Anchor Table/Inverted Page Table), starting at the entry for page. The location of the hatipt is taken from the appropriate MMU registers. 

help [cmd]
prints out a list of available commands or, if cmd is specified, the syntax and a quick summary of the effects of the given command.  If cmd is “∗”, summaries of all the commands are given. 

ident [addr [count] ]
prints out all the RCS $Header$ lines in the given program or from the given address onward.

inb [port [count] ]
reads a byte from the PC I/O port port and displays it.  If count is specified then the processes is repeated that many times with port incremented by 1 each time. 

inhw  [port [count] ]
reads a half word (16 bits) from the PC I/O port port and displays it.  If count is specified then the processes is repeated that many times with port incremented by 1 each time. 

ior [addr [count] ]
issues an IOR instruction for the given address and following locations, for a total of count locations. 

iow addr value
issues an IOW instruction for the given address and value.

lookup [symbol]
looks up all symbols in the symbol table beginning with symbol and prints them.  If symbol is not specified, the entire symbol table is printed. 

move from count to
moves count bytes of memory from from to to. 

option [n [count]]
sets internal debugger options.  Currently, n can have the following values:  “1” selects the option that can be used to trace internal debugger operation; “2” selects automatic status-updating during step commands; “3” scans for symbol definitions in the program text (note that hc does not produce such definitions); “4” displays condition codes symbolically.  The optional second value, count, is taken as the power of two of the number of instructions to execute between displays. 

outb [port [value] ]
writes the byte value to the PC I/O port port. 

outhw [port [value] ]
writes the halfword value to the PC I/O port port. 

reflect
reflects a debugger interrupt back to whomever owned it before the debugger took over the interrupt vector.  The debugger saves the previous value of the interrupt vector and the reflect command can be used to pass the interrupt to that program.  WARNING: since the debugger has executed an “LPS” instruction and accessed various status registers, a reflected program-check or machine-check interrupt may behave differently from a directly serviced one. 

register [number [value] ]
with no operands, this displays the contents of the general registers. With two operands, the specified register is changed to the given value.

scr [number [value] ]
with no operands, this displays all the system control registers.  With two operands, the specified system control register is given the specified value. Not all registers can be changed and not all bits of some registers can be changed. A warning is printed when a system control register does not end up with the requested value.

ser [value]
with no operands, this prints out the Storage Exception Register (SER), including the segment registers and the RAM and ROS specification registers. This gives useful information after a page fault or some other problem detected by the storage register. if value is specified, then this is displayed symbolically as the contents of the SER. 

show [addr]
shows the contents of the screen at the time the debugger was entered.  Use the <Print Screen> key to print, then cls to clear the screen.  On subsequent entry to the debugger, the monochrome-screen image is saved at a specified address.  If no address is specified, the debugger displays the contents of the monochrome-screen save region, which contains the screen contents at the point at which the debugger gained control.  The debugger then reads a single character from the keyboard so that the screen may be viewed.  In kernel debug mode, the screen is automatically saved when using the monochrome screen.  Once the screen save area has been specified, the debugger automatically restores the screen when a go or step command is issued.  An addr of “0” tells the debugger not to save the screen.  This is sometimes useful when single-stepping. 

step [[addr] count]
executes count instructions and returns control to the debugger.  If two parameters are specified, the first is taken as an address at which to start execution (e.g. the IAR is set to addr); count instructions are then executed.  Note that step will force the CPU priority to 1 if it was at 0 so that level-zero interrupts can be used to regain control after executing a single instruction.  Currently, breakpoints are NOT set during the execution of a step command; however, they are checked for by address comparison.  So, unless breakpoints are set on the second instruction of a branch-and-execute, they will be detected. 

symbol [addr [count] ]
prints out the symbol at addr (or the closest preceding one within count bytes).  Count defaults to 0x10000 (65536). 

symtab [addr]
notifies the debugger that a symbol table in the appropriate format is at the given address.  In kernel mode this is done automatically, before the debugger gets control, by the “rdb” interface.

trace [iar] [sp]
traces back the C call stack and prints the parameters for each routine. Iar and sp may be specified instead of the IAR and SP at the time that the debugger was entered. This is particularly useful when the debugger has been entered after a kernel trap panic, where it useful to provide the IAR and SP from the kernel trap message. 

unasm [addr [count] ]
disassembles the given address and the following ones, up to count lines of output. If a symbol table is available, the symbolic address of the instruction is printed to the right of the disassembled code. 

vector [value]
if no value is specified, the interrupt vectors for interrupt level 0, program check, machine check and the debugger’s simulated interrupt vector at 0x1A0 are reset to the debugger.  If value is specified, it defines a mask that shows which vectors to initialize.  The interpretation of value is that used when requesting interrupts via the IRB.  (For example, 8000 will reset the interrupt level 0 vector). 

version
prints out the current revision level of the debugger.

watch  [addr]
sets a watchpoint at the given address or, if no address is specified, lists the current watchpoints.

Break and Watchpoints

A breakpoint is a “TGTE R1,R1” instruction that is inserted in place of the actual instruction when executing in “non-stepped” mode. 

The debugger can handle “static” breakpoints inserted into the source code in much the same way that it handles its own breakpoints. 

Watchpoints are location values that are monitored whenever the debugger has control.  Since the debugger has control after almost every instruction when in single-step mode, it is possible to locate the exact instruction that modifies a memory location by setting a watchpoint on that location.  Only a fullword address can be a watchpoint. 

It is possible to watch a general register, since general registers are saved in locore at location 0x300.  Doing a watch 300 watches the value of R0. 

Expressions

All commands accept several possible operand types:

•a hex number (of the form of 0xnnnnnnnn); e.g. 0x123b. 

•a decimal number (of the form 0dnnnnnn); e.g. 0d12.  Also, a number with a leading sign is taken as a decimal number. 

•a symbolic address (if a symbol table is available); e.g. “main”. 

•a number without an explicit base.  Depending on context, the value will be taken as either decimal or hexadecimal.  Normally a number representing an address (such as the first operand in a command) will be taken as hexadecimal, while a number appearing as a count (such as the second operand) will be taken as decimal. 

•the contents of a register (registers are specified by “r#” where “#” is in the range 0<=#<=15. (e.g. “r0”). Note that the contents of the register are used, rather than the “address” of the register.  For example, if one has set a breakpoint at the start of a C procedure, then when that breakpoint trips, it is possible to set a breakpoint at the return address (which is in r15) by a break r15 command. 

These operands may be combined with “+” and “-” operators in the usual ways.  Spaces are not allowed in an expression. 

Virtual Addresses

Any of the operand values may be preceded with the “=” monadic operator that takes the real address of a virtual address.  Thus “=0” might have the value 0xfb000 if page zero of a user program is located there. If there is no physical page for a given virtual page, an appropriate message will be printed. This method of specifying a virtual address allows it to be used in any command that accepts an address. 

Replacement Options

The “/” commands accept some optional values that control the interactive changing of memory locations:

expr is a normal address expression as given above. 

end ends the “/” command.  You may use “_end” for the address of “end”, if necessary. 

backs up to the previous location in memory.  The amounts backed up are 1, 2, or 4 bytes, as appropriate for the “/” command given. 

space (or a null line) goes to the next location in memory. 

Notes About the / Commands

Normally the “/” commands, which open memory locations for change, refer to the given location up to three times:

1 to validate the given address before using it. 

2 to pick up the existing value for display. 

3 (optionally) to deposit the new value entered. 

In addition, the next location automatically opens after this one closes (subject to the value of count).

Sometimes, particularly with I/O addresses, this procedure can cause problems, since these hidden references change the expected behavior of the device being accessed.  This can happen because some devices have only a small window; when accessing this window, one can get different internal registers with different references. 

The solution is to use a special value in the count parameter of the “/” commands that cause abnormal behavior:

count == 0
here, the address validation reference is not done, so only the reference to read the old value and, possibly, the reference to write a new value are done.

count < 0
here, the only reference is to write a new value, if any, into the location.  Because the old value is not picked up, only the address is printed.

In both of the above cases only the addressed location is opened.  The following location is not opened automatically, because successive locations are often part of the same device. 

Symbol Table

The debugger can use a symbol table to display addresses symbolically and to refer to addresses symbolically.  The symbol table has a fixed format.  Currently it has an 8-character name (with the leading “_” stripped), and a 4-byte value (address).  This format was chosen because:

•it is compact

•it is the format used by RDB. 

•it is in one piece (the a.out format is in two pieces). 

•it is easily processed. 

•corrupting the symbol table will lead to a symbol not being found, but not to program checks inside the debugger. 

•it can be truncated to fit a particular slot in memory without invalidating the non-truncated part. 

The kernel version of the debugger has the symbol table automatically built by the kernel makefile. 

Locore Locations Used by the Debugger

The debugger uses several “locore” locations for its operations. 

100 interrupt level zero vector.  This is used in single instruction stepping. 

110 interrupt level one vector.  This is normally reset in standalone mode but not kernel mode. 

120 interrupt level two vector.  This is normally reset in standalone mode but not kernel mode. 

130 interrupt level three vector.  This is normally reset in standalone mode but not kernel mode. 

140 interrupt level four vector.  This is normally reset in standalone mode but not kernel mode. 

150 interrupt level five vector.  This is normally reset in standalone mode but not kernel mode. 

160 interrupt level six vector.  This is normally reset in standalone mode but not kernel mode. 

170 machine check vector.  This intercepts machine checks. 

180 program check vector.  This intercepts program checks. 

190 SVC (supervisor call) vector.  This is normally reset in standalone mode but not kernel mode. 

1A0 A simulated vector used for debugger calls.  This passes control to the debugger as if an interrupt had happened. 

280 is used when the debugger resumes execution after an interrupt.  The debugger places a “lm r0,0x300” and a “lps t,vector” instruction here. 

300...340
is used as a locore register save area by the debugger.

340...800
is used as an interrupt stack by the debugger as it cannot assume that the normal stack pointer is valid when an interrupt happens.

The debugger does not use locations 0...FF or locations 1B0...27F. 

NOTES

It is possible to give commands to the debugger that will cause it to generate a program or machine check.  This will cause recursive re-entry into the debugger, which will then lose track of its original entry reason.  In that case, a call or go addr command should be used to transfer control to the original program at its entry point. 

When using the call command from within the debugger after an interrupt, remember that the size-limited debugger stack is used.  This is not a problem when the program’s main entry point is called, since that establishes a new stack after a few instructions. 

Single-stepping is carried out by requesting a level zero interrupt via the IRB, then doing an “LPS 1,...”.  If the instruction being executed suppresses interrupts (e.g. it is a LPS and sets the priority to zero or masks all interrupts) or clears the IRB IRQ 0 bit, then single-stepping will either be lost or suppressed until interrupts are again possible.  This problem is handled by compiling the kernel with “-DLORDB” (specify option LORDB in the config(8) file), which causes the kernel not to go to priority level zero and not to clear the IRQ 0 bit.  The intent of -DLORDB is to allow debugging of the kernel locore routines, particularly, the interrupt service code.

SEE ALSO

“Building Systems with Config” in Volume II, Supplementary Documents
 

PRPQs 5799-WZQ/5799-PFF: IBM/4.3  —  July 1987

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026