forsyth20121205-174063a80cc13 years agoHistory
1062 lines · 35.0 KB · Text
RawDownload
.de d0.nr dP +1.nr dV +1p...de d1.nr dP -1.nr dV -1p...nr dT 4.de Af	\" acid function.CW "\\$1(" "\fI\\$2\fP\f(CW)\fP"...TLNative Kernel Debugging with Acid.AUTad Hunttad@plan9.bell-labs.com.brLucent Technologies Inc.br(Revised 22 May 2000 by Vita Nuova).SHIntroduction.PPThis tutorial provides an introduction to the Acid debugger. It assumes that you are familiar with the features of a typical source-level debugger. The Acid debugger is built round a command language with a syntax similar to C.This tutorial is not anintroduction to Acid as a whole, butoffers a brief tourof the basic built in and standard library functions,especially those needed for debugging native Inferno kernels on a target board..PPAcid was originally developed by Phil Winterbottomto help debug multi-threaded programs inthe concurrent language Alef, and provide more sophisticateddebugging for C programs.In the paper.I "Acid: A Debugger Built From a Language" ,Winterbottomdiscusses Acid's design, including some worked examples of unusualapplications of Acid to find memory leaks and assist code coverage analysis.Following that is the.I "Acid Reference Manual" ,also by Phil Winterbottom,which gives a more precise specification of the Acid debugging language and its libraries..SHPreliminaries -- the environment.PPAcid runs under the host operating system used for cross-development,in the same way as the Inferno compilers.Before running either compilers or Acid, the followingenvironment variables must be set appropriately:.TScenter;lf(CW) lf(R)w(4i) .ROOT	T{the directory in which Inferno lives (eg,.CW /usr/inferno ).T}SYSHOST	T{.I hostoperating system type:.CW Nt ,.CW Solaris ,.CW Plan9 ,.CW Linuxor.CW FreeBSDT}OBJTYPE	T{.I hostmachine's architecture type:.CW 386 ,.CW sparc ,.CW mips ,or.CW powerpcT}.TEThey might be set by a login shell profile(eg,Unix.CW ".profile" ,orPlan 9.CW lib/profile ).Also ensure that the directory.P1$ROOT/$SYSHOST/$OBJTYPE/bin.P2is on your search path.For example, on a Solaris sparc, one might use:.P1ROOT=\fIinferno_root\fPSYSHOST=SolarisOBJTYPE=sparcACIDLIB=$ROOT/lib/acidPATH=$ROOT/$SYSHOST/$OBJTYPE/bin:$PATHexport ROOT ACIDLIB PATH OBJTYPE SYSHOST.P2where.I "inferno_root"is the directory in which Inferno lives (eg,.CW "/usr/inferno" )..SHAn Example Program.PPThe first example is not kernel code, but a small program thatwill be compiled but not run, to demonstrate basic Acid commands forsource and object file inspection.The code is shown below:.P1intfactorial(int n){	if (n == 1)		return 1;	return n * factorial(n-1);} int f;voidmain(void){	f = factorial(5);} void_main(void){	main();}.P2.SHCompiling and Linking.PPThe first step is to create an executable.  The example shows the process for creating ARM executables.  Substitute the appropriate compiler and linker for other cpu types..P1% 5c factorial.c% 5l -o factorial factorial.5% lsfactorialfactorial.5factorial.c.P2.SHStarting Acid.PPEven without the target machine on whichto run the program, many Acid features are available.The following command starts debugging the.CW "factorial"executable. Note that, upon startup, Acid will attempt to load some libaries from the directory specified in the.CW "ACIDLIB"environment variable (defaults to.CW "/usr/inferno/lib/acid" ).It will also attempt to load the file.CW "$HOME/lib/acid" ,in which you can place commands to be executed during startup..P1% acid factorialfactorial:Arm plan 9 executable $ROOT/lib/acid/port$ROOT/lib/acid/armacid:.P2.SHExploring the Executable.PPTo find out what symbols are in the program:.P1acid: symbols("")etext	T	0x00001068f	D	0x00002000setR12	D	0x00002ffcend	B	0x00002008bdata	D	0x00002000edata	D	0x00002008factorial	T	0x00001020main	T	0x00001048_main	T	0x0000105cacid:.P2The output from the.CW symbols()function is similar to the output from the.I nm (10.1)command. The first column is the symbol name, the second column gives the section the symbol is in, and the third column is the address of the symbol..PPThere is also a.CW "symbols"global variable.  Variables and functions can have the same names.  It holds the list of symbol information that the.CW symbolsfunction uses to generate the table:.d0.P1acid: symbols{{"etext", T, 0x00001068}, {"f", D, 0x00002000}, {"setR12", D, 0x00002ffc}, {"end", B, 0x00002008}, {"bdata", D, 0x00002000}, {"edata", D, 0x00002008}, {"factorial", T, 0x00001020}, {"main", T, 0x00001048}, {"_main", T, 0x0000105c}}acid:.P2.d1In large programs, finding the symbol you are interested in from a list that may be thousands of lines long would be difficult. The string argument of.CW symbols()is a regular expression against which to match symbols.All symbols that contain the pattern will be displayed.  For example:.P1acid: symbols("main")main	T	0x00001048_main	T	0x0000105cacid: symbols("^main")main	T	0x00001048acid:.P2The.CW symbolsfunction is written in the.I acidcommand language and lives in the.CW "port"library.CW $ACIDLIB/port ). (.P1defn symbols(pattern){	local l, s; 	l = symbols;	while l do {		s = head l;		if regexp(pattern, s[0]) then			print(s[0], "\t", s[1], "\t", s[2], "\n");		l = tail l;	}}.P2Acid retrieves the list of symbols from the executable and turns each one into a global variable whose value is the address of the symbol. If the symbol clashes with a builtin name or keyword or a previously defined function, enough.CW "$"characters are prepended to the name to make it unique.  The list of such renamings is printed at startup..PPMost acid functions operate on addresses.  For example, to view the source code for a given address, use the.CW srcfunction:.P1acid: src(main)/usr/jrf/factorial.c:10 5		return n * factorial(n-1); 6	} 7	 8	int f; 9	void>10	main(void) 11	{ 12		f = factorial(5); 13	} 14	 15	void.P2The.Af "src" addrfunction displays a section of source code, with the line containing the address passed as an argument in the middle of the display. To print the assembly code beginning at a given address, use the.CW asm()function..P1acid: asm(factorial)factorial 0x00001020	MOVW.W	R14,#-0x8(R13)factorial+0x4 0x00001024	CMP.S	$#0x1,R0factorial+0x8 0x00001028	MOVW.EQ	$#0x1,R0factorial+0xc 0x0000102c	RET.EQ.P	#0x8(R13)factorial+0x10 0x00001030	MOVW	R0,n+0(FP)factorial+0x14 0x00001034	SUB	$#0x1,R0,R0factorial+0x18 0x00001038	BL	factorialfactorial+0x1c 0x0000103c	MOVW	n+0(FP),R2factorial+0x20 0x00001040	MUL	R2,R0,R0factorial+0x24 0x00001044	RET.P	#0x8(R13)main 0x00001048	MOVW.W	R14,#-0x8(R13)acid:.P2The output contains the symbolic address (symbol name+offset, where symbol name is the name of the enclosing function) followed by the absolute address, followed by the disassembled code.The.Af "asm" addrfunction prints the assembly beginning at.I "addr"and ending after either 30 lines have been printed, or the end of the function has been reached.  The.CW "casm()"function continues the assembly listing from where it left off, even past the end of the function and into the next one..P1acid: casm()main+0x4 0x0000104c	MOVW	$#0x5,R0main+0x8 0x00001050	BL	factorialmain+0xc 0x00001054	MOVW	R0,$f-SB(SB)main+0x10 0x00001058	RET.P	#0x8(R13)_main 0x0000105c	MOVW.W	R14,#-0x4(R13)acid:.P2All the functions presented so far are written in the acid command language. To see the source of a comand written in the acid command language, use the builtin command.CW "whatis [" "\fIname\fP\f(CW ]\fP."It prints the definition of the optional argument.I "name" .If.I "name"is an Acid builtin,.CW whatisprints.CW "builtin function" ..P1acid: whatis casmdefn casm() {        asm(lasmaddr);}acid:acid: whatis atofbuiltin functionacid:.P2If.I nameis a variable, it prints the type of variable, and for the integer type, gives the format code used to print the value:.P1acid: whatis pidinteger variable format Dacid:.P2With no arguments,.CW whatislists all available functions:.P1acid: whatisBsrc       bpmask     follow     new        sh         _bpconddel bpneq      func       newproc    source     _bpcondset bpor       gpr        next       spr        _stk       bpprint    include    notestk    spsrch     access     bppush     interpret  params     src        acidinit   bpset      itoa       pcfile     start      addsrcdir  bptab      kill       pcline     startstop  asm        casm       kstk       pfl        status     atof       cont       labstk     print      stk        atoi       debug      line       printto    stmnt      bpaddr     dump       linkreg    procs      stop       bpand      error      lkstk      rc         stopped    bpconddel  file       locals     readfile   strace     bpcondset  filepc     lstk       reason     symbols    bpdel      findsrc    map        regexp     waitstop   bpderef    fmt        match      regs       bpeq       fnbound    mem        setproc    acid:.P2The.Af "Bsrc" addrfunction brings up an editor on the line containing.I "addr" .It simply invokes a shell script named.CW "B"that takes two arguments,.I "-line"and.I "file"The shell script invokes.CW "$EDITOR +".I "line file" .If unset,.CW "EDITOR"defaults to.I vi .The shell script, or the.CW Bsrcfunction can be easily rewritten to work with your favorite editor..PPEntering a symbol name by itself will print the address of the symbol. Prefixing the symbol name with a.CW "*"will print the value at the address in the variable. Continuing to use our.CW "factorial"example:.P1acid: f0x00002000acid: *f0x00000000acid:.P2.SHRemote Debugging.PPNow that you have a basic understanding of how to explore the executable, it is time to examine a real remote debugging session..PPWe'll use the SA1100 keyboard driver as an example. Examining the kernel configuration file, you'll see the following:.P1dev        keyboardlink    driver/keyboard port        scanfujn860     kbd.h keycodes.hlink    ./../driver     plat        kbdfujitsu      ./../common/ssp.h \e                        /driver/keyboard/kbd.h \e                        /driver/keyboard/keycodes.hport        const char *defaultkeyboard = "fujitsu";        const char *defaultkeytable = "scanfujn860";        int debugkeys = 1;      /* 1 = enabled, 0 = disabled */.P2This describes the pieces of the keyboard driver which are linked into the kernel. The source code lives in two places,.CW "$ROOT/os/driver/keyboard" ,and.CW "$ROOT/os/plat/sa1100/driver" ..PPThe next step is to build a kernel. Use the.I mktarget.CW acidto ensure that the Acid symbolic debugging data isproduced.For example:.P1% mk 'CONF=sword' acid isword.p9.gz.P2This creates the Acid file.CW isword.acid ,containing Acid declarations describing kernel structures,the kernel executable.CW isword.p9 ;and finally.I gzip sa copy of the kernel in.CW isword.p9.gzto load onto the device. Next, copy the gzipped image onto the device and then boot it. Follow the directions found elsewhere for details of this process..PPFrom a shell prompt on the target device, start the remote debugger by writing the letter.CW r(for run) to.CW "#b/dbgctl" .Next, start Acid in remote debug mode, specifying the serial port it is connected to with the.CW "-R"option..CW "$CONF"is the name of the configuration file used, for example.CW "sword" ..P1% acid -R /dev/cua/b -l i$CONF.acid i$CONFisword:Arm plan 9 executable$ROOT/lib/acid/porti$CONF.acid$ROOT/lib/acid/arm/usr/jrf/lib/acidacid:.P2You are now debugging the kernel that is running on the target device. All of the previously listed commands will work as described before, in addition, there are many more commands available..SHKernel Process Listing.PPTo get a list of kernel processes, use the.CW "ps()"function:.P1acid: ps()PID     PC              PRI     STATE   NAME1       0x00054684      5       Queueing        interp2       0x00000000      1       Wakeme  consdbg3       0x00000000      5       Wakeme  tcpack4       0x00000000      5       Wakeme  Fs.sync5       0x00000000      4       Wakeme  touchscreen6       0x00054684      5       Queueing        dis7       0x00059788      5       Wakeme  dis8       0x00054684      5       Queueing        dis9       0x00054684      5       Queueing        dis10      0x00054684      5       Wakeme  dis11      0x0004c26c      1       Running dbgacid:.P2The.CW "PC"column shows the address the process was executing at when the.CW pscommand retrieved statistics on it. The.CW "PRI"column lists process priorities. The smaller the number the higher the process priority. Notice that the kernel process (kproc) running the debugger is the highest priority process in the system. The only process you will ever see in the.CW "Running"state while executing the.CW pscommand will be the debugger, since it is gathering information about the other processes..SHBreakpoints.PPBreakpoints in Inferno, unlike most traditional kernel debuggers, are conditional breakpoints. There are minimally two conditions which must be met. These conditions are address and process id. A breakpoint will only be taken when execution for a specific kernel process reaches the specified address. The user can create additional conditions that are evaluated if the address and process id match. If evaluation of these conditions result in a nonzero value, the breakpoint is taken, otherwise it is ignored, and execution continues..PPAgain, the best way to proceed is with an example:.P1acid: setproc(7).P2The.Af setproc pidfunction selects a kproc to which later commands will be applied;the one with process ID (\fIpid\fP)in this case..P1acid: bpset(keyboardread)Waiting...7: stopped      flush8to4+0x18c MOVW    (R3<<#4),R3.P2

Lines 1–500 of 1062.