This chapter explains how to use symmon, the kernel debugger. It contains the following sections:
![]() | Note: This program requires an ASCII terminal on the first serial port. |
Like all software, the IRIX kernel needs a reliable debugging tool. This chapter describes the kernel debugger, symmon(1), an indispensable tool for debugging device driver software. symmon(1) and the other kernel debugging tools are not automatically loaded during installation. To put these tools onto your system, install the subsystem eoe2.sw.kdebug manually from your software release CD-ROMs.
You can load symmon(1) coresident with a standalone program or operating system, then use symmon(1) to control the execution of that program or operating system. symmon(1) gives you commands to examine and alter memory and registers, set breakpoints, and execute programs.
To make a kernel that you can debug from symmon(1), you need to create a kernel slightly different from the standard one. Use the following steps (many of which you used when you added a device driver to the kernel) to create a debuggable kernel.
Become root:
% su |
Edit /var/sysgen/system/irix.sm.
Change the line:
EXCLUDE idbg |
to
INCLUDE idbg |
Find the two lines containing LDOPTS toward the end of the file. Comment out the uncommented lines and remove the comment marker for the currently commented out lines. (To comment out a line, put an asterisk character in the first column.)
Make a note of the change. When you are finished debugging, undo the change so that you can make a standard kernel.
Copy the current kernel to a safe place before rebooting.
# cp /unix /unix.orig or # ln /unix /unix.orig |
Run /etc/autoconfig and answer yes if prompted.
Use halt to bring the system down. When you issue the halt command, the system overwrites the current kernel, /unix, with the kernel you have just created, /unix.install.
# halt |
On IRIS-4D/100, 4D/200, 4D/300, and 4D/400 Series workstations, set the front panel dip switches as shown in Figure 10-1.
![]() | Caution: For these workstations, you must not use any odd-numbered port connected to a CPU for data transfer because an inadvertent <ctrl-A> in the data stream can put the system into symmon. This is true of any odd-numbered port not connected to a 6-port serial card. |
Personal IRIS, Indigo, Indigo2, Indy, Crimson, CHALLENGE/Onyx, and POWER CHALLENGE/POWER Onyx systems do not require physical switches for kernel debugging.
After halting the system, push the <Reset> button to force the processor to read the switches.
To use the kernel debugger, you must install an ASCII terminal as the system console. If you do not install an ASCII terminal as the system console, you can still use the newly built kernel under your normal configuration, but you cannot use the kernel debugger. Some systems (IRIS-4D/20, -4D/25, -4D/30, -4D/35, Indigo, Indigo2, Indy, and Crimson) allow you to use the graphics text port when the window system is not running. symmon may fail occasionally in this configuration, but it can be useful when no ASCII terminal is available.
To install an ASCII terminal as the system console:
Connect the terminal to Serial Port 1 for a single processor (or to the appropriate port number for multiprocessor systems).
Shut the system down in an orderly fashion.
Select the Command Monitor mode from the Bootstrap menu.
Type the following from the Command Monitor mode:
setenv console d |
init |
At this point, all console input and output occur on the ASCII terminal. Boot the system as usual. The kernel loads and, because the kernel includes the module idbg(), symmon() loads automatically from the root disk volume header partition for those systems where it is not part of the PROM.
![]() | Note: Although kernel output normally appears in a graphics window once graphics are started, the debugger still uses the ASCII terminal. The interactive version of symmon, called idbg, uses the same commands as symmon but does not stop the system from processing and does not require an ASCII terminal. You can use idbg to look at variables but not to set them. (See “Using symmon's Kernel Print Command”.) |
Once symmon(1) is loaded, control is transferred to the kernel. Control transfers to symmon(1) in any of the following ways:
From the console, press <ctrl-A>
![]() | Note: symmon can also be invoked from any odd-numbered CPU port on IP5 and IP7 systems, except for the IRIS-4D/210. |
Set the dbgstop environment variable from command mode before booting the kernel. (You cannot use kernel symbols at this point, but all other functions work.) To do so, set the dbgstop environment variable:
> setenv dbgstop 1 |
This transfers control to symmon(1) early in system startup. (Symbolic debugging is not enabled at this point.)
Set the symstop environment variable from command mode before booting the kernel:
> setenv symstop 1 |
This transfers control to symmon(1) after the symbol table has been loaded but early in the system startup procedure.
Insert a call to the debug(uchar_t *msg) service from a known location within your kernel.
The IRIX kernel executes a breakpoint instruction.
A system panic occurs.
symmon(1) provides commands that allow you to display and alter the processor and coprocessor general-purpose registers. To identify a general-purpose register (there are 32 registers, numbered 0 through 31), you can use names such as “r0” or “r31,” or you can use the compiler usage names (in some cases, you may need to prepend a “$”). The compiler names and the associated “r” names are listed in Table 10-1.
Table 10-1. Processor and Coprocessor General-purpose Registers
Compiler | Processor | Usage |
|---|---|---|
zero | r0 | Wired zero |
at | r1 | Assembler temporary |
v0 | r2 | Function value registers |
v1 | r3 |
|
a0 | r4 | Argument registers |
a1 | r5 |
|
a2 | r6 |
|
a3 | r7 |
|
t0 | r8 | Caller saved registers |
t1 | r9 |
|
t2 | r10 |
|
t3 | r11 |
|
t4 | r12 |
|
t5 | r13 |
|
t6 | r14 |
|
t7 | r15 |
|
s0 | r16 | Callee saved |
s1 | r17 |
|
s2 | r18 |
|
s3 | r19 |
|
s4 | r20 |
|
s5 | r21 |
|
s6 | r22 |
|
s7 | r23 |
|
t8 | r24 | Caller saved |
t9 | r25 |
|
k0 | r26 | Kernel temporary |
k1 | r27 |
|
gp | r28 | Global pointer |
sp | r29 | Stack pointer |
fp/s8 | r30 | Callee saved |
ra | r31 | Return address |
You can refer to special R2000/3000/4000/8000 registers and system coprocessor registers by using the names listed in Table 10-2, Table 10-3, and Table 10-4.
Table 10-2. R2000-R4000 Processor and Coprocessor Special Registers
Name | R2000/3000/4000 Register |
|---|---|
mdlo | Mul/div register lower word |
mdhi | Mul/div register higher word |
pc epc | Exception PC |
sr | Status register |
cause | Cause register |
tlbhi entryhi | TLB entry hi register |
tlblo entrylo | TLB entry lo register |
badvaddr | Bad virtual address |
index inx | TLB index register |
context ctxt | Context register |
random | Random register |
Table 10-3. R4000-only System Coprocessor Registers
Name | R4000Series System Coprocessor Register |
|---|---|
tlblo0 | TLB entrylo0 register |
tlblo1 | TLB entrylo1 register |
pagemask | TLB pagemask register |
wired | TLB wired register |
count | Timer count register |
compare | Timer compare register |
watchlo | WatchLo register |
watchhi | WatchHi register |
ecc | Ecc register |
cacherr | Cache error and status register |
errepc | Cache ErrorEpc register |
taglo | Cache tag register |
config | Configuration register |
Table 10-4. R8000-only Special Registers
Name | R8000 Series Special Register |
|---|---|
tlbset | TLBset register |
trapbase | Trapbase register |
ubase | UBase register |
pbase | PBase register |
gbase | GBase register |
shiftamt | ShiftAmt register |
wired | Wired register |
badpaddr | BadPAddr register |
This section describes the symmon commands. “symmon's dbgmon Mode Commands” describes the general symmon commands, which are referred to as dbgmon mode commands. “Using symmon's Kernel Print Command” describes the symmon command kp. The kp command briefly accesses another mode of the kernel debugger, Kernel Print mode (also called KP mode). After symmon executes the kp command, it returns to dbgmon mode.
Use symmon's dgbmon mode when you need ordinary debugger commands such as brk, dump, get. Use symmon's KP mode when you want to view kernel structures and other information.
To see a listing of messages concerning the symmon commands while running symmon, type a question mark (?) and press <Enter>. In addition, commands that require arguments give a usage summary if you enter the command without arguments.
This section describes the commands of symmon's dbgmon mode. Each heading lists the name of the command, its option flags, and its arguments. The headings use square brackets to indicate optional arguments and option flags. Following each heading is text that describes the purpose of the command. Following the command description are descriptions of each argument or option flag (if any). Different systems and operating system releases may have slightly different commands or options. For example, symmon is part of the PROM on some systems, while it is loaded at boot time on others. (See Table 10-5.)
Table 10-5. symmon's dbgmon Mode Commands
Command | Description |
|---|---|
Mark breakpoints at specified addresses. | |
Show the backtrace leading up to entry to the debugger. Also see the kp ubt command. | |
c | Leave the debugger environment and continue execution. |
cacheflush range | Flush both the instruction and the data caches over the range of addresses given. |
clear | Clear the screen. |
call [pc] [arg1, arg2, arg3, arg4] | Execute the code starting at the address specified. |
dis range | Disassemble MIPS assembly instructions for the specified range of memory locations. |
dump [-Bcdoux] [-bhw] range | Get a formatted display of an area of memory. |
g [-bhw] location | Display the contents of a memory location or a register. |
goto list | Continue execution of the client process from the location indicated by the client pc register to the location specified. |
help | List a short summary of the built-in commands. |
hx namelist | Convert a name or list of names into their equivalent hexadecimal address values. |
lkaddr address | Print symbols “near” the given address. |
lkup name | Print address of the specific partial name. |
nm addresslist | Display the equivalent symbol name of a hexadecimal address or list of hexadecimal addresses. |
p [-bhw] location value | Set the contents of the register or memory location to a value. |
s [count] and S [count] | Execute one or more instructions of client code. |
sleep | Put a processor into the waiting loop on multiprocessing systems. |
string address [maxlen] | Display memory as a null-terminated ASCII string. |
tlbdump [range] | Display the current contents of an R2000/3000/4000 address translation buffer. |
tlbflush [range] | Flush mappings from R2000/3000/4000 address translation buffer. |
tlbmap
[-i index] | Establish a virtual-to-physical address map in the R2000/ 3000/4000 translation buffer. |
tlbpid [pid] | Get or set the process identifier (pid). |
tlbptov physaddr | Display the tlb entries that map a physical address. |
tlbvtop vaddress [pid] | Display the R2000/3000/4000 translation buffer entries that map the specified virtual address. |
unbrk bpnumlist | Remove breakpoints. |
wake | Wake up slave processors. |
wpt | Set a read, write, or read/write watch point at physical address physaddr, using the R4000 watch point registers. |
Use brk to mark breakpoints at specified addresses. If you do not specify an argument, brk shows all currently set breakpoints.
Synopsis
brk [addresslist] |
Arguments
| addresslist | Use this parameter to specify the addresses at which you want breakpoints. You can enter addresses either numerically or symbolically. If you enter the addresses numerically, brk assumes that all address values are in base 10 unless you specify otherwise. To enter a hexadecimal value, precede the value with 0x. To enter an octal value, precede the value with 0. If you enter the addresses as symbolic names, enter the addresses according to the format symbol or symbol+hexval, where hexval is a word-aligned hexadecimal value. |
bt shows the backtrace leading up to the entry to the debugger. However, you will probably find the information from kp ubt to be more useful. In general, backtraces do not go past the last interrupt or exception.
Synopsis
bt |
c allows you to leave the debugger environment and continue execution. c directs symmon to continue execution from the location indicated by the current value of the client program counter register. This command is the counterpart of the <ctrl-a> character combination that returns control to the debugger. See also q(uit).
Synopsis
c |
call executes the code starting at the address specified.
Synopsis
call [pc] [arg1 arg2 arg3 arg4] |
Arguments
| [pc] | Use this argument to specify the starting address of a client routine. If no argument is specified, the saved pc is used. | |
| [args] | Use these optional arguments to specify the arguments (up to four) that you want to pass to the routine pointed to by pc. |
dis disassembles MIPS assembly instructions for the specified range of memory locations.
Synopsis
dis range |
Arguments
| range | Use this argument to specify the range of memory you want to display. You can specify the range argument in one of the following three formats: baserange is a base address. Use this format to disassemble the contents of a single location. The base address can be a hexadecimal address, a symbol name, or a symbol name plus a hexadecimal offset. base#count range is a base address, followed by a number “#” character, followed by a count value. Use this format to disassemble a range of count words, starting at the base address. The base address can be a hexadecimal address, a symbol name, or a symbol name plus a hexadecimal offset. However, the count value is a hexadecimal value. base:limit range is a base address, followed by a colon “:” character, followed by an upper limit address. base is a hexadecimal address or a symbol name. Use this format to disassemble the contents of those words whose addresses are greater than or equal to the base address, but less than the limit address. The value given as the base address or as the limit can be a hexadecimal address, a symbol name, or a symbol name plus a hexadecimal offset.
|
Use dump to get a formatted display of an area of memory.
Synopsis
dump [-Bcdoux] [-bhw] range |
Arguments
| [-Bcdoux] | Use these options to set the format in which dump displays the contents of a memory location. The default format is hexadecimal. The formats associated with these options are: x = hexadecimal | |
| [-bhw] | Use these options to specify the size of the memory location. The default is word. The associated sizes are: b = byte | |
| range | Use range to specify the amount of memory to be displayed. You can specify range in one of the following formats: base range is a base address. Use this format to disassemble the contents of a single location. The base address can be a hexadecimal address, a symbol name, or a symbol name plus a hexadecimal offset. base#count range is a base address, followed by a number “#” character, followed by a count value. Use this format to disassemble a range of count words, starting at the base address. The base address can be a hexadecimal address, a symbol name, or a symbol name plus a hexadecimal offset. However, the count value is a hexadecimal value. base:limit range is a base address, followed by a colon “:” character, followed by an upper limit address. base is a hexadecimal address or a symbol name. Use this format to disassemble the contents of those words whose addresses are greater than or equal to the base address, but less than the limit address. The value given as the base address or as the limit can be a hexadecimal address, a symbol name, or a symbol name plus a hexadecimal offset. |
Use g (or get) to display the contents of a memory location, general-purpose register, special-purpose register, or a system coprocessor register.
Synopsis
g [-bhw] location |
Arguments
| [-bhw] | Use these options to specify the size of the location you want to display. The default size is a word. The sizes associated with these options are: b = byte | |
| location | Use location to specify the location or register you want to get. The format for a location or register can be a hexadecimal value or the symbolic name (plus a hexadecimal offset) of the address or the client register you want to display. To specify one of the 32 general-purpose registers, 0 through 31, use the names r0 through r31, or use the compiler-usage names. See Table 10-1 for a list of such registers. |
goto continues the execution of the client process from the location indicated by the client program counter (pc register) to the instruction at the location(s) you specify. Use this command to set a list of temporary breakpoints.
Synopsis
goto list |
Arguments
| list | Use this parameter to specify a list of hexadecimal addresses and/or names of locations at which you want to set temporary breakpoints. These temporary breakpoints are automatically removed once they have been encountered. |
Use hx to convert a name or list of names into their equivalent hexadecimal address values.
Synopsis
hx namelist |
Arguments
| namelist | Use this argument to specify the list of names you want to convert. This argument can be one or more symbol names (plus hexadecimal offset). |
The next two items (lkaddr and lkup) are not available in older versions:
lkaddr prints symbols “near” the given address.
Synopsis
lkaddr address |
Arguments
| address | Use this argument to specify the starting address of the string you want to display. |
name may be only a partial name, such as “init.”. Symbols containing name are printed with their respective addresses.
Synopsis
lkup name |
Arguments
| name | name is a filename. |
Use nm to display the equivalent symbol name (plus hexadecimal offset) of a hexadecimal address or list of hexadecimal addresses.
Synopsis
nm addresslist |
Arguments
| addresslist | Use this parameter to specify the addresses at which you want breakpoints. You can enter addresses either numerically or symbolically. |
Use p (or put) to set the contents of the register or memory location to a value.
Synopsis
p [-bhw] location value |
Arguments
| [-bhw] | Use these options to specify the size of the memory location or register value you want to set. The default size is word. The sizes associated with each of these options are: b = byte | |
| location | Use this argument to specify the memory location or register you want to set. To specify a memory location, use the hexadecimal name of the memory location, or the symbolic name (plus a hexadecimal offset) of a memory location you want to set. To specify any of the 32 general-purpose registers, use the names r0, r1, r2 through r31, or use the compiler mnemonics for these registers (see Table 10-1). You can also set special-purpose registers and the system coprocessor registers (see Table 10-2). To specify the pc register, use the entry point of a client routine as the location argument. | |
| value | Use this argument to specify the hexadecimal value you want to write to the specified memory location or register (value is always assumed to be hexadecimal.) |
Use sleep to put a processor into the waiting loop on multiprocessing systems. To awaken the sleeping processor, use the wake command. On IRIS-4D 100/200/300/400 Series workstations, do not use this command on CPU 0.
Synopsis
sleep |
Both s and S allow you to execute one or more instructions of client code. These two commands differ only in the way they handle jal and bal, instructions that execute subroutines.
When S executes an instruction that calls a subroutine, it executes the entire subroutine as a single instruction, up to and including the return instruction. S fails to regain control if the subprocedure does not return.
When s executes an instruction that calls a subroutine, it counts the jump to the subroutine as a single instruction, then executes instructions within that subroutine up to the number you have specified (minus the one counted when executing the jump instruction). If you specify only one instruction (the default), and the next instruction calls a subroutine, s jumps to the subroutine and stops.
Synopsis
s [count] S [count] |
Arguments
| [count] | Use this optional argument to specify the number of instructions you want s or S to execute. The default is 1. |
Use this command to display memory as a null-terminated ASCII string. This argument escapes non-printable characters with the backslash character, just as is done in the C programming language.
Synopsis
string address [maxlen] |
Arguments
| address | Use this argument to specify the starting address of the string you want to display. | |
| [maxlen] | Use this optional argument to specify the length of the string. The default value for this argument is 70. |
Use tlbdump to display the current contents of an R2000/3000/4000 address translation buffer.
Synopsis
tlbdump [range] |
Arguments
| [range] | Use this optional argument to select a range of tlb entries. The default behavior is to display the entire contents of tlb. The three formats for range are: baserange is a hexadecimal value. An index into tlb. tlbdump displays the contents of this single location. base#countrange is a table index followed by a number “#” character, followed by a count value. tlbdump displays the contents of a range of count tlb entries starting at the tlb entry whose index is base. Both base and count are hexadecimal values. base:limitrange is a table index followed by a colon “:” character, followed by an upper limit index. Use this format to display a range of tlb entries whose indices are greater than or equal to base, but less than limit. These index values are all hexadecimal values. |
Use tlbflush to flush mappings from the R2000/3000/4000 address translation buffer, thus making them invalid, not matching any possible address/pid pair. You can use this command to clear translations for both symmon and the client process.
Synopsis
tlbflush [range] |
Arguments
| [range] | Use this optional argument to specify the range of tlb entries that you want to flush. If you do not specify a range, tlbflush defaults to clearing all tlb entries. To specify a [range], use one of the following formats: |
![]() | Note: Multiprocessor systems have an address translation buffer associated with each processor. A command that dumps or changes translation buffers affects only the processor associated with the debug terminal from which such commands issued. |
Use tlbmap to establish a virtual to physical address map in the R2000/3000/4000 translation buffer. You can use tlbmap to establish mappings for both symmon and the client process.
Synopsis
tlbmap [-i index] [-ndgv] [-dgv] [-c algo] vaddress paddress |
Arguments
| [-i index] | Use the -i option to specify the particular tlb entry, index, that you want to use to contain the mapping. If you do not specify a tlb index, tlbmap uses a random tlb entry, at an index ranging 8 to 63. | |
| [-ndgv] | (R2000/3000 only) | |
| [-dgv] | (R4000 only) Use these options to set bits in the tlb entry for the map. Each option controls a single bit. By default, these bits are unset (zero). The significance of setting a bit (and the associated options) are: n = non-cacheable (R2000/3000 only) | |
| [-c algo] | (R4000 only) Use this to set the cache algorithm in the tlb entry for the map. The algorithms are specified by a number. The designations are: 0: reserved | |
| vaddress | Use this argument to specify the virtual address side of the map. | |
| paddress | Use this argument to specify the physical address side of the map. |
Use tlbpid to get or set the process identifier (pid), a value in the R2000/3000/4000 system coprocessor register, tlbhi. The tlbpid command affects only the process identifier used by symmon and client code executed through the call command. tlbpid does not affect the process identifier used when client code is executed by single stepping or when continuing execution.
Synopsis
tlbpid [pid] |
Arguments
| [pid] | Use this optional argument to indicate the value to which you want tlbpid to set the pid value in the R2000/3000/4000 coprocessor register, tlbhi. |
If you specify no [pid] argument, tlbpid displays the pid value currently in the R2000/3000/4000 coprocessor register, tlbhi.
Use tlbptov to display the tlb entries that map a physical address. tlbptov searches the R2000/3000/4000 translation buffer, looking for translations that map the specified physical address. tlbptov displays all matches, whether valid or invalid.
Synopsis
tlbptov physaddr |
Arguments
| physaddr | Use this argument to specify the physical address for which you want to find tlb entries. |
Use tlbvtop to display the R2000/3000/4000 translation buffer entries that map the specified virtual address.
Synopsis
tlbvtop vaddress [pid] |
Arguments
| vaddress | Use this argument to specify the virtual address for which you want to find tlb entries. | |
| [pid] | Use this optional argument to specify the pid associated with the tlb entry. If you do not specify a pid, tlbvtop defaults to using the pid value currently in the coprocessor register tlbhi. |
Use unbrk to remove breakpoints.
Synopsis
unbrk bpnumlist |
Arguments
| bpnumlist | Use this argument to specify the ordinal of a particular breakpoint you want to remove. Use the brk command to get the ordinal of a particular breakpoint. |
Use wake to wake up slave processors. wake brings all slave processors into a waiting loop, whether those processors are scanning for a keystroke on the console to drop into symmon or looking for the address to which to jump to execute the boot() routine.
Synopsis
wake |
Use wpt to set a read, write, or read/write watch point on a physical address, using the R4000 watch point registers.
Synopsis
wpt [r|w|rw|] [0|physaddr] |
Arguments
| r | Read | |
| w | Write | |
| rw | Read/write | |
| physaddr | Double word aligned address. The watch point will trip on any access within the next eight bytes. | |
| 0 | An argument of 0 clears the watch point. |
The kernel print mode command, kp, allows the user to print kernel structures or information summarized from kernel structures. If you do not know the names of the kernel structures or summaries that you want to see, just issue the kp command without specifying an argument. If you do not specify an argument for kp, the command displays the names of all its subcommands. The ?? command lists the names of all the kp subcommands with short descriptions. For systems that do not have symmon in PROM, you may omit the leading “kp”.
Some of the information you can view using the kp command is not of interest to you when debugging device drivers. In the following sections, we describe only those structures and summaries useful when debugging a device driver. kp commands that display data are also used with the idbg command (without the kp keyword).
![]() | Note: The following sections mention a number called the “process table entry index.” This number is not the process ID. To find the process table entry index that corresponds to a particular process ID, issue the command: kp plist proc_id, where proc_id is the process ID for which you want to find the process table entry index. |
The kernel can contain any number of buf type structures. Use these structures to manage data transfers to and from a device. To view all of these structures, use kp buf without specifying [index/address]. To see a particular buf type structure, specify either the buffer index number for the structure or the address for the buf type structure as the [index/address] argument.
This displays the exception frame at the given address. The exception frame holds the contents of the general purpose registers at the time the process last executed. If the address is a small integer, the exception frame of the process with that process table index is used.
Use kp inode to view the contents of an inode structure. To specify which inode structure you want to see, provide the number or the address of the inode structure as the [number/address] argument. kp inode is obsolete in 5.x. See vnode structures.
Synopsis
kp inode number/address |
Use ID to print symbols for the dynamically loaded module ID, which can be found using the ml list command or the lboot -V command.
This prints the contents of the console print buffer, which can be useful when an important message scrolls off the screen.
Without an argument, the kp command describes all the processes on the system. To see the plist information that applies to a particular process, specify the process ID as the [#] argument. Thus, to see the plist information that applies to a process with a pid of 16672, enter the command:
% kp plist 16672 |
The information that kp plist [#] displays for a process consists of items such as:
process table entry number, or index (also known as the process slot number). You use this number, instead of the pid, when selecting process-specific information from other kernel structures via kp, so be careful not to confuse it with the pid.
process ID
process status (such as sleep)
The pda structure contains information about a processor's private data area. If you do not specify [index], kp pda gives you the pda structure for all the processors. To see the pda structure for a specific processor only, use the [index] argument to specify the processor array index for that processor. The value of this argument must be 0 on a single-processor system or a number between 0 and n on a multiprocessor system.
A proc structure contains process-specific information not listed in the plist summaries. kp requires that you specify the proc structure you want to see. You can specify a particular proc structure by giving either the process table entry number (index) for the process or the address (address) for the proc structure (in u.u_proc.p for the currently mapped process).
Dump the contents of buffers queued for the given device. The device argument is given as the major/minor device number of the desired device.
The runq structure contains information describing the processes in the run queue. These are processes that are not running but that could run. kp runq displays all the information for every process in the runq structure.
The system uses sema type structures to manage the information associated with a semaphore (for example, the semaphore's name, the number of times it was used, whether it is free or locked). Use kp sema address to list the contents of a particular sema structure.
Use this command to view information on all sleeping processes. This information includes such items as the process name, the process address, and the name and address of the semaphore upon which the process is sleeping. kp slpproc lists all the information in the slpproc structure.
Use this command to view subroutine backtrace information for a user process. This information includes such items as the stack pointer, the caller, and the called function. If you do not specify [index], this command reports on the currently mapped user process. To specify a particular user process (one that may or may not currently be mapped) give kp ubt [index], the index into the process table for the user process in which you are interested.
![]() | Caution: If a process is currently running on a CPU, you must issue the ubt command on the CPU the process is running on. Using ubt # on currently running process will produce erroneous results. |
kp ubt [index] is analogous to the dbx command, where.
The user structure contains information that describes a user area. If you do not specify [index], kp user displays the user structure for the currently mapped user. To view the user structure for a particular process (one that may or may not currently be mapped), give kp user [index], the index into the process table for the user process in which you are interested.
Use kp WD93 to view information concerning WD93 SCSI devices.
Synopsis
kp wd [0, 1, 2, address] |
Arguments
| 0 | Use this option to display the contents of the WD93 registers. No equivalent yet exists for WD95. | |
| 1 | Use this option to display the host structure and active scsi_request_t. | |
| 2 | Use this option to show all allocated subchannels. | |
| address | Use this option to show the subchannel at the specified address. |
Debugging multiprocessor device drivers with symmon is similar to debugging multiprocess code in general. There are two phases: debugging multiprocess code forced to run on a single processor, followed by debugging the same code as it runs on multiple processors.
To force a multiprocess device driver to run on one processor only, you must deactivate all but one processor. Currently, network load is spread across CPUs by default. To preempt network packet processing, see the rtnetd(1M) and network(1M) man pages.
On IRIS-4D and POWER Series systems, multiprocessor debugging requires that you connect an ASCII terminal to each processor. On a two-processor system, the second terminal connects to Serial Port 3. For four-processor systems, the additional terminals connect to ports 5 and 7. Additionally, you must set the MODE switches 4 and 8 (located at the front of the 4D system panel) to “open.” When these MODE switches are open, power-on diagnostics display on the terminal attached to each processor. symmon loads automatically on all non-console processors, and each prints a message to its terminal. The mode switches are depicted in Table 10-1.
![]() | Note: Indigo, Indigo2, Indy, Crimson, CHALLENGE/Onyx, POWER CHALLENGE/POWER Onyx systems do not require physical manipulation of MODE switches. |
On multiprocessor systems, a separate symmon runs on each processor. Breakpoints, however, are shared. When a processor reaches a breakpoint instruction, control is transferred to the symmon associated with that processor. Other processors may continue to run independently until they also happen to hit that breakpoint, which can happen if you set a breakpoint in a kernel function or anywhere in a multiprocessor device driver.
At this point, before the kernel is loaded (through a boot command from command mode), you can disable processors not associated with the console (the console processor is referred to as the master processor) by pressing the <Enter> key on the keyboard. Disabling processors is useful during the initial debugging phase of a multiprocess program because it is easier to debug a multiprocess program first in single-processor mode. This way, you eliminate the usual sorts of bugs before you have to deal with bugs associated specifically with multiprocessing (such as synchronization bugs).
(See also M. Maekawa, A. Oldehoeft, and R. Oldehoeft. Operating Systems Advanced Concepts. The Benjamin/Cummings Publishing Company, Inc., 1987 and A. Silberschatz, J. Peterson, and P. Galvin. Operating System Concepts, Third Edition. Addison Wesley Publishing Company, 1991.)
By default, all device driver software runs only on the master processor. A driver that understands the multiprocessor environment can indicate that it contains semaphored code through a flag in the master file. However, it is still easier to debug drivers initially on a single-processor system.
If you do not disable the non-master processors, processes run on them as usual. If a breakpoint is encountered on that (non-master) processor, or if a <ctrl-A> character sequence is entered on that (non-master) processor's terminal, control transfers to symmon on that processor. Other processors continue to execute kernel (and user) code until they detect a <ctrl-A> character sequence, reach a break instruction, or hit a lock or semaphore held by the stopped CPU.
Debugging on CHALLENGE/Onyx and POWER CHALLENGE/POWER Onyx systems requires only a single ASCII terminal. All symmon output for all CPUs is multiplexed to the one port. To talk to an individual CPU, use the cpu# command. CPUs must be stopped (with the stop command) before you can connect to them. To restart all CPUs, use the C all command.
![]() | Note: It may be necessary to use <ctrl-A> several times when entering symmon. |
Because the code to force all CPUs, other than the one that does the dump, to spin is at a very high level, the best way to force a memory dump is to use symmon to call panic with the address of some string in the kernel, as in:
kp call panic addr |
On CHALLENGE/Onyx and POWER CHALLENGE/POWER Onyx series systems, an alternative is to use the NMI button.