.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.P2Lines 1–500 of 1062. Load more
.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" .. .TL Native Kernel Debugging with Acid .AU Tad Hunt tad@plan9.bell-labs.com .br Lucent Technologies Inc .br (Revised 22 May 2000 by Vita Nuova) .SH Introduction .PP This 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 an introduction to Acid as a whole, but offers a brief tour of the basic built in and standard library functions, especially those needed for debugging native Inferno kernels on a target board. .PP Acid was originally developed by Phil Winterbottom to help debug multi-threaded programs in the concurrent language Alef, and provide more sophisticated debugging for C programs. In the paper .I "Acid: A Debugger Built From a Language" , Winterbottom discusses Acid's design, including some worked examples of unusual applications 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. .SH Preliminaries -- the environment .PP Acid 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 following environment variables must be set appropriately: .TS center; lf(CW) lf(R)w(4i) . ROOT T{ the directory in which Inferno lives (eg, .CW /usr/inferno ). T} SYSHOST T{ .I host operating system type: .CW Nt , .CW Solaris , .CW Plan9 , .CW Linux or .CW FreeBSD T} OBJTYPE T{ .I host machine's architecture type: .CW 386 , .CW sparc , .CW mips , or .CW powerpc T} .TE They might be set by a login shell profile (eg, Unix .CW ".profile" , or Plan 9 .CW lib/profile ). Also ensure that the directory .P1 $ROOT/$SYSHOST/$OBJTYPE/bin .P2 is on your search path. For example, on a Solaris sparc, one might use: .P1 ROOT=\fIinferno_root\fP SYSHOST=Solaris OBJTYPE=sparc ACIDLIB=$ROOT/lib/acid PATH=$ROOT/$SYSHOST/$OBJTYPE/bin:$PATH export ROOT ACIDLIB PATH OBJTYPE SYSHOST .P2 where .I "inferno_root" is the directory in which Inferno lives (eg, .CW "/usr/inferno" ). .SH An Example Program .PP The first example is not kernel code, but a small program that will be compiled but not run, to demonstrate basic Acid commands for source and object file inspection. The code is shown below: .P1 int factorial(int n) { if (n == 1) return 1; return n * factorial(n-1); } int f; void main(void) { f = factorial(5); } void _main(void) { main(); } .P2 .SH Compiling and Linking .PP The 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 % ls factorial factorial.5 factorial.c .P2 .SH Starting Acid .PP Even without the target machine on which to 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 factorial factorial:Arm plan 9 executable $ROOT/lib/acid/port $ROOT/lib/acid/arm acid: .P2 .SH Exploring the Executable .PP To find out what symbols are in the program: .P1 acid: 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 The 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. .PP There 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 symbols function uses to generate the table: .d0 .P1 acid: 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, 0x00001 05c}} acid: .P2 .d1 In 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: .P1 acid: symbols("main") main T 0x00001048 _main T 0x0000105c acid: symbols("^main") main T 0x00001048 acid: .P2 The .CW symbols function is written in the .I acid command language and lives in the .CW "port" library .CW $ACIDLIB/port ). ( .P1 defn 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; } } .P2 Acid 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. .PP Most acid functions operate on addresses. For example, to view the source code for a given address, use the .CW src function: .P1 acid: 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 .P2 The .Af "src" addr function 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. .P1 acid: asm(factorial) factorial 0x00001020 MOVW.W R14,#-0x8(R13) factorial+0x4 0x00001024 CMP.S $#0x1,R0 factorial+0x8 0x00001028 MOVW.EQ $#0x1,R0 factorial+0xc 0x0000102c RET.EQ.P #0x8(R13) factorial+0x10 0x00001030 MOVW R0,n+0(FP) factorial+0x14 0x00001034 SUB $#0x1,R0,R0 factorial+0x18 0x00001038 BL factorial factorial+0x1c 0x0000103c MOVW n+0(FP),R2 factorial+0x20 0x00001040 MUL R2,R0,R0 factorial+0x24 0x00001044 RET.P #0x8(R13) main 0x00001048 MOVW.W R14,#-0x8(R13) acid: .P2 The 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" addr function 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. .P1 acid: casm() main+0x4 0x0000104c MOVW $#0x5,R0 main+0x8 0x00001050 BL factorial main+0xc 0x00001054 MOVW R0,$f-SB(SB) main+0x10 0x00001058 RET.P #0x8(R13) _main 0x0000105c MOVW.W R14,#-0x4(R13) acid: .P2 All 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 whatis prints .CW "builtin function" . .P1 acid: whatis casm defn casm() { asm(lasmaddr); } acid: acid: whatis atof builtin function acid: .P2 If .I name is a variable, it prints the type of variable, and for the integer type, gives the format code used to print the value: .P1 acid: whatis pid integer variable format D acid: .P2 With no arguments, .CW whatis lists all available functions: .P1 acid: whatis Bsrc 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: .P2 The .Af "Bsrc" addr function 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 Bsrc function can be easily rewritten to work with your favorite editor. .PP Entering 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: .P1 acid: f 0x00002000 acid: *f 0x00000000 acid: .P2 .SH Remote Debugging .PP Now that you have a basic understanding of how to explore the executable, it is time to examine a real remote debugging session. .PP We'll use the SA1100 keyboard driver as an example. Examining the kernel configuration file, you'll see the following: .P1 dev keyboard link driver/keyboard port scanfujn860 kbd.h keycodes.h link ./../driver plat kbdfujitsu ./../common/ssp.h \e /driver/keyboard/kbd.h \e /driver/keyboard/keycodes.h port const char *defaultkeyboard = "fujitsu"; const char *defaultkeytable = "scanfujn860"; int debugkeys = 1; /* 1 = enabled, 0 = disabled */ .P2 This 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" . .PP The next step is to build a kernel. Use the .I mk target .CW acid to ensure that the Acid symbolic debugging data is produced. For example: .P1 % mk 'CONF=sword' acid isword.p9.gz .P2 This creates the Acid file .CW isword.acid , containing Acid declarations describing kernel structures, the kernel executable .CW isword.p9 ; and finally .I gzip s a copy of the kernel in .CW isword.p9.gz to 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. .PP From 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$CONF isword:Arm plan 9 executable $ROOT/lib/acid/port i$CONF.acid $ROOT/lib/acid/arm /usr/jrf/lib/acid acid: .P2 You 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. .SH Kernel Process Listing .PP To get a list of kernel processes, use the .CW "ps()" function: .P1 acid: ps() PID PC PRI STATE NAME 1 0x00054684 5 Queueing interp 2 0x00000000 1 Wakeme consdbg 3 0x00000000 5 Wakeme tcpack 4 0x00000000 5 Wakeme Fs.sync 5 0x00000000 4 Wakeme touchscreen 6 0x00054684 5 Queueing dis 7 0x00059788 5 Wakeme dis 8 0x00054684 5 Queueing dis 9 0x00054684 5 Queueing dis 10 0x00054684 5 Wakeme dis 11 0x0004c26c 1 Running dbg acid: .P2 The .CW "PC" column shows the address the process was executing at when the .CW ps command 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 ps command will be the debugger, since it is gathering information about the other processes. .SH Breakpoints .PP Breakpoints 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. .PP Again, the best way to proceed is with an example: .P1 acid: setproc(7) .P2 The .Af setproc pid function selects a kproc to which later commands will be applied; the one with process ID (\fIpid\fP) in this case. .P1 acid: bpset(keyboardread) Waiting... 7: stopped flush8to4+0x18c MOVW (R3<<#4),R3 .P2