4.1cBSD/usr/doc/debug.ms

Compare this file to the similar file:
Show the results in this format:

.bd S B 3
.de UX
.ie \\n(GA>0 \\$2UNIX\\$1
.el \{\
.if n \\$2UNIX\\$1*
.if t \\$2UNIX\\$1\\f1\(dg\\fP
.FS
.if n *UNIX
.if t \(dgUNIX
.ie \\$3=1 is a Footnote of Bell Laboratories.
.el is a Trademark of Bell Laboratories.
.FE
.nr GA 1\}
..
.TL
Using ADB to Debug the
.UX
Kernel
.br
Revised March, 1983
.AU
Samuel J. Leffler
.AU
William N. Joy
.AI
Computer Systems Research Group
Department of Electrical Engineering and Computer Science
University of California, Berkeley
Berkeley, California  94720
(415) 642-7780
.de IR
\fI\\$1\fP\\$2
..
.de DT
.TA 8 16 24 32 40 48 56 64 72 80
..
.AB
.PP
.FS
*DEC and VAX are trademarks of
Digital Equipment Corporation.
.FE
This document describes the use of extensions made
to the 4.1bsd release of the VAX*
.UX
debugger
.I adb for the purpose of debugging the
.UX
kernel.
It discusses the changes made to allow
standard
.I adb
commands to
function properly with the kernel and
introduces the basics necessary for users
to write
.I adb
command scripts which
may be used to augment the standard
.I adb
command set.  The examination techniques described here
may be applied to running systems, as well as 
the post-mortem dumps automatically created
by the 
.IR savecore (8)
program after a system crash.
The reader is expected to have at least a
passing familiarity with the debugger command
language.
.AE
.ds LH "Using ADB on the UNIX Kernel
.ds RH Introduction
.ds CF \*(DY
.LP
.nr H1 1
.ds CH "
.bp
.nr % 1
.ds CH "\(hy \\n(PN \(hy
.LG
.B
.ce
1. INTRODUCTION
.sp 2
.R
.NL
.PP
Modifications have been made to the
standard VAX
.UX
debugger
.I adb
to simplify
examination of post-mortem
dumps automatically generated following a system crash.
These changes may also be used when examining
.UX
in its normal operation.
This document serves as
an introduction to the
.B use
of these facilities, and
should not be construed as a description
of \fIhow to debug the kernel\fP.
.NH 2
Invocation
.PP
When examining the
.UX
kernel a new option,
\fB\-k\fP, should be used, e.g.
.sp 1
.ti +5
adb \-k /vmunix /dev/mem
.sp 1
This flag causes
.I adb
to partially simulate
the VAX virtual memory hardware when
accessing the
.I core
file.
In addition the internal state maintained
by the debugger is initialized from
data structures maintained by the
.UX
kernel explicitly for debugging\(dd.
A post-mortem dump may be examined in a similar
fashion,
.sp 1
.ti +5
adb \-k vmunix.? vmcore.?
.sp 1
where the appropriate version of the saved operating system
image and core dump are supplied in place of ``?''.
.FS
\(dd If the \-k flag is not used when invoking
.I adb
the user must explicitly calculate virtual
addresses.  With the
.B \-k
option
.I adb
interprets page tables to automatically
perform virtual to physical address translation.
.FE
.NH 2
Establishing Context
.PP
During initialization
.I adb
attempts to establish the
context of the ``currently active process'' by examining
the value of the kernel variable \fImasterpaddr\fP.
This variable contains the virtual address of the 
process context block of the last process which
was set executing by the \fISwtch\fP routine.
\fIMasterpaddr\fP normally provides sufficient information
to locate the current stack frame (via the stack
pointers found in the context block).
By locating the VAX process context block for the
process,
.I adb
may then perform virtual to
physical address translation using that process's
in-core page tables.
.PP
When examining post-mortem dumps locating the
most recent stack frame of the
``currently active process'' is nontrivial.
This is due to the different ways in which the
VAX may save state after a nonrecoverable error. 
Crashes may or may not be ``clean'' (i.e.
the top of the interrupt stack contains the process's
kernel mode stack pointer and program counter);
an ``unclean'' crash will occur, for instance,
if the interrupt stack overflows.
Thus, one must manually try one of two possible techniques
to get a stack trace from a post-mortem dump.  If the
crash was clean the current stack pointer is present at the
``top'' of the interrupt stack, \fIintstack\-4\fP,
and the command
.sp 1
.ti +5
*(\fBintstack\fP\-4)$c
.sp 1
will generate a stack trace all the way from the kernel
to the top of the user process's stack (e.g. to the
\fImain\fP routine in the user process which was running).
Otherwise, one must scan through the interrupt stack
looking for the stack frame.  This is usually indicated
by a zero longword entry (the procedure call handler)
followed by a longword entry with bit 29 set (indicating
the call frame was generated as a result of a ``calls''
instruction).
.sp 1
.in +5
.nf
\fBintstack\fP/\fBX\fP
.fi
.in -5
.sp 1
Once the stack pointer has been located, the command
.sp 1
.ti +5
\fB*.$c\fP
.sp 1
will generate a stack trace.
An alternate method may be used when a trace of a particular
process is required, see section 2.3.
.ds RH "Command Scripts
.LP
.nr H1 2
.bp
.LG
.B
.ce
2. ADB COMMAND SCRIPTS
.sp 2
.R
.nr H2 0
.NL
.NH 2
Extending the Formatting Facilities
.PP
Once the process context has been established, the
complete
.I adb
command set is available for interpreting
data structures.  In addition, a number of
.I adb
scripts have
been created to simplify the structured printing of commonly
referenced kernel data structures.  The scripts normally
reside in
the directory \fI/usr/lib/adb\fP, and are invoked
with the ``$<'' operator.
(A later table lists the ``standard'' scripts.)
.PP
As an example, consider the following listing which
contains a dump of a faulty process's state
(our typing is shown emboldened).
.sp 1
.nf
.DT
% \fBadb \-k vmunix.17 vmcore.17\fP
sbr 8001d064 slr d9c
p0br 800efa00 p0lr 34 p1br 7f8efe00 p1lr 1ffff2
\fB*(intstack\-4)$c\fP
_boot() from 80004025
_boot(0,4) from 80004025
_panic(80021185) from 800057e2
_soreceive(8017478c,0) from 80007c90
_read() from 800098d7
_syscall() from 8000b6e2
_Xsyscall(3,7fffe834,258) from 80000f64
?() from c1c
?() from 26a
?(0,7fffef18,7fffef1c) from 1d3
?() from 2f
\fB800021185/s\fP
_icpreg+99:	receive
\fBu$<u\fP
_u:
_u:		ksp		usp
		7fffff9c	7fffe59c
		r0		r1		r2		r3
		155c00		800237d4	80041800	3
		r4		r5		r6		r7
		0		0		11090		80041800
		r8		r9		r10		r11
		80021244	c		7fffe5b4	80000000
		ap		fp		pc		psl
		7fffffe8		7fffffa4		8000b784	d80004
		p0br		p0lr		p1br		p1lr
		800efa00	4000034	7f8efe00	1ffff2
		szpt		cmap2		sswap
		2		94000307	0
		sigc1		sigc2		sigc3
		1af03fb		fa007f02	40cbc6c
_u+78:		arg0		arg1		arg2
		3		7fffe834	258
_u+8c:		segflg	error	uid	gid	ruid	rgid	procp
		0	0	4	a	4	a	80041800

_u+d4:		uap		rv1		rv2		ubase
		7ffff078		0		1		7fffe834
		count		off		cdir		rdir
		258		150		8003cf00	0
_u+f4:		pathname
		.netrc
		dirp		dino	entry	pdir
		3		1395	.netrc0
7ffff11c:	ofiles
		80040818	80040818	80040818	800406b0
		800406d4	800406ec	0		0
		0		0		0		0
		0		0		0		0
		0		0		0		0

		ofileflg
		0	0	0	0	0	0	0	0
		0	0	0	0	0	0	0	0
		0	0	0	0
7ffff180:	sigs
		0		360c		1		360c
		0		0		0		aae
		0		0		0		0
		0		0		0		0
		0		0		0		0
		1		0		0		0
		0		0		0		0
		0		0		0		0

		code		ar0		prbase		prsize
		0		80000000	0		0

.ne 2
7ffff248:	proff		prscal		eosys	sep	ttyp
		0		0		0	0	800288b4

7ffff258:	ttymin	ttymaj
		0	0
7ffff25e:	xmag		xtsiz		xdsiz		xbsiz
		3c000000	10000000	108c0000	a680000

		xssiz		entloc		relflg
		0		0		6c720000
7ffff27e:	directory
		ogin
		start		acflg	fpflg	cmsk	tsiz	dsiz
		11688		0	12	0	160000		60000

7ffff2a2:	ssiz
		80000
\fB80041800$<proc\fP
80041800:	link		rlink		addr
		800237d4	0		800efde0
8004180c:	upri	pri	cpu	stat	time	nice	slp	cursig
		073	073	045	03	023	024	0	0
80041814:	sig		siga0		siga1		flag
		0		80002		45		8001
80041824:	uid	pgrp	pid	ppid	poip	szpt	tsize
		4	bb	bc	bb	0	2	1e
80041834:	dsize		ssize		rssize		maxrss
		16		6		14		3fffff
80041844:	swrss		swaddr		wchan		textp
		0		0		0		80044ee0
80041854:	clktim		p0br		xlink		ticks
		0		800efa00	80041720	22
80041864:	%cpu				ndx	idhash	pptr
		+5.1369253545999527e\-02	1c	8	80041720
\fB80044ee0$<text\fP
80044ee0:	daddr
		7e2		0		0		0
		0		0		0		0
		0		0		0		0

		ptdaddr	size		caddr		iptr
		352		1e		80041800	8003cfa0

		rssize	swrss	count	ccount	flag	slptim	poip
		1a	0	02	02	042	0	0
.sp 1
.fi
.PP
The cause of the crash was a ``panic''
(see the stack trace) due to the 0
argument passed the \fIsoreceive\fP routine.  The majority
of the dump was done to illustrate the use of two command
scripts used to format kernel data structures.  The ``u''
script, invoked by the command ``u$<u'', is a lengthy series
of commands which pretty-prints the user vector.  Likewise,
``proc'' and ``text'' are scripts used to format the obvious
data structures.  Let's quickly examine the ``text'' script (the
script has been broken into a number of lines for convenience
here; in actuality it is a single line of text).
.sp 1
.nf
\&./"daddr"n12Xn\e
"ptdaddr"16t"size"16t"caddr"16t"iptr"n4Xn\e
"rssize"8t"swrss"8t"count"8t"ccount"8t"flag"8t"slptim"8t"poip"n2x4bx++n
.sp 1
.fi
The first line produces the list of disk block addresses associated
with a swapped out text segment.  The ``n'' format forces a new-line
character, with 12 hexadecimal integers printed immediately after.
Likewise, the remaining two lines of the command format the remainder
of the text structure.  The expression ``16t'' causes
.I adb
to tab
to the next column which is a multiple of 16.  
The last two plus operators are present
to round ``.'' to the end of the text structure.  This allows the
user to reinvoke the format on consecutive text structures without
having to be concerned about proper alignment of ``.''.
.PP
The majority of the scripts provided are of this nature.
When possible, the formatting scripts print a data structure
with a single format to allow subsequent reuse when interrogating
arrays of structures.  That is, the previous script could have
been written
.sp 1
.nf
\&./"daddr"n12Xn
+/"ptdaddr"16t"size"16t"caddr"16t"iptr"n4Xn
+/"rssize"8t"swrss"8t"count"8t"ccount"8t"flag"8t"slptim"8t"poip"n2x4bx++n
.sp 1
.fi
but then reuse of the format would have invoked only the last
line of the format.
.NH 2
Traversing Data Structures
.PP
The
.I adb
command language can be used to traverse complex data
structures.  One such data structure, a linked list, occurs
quite often in the kernel.  By using
.I adb
variables and the
normal expression operators it is a simple matter to construct
a script which chains down the list printing each element
along the way.
.PP
For instance, the queue of processes awaiting timer events,
the callout queue, is printed with the following two scripts:
.sp 1
.nf
.ne 4
\fBcallout\fP:
.in +5
.sp 1
calltodo/"time"16t"arg"16t"func"12+
*+$<callout.next
.sp 1
.ne 6
.ti -5
\fBcallout.next\fP:
.sp 1
\&./Dpp
*+>l
,#<l$<
<l$<callout.next
.sp 1
.in -5
.fi
.PP
The first line of the script \fBcallout\fP starts the traversal
at the global symbol
\fIcalltodo\fP and prints a set of headings.
It then skips the empty portion of the structure used
as the head of the queue.
The second line then invokes the script \fBcallout.next\fP
moving ``.'' to
the top of the queue (``*+'' performs the indirection
through the link entry of the structure at the head of the queue).
.PP
\fBcallout.next\fP prints values for each column, then performs
a conditional test on the link to the next entry.  This test
is performed as follows,
.IP "*+>l" 9
Place the value of the ``link'' in the
.I adb
variable ``<l''.
.IP ",#<l$<"
If the value stored in ``<l'' is non-zero, then the current
input stream (i.e. the script \fBcallout.next\fP) is terminated.
Otherwise, the expression ``#<l'' will be zero, and the ``$<''
will be ignored.  That is, the combination of the logical negation
operator ``#'',
.I adb
variable ``<l'', and ``$<'' operator
creates a statement of the form,
.sp 1
.ti +0.5i
if (!link) exit;
.sp 1
The remaining line of \fBcallout.next\fP simply reapplies the
script on the next element in the linked list.
.LP
A sample \fIcallout\fP dump is shown below.
.nf
.sp 1
.ne 14
% \fBadb \-k /vmunix /dev/mem\fP
sbr 8001f864 slr d9c
p0br 800efa00 p0lr 8e p1br 7f8efe00 p1lr 1ffff2
\fB$<callout\fP
_calltodo:
_calltodo:	time		arg			func
8004ecfc:	26		0			_dzscan
8004ed0c:	8		0			_upwatch
8004ed1c:	0		0			_ip_timeo
8004ed5c:	0		0			_tcp_timeo
8004ed6c:	0		0			_rkwatch
8004ecfc:	52		0			_dzscan
8004ed2c:	68		_Syssize+70	_tmtimer
8004ed3c:	2920		0			_memenable
.fi
.sp 1
.NH 2
Supplying Parameters
.PP
If one is clever, a command script may use the address
and count portions of an
.I adb
command as parameters.  An example of
this is the \fBsetproc\fP script used to switch to the
context of a process with a known process-id;
.sp 1
.ti +5
\fB0t99$<setproc\fP
.sp 1
The body of \fBsetproc\fP is
.sp 1
.in +5
.nf
\&.>4
*nproc>l
*proc>f
$<setproc.nxt
.in -5
.sp 1
.fi
while \fBsetproc.nxt\fP is
.sp 1
.nf
.in +5
(*(<f+28))&0xffff="pid "X
,#((*(<f+28)&0xffff)-<4)$<setproc.done
<l-1>l
<f+70>f
,#<l$<
$<setproc.nxt
.in -5
.sp 1
.fi
The process-id, supplied as the parameter, is stored in the
variable ``<4'', the number of processes is placed in ``<l'',
and the base of the array of process structures in ``<f''.
\fBsetproc.nxt\fP then performs a linear search through the
array until it matches the process-id requested, or until
it runs out of process structures to check.  The script
\fBsetproc.done\fP simply establishes the context of the
process, then exits.
.NH 2
Standard Scripts
.PP
The following table summarizes the command scripts currently
available in the directory \fI/usr/lib/adb\fP.
.TS
center, box;
c s s
l | l | l
lb | l | l.
Standard Command Scripts
_
Name	Use	Description
_
buf	\fIaddr\fP$<\fBbuf\fP	format block I/O buffer
callout	$<\fBcallout\fP	print timer queue
clist	\fIaddr\fP$<\fBclist\fP	format character I/O linked list
dino	\fIaddr\fP$<\fBdino\fP	format directory inode
dir	\fIaddr\fP$<\fBdir\fP	format directory entry
dirblk	\fIaddr\fP$<\fBdirblk\fP	scan directory entries
file	\fIaddr\fP$<\fBfile\fP	format open file structure
filsys	\fIaddr\fP$<\fBfilsys\fP	format in-core super block structure
findproc	\fIpid\fP$<\fBfindproc\fP	find process by process id
hosts	\fIaddr\fP$<\fBhosts\fP	format IMP host table entries
hosttable	$<\fBhosttable\fP	show all IMP host table entries
ifnet	\fIaddr\fP$<\fBifnet\fP	format network interface structure
ifuba	\fIaddr\fP$<\fBifuba\fP	format UNIBUS resource structure
inode	\fIaddr\fP$<\fBinode\fP	format in-core inode structure
inpcb	\fIaddr\fP$<\fBinpcb\fP	format internet protocol control block
iovec	\fIaddr\fP$<\fBiovec\fP	format a list of \fIiov\fP structures
ipreass	\fIaddr\fP$<\fBipreass\fP	format an ip reassembly queue
mact	\fIaddr\fP$<\fBmact\fP	show ``active'' list of mbuf's
mbstat	$<\fBmbstat\fP	show mbuf statistics
mbuf	\fIaddr\fP$<\fBmbuf\fP	show ``next'' list of mbuf's
mbufs	\fIaddr\fP$<\fBmbufs\fP	show a number of mbuf's
mount	\fIaddr\fP$<\fBmount\fP	format mount structure
pcb	\fIaddr\fP$<\fBpcb\fP	format process context block
proc	\fIaddr\fP$<\fBproc\fP	format process table entry
rawcb	\fIaddr\fP$<\fBrawcb\fP	format a raw protocol control block
rtentry	\fIaddr\fP$<\fBrtentry\fP	format a routing table entry
setproc	\fIpid\fP$<\fBsetproc\fP	switch process context to \fIpid\fP
socket	\fIaddr\fP$<\fBsocket\fP	format socket structure
tcpcb	\fIaddr\fP$<\fBtcpcb\fP	format TCP control block
tcpip	\fIaddr\fP$<\fBtcpip\fP	format a TCP/IP packet header
tcpreass	\fIaddr\fP$<\fBtcpreass\fP	show a TCP reassembly queue
text	\fIaddr\fP$<\fBtext\fP	format text structure
traceall	$<\fBtraceall\fP	show stack trace for all processes
tty	\fIaddr\fP$<\fBtty\fP	format tty structure
u	\fIaddr\fP$<\fBu\fP	format user vector, including pcb
ubahd	\fIaddr\fP$<\fBubahd\fP	format a UNIBUS header structure
.TE
.ds RH "Summary
.LP
.nr H1 2
.bp
.LG
.B
.ce
3. SUMMARY
.sp 2
.R
.nr H2 0
.NL
.PP
The extensions made to
.I adb
provide basic support for debugging the
.UX
kernel by eliminating the need for a user to carry
out virtual to physical address translation.  A collection
of scripts have been written to nicely format the major
kernel data structures and aid in switching between
process contexts.  This has been carried out with
only minimal changes to the debugger.
.PP
More work is needed to provide enough information
for the debugger to automatically establish context
after a system crash.  The system currently does not
always save enough state to allow the debugger to reliably
locate the stack frame just prior to an exception.
.PP
More work is also required on the user interface
to \fIadb\fP.  It appears the inscrutable
.I adb
command language
has limited widespread use of much of the power of
\fIadb\fP.  One possibility is to provide a more comprehensible
``adb frontend'', just as \fIbc\fP(1) is used to
frontend \fIdc\fP(1).
.PP
Finally,
.I adb
could be significantly improved if it
were knowledgeable about a program's data structures.
This would eliminate the use of numeric offsets into
C structures.