%patch Index: 2.6.x-xfs/Documentation/kdb/kdb.mm =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/kdb.mm 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/kdb.mm 2006-02-28 11:26:53.480608406 +1100 @@ -0,0 +1,492 @@ +.TH KDB 8 "September 21, 2005" +.hy 0 +.SH NAME +Built-in Kernel Debugger for Linux - v4.4 +.SH "Overview" +This document describes the built-in kernel debugger available +for linux. This debugger allows the programmer to interactively +examine kernel memory, disassemble kernel functions, set breakpoints +in the kernel code and display and modify register contents. +.P +A symbol table is included in the kernel image and in modules which +enables all non-stack symbols (including static symbols) to be used as +arguments to the kernel debugger commands. +.SH "Getting Started" +To include the kernel debugger in a linux kernel, use a +configuration mechanism (e.g. xconfig, menuconfig, et. al.) +to enable the \fBCONFIG_KDB\fP option. Additionally, for accurate +stack tracebacks, it is recommended that the \fBCONFIG_FRAME_POINTER\fP +option be enabled (if present). \fBCONFIG_FRAME_POINTER\fP changes the compiler +flags so that the frame pointer register will be used as a frame +pointer rather than a general purpose register. +.P +After linux has been configured to include the kernel debugger, +make a new kernel with the new configuration file (a make clean +is recommended before making the kernel), and install the kernel +as normal. +.P +You can compile a kernel with kdb support but have kdb off by default, +select \fBCONFIG_KDB_OFF\fR. Then the user has to explicitly activate +kdb by booting with the 'kdb=on' flag or, after /proc is mounted, by +.nf + echo "1" > /proc/sys/kernel/kdb +.fi +You can also do the reverse, compile a kernel with kdb on and +deactivate kdb with the boot flag 'kdb=off' or, after /proc is mounted, +by +.nf + echo "0" > /proc/sys/kernel/kdb +.fi +.P +When booting the new kernel, the 'kdb=early' flag +may be added after the image name on the boot line to +force the kernel to stop in the kernel debugger early in the +kernel initialization process. 'kdb=early' implies 'kdb=on'. +If the 'kdb=early' flag isn't provided, then kdb will automatically be +invoked upon system panic or when the \fBPAUSE\fP key is used from the +keyboard, assuming that kdb is on. Older versions of kdb used just a +boot flag of 'kdb' to activate kdb early, this is no longer supported. +.P +KDB can also be used via the serial port. Set up the system to +have a serial console (see \fIDocumentation/serial-console.txt\fP), you +must also have a user space program such as agetty set up to read from +the serial console. +The control sequence \fBKDB\fP on the serial port will cause the +kernel debugger to be entered, assuming that kdb is on, that some +program is reading from the serial console, at least one cpu is +accepting interrupts and the serial console driver is still usable. +.P +\fBNote:\fR\ When the serial console sequence consists of multiple +characters such as KDB then all but the last character are passed +through to the application that is reading from the serial console. +After exiting from kdb, you should use backspace to delete the rest of +the control sequence. +.P +You can boot with kdb activated but without the ability to enter kdb +via any keyboard sequence. +In this mode, kdb will only be entered after a system failure. +Booting with kdb=on-nokey will activate kdb but ignore keyboard +sequences that would normally drop you into kdb. +kdb=on-nokey is mainly useful when you are using a PC keyboard and your +application needs to use the Pause key. +You can also activate this mode by +.nf + echo "2" > /proc/sys/kernel/kdb +.fi +.P +If the console is sitting on the login prompt when you enter kdb, then +the login command may switch into upper case mode. +This is not a kdb bug, it is a "feature" of login - if the userid is +all upper case then login assumes that you using a TeleType (circa +1960) which does not have lower case characters. +Wait 60 seconds for login to timeout and it will switch back to lower +case mode. +.P +\fBNote:\fR\ Your distributor may have chosen a different kdb +activation sequence for the serial console. +Consult your distribution documentation. +.P +If you have both a keyboard+video and a serial console, you can use +either for kdb. +Define both video and serial consoles with boot parameters +.P +.nf + console=tty0 console=ttyS0,38400 +.fi +.P +Any kdb data entered on the keyboard or the serial console will be echoed +to both. +.P +If you are using a USB keyboard then kdb commands cannot be entered +until the kernel has initialised the USB subsystem and recognised the +keyboard. +Using kdb=early with a USB keyboard will not work, the USB subsystem is +initialised too late. +.P +While kdb is active, the keyboard (not serial console) indicators may strobe. +The caps lock and scroll lock lights will turn on and off, num lock is not used +because it can confuse laptop keyboards where the numeric keypad is mapped over +the normal keys. +On exit from kdb the keyboard indicators will probably be wrong, they will not match the kernel state. +Pressing caps lock twice should get the indicators back in sync with +the kernel. +.SH "Basic Commands" +There are several categories of commands available to the +kernel debugger user including commands providing memory +display and modification, register display and modification, +instruction disassemble, breakpoints and stack tracebacks. +Any command can be prefixed with '-' which will cause kdb to ignore any +errors on that command, this is useful when packaging commands using +defcmd. +A line whose first non-space character is '#' is printed and ignored. +.P +The following table shows the currently implemented standard commands, +these are always available. Other commands can be added by extra +debugging modules, type '?' at the kdb prompt to get a list of all +available commands. +.DS +.TS +box, center; +l | l +l | l. +Command Description +_ +bc Clear Breakpoint +bd Disable Breakpoint +be Enable Breakpoint +bl Display breakpoints +bp Set or Display breakpoint +bph Set or Display hardware breakpoint +bpa Set or Display breakpoint globally +bpha Set or Display hardware breakpoint globally +bt Stack backtrace for current process +btp Stack backtrace for specific process +bta Stack backtrace for all processes +btc Cycle over all live cpus and backtrace each one +cpu Display or switch cpus +dmesg Display system messages +defcmd Define a command as a set of other commands +ef Print exception frame +env Show environment +go Restart execution +handlers Control the display of IA64 MCA/INIT handlers +help Display help message +id Disassemble Instructions +kill Send a signal to a process +ll Follow Linked Lists +lsmod List loaded modules +md Display memory contents +mdWcN Display memory contents with width W and count N. +mdp Display memory based on a physical address +mdr Display raw memory contents +mds Display memory contents symbolically +mm Modify memory contents, words +mmW Modify memory contents, bytes +per_cpu Display per_cpu variables +pid Change the default process context +ps Display process status +reboot Reboot the machine +rd Display register contents +rm Modify register contents +rq Display runqueue for one cpu +rqa Display runqueue for all cpus +set Add/change environment variable +sr Invoke SysReq commands +ss Single step a cpu +ssb Single step a cpu until a branch instruction +stackdepth Print the stack depth for selected processes +summary Summarize the system +.TE +.DE +.P +Some commands can be abbreviated, such commands are indicated by a +non-zero \fIminlen\fP parameter to \fBkdb_register\fP; the value of +\fIminlen\fP being the minimum length to which the command can be +abbreviated (for example, the \fBgo\fP command can be abbreviated +legally to \fBg\fP). +.P +If an input string does not match a command in the command table, +it is treated as an address expression and the corresponding address +value and nearest symbol are shown. +.P +Some of the commands are described here. +Information on the more complicated commands can be found in the +appropriate manual pages. +.TP 8 +cpu +With no parameters, it lists the available cpus. +\&'*' after a cpu number indicates a cpu that did not respond to the kdb +stop signal. +\&'+' after a cpu number indicates a cpu for which kdb has some data, but +that cpu is no longer responding to kdb, so you cannot switch to it. +This could be a cpu that has failed after entering kdb, or the cpu may +have saved its state for debugging then entered the prom, this is +normal for an IA64 MCA event. +\&'I' after a cpu number means that the cpu was idle before it entered +kdb, it is unlikely to contain any useful data. +\&'F' after a cpu number means that the cpu is offline. +There is currenly no way to distinguish between cpus that used to be +online but are now offline and cpus that were never online, the kernel +does not maintain the information required to separate those two cases. +.I cpu +followed by a number will switch to that cpu, you cannot switch to +a cpu marked '*', '+' or 'F'. +This command is only available if the kernel was configured for SMP. +.TP 8 +dmesg [lines] [adjust] +Displays the system messages from the kernel buffer. +If kdb logging is on, it is disabled by dmesg and is left as disabled. +With no parameters or a zero value for 'lines', dmesg dumps the entire +kernel buffer. +If lines is specified and is positive, dmesg dumps the last 'lines' +from the buffer. +If lines is specified and is negative, dmesg dumps the first 'lines' +from the buffer. +If adjust is specified, adjust the starting point for the lines that +are printed. +When 'lines' is positive, move the starting point back by 'adjust' +lines, when 'lines' is negative, move the starting point forward by +\&'adjust' lines. +.I dmesg -100 +will dump 100 lines, from the start of the buffer. +.I dmesg 100 +will dump 100 lines, starting 100 lines from the end of the buffer, +.I dmesg 100 100 +will dump 100 lines, starting 200 lines from the end of the buffer. +.I dmesg -100 100 +will dump 100 lines, starting 100 lines from the start of the buffer. +.TP 8 +defcmd +Defines a new command as a set of other commands, all input until +.I endefcmd +is saved and executed as a package. +.I defcmd +takes three parameters, the command name to be defined and used to +invoke the package, a quoted string containing the usage text and a +quoted string containing the help text for the command. +When using defcmd, it is a good idea to prefix commands that might fail +with '-', this ignores errors so the following commands are still +executed. +For example, +.P +.nf + defcmd diag "" "Standard diagnostics" + set LINES 2000 + set BTAPROMPT 0 + -id %eip-0x40 + -cpu + -ps + -dmesg 80 + -bt + -bta + endefcmd +.fi +.P +When used with no parameters, defcmd prints all the defined commands. +.TP 8 +go +Continue normal execution. +Active breakpoints are reestablished and the processor(s) allowed to +run normally. +To continue at a specific address, use +.I rm +to change the instruction pointer then go. +.TP 8 +handlers +Control the display of IA64 MCA/INIT handlers. +The IA64 MCA/INIT handlers run on separate tasks. +During an MCA/INIT event, the active tasks are typically the handlers, +rather than the original tasks, which is not very useful for debugging. +By default, KDB hides the MCA/INIT handlers so commands such as ps and +btc will display the original task. +You can change this behaviour by using +.I handlers show +to display the MCA/INIT handlers instead of the original tasks or use +.I handlers hide +(the default) to hide the MCA/INIT handlers and display the original +tasks. +.I handlers status +will list the address of the handler task and the original task for +each cpu. +\fBNote:\fR\ If the original task was running in user space or it +failed any of the MCA/INIT verification tests then there is no original +task to display. +In this case, the handler will be displayed even if +.I handlers hide +is set and +.I handlers status +will not show an original task. +.TP 8 +id +Disassemble instructions starting at an address. +Environment variable IDCOUNT controls how many lines of disassembly +output the command produces. +.TP 8 +kill +Internal command to send a signal (like kill(1)) to a process. +kill -signal pid. +.TP 8 +lsmod +Internal command to list modules. +This does not use any kernel nor user space services so can be used at any time. +.TP 8 +per_cpu [] [] +Display the values of a per_cpu variable, the variable_name is +specified without the \fIper_cpu__\fR prefix. +Length is the length of the variable, 1-8, if omitted or 0 it defaults +to the size of the machine's register. +To display the variable on a specific cpu, the third parameter is the +cpu number. +When the third parameter is omitted, the variable's value is printed +from all cpus, except that zero values are suppressed. +For each cpu, per_cpu prints the cpu number, the address of the +variable and its value. +.TP 8 +pid +Change the current process context, with no parameters it displays the +current process. +The current process is used to display registers, both kernel and user +space. +It is also used when dumping user pages. +.I pid R +resets to the original process that was running when kdb was entered. +This command is useful if you have been looking at other processes and/or +cpus and you want to get back to the original process. +It does not switch cpus, it only resets the context to the original process. +.TP 8 +reboot +Reboot the system, with no attempt to do a clean close down. +.TP 8 +rq +Display the runqueues for the specified cpu. +.TP 8 +rqa +Display the runqueues for all cpus. +.TP 8 +stackdepth +Print the stack usage for processes using more than the specified +percentage of their stack. +If percentage is not supplied, it defaults to 60. +This command is only implemented on i386 and ia64 architectures, +patches for other architectures will be gratefully accepted. +.TP 8 +summary +Print a summary of the system, including the time (no timezone is +applied), uname information and various critical system counters. +.SH INITIAL KDB COMMANDS +kdb/kdb_cmds is a plain text file where you can define kdb commands +which are to be issued during kdb_init(). One command per line, blank +lines are ignored, lines starting with '#' are ignored. kdb_cmds is +intended for per user customization of kdb, you can use it to set +environment variables to suit your hardware or to set standard +breakpoints for the problem you are debugging. This file is converted +to a small C object, compiled and linked into the kernel. You must +rebuild and reinstall the kernel after changing kdb_cmds. This file +will never be shipped with any useful data so you can always override +it with your local copy. Sample kdb_cmds: +.P +.nf +# Initial commands for kdb, alter to suit your needs. +# These commands are executed in kdb_init() context, no SMP, no +# processes. Commands that require process data (including stack or +# registers) are not reliable this early. set and bp commands should +# be safe. Global breakpoint commands affect each cpu as it is booted. + +set LINES=50 +set MDCOUNT=25 +set RECURSE=1 +bp sys_init_module +.fi +.SH INTERRUPTS AND KDB +When a kdb event occurs, one cpu (the initial cpu) enters kdb state. +It uses a cross system interrupt to interrupt the +other cpus and bring them all into kdb state. All cpus run with +interrupts disabled while they are inside kdb, this prevents most +external events from disturbing the kernel while kdb is running. +.B Note: +Disabled interrupts means that any I/O that relies on interrupts cannot +proceed while kdb is in control, devices can time out. The clock tick +is also disabled, machines will lose track of time while they are +inside kdb. +.P +Even with interrupts disabled, some non-maskable interrupt events will +still occur, these can disturb the kernel while you are debugging it. +The initial cpu will still accept NMI events, assuming that kdb was not +entered for an NMI event. Any cpu where you use the SS or SSB commands +will accept NMI events, even after the instruction has finished and the +cpu is back in kdb. This is an unavoidable side effect of the fact that +doing SS[B] requires the cpu to drop all the way out of kdb, including +exiting from the event that brought the cpu into kdb. Under normal +circumstances the only NMI event is for the NMI oopser and that is kdb +aware so it does not disturb the kernel while kdb is running. +.P +Sometimes doing SS or SSB on ix86 will allow one interrupt to proceed, +even though the cpu is disabled for interrupts. I have not been able +to track this one down but I suspect that the interrupt was pending +when kdb was entered and it runs when kdb exits through IRET even +though the popped flags are marked as cli(). If any ix86 hardware +expert can shed some light on this problem, please notify the kdb +maintainer. +.SH RECOVERING FROM KDB ERRORS +If a kdb command breaks and kdb has enough of a recovery environment +then kdb will abort the command and drop back into mainline kdb code. +This means that user written kdb commands can follow bad pointers +without killing kdb. Ideally all code should verify that data areas +are valid (using kdb_getarea) before accessing it but lots of calls to +kdb_getarea can be clumsy. +.P +The sparc64 port does not currently provide this error recovery. +If someone would volunteer to write the necessary longjmp/setjmp +code, their efforts would be greatly appreciated. In the +meantime, it is possible for kdb to trigger a panic by accessing +a bad address. +.SH DEBUGGING THE DEBUGGER +kdb has limited support for debugging problems within kdb. If you +suspect that kdb is failing, you can set environment variable KDBDEBUG +to a bit pattern which will activate kdb_printf statements within kdb. +See include/linux/kdb.h, KDB_DEBUG_FLAG_xxx defines. For example +.nf + set KDBDEBUG=0x60 +.fi +activates the event callbacks into kdb plus state tracing in sections +of kdb. +.nf + set KDBDEBUG=0x18 +.fi +gives lots of tracing as kdb tries to decode the process stack. +.P +You can also perform one level of recursion in kdb. If environment +variable RECURSE is not set or is 0 then kdb will either recover from +an error (if the recovery environment is satisfactory) or kdb will +allow the error to percolate, usually resulting in a dead system. When +RECURSE is 1 then kdb will recover from an error or, if there is no +satisfactory recovery environment, it will drop into kdb state to let +you diagnose the problem. When RECURSE is 2 then all errors drop into +kdb state, kdb does not attempt recovery first. Errors while in +recursive state all drop through, kdb does not even attempt to recover +from recursive errors. +.SH KEYBOARD EDITING +kdb supports a command history, which can be accessed via keyboard +sequences. +It supports the special keys on PC keyboards, control characters and +vt100 sequences on a serial console or a PC keyboard. +.P +.DS +.TS +box, center; +l | l | l l | l +l | l | l l | l. +PC Special keys Control VT100 key Codes Action +_ +Backspace ctrl-H Backspace 0x7f Delete character to the left of the cursor +Delete ctrl-D Delete \\e[3~ Delete character to the right of the cursor +Home ctrl-A Home \\e[1~ Go to start of line +End ctrl-E End \\e[4~ Go to end of line +Up arrow ctrl-P Up arrow \\e[A Up one command in history +Down arrow ctrl-N Down arrow \\e[B Down one command in history +Left arrow ctrl-B Left arrow \\e[D Left one character in current command +Right arrow ctrl-F Right arrow \\e[C Right one character in current command +.TE +.DE +.P +There is no toggle for insert/replace mode, kdb editing is always in +insert mode. +Use delete and backspace to delete characters. +.P +kdb also supports tab completion for kernel symbols +Type the start of a kernel symbol and press tab (ctrl-I) to complete +the name +If there is more than one possible match, kdb will append any common +characters and wait for more input, pressing tab a second time will +display the possible matches +The number of matches is limited by environment variable DTABCOUNT, +with a default of 30 if that variable is not set. +.SH AUTHORS +Scott Lurndal, Richard Bass, Scott Foehner, Srinivasa Thirumalachar, +Masahiro Adegawa, Marc Esipovich, Ted Kline, Steve Lord, Andi Kleen, +Sonic Zhang. +.br +Keith Owens - kdb maintainer. +.SH SEE ALSO +.P +linux/Documentation/kdb/kdb_{bp,bt,env,ll,md,ps,rd,sr,ss}.man Index: 2.6.x-xfs/Documentation/kdb/kdb_bp.man =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/kdb_bp.man 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/kdb_bp.man 2006-02-28 11:26:53.481584836 +1100 @@ -0,0 +1,197 @@ +.TH BD 1 "July 12, 2004" +.SH NAME +bp, bpa, bph, bpha, bd, bc, be, bl \- breakpoint commands +.SH SYNOPSIS +bp \fIaddress-expression\fP +.LP +bpa \fIaddress-expression\fP +.LP +bph \fIaddress-expression\fP [\f(CWDATAR|DATAW|DATAA|IO\fP [\fIlength\fP]] +.LP +bpha \fIaddress-expression\fP [\f(CWDATAR|DATAW|DATAA|IO\fP [\fIlength\fP]] +.LP +bd \fIbreakpoint-number\fP +.LP +bc \fIbreakpoint-number\fP +.LP +be \fIbreakpoint-number\fP +.LP +bl +.SH DESCRIPTION +.hy 0 +The +.B bp +family of commands are used to establish a breakpoint. +The \fIaddress-expression\fP may be a numeric value (decimal or +hexidecimal), a symbol name, a register name preceeded by a +percent symbol '%', or a simple expression consisting of a +symbol name, an addition or subtraction character and a numeric +value (decimal or hexidecimal). +.P +\fBbph\fP and \fBbpha\fP will force the use of a hardware register, provided +the processor architecture supports them. +.P +The \fIaddress-expression\fP may also consist of a single +asterisk '*' symbol which indicates that the command should +operate on all existing breakpoints (valid only for \fBbc\fP, +\fBbd\fP and \fBbe\fP). +.P +Four different types of +breakpoints may be set: + +.TP 8 +Instruction +Causes the kernel debugger to be invoked from the debug exception +path when an instruction is fetched from the specified address. This +is the default if no other type of breakpoint is requested or when +the \fBbp\fP command is used. + +.TP 8 +DATAR +Causes the kernel debugger to be entered when data of length +\fIlength\fP is read from or written to the specified address. +This type of breakpoint must use a processor debug register which +places an architecture dependent limit on the number of data and I/O +breakpoints that may be established. On arm mode XScale platform +(thumb mode is not supported yet), +debugger is triggered by reading from the specified address. +The \fBbph\fP or \fBbpha\fP commands must be used. + +.TP 8 +DATAW +Enters the kernel debugger when data of length \fIlength\fP +is written to the specified address. \fIlength\fP defaults +to four bytes if it is not explicitly specified. +Note that the processor may have already overwritten the prior data at +the breakpoint location before the kernel debugger is invoked. +The prior data should be saved before establishing the breakpoint, if +required. On arm mode XScale platform, the debugger is triggered +after having overwritten the specified address. +The \fBbph\fP or \fBbpha\fP commands must be used. + +.TP 8 +IO +Enters the kernel debugger when an \fBin\fP or \fBout\fP instruction +targets the specified I/O address. The \fBbph\fP or \fBbpha\fP +commands must be used. This type of breakpoint is not valid in +arm mode XScale platform. This option is not valid in arm +mode XScale platform. + +.TP 8 +DATAA +Enters the kernel debugger after the data in specified address has +been accessed (read or write), this option is only used in arm +mode XScale platform. + +.P +The +.B bpha +command will establish a breakpoint on all processors in an +SMP system. This command is not available in an uniprocessor +kernel. +.P +The +.B bd +command will disable a breakpoint without removing it from the kernel +debugger's breakpoint table. +This can be used to keep breakpoints in the table without exceeding the +architecture limit on breakpoint registers. +A breakpoint-number of \fI*\fR will disable all break points. +.P +The +.B be +command will re-enable a disabled breakpoint. +A breakpoint-number of \fI*\fR will enable all break points. +.P +The +.B bc +command will clear a breakpoint from the breakpoint table. +A breakpoint-number of \fI*\fR will clear all break points. +.P +The +.B bl +command will list the existing set of breakpoints. +.SH LIMITATIONS +There is a compile time limit of sixteen entries in the +breakpoint table at any one time. +.P +There are architecture dependent limits on the number of hardware +breakpoints that can be set. +.IP ix86 8 +Four. +.PD 0 +.IP xscale 8 +Two for insruction breakpoints and another two for data breakpoint. +.PD 0 +.IP ia64 8 +? +.PD 0 +.IP sparc64 8 +None. +.PD 1 +When issuing the "go" command after entering the debugger due to +a breakpoint, kdb will silently perform a single step in order to +reapply the breakpoint. The sparc64 port has some limitations on +single stepping, which may limit where a breakpoint may be safely +set. Please read the man page for \fBss\fP for more information. +.SH ENVIRONMENT +The breakpoint subsystem does not currently use any environment +variables. +.SH SMP CONSIDERATIONS +Using +.B bc +is risky on SMP systems. +If you clear a breakpoint when another cpu has hit that breakpoint but +has not been processed then it may not be recognised as a kdb +breakpoint, usually resulting in incorrect program counters and kernel +panics. +It is safer to disable the breakpoint with +.BR bd , +then +.B go +to let any other processors that are waiting on the breakpoint to +clear. +After all processors are clear of the disabled breakpoint then it is +safe to clear it using +.BR bc . +.P +Breakpoints which use the processor breakpoint registers +are only established on the processor which is +currently active. If you wish breakpoints to be universal +use the +.B bpa +or +.B bpha +commands. +.SH EXAMPLES +.TP 8 +bp schedule +Sets an instruction breakpoint at the begining of the +function \fBschedule\fP. + +.TP 8 +bp schedule+0x12e +Sets an instruction breakpoint at the instruction located +at \fBschedule\fP+\fI0x12e\fP. + +.TP 8 +bph ttybuffer+0x24 dataw +Sets a data write breakpoint at the location referenced by +\fBttybuffer\fP+\fI0x24\fP for a length of four bytes. + +.TP 8 +bph 0xc0254010 datar 1 +Establishes a data reference breakpoint at address \fB0xc0254010\fP +for a length of one byte. + +.TP 8 +bp +List current breakpoint table. + +.TP 8 +bd 0 +Disable breakpoint #0. + +.TP 8 +bc * +Clear all breakpoints Index: 2.6.x-xfs/Documentation/kdb/kdb_bt.man =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/kdb_bt.man 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/kdb_bt.man 2006-02-28 11:26:53.483537695 +1100 @@ -0,0 +1,223 @@ +.TH BT 1 "September 21, 2005" +.SH NAME +bt \- Stack Traceback command +.SH SYNOPSIS +bt [ ] +.LP +btp +.LP +btt +.LP +bta [ DRSTZUIMA ] +.LP +btc [] +.SH DESCRIPTION +.hy 0 +The +.B bt +command is used to print a stack traceback. It uses the +current registers (see \fBrd\fP command) to determine +the starting context and attempts to provide a complete +stack traceback for the active thread. If \fIstack-frame-address\fP +is supplied, it is assumed to point to the start of a valid +stack frame and the stack will be traced back from that +point (e.g. on i386 architecture, \fIstack-frame-address\fP +should be the stack address of a saved \fB%eip\fP value from a \fBcall\fP +instruction. on sparc64 architecture, it should be a pointer to a +saved register window, as is found in the \fB%fp\fP register). +.P +If present, a kernel configuration option \fBCONFIG_FRAME_POINTER\fP +should be enabled so that the compiler will utilize the frame pointer +register properly to maintain a stack which can be correctly +analyzed. Some architectures (e.g. sparc64) always use +\fBCONFIG_FRAME_POINTER\fP, and so the option is not present. +.P +The \fBbt\fP command will attempt to analyze the stack without +frame pointers if the \fBCONFIG_FRAME_POINTER\fP option is not +enabled, but the analysis is difficult and may not produce +accurate nor complete results. +.P +The \fBbtp\fP command will analyze the stack for the given +process identification (see the \fBps\fP command). +\fBbtp\fP sets the current process for any following register display or update +commands. +.P +The \fBbtt\fP command will analyze the stack for the given task +structure. +It is exactly equivalent to \fBbtp\fR on the pid extracted from the +task structure. +\fBbtt\fP sets the current process for any following register display or update +commands. +.P +The \fBbta\fP command lists the stack for all processes in the desired +state. +Without any parameters, \fBbta\fP gives a backtrace for all useful processes. +If a parameter is specified, it is a single string consisting of the +letters D, R, S, T, Z, U, I, M and A in any order. +See the kdb \fBps\fR man page for more details. +\fBbta\fP does not change the current process. +.P +The \fBbtc\fP command will analyze the stack for the current process on +a specified cpu or, if no cpu number is supplied, for the current +process on all cpus. +It does not switch to the other cpus, instead it uses the task +structures to identify and issue \fBbtt\fR against the current task on +the desired cpus. +\fBbtc\fP with no arguments does not change the current process. +\fBbtc\fP with a cpu number sets the current process for any following register +display or update commands. +.P +For each function, the stack trace prints at least two lines. +The first line contains four or five fields\ :- +.IP * 3 +The pointer to the previous stack frame, blank if there is no valid +frame pointer. +.PD 0 +.IP * 3 +The current address within this frame. +.IP * 3 +The address converted to a function name (actually the first non-local +label which is <= the address). +.IP * 3 +The offset of the address within the function. +.IP * 3 +Any parameters to the function. +.PD 1 +.PP +On the next line there are five fields which are designed to make it +easier to match the trace against the kernel code\ :- +.IP * 3 +The module name that contains the address, "kernel" if it is in the +base kernel. +.PD 0 +.IP * 3 +The section name that contains the address (not available on 2.6 kernels). +.IP * 3 +The start address of the section (not available on 2.6 kernels). +.IP * 3 +The start address of the function. +.IP * 3 +The end address of the function (the first non-local label which is > +the address). +.PD 1 +.PP +If arguments are being converted to symbols, any argument which +converts to a kernel or module address is printed as\ :- +.IP * 3 +Argument address. +.PD 0 +.IP * 3 +The module name that contains the address, "kernel" if it is in the +base kernel. +.IP * 3 +The symbol name the argument maps to. +.IP * 3 +The offset of the argument from the symbol, suppressed if 0. +.PD 1 +.SH MATCHING TRACE TO KERNEL CODE +The command "objdump\ -S" will disassemble an object and, if the code +was compiled with debugging (gcc flag -g), objdump will interleave the +C source lines with the generated object. +.PP +A complete objdump of the kernel or a module is too big, normally you +only want specific functions. +By default objdump will only print the .text section but Linux uses +other section names for executable code. +When objdump prints relocatable objects (modules) it uses an offset of +0 which is awkward to relate to the stack trace. +The five fields which are printed for each function are designed to +make it easier to match the stack trace against the kernel code using +"objdump\ -S". +.PP +If the function is in the kernel then you need the section name, the +start and end address of the function. The command is +.PP +.nf + objdump -S -j \\ + --start-address= \\ + --stop-address= \\ + /usr/src/linux/vmlinux +.fi +.PP +If the function is in a module then you need the section name, the +start address of the section, the start and end address of the +function, the module name. The command is +.PP +.nf + objdump -S -j \\ + --adjust-vma= \\ + --start-address= \\ + --stop-address= \\ + /path/to/module/.o +.fi +.PP +Unfortunately the 2.6 kernel does not provide the information required +to locate the start of the section, which makes it very difficult to +perform a reliable objdump on a module. +.PP +All addresses to objdump must be preceded by '0x' if they are in hex, +objdump does not assume hex. +The stack trace values are printed with leading '0x' to make it easy to +run objdump. +.SH LIMITATIONS +If the kernel is compiled without frame pointers, stack tracebacks +may be incomplete. The \fBmds %esp\fP (i386) or \fBmds %fp\fP (sparc64) +command may be useful in attemping to determine the actual stack +traceback manually. +.P +A stack trace can be misleading if any code in a function exit has been +executed, the stack is partially unwound at that stage. +.P +The \fBbt\fP command may print more arguments for a function +than that function accepts; For sparc64, this will always happen +as the debugger cannot determine the correct number. For i386, this happens +when the C compiler doesn't immediately pop the arguments off the stack upon +return from a called function. When this is this case, these extra +stack words will be considered additional arguments by the \fBbt\fP +command. +.SH ENVIRONMENT +The \fBBTARGS\fP environment variable governs the maximum number +of arguments that are printed for any single function. +On IA64 hardware, there is no difference between input and local registers, the +first \fBBTARGS\fP registers are printed, up to the total limit of input plus +local registers. +Use a large value for \fBBTARGS\fP if you want to see the local registers on +IA64. +.PP +If the \fBBTSP\fP environment variable is non-zero then each backtrace frame +may print an extra line giving information about the stack pointers, this is +architecture specific. +.PP +If the \fBBTSYMARG\fP environment variable is non-zero then any +arguments that fall within the kernel are converted to symbols. +.PP +If the \fBNOSECT\fP environment variable is non-zero then the +section information is suppressed. +The default is NOSECT=1 so section data is suppressed; use set\ NOSECT=0 +to see section information. +.PP +The \fBBTAPROMPT\fP environment variable controls the prompt after each +process is listed by the \fBbta\fP command. If \fBBTAPROMPT\fP is not +set or is non-zero then \fBbta\fP issues a prompt after each process is +listed. If \fBBTAPROMPT\fP is set to zero then no prompt is issued and +all processes are listed without human intervention. +.PP +\fBbt\fR with no parameters uses the \fBPS\fR environment variable, see +the kdb \fBps\fR man page. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.nf +.na +.ft CW +Entering kdb (0xc3cb4000) due to Breakpoint @ 0xc011725d +Instruction(i) breakpoint #0 at 0xc011725c +qm_modules+0xd1: movl %ebp,%esp +kdb> bt + EBP EIP Function(args) +0xc3cb5f98 0xc011725d qm_modules+0xd1 (0x80721c0, 0x100, 0xbfff5000) + kernel .text 0xc0100000 0xc011718c 0xc0117264 +0xc3cb5fbc 0xc0117875 sys_query_module+0x1b1 (0x0, 0x1, 0x80721c0, 0x100, 0xbfff5000) + kernel .text 0xc0100000 0xc01176c4 0xc01178e8 + 0xc01095f8 system_call+0x34 + kernel .text 0xc0100000 0xc01095c4 0xc01095fc Index: 2.6.x-xfs/Documentation/kdb/kdb_env.man =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/kdb_env.man 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/kdb_env.man 2006-02-28 11:26:53.484514125 +1100 @@ -0,0 +1,46 @@ +.TH ENV 1 "24 September 2000" +.SH NAME +env, set \- Environment manipulation commands +.SH SYNOPSIS +env +.LP +set \fIenvironment-variable\fP=\fIvalue\fP +.SH DESCRIPTION +The kernel debugger contains an environment which contains a series +of name-value pairs. Some environment variables are known to the +various kernel debugger commands and have specific meaning to the +command; such are enumerated on the respective reference material. +.P +Arbitrary environment variables may be created and used with +many commands (those which require an \fIaddress-expression\fP). +.P +The +.B env +command is used to display the current environment. +.P +The +.B set +command is used to alter an existing environment variable or +establish a new environment variable. +.SH LIMITATIONS +There is a compile-time limit of 33 environment variables. +.P +There is a compile-time limit of 512 bytes (\fBKDB_ENVBUFSIZE\fP) +of heap space available for new environment variables and for +environment variables changed from their compile-time values. +.SH ENVIRONMENT +These commands explicitly manipulate the environment. +.SH SMP CONSIDERATIONS +None. +.SH USER SETTINGS +You can include "set" commands in kdb/kdb_cmds (see kdb.mm) to define +your environment variables at kernel startup. +.SH EXAMPLES +.TP 8 +env +Display current environment settings. + +.TP 8 +set IDCOUNT=100 +Set the number of lines to display for the \fBid\fP command +to the value \fI100\fP. Index: 2.6.x-xfs/Documentation/kdb/kdb_ll.man =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/kdb_ll.man 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/kdb_ll.man 2006-02-28 11:26:53.485490555 +1100 @@ -0,0 +1,134 @@ +.TH LL 1 "19 April 1999" +.SH NAME +ll \- Linked List examination +.SH SYNOPSIS +ll +.SH DESCRIPTION +The +.B ll +command is used to execute a single command repetitively for +each element of a linked list. +.P +The command specified by will be executed with a single +argument, the address of the current element. +.SH LIMITATIONS +Be careful if using this command recursively. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.nf +.na +.ft CW +# cd modules +# insmod kdbm_vm.o +# Entering kdb on processor 0 due to PAUSE +kdb> ps +Task Addr Pid Parent cpu lcpu Tss Command +0xc03de000 0000000001 0000000000 0000 0000 0xc03de2d4 init +0xc0090000 0000000002 0000000001 0000 0000 0xc00902d4 kflushd +0xc000e000 0000000003 0000000001 0000 0000 0xc000e2d4 kpiod +0xc000c000 0000000004 0000000001 0000 0000 0xc000c2d4 kswapd +0xc7de2000 0000000056 0000000001 0000 0000 0xc7de22d4 kerneld +0xc7d3a000 0000000179 0000000001 0000 0000 0xc7d3a2d4 syslogd +0xc7a7e000 0000000188 0000000001 0000 0000 0xc7a7e2d4 klogd +0xc7a04000 0000000199 0000000001 0000 0000 0xc7a042d4 atd +0xc7b84000 0000000210 0000000001 0000 0000 0xc7b842d4 crond +0xc79d6000 0000000221 0000000001 0000 0000 0xc79d62d4 portmap +0xc798e000 0000000232 0000000001 0000 0000 0xc798e2d4 snmpd +0xc7904000 0000000244 0000000001 0000 0000 0xc79042d4 inetd +0xc78fc000 0000000255 0000000001 0000 0000 0xc78fc2d4 lpd +0xc77ec000 0000000270 0000000001 0000 0000 0xc77ec2d4 sendmail +0xc77b8000 0000000282 0000000001 0000 0000 0xc77b82d4 gpm +0xc7716000 0000000300 0000000001 0000 0000 0xc77162d4 smbd +0xc7ee2000 0000000322 0000000001 0000 0000 0xc7ee22d4 mingetty +0xc7d6e000 0000000323 0000000001 0000 0000 0xc7d6e2d4 login +0xc778c000 0000000324 0000000001 0000 0000 0xc778c2d4 mingetty +0xc78b6000 0000000325 0000000001 0000 0000 0xc78b62d4 mingetty +0xc77e8000 0000000326 0000000001 0000 0000 0xc77e82d4 mingetty +0xc7708000 0000000327 0000000001 0000 0000 0xc77082d4 mingetty +0xc770e000 0000000328 0000000001 0000 0000 0xc770e2d4 mingetty +0xc76b0000 0000000330 0000000001 0000 0000 0xc76b02d4 update +0xc7592000 0000000331 0000000323 0000 0000 0xc75922d4 ksh +0xc7546000 0000000338 0000000331 0000 0000 0xc75462d4 su +0xc74dc000 0000000339 0000000338 0000 0000 0xc74dc2d4 ksh +kdb> md 0xc74dc2d4 +c74dc2d4: 00000000 c74de000 00000018 00000000 .....`MG........ +c74dc2e4: 00000000 00000000 00000000 074de000 .............`M. +c74dc2f4: c01123ff 00000000 00000000 00000000 #.@............ +c74dc304: 00000000 00000000 c74dded0 00000000 ........P^MG.... +[omitted] +c74dc474: 00000000 00000000 00000000 00000000 ................ +c74dc484: 00000000 c7c15d00 c77b0900 c026fbe0 .....]AG..{G`{&@ +c74dc494: 00000000 c76c2000 00000000 00000000 ..... lG........ +c74dc4a4: 00000000 00000000 00000000 c74dc4ac ............,DMG +kdb> md 0xc026fbe0 +c026fbe0: c0262b60 00000000 c7594940 c74de000 @HYG....@IYG.`MG +[omitted] +kdb> md 0xc0262b60 +c0262b60: c0266660 08048000 0804c000 c7bec360 `f&@.....@..`C>G +kdb> ll c0262b60 12 md +c0262b60: c0266660 08048000 0804c000 c7bec360 `f&@.....@..`C>G +c7bec360: c0266660 0804c000 0804d000 c7becb20 `f&@.@...P.. K>G +c7becb20: c0266660 0804d000 08050000 c7bec3a0 `f&@.P...... C>G +c7bec3a0: c0266660 40000000 40009000 c7bec420 `f&@...@...@ D>G +c7bec420: c0266660 40009000 4000b000 c7bec4a0 `f&@...@.0.@ D>G +c7bec4a0: c0266660 4000b000 40010000 c7bec8e0 `f&@.0.@...@`H>G +c7bec8e0: c0266660 40010000 400a1000 c7becbe0 `f&@...@...@`K>G +c7becbe0: c0266660 400a1000 400a8000 c7becc60 `f&@...@...@`L>G +c7becc60: c0266660 400a8000 400b4000 c7952300 `f&@...@.@.@.#.G +c7952300: c0266660 400b5000 400bc000 c79521c0 `f&@.P.@.@.@@!.G +c79521c0: c0266660 400bc000 400bd000 c7bec6e0 `f&@.@.@.P.@`F>G +c7bec6e0: c0266660 bffff000 c0000000 00000000 `f&@.p?...@.... +kdb> +kdb> ll c0262b60 12 vm +struct vm_area_struct at 0xc0262b60 for 56 bytes +vm_start = 0x8048000 vm_end = 0x804c000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +struct vm_area_struct at 0xc7bec360 for 56 bytes +vm_start = 0x804c000 vm_end = 0x804d000 +page_prot = 0x25 avl_height = -31808 vm_offset = 0x3000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +struct vm_area_struct at 0xc7becb20 for 56 bytes +vm_start = 0x804d000 vm_end = 0x8050000 +page_prot = 0x25 avl_height = -28664 vm_offset = 0x0 +flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec3a0 for 56 bytes +vm_start = 0x40000000 vm_end = 0x40009000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE +struct vm_area_struct at 0xc7bec420 for 56 bytes +vm_start = 0x40009000 vm_end = 0x4000b000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x8000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE +struct vm_area_struct at 0xc7bec4a0 for 56 bytes +vm_start = 0x4000b000 vm_end = 0x40010000 +page_prot = 0x25 avl_height = 26853 vm_offset = 0x0 +flags: READ MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec8e0 for 56 bytes +vm_start = 0x40010000 vm_end = 0x400a1000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7becbe0 for 56 bytes +vm_start = 0x400a1000 vm_end = 0x400a8000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x90000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7becc60 for 56 bytes +vm_start = 0x400a8000 vm_end = 0x400b4000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7952300 for 56 bytes +vm_start = 0x400b5000 vm_end = 0x400bc000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc79521c0 for 56 bytes +vm_start = 0x400bc000 vm_end = 0x400bd000 +page_prot = 0x25 avl_height = -16344 vm_offset = 0x6000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec6e0 for 56 bytes +vm_start = 0xbffff000 vm_end = 0xc0000000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC GROWSDOWN +kdb> Index: 2.6.x-xfs/Documentation/kdb/kdb_md.man =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/kdb_md.man 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/kdb_md.man 2006-02-28 11:26:53.486466984 +1100 @@ -0,0 +1,136 @@ +.TH MD 1 "August 4, 2004" +.SH NAME +md, mdWcN, mdr, mds, mm, mmW\- Memory manipulation commands +.SH SYNOPSIS +md [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] +.LP +md\fIW\fRc\fIn\fR [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] +.LP +mdp \fIphysical-address-expression\fP,\fIbytes\fP +.LP +mdr \fIaddress-expression\fP,\fIbytes\fP +.LP +mds [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] +.LP +mm \fIaddress-expression\fP \fInew-contents\fP +.LP +mm\fIW\fR \fIaddress-expression\fP \fInew-contents\fP +.SH DESCRIPTION +The +.B md +command is used to display the contents of memory. +The \fIaddress-expression\fP may be a numeric value (decimal or +hexidecimal), a symbol name, a register name preceeded by one or more +percent symbols '%', an environment variable name preceeded by +a currency symbol '$', or a simple expression consisting of a +symbol name, an addition or subtraction character and a numeric +value (decimal or hexidecimal). +.P +If an address is specified and the \fIline-count\fP or \fIradix\fP arguments +are omitted, they default to the values of the \fBMDCOUNT\fP and \fBRADIX\fP +environment variables respectively. If the \fBMDCOUNT\fP or \fBRADIX\fP +environment variables are unset, the appropriate defaults will be used [see +\fBENVIRONMENT\fP below]. If no address is specified then md resumes +after the last address printed, using the previous values of count and +radix. The start address is rounded down to a multiple of the +BYTESPERWORD (md) or width (md\fIW\fR). +.P +md uses the current value of environment variable \fBBYTESPERWORD\fP to +read the data. When reading hardware registers that require special +widths, it is more convenient to use md\fIW\fRc\fIn\fR where \fIW\fR is +the width for this command and \fRc\fIn\fR is the number of entries to +read. For example, md1c20 reads 20 bytes, 1 at a time. To continue +printing just type md, the width and count apply to following md +commands with no parameters. \fBNote:\fR The count is the number of +repeats of the width, unlike MDCOUNT which gives the number of md lines +to print. +.P +The +.B mdp +command displays the contents of physical memory, starting at the +specified physical address for the specified number of bytes. +The address is preceded by 'phys'. +.P +The +.B mdr +command displays the raw contents of memory, starting at the specified +address for the specified number of bytes. +The data is printed in one line without a leading address and no +trailing character conversion. +.B mdr +is intended for interfacing with external debuggers, it is of little +use to humans. +.P +The +.B mds +command displays the contents of memory one word per line and +attempts to correlate the contents of each word with a symbol +in the symbol table. If no symbol is found, the ascii representation +of the word is printed, otherwise the symbol name and offset from +symbol value are printed. +By default the section data is printed for kernel symbols. +.P +The +.B mm +and +\fBmm\fIW\fR +commands allow modification of memory. The bytes at the address +represented by \fIaddress-expression\fP are changed to +\fInew-contents\fP. \fInew-contents\fP is allowed to be an +\fIaddress-expression\fP. +.B mm +changes a machine word, \fBmm\fIW\fR changes \fIW\fR bytes at that +address. +.SH LIMITATIONS +None. +.SH ENVIRONMENT +.TP 8 +MDCOUNT +This environment variable (default=8) defines the number of lines +that will be displayed by each invocation of the \fBmd\fP command. + +.TP 8 +RADIX +This environment variable (default=16) defines the radix used to +print the memory contents. + +.TP 8 +BYTESPERWORD +This environment variable (default=4) selects the width of output +data when printing memory contents. Select the value two to get +16-bit word output, select the value one to get byte output. + +.TP 8 +LINES +This environment variable governs the number of lines of output +that will be presented before the kernel debugger built-in pager +pauses the output. This variable only affects the functioning +of the \fBmd\fP and \fBmds\fP if the \fBMDCOUNT\fP variable +is set to a value greater than the \fBLINES\fP variable. + +.TP 8 +NOSECT +If the \fBNOSECT\fP environment variable is non-zero then the +section information is suppressed. +The default is NOSECT=1 so section data is suppressed; use set\ NOSECT=0 +to see section information. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.TP 8 +md %edx +Display memory starting at the address contained in register \fB%edx\fP. + +.TP 8 +mds %esp +Display stack contents symbolically. This command is quite useful +in manual stack traceback. + +.TP 8 +mm 0xc0252110 0x25 +Change the memory location at 0xc0252110 to the value 0x25. + +.TP 8 +md chrdev_table 15 +Display 15 lines (at 16 bytes per line) starting at address +represented by the symbol \fIchrdev_table\fP. Index: 2.6.x-xfs/Documentation/kdb/kdb_ps.man =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/kdb_ps.man 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/kdb_ps.man 2006-02-28 11:26:53.487443414 +1100 @@ -0,0 +1,96 @@ +.TH PS 1 "September 14, 2004" +.SH NAME +ps \- Display processes +.SH SYNOPSIS +ps [ DRSTCZEUIMA ] +.SH DESCRIPTION +The +.B ps +command displays the status of all processes in the desired state. +This command does not take any locks (all cpus should be frozen while +kdb is running) so it can safely be used to debug lock problems with +the process table. +.P +Without any parameters, \fBps\fP displays all the interesting +processes, excluding idle tasks and sleeping system daemons. +If a parameter is specified, it is a single string consisting of the +letters D, R, S, T, C, Z, E, U, I and M, in any order. +Each letter selects processes in a specific state, when multiple +letters are specified, a process will be displayed if it is in any of +the specified states. +The states are\ :- +.P +.DS +.TS +box, center; +l | l +l | l. +D Uninterruptible sleep +R Running +S Interruptible sleep +T Stopped +C Traced +Z Zombie +E Dead +U Unrunnable +I Idle task +M Sleeping system daemon +A All +.TE +.DE +.P +For state R (running), the process may not be on a cpu at the moment, +but it is ready to run. +The header line above the backtrace contains '1' in the fourth field if +the process is actually on a cpu. +.P +The idle task is run on each cpu when there is no work for that cpu to do. +Unless the idle task is servicing an interrupt, there is no point in +printing the idle task. +An idle task that is not servicing a interrupt is marked as state I, +while servicing an interrupt it is in state R. +By default, idle tasks are not printed, use \fBps\ I\fR to print them. +If the idle tasks are not being printed, the start of the \fBps\R +output contains a list of which cpus are idle. +.P +Each cpu has one or more system daemons to handle per cpu work such as +soft irqs. +A system daemon (idenified by a NULL mm pointer) that is sleeping is +marked as state M. +These processes rarely have any useful data and generate a lot of +output on large machines, so sleeping system daemons are not printed by +default. +Use \fBps\ M\fR to print them. +.P +At the start of the \fBps\fR output is a line giving the cpu status, +see the kdb \fBcpu\fR command. +.SH LIMITATIONS +None. +.SH ENVIRONMENT +.TP 8 +PS +This environment variable (default=DRSTCZEU) is used when \fBps\fR +is issued with no parameters. + +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.TP 8 +\fBps\fR +displays the useful tasks, suppressing idle tasks and sleeping +system daemons. + +.TP 8 +\fBps\ RD\fR +displays only tasks that are running or are in an uninterruptible +sleep. + +.TP 8 +\fBps\ DRSTCZEUIM\fR +displays all tasks. + +.TP 8 +\fBps\ A\fR +displays all tasks. +This is easier than remembering DRSTCZEUIM. + Index: 2.6.x-xfs/Documentation/kdb/kdb_rd.man =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/kdb_rd.man 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/kdb_rd.man 2006-02-28 11:26:53.488419844 +1100 @@ -0,0 +1,170 @@ +.TH RD 1 "September 20, 2005" +.SH NAME +rd, rm\- Register manipulation commands +.SH SYNOPSIS +rd [[c [n]]|d|u] +.LP +rm \fIregister-name\fP \fInew-contents\fP +.LP +ef
+.SH DESCRIPTION +The +.B rd +command is used to display the contents of processor and coprocessor registers. +Without any arguments, the rd command displays the contents of the general +register set at the point at which the kernel debugger was entered. +If the bt* or pid commands have been used to change the current process then +.B rd +and +.B rm +may not be able to display any registers. +'n' argument is only used for XScale platform to identify the desired +coprocessor number, while 'd' option is not valid for XScale platform. +.P +On IA32 and IA64, with the 'c' argument, the processor control registers +%cr0, %cr1, %cr2 and %cr4 are displayed, while with the 'd' argument +the processor debug registers are displayed. If the 'u' argument +is supplied, the registers for the current task as of the last +time the current task entered the kernel are displayed. +.P +On XScale, 'c' argument is used to display the +all coprocessor control registers or specified coprocessor registers by +argumnet 'n'. Argument 'u' is used to display the +registers for the current task as of the last time the current task +entered the kernel. Argument 'd' is not supported. +.P +On ix86, the +.B rm +command allows modification of a register. The following +register names are valid: \fB%eax\fP, \fB%ebx\fP, \fB%ecx\fP, +\fB%edx\fP, \fB%esi\fP, \fB%edi\fP, \fB%esp\fP, \fB%eip\fP, +and \fB%ebp\fP. Note that if two '%' symbols are used +consecutively, the register set displayed by the 'u' argument +to the \fBrd\fP command is modified. +.P +The debug registers, \fBdr0\fP through \fBdr3\fP and both +\fBdr6\fP and \fBdr7\fP can also be modified with the \fBrm\fP +command. +.P +On sparc64, the valid registers are named \fB%g0\fP through +\fB%g7\fP, \fB%l0\fP through \fB%l7\fP, \fB%o0\fP through +\fB%o7\fP, and \fB%i0\fP through \fB%i7\fP, with the exceptions +that \fB%o6\fP is called \fB%sp\fP and that \fB%i6\fP is called +\fB%fp\fP. The registers \fB%tstate\fP, \fB%tpc\fP, \fB%tnpc\fP, +\fB%y\fP, and \fB%fprs\fP provide state information at the time +the system entered kdb. Additionally, when viewing registers, two +convenience names are provided: \fB%®s\fP shows the +address on the stack of the current registers, and \fB%csp\fP +shows the current stack pointer within kdb itself. +.P +While on XScale, both the cpu registers and most coprocessor +registers can be be modified. \fIregister-name\fP can be followings like +r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, +r15, cpsr to address cpu registers. For the coprocessor registers in XSacle, +either alias name or \fICpcc[CRndd[CRmbb[Opaa]]]\fP can be used to address +the register in coprocessor cc with CRn=dd, CRm=bb and opcode2=aa. All aa, bb, cc, dd can be +1 or 2 decimal digitals, the default value is 0 when any of them is omitted. Name +acc0_h and acc0_l are used to identify the high byte and +low word of accumulator in coprocessor 0. +.P +On IA64, the parameter to +.B rd +can be d (debug registers), u (user registers at most recent entry to kernel), +i (interrupt registers), %isr (current interrupt status), s (stacked +registers), k (kernel registers). You can also specify these individual +registers - +psr, +ifs, +ip, +unat, +pfs, +rsc, +rnat, +bsps, +pr, +ldrs, +ccv, +fpsr, +b0, +b6, +b7, +r1, +r2, +r3, +r8, +r9, +r10, +r11, +r12, +r13, +r14, +r15, +r16, +r17, +r18, +r19, +r20, +r21, +r22, +r23, +r24, +r25, +r26, +r27, +r28, +r29, +r30, +r31. +.B rm +can change any of the individual registers or the stacked registers. +.P +The +.B ef +command displays an exception frame at the specified address. +.SH LIMITATIONS +Currently the \fBrm\fP command will not allow modification of the +control registers. +.P +Currently neither the \fBrd\fP command nor the \fBrm\fP command will +display or modify the model specific registers on the Pentium +and Pentium Pro families. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.TP 8 +rd +Display general register set from kdb's current task. + +.TP 8 +rd c 0 +Display coprocessor 0 registers. + +.TP 8 +rm %eax 0 +Set the contents of \fB%eax\fP to zero. This will be the +value of %eax when kdb returns from the condition which +invoked it. + +.TP 8 +rm %%eax 0 +Set the value of the \fB%eax\fP register to zero. This will +be the value the user-mode application will see upon returning +from the kernel. + +.TP 8 +rm %acc0_h 0 +Set the contents of high byte of accumulator to zero. + +.TP 8 +rm dr0 0xc1287220 +Set the value of the \fBdr0\fB register to \f(CW0xc1287220\fP. + +.TP 8 +rm %InVLD_BTB 0 +Write 0 to coprocessor 15 register with CRn=7, CRm=5, opcode2=6. + +.TP 8 +rm %CP15CRn7CRm5Op6 0 +Same with above. Index: 2.6.x-xfs/Documentation/kdb/kdb_sr.man =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/kdb_sr.man 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/kdb_sr.man 2006-02-28 11:26:53.489396273 +1100 @@ -0,0 +1,68 @@ +.TH SR 1 "7 October 2002" +.SH NAME +sr \- invoke sysrq commands from kdb +.SH SYNOPSIS +sr \fIx\fP +.SH DESCRIPTION +.hy 0 +The +.B sr +command invokes the existing sysrq handler code in the kernel. +This command takes a single character which is passed to sysrq +processing, as if you had entered the sysrq key sequence followed by +that character. +.P +.B Caveats: +.P +kdb will always call the sysrq code but sysrq may be disabled. +If you expect to use sysrq functions during debugging then +.IP "" +echo "1" > /proc/sys/kernel/sysrq +.P +before starting the debug session. +Alternatively issue +.IP "" +mm4 sysrq_enabled 1 +.P +during debugging. +.P +The sysrq code prints a heading using console loglevel 7 then reverts +to the original loglevel for the rest of the sysrq processing. +If the rest of the sysrq output is printed at a level below your +current loglevel then you will not see the output on the kdb console, +the output will only appear in the printk buffer. +It is the user's responsibility to set the loglevel correctly if they +want to see the sysrq output on the console. +Issue +.IP "" +sr 7 +.P +before any other +.B sr +commands if you want to see the output on the console. +You may even have to adjust the default message loglevel in order to +see any output from +.BR sr . +See Documentation/sysctl/kernel.txt for details on setting console +loglevels via /proc. +You can also adjust the loglevel variables via kdb +.BR mm ; +on older kernels there are variables such as default_message_level, on +newer kernels all the loglevel variables are in array console_printk, +see kernel/printk.c for your kernel. +.P +Operations that require interrupt driven I/O can be invoked from kdb +.BR sr , +but they will not do anything until you type 'go' to exit from kdb +(interrupts are disabled while in kdb). +There is no guarantee that these operations will work, if the machine +entered kdb because of an error then interrupt driven I/O may already +be dead. +Do not assume that +.B sr\ s +does anything useful. +.P +The sysrq handler uses locks and calls printk which also uses locks. +If the sysrq handler or any of the sysrq functions have to wait for a +lock then they will never return and kdb will appear to hang. +Invoking sysrq code from kdb is inherently unsafe. Index: 2.6.x-xfs/Documentation/kdb/kdb_ss.man =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/kdb_ss.man 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/kdb_ss.man 2006-02-28 11:26:53.490372703 +1100 @@ -0,0 +1,109 @@ +.TH SS 1 "17 January 2002" +.SH NAME +ss, ssb \- Single Step +.SH SYNOPSIS +ss +.LP +ssb +.SH DESCRIPTION +The +.B ss +command is used to execute a single instruction and return +to the kernel debugger. +.P +Both the instruction that was single-stepped and the next +instruction to execute are printed. +.P +The \fBssb\fP command will execute instructions from the +current value of the instruction pointer. Each instruction +may be printed as it is executed, depending upon architecture; +execution will stop at any instruction which would cause the flow +of control to change (e.g. branch, call, interrupt instruction, +return, etc.) +.SH LIMITATIONS +On sparc64, there are some circumstances where single-stepping +can be dangerous. Do not single-step across an instruction which +changes the interrupt-enable bit in %tstate. Do not single step +through code which is invoked when entering or leaving the +kernel, particularly any kernel entry code before %tl is set to +0, or any kernel exit code after %tl is set to 1. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +Other processors are held in the kernel debugger when the instruction +is traced. Single stepping though code that requires a lock which is +in use by another processor is an exercise in futility, it will never +succeed. +.SH INTERRUPT CONSIDERATIONS +When a kdb event occurs, one cpu (the initial cpu) enters kdb state. +It uses a cross system interrupt to interrupt the +other cpus and bring them all into kdb state. All cpus run with +interrupts disabled while they are inside kdb, this prevents most +external events from disturbing the kernel while kdb is running. +.B Note: +Disabled interrupts means that any I/O that relies on interrupts cannot +proceed while kdb is in control, devices can time out. The clock tick +is also disabled, machines will lose track of time while they are +inside kdb. +.P +Even with interrupts disabled, some non-maskable interrupt events +will still occur, these can disturb the kernel while you are +debugging it. The initial cpu will still accept NMI events, +assuming that kdb was not entered for an NMI event. Any cpu +where you use the SS or SSB commands will accept NMI events, even +after the instruction has finished and the cpu is back in kdb. +This is an unavoidable side effect of the fact that doing SS[B] +requires the cpu to drop all the way out of kdb, including +exiting from the NMI event that brought the cpu into kdb. Under +normal circumstances the only NMI event is for the NMI oopser and +that is kdb aware so it does not disturb the kernel while kdb is +running. +.P +Sometimes doing SS or SSB on ix86 will allow one interrupt to proceed, +even though the cpu is disabled for interrupts. I have not been able +to track this one down but I suspect that the interrupt was pending +when kdb was entered and it runs when kdb exits through IRET even +though the popped flags are marked as cli(). If any ix86 hardware +expert can shed some light on this problem, please notify the kdb +maintainer. +.SH EXAMPLES +.nf +.na +.ft CW +kdb> bp gendisk_head datar 4 +Data Access Breakpoint #0 at 0xc024ddf4 (gendisk_head) in dr0 is enabled on cpu 0 +for 4 bytes +kdb> go +... +[root@host /root]# cat /proc/partitions +Entering kdb on processor 0 due to Debug Exception @ 0xc01845e3 +Read/Write breakpoint #0 at 0xc024ddf4 +[0]kdb> ssb +sd_finish+0x7b: movzbl 0xc02565d4,%edx +sd_finish+0x82: leal 0xf(%edx),%eax +sd_finish+0x85: sarl $0x4,%eax +sd_finish+0x88: movl 0xc0256654,%ecx +sd_finish+0x8e: leal (%eax,%eax,4),%edx +sd_finish+0x91: leal (%eax,%edx,2),%edx +sd_finish+0x94: movl 0xc0251108,%eax +sd_finish+0x99: movl %eax,0xffffffc(%ecx,%edx,4) +sd_finish+0x9d: movl %ecx,0xc0251108 +sd_finish+0xa3: xorl %ebx,%ebx +sd_finish+0xa5: cmpb $0x0,0xc02565d4 +[0]kdb> go +[root@host /root]# + +[0]kdb> ss +sys_read: pushl %ebp +SS trap at 0xc01274c1 +sys_read+0x1: movl %esp,%ebp +[0]kdb> ss +sys_read+0x1: movl %esp,%ebp +SS trap at 0xc01274c3 +sys_read+0x3: subl $0xc,%esp +[0]kdb> ss +sys_read+0x3: subl $0xc,%esp +SS trap at 0xc01274c6 +sys_read+0x6: pushl %edi +[0]kdb> + Index: 2.6.x-xfs/Documentation/kdb/slides =================================================================== --- 2.6.x-xfs.orig/Documentation/kdb/slides 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/Documentation/kdb/slides 2006-02-28 11:26:53.495254851 +1100 @@ -0,0 +1,1382 @@ +#! /opt/cpg/bin/do-mgp +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%deffont "standard" tfont "comic.ttf" +%deffont "thick" tfont "arialb.ttf" +%deffont "typewriter" xfont "courier new-bold-r" +%deffont "type2writer" xfont "arial narrow-bold-r" +%% +%% Default settings per each line numbers. +%% +#%default 1 leftfill, size 2, fore "black", back "LemonChiffon2", font "thick" +%default 1 leftfill, size 2, fore "black", back "white", font "thick" +%default 2 size 10, vgap 10, prefix " ", center +%default 3 size 2, bar "gray70", vgap 10 +%default 4 size 6, fore "black", vgap 30, prefix " ", font "standard", left +%% +%% Default settings that are applied to TAB-indented lines. +%% +%tab 1 size 4, vgap 35, prefix " ", icon arc "red" 40 +%tab 2 size 4, vgap 20, prefix " ", icon delta3 "blue" 40 +%tab 3 size 4, vgap 20, prefix " ", icon delta3 "green" 40 +%% +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +KDB - Kernel Debugger + + + +%size 7,center, font "thick" +Introduction + +And + +Demonstration + + +%size 3 + +February 5, 2002 IBM Linux Technology Center Paul Dorwin +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +IBM Legal + + + IBM Legal requires this information: + +%size 3 + + THE INFORMATION IN THE FOLLOWING PRESENTATION IS PREPARED + SOLELY FOR THE INFORMATION OF THE READER, AND COMES "AS IS" + AND WITHOUT WARRANTY OR REPRESENATION OF ANY KIND. + + ANY PARTY USING THE MATERIALS IN THIS PRESENTATION DOES SO + AT ITS OWN RISK LIABILITY AND THE PROVIDER OF THE MATERIALS + ACCEPTS NO RISK OR LIABILITY FOR SUCH USE OR RESULTING FROM + DISSEMINATION TO OR USE BY ANY OTHER PARTY + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Agenda + +%size 5 + + Installing and Configuring KDB + + KDB Commands + + Scull Demo + + Setting Breakpoints + + Displaying Data Structures + + Kernel Data structures + + Take a walk through an IO operation +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Installing Configuring KDB + + + Install KDB patch. + Start with a clean source tree + Apply architecture specific patches + Obtain patch for your kernel version + see http://oss.sgi.com/projects/kdb/ + Apply the kdb patch + patch -p 1 -N -u -i /path/to/patch + Apply any other patches + Build and reboot on your kdb enabled kernel + Man pages can be found at Documentation/kdb + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Configuring KDB + + + Config kernel with the following options: + These are documented in Documentation/Configure.help + + CONFIG_KDB=y + Enable compilation of KDB in the kernel.. + Setting this also sets CONFIG_KALLSYMS=y. + CONFIG_KDB_MODULES=n + KDB may be extended, compiling kdb/modules. + CONFIG_KDB_OFF=n + y = KDB is disabled by default. + boot with kdb=on to enable at boot. + /proc/sys/kernel/kdb to enable/disable when system is up. + CONFIG_KALLSYMS=y + This causes all symbols to be exported. + CONFIG_FRAME_POINTER=y +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Invoking KDB + + + KDB can be invoked in the following ways: + + Early init with "kdb=early" lilo flag + Hits breakpoint prior to fork_init() (init/main.c) + + Serial console with CNTRL-A + + Console with PAUSE key + + When a pre-set breakpoint is hit + + On panic + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +KDB Commands + + + KDB environment + env Show environment variables + set Set environment variables + help Display Help Message + ? Display Help Message + + System related + sections List kernel and module sections + lsmod List loaded kernel modules + reboot Reboot the machine immediately + cpu Switch to new cpu + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +KDB Commands + + + Memory Manipulation + md Display Memory Contents + mdr Display Raw Memory + mds Display Symbolically + mm Modify Memory Contents + id Display Instructions + + Register Manipulation + rd Display Registers + rm Modify Registers + ef Display exception frame + + Stack + bt [] Stack traceback + btp Display stack for + bta Display all stacks + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +KDB Commands + + + Breakpoint + bc Clear Breakpoint + bd Disable Breakpoint + be Enable Breakpoint + bl [] Display breakpoints + bp [] Set/Display breakpoints + bpa [] Set/Display global breakpoints + bph [] Set hardware breakpoint + bpha [] Set global hardware breakpoint + bp* modifiers: + instruction - break on instruction fetch (default) + datar - break on read at vaddr + dataw - break on write at vaddr + IO - break on in or out op at vaddress + + Execution control + go [] Continue Execution + ss [<#steps>] Single Step + ssb Single step to branch/call +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +KDB Commands + + + Kernel structures + ll Traverse list and execute command + ps Display active task list + vm Display vm_area_struct + dentry Display interesting dentry stuff + filp Display interesting filp stuff + sh Show scsi_host + sd Show scsi_device + sc Show scsi_cmnd + kiobuf Display kiobuf + page Display page + inode Display inode + bh Display buffer head + inode_pages Display pages in an inode +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo + + + Objective + Find and display the data associated with a scull device + + The sequence of events + Populate the scull device with data + Identify the breakpoints + Set breakpoint in the device read function + Identify the data structure elements + Identify device structures used to track data + Display data structures containing the data + Show the usage of the filp command + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Populate Device + + + Obtain the code + Surf to http://examples.oreilly.com/linuxdrive2/ + Download the tarball + Untar it to /usr/src + + Build and install the module + cd /usr/src/ldd2-samples-1.0.1/scull + make + ./scull.init start + + Populate the scull device + cat main.c > /dev/scull0 + cat /dev/scull0 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Driver Details + + + cat /dev/scull0 + fd = +%fore "blue", cont +open +%fore "black", cont +("/dev/scull0", O_RDONLY); + Kernel finds the file_operations structure + Kernel then invokes the open function +%fore "blue" + read +%fore "black", cont +(fd, buf, size); + Kernel finds the file_operations structure + Kernel then invokes the read function + + Scull device file operations structure + +%font "typewriter", size 3 + struct file_operations scull_fops = { + llseek: scull_llseek, +%fore "blue" + read: scull_read, +%fore "black" + write: scull_write, + ioctl: scull_ioctl, +%fore "blue" + open: scull_open, +%fore "black" + release: scull_release, + }; +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Driver Details + +%font "typewriter", size 3 + scull_open code +%font "typewriter", size 3 + int +%fore "blue", cont +scull_open +%fore "black", cont +(struct inode *inode, struct file *filp) + { + Scull_Dev *dev; /* device information */ + int num = NUM(inode->i_rdev); + + + + dev = (Scull_Dev *)filp->private_data; + if (!dev) { + if (num >= scull_nr_devs) return -ENODEV; +%fore "blue" + dev = &scull_devices[num]; + filp->private_data = dev; +%fore "black" + } + + + + } +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Driver Details + +%font "typewriter", size 3 + scull_read code +%font "typewriter", size 3 + ssize_t +%fore "blue", cont +scull_read +%fore "black", cont +(struct file *filp, char *buf, size_t count, + loff_t *f_pos) + { + +%fore "blue", cont + Scull_Dev *dev = filp->private_data; +%fore "black", cont + /* the first listitem */ +%fore "blue" + Scull_Dev *dptr; +%fore "black" + int quantum = dev->quantum; + int qset = dev->qset; + int itemsize = quantum * qset; + if (down_interruptible(&dev->sem)) + return -ERESTARTSYS; + if (*f_pos + count > dev->size) + count = dev->size - *f_pos; + + /* find listitem, qset index, and offset in the quantum */ + item = (long)*f_pos / itemsize; + rest = (long)*f_pos % itemsize; + s_pos = rest / quantum; q_pos = rest % quantum; + + /* follow the list up to the right position */ +%fore "blue" + dptr = scull_follow(dev, item); +%fore "black" + + + + } +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Breakpoints + + +%font "typewriter", size 3 + Determine where to set breakpoint +%font "typewriter", size 3 +%fore "blue" + dptr = scull_follow(dev, item); +%fore "black" + +%font "typewriter", size 3 + Disassemble scull_read +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +id scull_read +%fore "black" + 0xf8c083b4 scull_read: push %ebp + 0xf8c083b5 scull_read+0x1:mov %esp,%ebp + 0xf8c083b7 scull_read+0x3:push %edi + + 0xf8c08465 scull_read+0xb1:sub $0x8,%esp +%fore "blue" + 0xf8c08468 scull_read+0xb4:push %ecx + 0xf8c08469 scull_read+0xb5:push %esi + 0xf8c0846a scull_read+0xb6:call 0xf8c08364 scull_follow: +%fore "black" + 0xf8c0846f scull_read+0xbb:mov %eax, +%fore "blue", cont + %edx +%fore "black" + 0xf8c08471 +%fore "blue", cont +scull_read+0xbd +%fore "black", cont +:add $0x10,%esp + + + Set breakpoint in driver read +%font "typewriter", size 3 + [0]kdb> +%fore "blue",cont +bp scull_read+0xbd +%fore "black" + Instruction(i) BP #0 at 0xf8c08471 ([scull]scull_read+0xbd) + is enabled globally adjust 1 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Breakpoints + + +%font "typewriter", size 3 + Restart the system +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +go +%fore "black" + + Hit the Breakpoint +%font "typewriter", size 3 + [root@elm3b77 root]# +%fore "blue", cont +cat /dev/scull0 +%fore "black" + Instruction(i) breakpoint #0 at 0xf8c08471 (adjusted) + 0xf8c08471 scull_read+0xbd:int3 + Entering kdb (current=0xf73ec000, pid 1249) on processor 2 + due to Breakpoint @ 0xf8c08471 + + Display the registers +%font "typewriter", size 3 + [2]kdb> +%fore "blue", cont +rd +%fore "black" + eax = 0xf77d7b60 ebx = 0x00000000 ecx = 0x00000000 edx = +%fore "blue", cont +0xf77d7b60 +%fore "black" + esi = +%fore "blue", cont +0xf77d7b60 +%fore "black", cont + edi = 0x00001000 esp = 0xf7415f40 eip = 0xf8c08471 + ebp = 0xf7415f78 xss = 0x00000018 xcs = 0x00000010 eflags = 0x00000246 + xds = 0xf7590018 xes = 0x00000018 origeax = 0xffffffff ®s = 0xf7415f0c +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Data Structures + +%font "typewriter", size 3 + Display the Scull_Dev structure +%font "typewriter", size 3 + [2]kdb> +%fore "blue", cont +md 0xf77d7b60 2 +%fore "black" + 0xf77d7b60 +%fore "blue", cont +f7400000 +%fore "black", cont + 00000000 00000fa0 000003e8 ..@w.... ...h... + 0xf77d7b70 0000534e 00000000 00000000 00000000 NS.............. + + Scull Device Structure +%font "typewriter", size 3 + typedef struct Scull_Dev { +%fore "blue" + void **data; +%fore "black" + struct Scull_Dev *next; /* next listitem */ + int quantum; /* the current quantum size */ + int qset; /* the current array size */ + unsigned long size; + devfs_handle_t handle; /* only used if devfs is there */ + unsigned int access_key; /* used by sculluid and scullpriv */ + struct semaphore sem; /* mutual exclusion semaphore */ + } Scull_Dev; +%size 6 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: Data Structures + + +%font "typewriter", size 3 + Display the quantum set (dev->data) +%font "typewriter", size 3 + [2]kdb> +%fore "blue", cont +md f7400000 2 +%fore "black" + 0xf7400000 +%fore "blue", cont +f73ea000 +%fore "black", cont + f73f1000 f740c000 f7ab4000 . >w..?w.@@w.@+w + 0xf7400010 f73ef000 f755b000 00000000 00000000 .p>w.0Uw........ + + Display the first quantum (dev->data[0]) +%font "typewriter", size 3 + [2]kdb> +%fore "blue", cont +md f73ea000 +%fore "black" + 0xf73ea000 200a2a2f 616d202a 632e6e69 202d2d20 /*. * main.c -- + 0xf73ea010 20656874 65726162 75637320 63206c6c the bare scull c + 0xf73ea020 20726168 75646f6d 200a656c 2a200a2a har module. *. * + 0xf73ea030 706f4320 67697279 28207468 32202943 Copyright (C) 2 + 0xf73ea040 20313030 73656c41 646e6173 52206f72 001 Alessandro R + 0xf73ea050 6e696275 6e612069 6f4a2064 6874616e ubini and Jonath + 0xf73ea060 43206e61 6562726f 2a200a74 706f4320 an Corbet. * Cop + 0xf73ea070 67697279 28207468 32202943 20313030 yright (C) 2001 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: filp command + + +%font "typewriter", size 3 + Show filp usage - here is the scull_read prototype +%font "typewriter", size 3 + ssize_t scull_read( +%fore "blue", cont +struct file *filp +%fore "black", cont +, char *buf, + size_t count, loff_t *f_pos); + Show the stack trace: +%font "typewriter", size 3 +[2]kdb> +%fore "blue", cont +bt +%fore "black" + EBP EIP Function(args) + 0xee9dbf78 0xf8c08471 [scull]scull_read+0xbd ( +%fore "blue", cont +0xeaf6c0c0 +%fore "black", cont +, 0x804e128, + 0x1000, 0xeaf6c0e0, 0x804f000) + scull .text 0xf8c08060 0xf8c083b4 0xf8c084dc + 0xee9dbfbc 0xc0136278 sys_read+0x98 (0x3, 0x804e128, 0x1000, ... + kernel .text 0xc0100000 0xc01361e0 0xc01362b0 + 0xc010702b system_call+0x33 + kernel .text 0xc0100000 0xc0106ff8 0xc0107030 + And show the filp output +%font "typewriter", size 3 + [2]kdb> +%fore "blue", cont +filp 0xeaf6c0c0 +%fore "black" + name.name 0xe93889fc name.len 6 + File Pointer at 0xeaf6c0c0 + f_list.nxt = 0xe42deca0 f_list.prv = 0xf7e69070 +%fore "blue" + f_dentry = 0xe93889a0 +%fore "black", cont + f_op = 0xf8c0a200 + f_count = 2 f_flags = 0x8000 f_mode = 0x1 + f_pos = 0 f_reada = 0 f_ramax = 0 + f_raend = 0 f_ralen = 0 f_rawin = 0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Scull Demo: filp command + + +%font "typewriter", size 3 + filp output - continued +%font "typewriter", size 3 +%fore "blue" + Directory Entry at 0xe93889a0 +%fore "black" + d_name.len = 6 +%fore "orange", cont +d_name.name = 0xe93889fc +%fore "black", cont +> + d_count = 1 d_flags = 0x0 +%fore "blue", cont +d_inode = 0xe827b680 +%fore "black" + d_hash.nxt = 0xc215aec8 d_hash.prv = 0xc215aec8 + d_lru.nxt = 0xe93889b8 d_lru.prv = 0xe93889b8 + d_child.nxt = 0xe89e1e80 d_child.prv = 0xe9388940 + d_subdirs.nxt = 0xe93889c8 d_subdirs.prv = 0xe93889c8 + d_alias.nxt = 0xe827b690 d_alias.prv = 0xe827b690 + d_op = 0x00000000 d_sb = 0xf7e69000 + +%fore "blue" + Inode Entry at 0xe827b680 +%fore "black" + i_mode = 0x21a4 i_nlink = 1 i_rdev = 0xfe00 + i_ino = 37182 i_count = 1 i_dev = 0x821 + i_hash.nxt = 0xc20e6be8 i_hash.prv = 0xc20e6be8 + i_list.nxt = 0xe827b2c8 i_list.prv = 0xe827b868 + i_dentry.nxt = 0xe93889d0 i_dentry.prv = 0xe93889d0 + + Check the filename (display d_name.name) +%font "typewriter", size 3 + [2]kdb> +%fore "orange", cont +md 0xe93889fc 1 +%fore "black" + 0xe93889fc 6c756373 0000306c 00000000 00000000 scull0.......... + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Kernel Structures + + + Objective + Show output from various kernel related kdb commands + + Sequence of events + Simple Program + Write a simple program which allocates memory and hangs + Show usage of the ps, vm, and ll commands + Walk an IO operation + Hit a breakpoint in qlogic driver (isp1020_queuecommand) + Show usage of scsi related commands (sc, sh, and sd) + Show usage of vm related commands (bh, page, inode, inode_pages) + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple program + +%font "typewriter", size 3 + simple.c - simple program which allocates memory +%font "typewriter", size 3 +%fore "blue" + int foo_global[8192]; +%fore "black" + main() + { + int * +%fore "blue", cont +foo_malloc; +%fore "black" + int i; + foo_malloc = (int *)malloc(0x8192); + for(i = 0; i < 0x100; i++) { + foo_global[i] = 0xdead0000 | i; + foo_malloc[i] = 0xbeef0000 | i; + } + printf("foo_global at %x\n", (int)foo_global); + printf("foo_malloc at %x\n", (int)foo_malloc); + printf("sleep forever\n"); + sleep(2000000); + } + + simple output +%font "typewriter", size 3 + [root@elm3b77 scull]# cc -o simple simple.c + [root@elm3b77 scull]# ./simple + foo_global at +%fore "blue", cont +8049780 +%fore "black" + foo_malloc at +%fore "blue", cont +8051788 +%fore "black" + sleep forever + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple Program + +%font "typewriter", size 3 + Show the output of the ps command +%font "typewriter", size 3 + Entering kdb (current=0xc2010000, pid 0) on processor 3 due to + Keyboard Entry + [3]kdb> +%fore "blue", cont +ps +%fore "black" + Task Addr Pid Parent [*] cpu State Thread Command + 0xf7efe000 00000001 00000000 0 003 stop 0xf7efe370 init + 0xf7ef0000 00000002 00000001 0 001 stop 0xf7ef0370 keventd + 0xf7eec000 00000003 00000000 0 000 stop 0xf7eec370 ksoftirqd_CPU0 + 0xf7eea000 00000004 00000000 0 001 stop 0xf7eea370 ksoftirqd_CPU1 + 0xf7ee8000 00000005 00000000 0 002 stop 0xf7ee8370 ksoftirqd_CPU2 + 0xf7ee6000 00000006 00000000 0 003 stop 0xf7ee6370 ksoftirqd_CPU3 + + + + 0xf7b46000 00001006 00000737 0 003 stop 0xf7b46370 sshd + 0xf7ace000 00001007 00001006 0 000 stop 0xf7ace370 bash + 0xef06a000 00001066 00001007 0 003 stop 0xef06a370 su + 0xeef88000 00001067 00001066 0 000 stop 0xeef88370 bash + 0xeef64000 00001119 00000770 0 001 stop 0xeef64370 in.ftpd +%fore "blue" + 0xeeeac000 +%fore "black", cont + 00001138 00001067 0 001 stop 0xeeeac370 +%fore "blue", cont +simple +%fore "black" + [3]kdb> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple Program + +%font "typewriter", size 3 + Display the task struct +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +md 0xeeeac000 +%fore "black" + 0xeeeac000 00000001 00000000 00000000 c0000000 ................ + 0xeeeac010 c0339880 00000000 00000000 ffffffff ................ + 0xeeeac020 0000000a 00000000 00000000 +%fore "blue", cont +f7e10f00 +%fore "black", cont + ..............aw + 0xeeeac030 00000001 ffffffff ffffffff 00000000 ................ + +%font "typewriter", size 3 + Determine offset of mm_struct ptr in task_struct +%font "typewriter", size 3 + struct task_struct { + [0] volatile long state; + [4] unsigned long flags; + [8] int sigpending; + [c] mm_segment_t addr_limit; + [10] struct exec_domain *exec_domain; + [14] volatile long need_resched; + [18] unsigned long ptrace; + [1c] int lock_depth; + [20] long counter; + [24] long nice; + [28] unsigned long policy; +%fore "blue" + [2c] struct mm_struct *mm; +%fore "black" + [30] int processor; + [34] unsigned long cpus_runnable, cpus_allowed; + + }; +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple Program + + +%font "typewriter", size 3 + Display the mm_struct associated with simple process +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +md f7e10f00 +%fore "black" + 0xf7e10f00 +%fore "blue", cont +e8357a80 +%fore "black", cont + e8357978 f7ac77e0 eb15eac0 .z5hxy5h`w,w@j.k + 0xf7e10f10 00000001 00000002 0000000b 00000000 ................ + 0xf7e10f20 00000001 f7e10f24 f7e10f24 00000001 ................ + 0xf7e10f30 f7e35e70 eea7e8f0 08048000 0804862b ................ + 0xf7e10f40 0804962c 08049744 08051780 0805a000 ................ + 0xf7e10f50 bffffd10 bffffe00 bffffe09 bffffe09 ................ + 0xf7e10f60 bffffff3 0000005a 00000168 00000000 ................ + 0xf7e10f70 00000000 00000002 00000000 00000001 ................ + +%font "typewriter", size 3 + Determine offset of the first vma in the process +%font "typewriter", size 3 + struct mm_struct { +%fore "blue" + struct vm_area_struct * mmap; +%fore "black" + rb_root_t mm_rb; + struct vm_area_struct * mmap_cache; + + }; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple Program + +%font "typewriter", size 3 + Display the first vma using md +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +md e8357a80 +%fore "black" + 0xe8357a80 f7e10f00 08048000 08049000 +%fore "blue", cont +e8727e00 +%fore "black",cont + ..aw.........~rh + 0xe8357a90 00000025 00001875 e8727e18 00000001 %...u....~rh.... + + Display the first vma using vma +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +vma e8357a80 +%fore "black" + struct vm_area_struct at 0xe8357a80 for 68 bytes + vm_start = 0x8048000 vm_end = 0x8049000 + page_prot = 0x25 + flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +%font "typewriter", size 3 + + Determine the offset to the vma list +%font "typewriter", size 3 + struct vm_area_struct { + [0] struct mm_struct * vm_mm; + [4] unsigned long vm_start; + [8] unsigned long vm_end; +%fore "blue" + [c] struct vm_area_struct *vm_next; +%fore "black" + + }; + Display the next vma +%font "typewriter", size 3 + [3]kdb> vma e8727e00 + struct vm_area_struct at 0xe8727e00 for 68 bytes + vm_start = 0x8049000 vm_end = 0x804a000 + page_prot = 0x25 + flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Simple Program + +%font "typewriter", size 3 + Use the ll command to display the list of vma's +%font "typewriter", size 3 + [3]kdb> ll e8357a80 0xc vma +. + struct vm_area_struct at 0xe8357a80 for 68 bytes + vm_start = 0x8048000 vm_end = 0x8049000 + page_prot = 0x25 + flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +. + struct vm_area_struct at 0xe8727e00 for 68 bytes + vm_start = +%fore "orange", cont +0x8049000 +%fore "black", cont + vm_end = +%fore "orange", cont +0x804a000 +%fore "black" + page_prot = 0x25 + flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +. + struct vm_area_struct at 0xe8727c80 for 68 bytes + vm_start = +%fore "blue", cont +0x804a000 +%fore "black", cont + vm_end = +%fore "blue", cont +0x805a000 +%fore "black" + page_prot = 0x25 + flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC + + struct vm_area_struct at 0xe8357900 for 68 bytes + vm_start = 0xbfffe000 vm_end = 0xc0000000 + page_prot = 0x25 + flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC GROWSDOWN + + Match the vma to the displayed addresses +%font "typewriter", size 3 + foo_global at +%fore "orange", cont +8049780 +%fore "black" + foo_malloc at +%fore "blue", cont +8051788 +%fore "black" +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + + Objective + Show usage of various scsi and vm related kdb commands + + Sequence: + Set a breakpoint in the scsi driver + Stops when queueing a command to the controller + Cause IO on an idle disk + Show various IO stack traces + Display the IO data structures + Display vm information about the data + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Set the breakpoint + +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +bp isp1020_queuecommand +%fore "black" + Instruction(i) BP #0 at 0xc01ecfe0 (isp1020_queuecommand) + is enabled globally adjust 1 + +%font "typewriter", size 3 + Create some activity on a previously unused disk + +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +go +%fore "black" + [root@elm3b77 root]# +%fore "blue", cont +ls /rh62 +%fore "black" + + Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) + 0xc01ecfe0 isp1020_queuecommand:int3 + + Entering kdb (current=0xf75ba000, pid 1181) on processor 3 due to + Breakpoint @ 0xc01ecfe0 + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Show the stack. + This is a read of the /rh62 directory + +%font "typewriter", size 3 + [1]kdb> +%fore "blue", cont +bt +%fore "black" + EBP EIP Function(args) + 0xf75bbdf4 0xc01ecfe0 isp1020_queuecommand + 0xc01e2c77 scsi_dispatch_cmd+0x1f7 + 0xf75bbe24 0xc01e99b1 scsi_request_fn+0x2f1 + 0xf75bbe34 0xc01c84fd generic_unplug_device+0x2d + 0xf75bbe50 0xc011b3af __run_task_queue+0x5f + 0xf75bbe6c 0xc013a63c block_sync_page+0x1c + 0xf75bbe98 0xc0128127 __lock_page+0x77 + 0xf75bbea4 0xc0128178 lock_page+0x18 + 0xf75bbec8 0xc012a4b3 read_cache_page+0xc3 + 0xf75bbef4 0xc0168e23 ext2_get_page+0x23 + 0xf75bbf48 0xc0168fdd ext2_readdir+0xfd + 0xf75bbf68 0xc0143d2e vfs_readdir+0x7e + 0xf75bbfbc 0xc01442ed +%fore "blue", cont +sys_getdents64+0x4d +%fore "black" + 0xc010702b system_call+0x33 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Allow the operation to complete + +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +go +%fore "black" + bench build etc lib mnt oldsys rh72 spv usr + bin data h linux mnt1 opt root test var + boot dev home lost+found mnt2 proc sbin tmp + +%font "typewriter", size 3 + Force some more activity + +%font "typewriter", size 3 + [root@elm3b77 root]# +%fore "blue", cont +cd /rh62/tmp +%fore "black" + Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) + 0xc01ecfe0 isp1020_queuecommand:int3 + + Entering kdb (current=0xf768a000, pid 981) on processor 3 due to + Breakpoint @ 0xc01ecfe0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Show the stack. + This is an inode read for /rh62/tmp + +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +bt +%fore "black" + EBP EIP Function(args) + 0xf768bd68 0xc01ecfe0 isp1020_queuecommand + 0xc01e2c77 scsi_dispatch_cmd+0x1f7 + 0xf768bd98 0xc01e99b1 scsi_request_fn+0x2f1 + 0xf768bda8 0xc01c84fd generic_unplug_device+0x2d + 0xf768bdc4 0xc011b3af __run_task_queue+0x5f + 0xf768bdfc 0xc0137216 __wait_on_buffer+0x56 + 0xf768be1c 0xc0138600 bread+0x50 + 0xf768be5c 0xc016b684 ext2_read_inode+0x114 + 0xf768bf0c 0xc013fbec real_lookup+0x7c + 0xf768bf78 0xc014035d link_path_walk+0x5ad +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Create a new file, causing yet more disk activity + +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +go +%fore "black" + + [root@elm3b77 tmp]# +%fore "blue", cont +echo "Hello linux reading group" > j1;sync +%fore "black" + + Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) + 0xc01ecfe0 isp1020_queuecommand:int3 + + Entering kdb (current=0xf768a000, pid 981) on processor 3 due to + Breakpoint @ 0xc01ecfe0 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Show the stack + This is an inode read in response to the open +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +bt +%fore "black" + EBP EIP Function(args) + 0xf768bd78 0xc01ecfe0 isp1020_queuecommand + 0xc01e2c77 scsi_dispatch_cmd+0x1f7 + 0xf768bda8 0xc01e99b1 scsi_request_fn+0x2f1 + 0xf768bdb8 0xc01c84fd generic_unplug_device+0x2d + 0xf768bdd4 0xc011b3af __run_task_queue+0x5f + 0xf768bdf0 0xc013a63c block_sync_page+0x1c + 0xf768be1c 0xc0128127 __lock_page+0x77 + 0xf768be28 0xc0128178 lock_page+0x18 + 0xf768be4c 0xc012a4b3 read_cache_page+0xc3 + 0xf768be78 0xc0168e23 ext2_get_page+0x23 + 0xf768beb8 0xc01691ed ext2_find_entry+0x8d + 0xf768bed4 0xc016933a ext2_inode_by_name+0x1a + 0xf768befc 0xc016c077 ext2_lookup+0x27 + 0xf768bf1c 0xc014094a lookup_hash+0x9a + 0xf768bf64 0xc0140c4d open_namei+0xfd + 0xf768bfa0 0xc0135907 filp_open+0x37 + 0xf768bfbc 0xc0135c64 sys_open+0x34 + 0xc010702b system_call+0x33 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Let the operation continue +%font "typewriter", size 3 + [3]kdb> +%fore "blue", cont +go +%fore "black" + Instruction(i) breakpoint #0 at 0xc01ecfe0 (adjusted) + 0xc01ecfe0 isp1020_queuecommand: int3 + Entering kdb (current=0xc0352000, pid 0) on processor 0 due to + Breakpoint @ 0xc01ecfe0 + Show the stack + This is an io completion queuing the next request +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +bt +%fore "black" + EBP EIP Function(args) + 0xc0353df4 0xc01ecfe0 isp1020_queuecommand( +%fore "blue", cont +0xf7e63a00 +%fore "black", cont +,0xc01e7fc0... + 0xc01e2c77 scsi_dispatch_cmd+0x1f7 + 0xc0353e24 0xc01e99b1 scsi_request_fn+0x2f1 + 0xc0353e40 0xc01e8f6a +%fore "blue", cont +scsi_queue_next_request+0x4a +%fore "black" + 0xc0353e5c 0xc01e9166 __scsi_end_request+0x116 + 0xc0353ea8 0xc01e93e0 +%fore "blue", cont +scsi_io_completion+0x170 +%fore "black" + 0xc0353ecc 0xc01f658e rw_intr+0x14e + 0xc0353ef8 0xc01e8668 scsi_old_done+0x6a8 + 0xc0353fd4 0xc01052c2 cpu_idle+0x52 + Function prototype +%font "typewriter", size 3 + int isp1020_queuecommand( +%fore "blue", cont +Scsi_Cmnd *Cmnd, +%fore "black" + void (*done)(Scsi_Cmnd *)) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Show the command being queued +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +sc 0xf7e63a00 +%fore "black" + scsi_cmnd at 0xf7e63a00 +%fore "blue" + host = 0xf7e91400 +%fore "black", cont + state = 4099 owner = 258 +%fore "blue", cont +device = 0xf7ed5d80 +%fore "black" + bnext = 0x00000000 reset_chain = 0x00000000 eh_state = 0 + done = 0xc01f6440 + serial_number = 3402 serial_num_at_to = 0 retries = 0 timeout = 0 + id/lun/cmnd = [0/0/0] cmd_len = 10 old_cmd_len = 10 + cmnd = [2a/00/00/28/00/3f/00/00/10/00/ef/f7] + data_cmnd = [2a/00/00/28/00/3f/00/00/10/00/ef/f7] + request_buffer = 0xc03fd000 bh_next = 0x00000000 + request_bufflen = 8192 + use_sg = 2 old_use_sg = 2 sglist_len = 512 abore_reason = 0 + bufflen = 8192 buffer = 0xc03fd000 underflow = 8192 + transfersize = 512 + tag = 0 pid = 3401 + request struct + rq_status = RQ_ACTIVE rq_dev = [8/1] errors = 1 cmd = 0 + sector = 2621440 nr_sectors = 16 current_nr_sectors = 8 + buffer = 0xf7599000 +%fore "blue", cont +bh = 0xf75ca300 +%fore "black", cont + bhtail = 0xf75ca3c0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Display the host adapter +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +sh 0xf7e91400 +%fore "black" + Scsi_Host at 0xf7e91400 + next = 0x00000000 +%fore "blue", cont +host_queue = 0xf7ed5d80 +%fore "black" + ehandler = 0x00000000 eh_wait = 0x00000000 en_notify = 0x00000000 + eh_action = 0x00000000 + h_active = 0x0 host_wait = 0xc0353ac4 hostt = 0xc034bce0 + host_busy = 1 + host_failed = 0 extra_bytes = 524 host_no = 0 resetting = 0 + max id/lun/channel = [16/8/0] this_id = 7 + can_queue = 64 cmd_per_lun = 1 sg_tablesize = 427 u_isa_dma = 0 + host_blocked = 0 reverse_ordering = 0 + +%font "typewriter", size 3 + Display the scsi device +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +sd 0xf7ed5d80 +%fore "black" + scsi_device at 0xf7ed5d80 + next = 0xf7ed5c80 prev = 0x00000000 host = 0xf7e91400 + device_busy = 1 +%fore "blue", cont +device_queue 0xf7e63a00 +%fore "black" + id/lun/chan = [0/0/0] single_lun = 0 device_blocked = 0 + queue_depth = 1 current_tag = 0 scsi_level = 4 + IBM DGHS18X 0360 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Display the Buffer header associated with the command +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +bh 0xf75ca300 +%fore "black" + buffer_head at 0xf75ca300 + next 0x00000000 bno 327680 rsec 2621440 size 4096 + dev 0x801 rdev 0x801 + count 2 state 0x1d [Uptodate Lock Req Mapped] ftime 0x7695e + b_list 1 b_reqnext 0xf75ca3c0 b_data 0xf7599000 +%fore "blue" + b_page 0xc1dd6640 +%fore "black", cont + b_this_page 0xf75ca300 b_private 0x00000000 + + Display the associated page structure +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +page 0xc1dd6640 +%fore "black" + struct page at 0xc1dd6640 + next 0xc1dd7300 prev 0xc1dd6240 +%fore "blue", cont +addr space 0xf7af04d0 +%fore "black" + index 327680 (offset 0x50000000) + count 2 flags PG_referenced PG_lru virtual 0xf7599000 + buffers 0xf75ca300 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Display the Address space associated with the page +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +md 0xf7af04d0 +%fore "black" + 0xf7af04d0 c1dd6240 c1dea740 f7af04d8 f7af04d8 @b]A@'^AX./wX./w + 0xf7af04e0 f7af04e0 f7af04e0 00000007 c033b700 `./w`./w.....73@ + 0xf7af04f0 +%fore "blue", cont +f7af0420 +%fore "black", cont + 00000000 00000000 00000001 ./w............ + 0xf7af0500 000001d0 00000000 00000000 f7af050c P............./w + 0xf7af0510 f7af050c 00000000 f7a8afa0 00000000 ../w.... /(w.... + + The structure looks like: +%size 3 + struct address_space { + struct list_head clean_pages; /* list of clean pages */ + struct list_head dirty_pages; /* list of dirty pages */ + struct list_head locked_pages;/* list of locked pages */ + unsigned long nrpages; /* number of total pages */ + spinlock_t page_lock; /* spinlock protecting them*/ + struct address_space_operations *a_ops; /* methods */ +%fore "blue" + struct inode *host; /* owner: inode, block_dev */ +%fore "black" + + }; +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Display the inode associated with the address space + I think htis is the inode for the block device. + +%font "typewriter", size 3 + [1]kdb> +%fore "blue", cont +inode f7af0420 +%fore "black" + struct inode at 0xf7af0420 + i_ino = 289 i_count = 1 i_dev = 0x801 i_size 4301789184 + i_mode = 0x8000 i_nlink = 1 i_rdev = 0x801 + i_hash.nxt = 0xf7af0420 i_hash.prv = 0xf7af0420 + i_list.nxt = 0xf7af0608 i_list.prv = 0xf7af0068 + i_dentry.nxt = 0xf7af0430 i_dentry.prv = 0xf7af0430 + i_dirty_buffers.nxt = 0xf7af0438 i_dirty_buffers.prv = 0xf7af0438 + i_sb = 0xc201f200 i_op = 0xc03cfdc0 i_data = 0xf7af04d0 nrpages = 6 + i_mapping = 0xf7af04d0 + i_flags 0x0 i_state 0x0 [] fs specific info @ 0xf7af0540 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%page + +Walking IO structures + + +%font "typewriter", size 3 + Display the page list associated with the inode +%font "typewriter", size 3 + [0]kdb> +%fore "blue", cont +inode_pages f7af0420 +%fore "black" +CLEAN page_struct index cnt flags + 0xc1dd6240 327735 2 0x44 bh 0xf75caae0 bno 327735 + [Lock Req Mapped] +%fore "blue" + 0xc1dd6640 327680 2 0x44 bh 0xf75ca300 bno 327680 + [Uptodate Lock Req Mapped] +%fore "black" + 0xc1dd7300 327681 2 0x44 bh 0xf75ca3c0 bno 327681 + [Uptodate Lock Req Mapped] + 0xc1dd6e00 327684 2 0x44 bh 0xf75ca420 bno 327684 + [Uptodate Req Mapped] + 0xc1de8fc0 4 2 0xc0 bh 0xf7b5ade0 bno 4 + [Uptodate Req Mapped] + 0xc1dea700 1 2 0x44 bh 0xf7e02740 bno 1 + [Uptodate Req Mapped] + 0xc1dea740 0 2 0x44 bh 0xf7e028c0 bno 0 + [Uptodate Req Mapped] +DIRTY page_struct index cnt flags +LOCKED page_struct index cnt flags Index: 2.6.x-xfs/Makefile =================================================================== --- 2.6.x-xfs.orig/Makefile 2006-02-28 10:56:52.939158163 +1100 +++ 2.6.x-xfs/Makefile 2006-02-28 11:26:53.496231281 +1100 @@ -557,6 +557,7 @@ ifeq ($(KBUILD_EXTMOD),) core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ +core-$(CONFIG_KDB) += kdb/ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ Index: 2.6.x-xfs/drivers/char/keyboard.c =================================================================== --- 2.6.x-xfs.orig/drivers/char/keyboard.c 2006-01-10 17:07:47.342378429 +1100 +++ 2.6.x-xfs/drivers/char/keyboard.c 2006-02-28 11:26:53.498184140 +1100 @@ -39,6 +39,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ static void kbd_disconnect(struct input_handle *handle); extern void ctrl_alt_del(void); @@ -1062,6 +1065,13 @@ if (keycode < BTN_MISC) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); +#ifdef CONFIG_KDB + if (down && !rep && keycode == KEY_PAUSE && kdb_on == 1) { + kdb(KDB_REASON_KEYBOARD, 0, regs); + return; + } +#endif /* CONFIG_KDB */ + #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { sysrq_down = down; Index: 2.6.x-xfs/drivers/serial/8250.c =================================================================== --- 2.6.x-xfs.orig/drivers/serial/8250.c 2006-02-28 10:56:53.133467499 +1100 +++ 2.6.x-xfs/drivers/serial/8250.c 2006-02-28 11:26:53.500137000 +1100 @@ -46,6 +46,19 @@ #include #include "8250.h" +#ifdef CONFIG_KDB +#include +/* + * kdb_serial_line records the serial line number of the first serial console. + * NOTE: The kernel ignores characters on the serial line unless a user space + * program has opened the line first. To enter kdb before user space has opened + * the serial line, you can use the 'kdb=early' flag to lilo and set the + * appropriate breakpoints. + */ + +static int kdb_serial_line = -1; +static const char *kdb_serial_ptr = kdb_serial_str; +#endif /* CONFIG_KDB */ /* * Configuration: @@ -1143,6 +1156,18 @@ do { ch = serial_inp(up, UART_RX); +#ifdef CONFIG_KDB + if ((up->port.line == kdb_serial_line) && kdb_on == 1) { + if (ch == *kdb_serial_ptr) { + if (!(*++kdb_serial_ptr)) { + kdb(KDB_REASON_KEYBOARD, 0, regs); + kdb_serial_ptr = kdb_serial_str; + break; + } + } else + kdb_serial_ptr = kdb_serial_str; + } +#endif /* CONFIG_KDB */ flag = TTY_NORMAL; up->port.icount.rx++; @@ -2252,6 +2277,30 @@ if (!port->iobase && !port->membase) return -ENODEV; +#ifdef CONFIG_KDB + /* + * Remember the line number of the first serial + * console. We'll make this the kdb serial console too. + */ + if (co && kdb_serial_line == -1) { + kdb_serial_line = co->index; + kdb_serial.io_type = port->iotype; + switch (port->iotype) { + case SERIAL_IO_MEM: +#ifdef SERIAL_IO_MEM32 + case SERIAL_IO_MEM32: +#endif + kdb_serial.iobase = (unsigned long)(port->membase); + kdb_serial.ioreg_shift = port->regshift; + break; + default: + kdb_serial.iobase = port->iobase; + kdb_serial.ioreg_shift = 0; + break; + } + } +#endif /* CONFIG_KDB */ + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); Index: 2.6.x-xfs/drivers/serial/sn_console.c =================================================================== --- 2.6.x-xfs.orig/drivers/serial/sn_console.c 2006-02-06 11:07:59.990654866 +1100 +++ 2.6.x-xfs/drivers/serial/sn_console.c 2006-02-28 11:26:53.503066289 +1100 @@ -49,6 +49,22 @@ #include /* for mdelay */ #include #include +#ifdef CONFIG_KDB +#include +#include +#include +/* + * kdb_serial_line records the serial line number of the first serial console. + * NOTE: The kernel ignores characters on the serial line unless a user space + * program has opened the line first. To enter kdb before user space has opened + * the serial line, you can use the 'kdb=early' flag to lilo and set the + * appropriate breakpoints. + */ + +static int kdb_serial_line = -1; +static char *kdb_serial_ptr = (char *)kdb_serial_str; +#endif /* CONFIG_KDB */ + #include #include @@ -488,6 +504,26 @@ "obtaining data from the console (0x%0x)\n", ch); break; } +#ifdef CONFIG_KDB + if (kdb_on == 1) { + if (ch == *kdb_serial_ptr) { + if (!(*++kdb_serial_ptr)) { + spin_unlock_irqrestore(&port->sc_port.lock, flags); + if (!regs) { + KDB_STATE_SET(KEYBOARD); + KDB_ENTER(); /* to get some registers */ + } else + kdb(KDB_REASON_KEYBOARD, 0, regs); + kdb_serial_ptr = (char *)kdb_serial_str; + spin_lock_irqsave(&port->sc_port.lock, flags); + break; + } + } + else + kdb_serial_ptr = (char *)kdb_serial_str; + } +#endif /* CONFIG_KDB */ + #ifdef CONFIG_MAGIC_SYSRQ if (sysrq_requested) { unsigned long sysrq_timeout = sysrq_requested + HZ*5; @@ -1030,6 +1066,15 @@ */ static int __init sn_sal_console_setup(struct console *co, char *options) { +#ifdef CONFIG_KDB + /* + * Remember the line number of the first serial + * console. We'll make this the kdb serial console too. + */ + if (kdb_serial_line == -1) { + kdb_serial_line = co->index; + } +#endif /* CONFIG_KDB */ return 0; } @@ -1105,3 +1150,31 @@ } console_initcall(sn_sal_serial_console_init); + +#ifdef CONFIG_KDB +int +l1_control_in_polled(int offset) +{ + int sal_call_status = 0, input; + int ret = 0; + if (offset == UART_LSR) { + ret = (UART_LSR_THRE | UART_LSR_TEMT); /* can send anytime */ + sal_call_status = ia64_sn_console_check(&input); + if (!sal_call_status && input) { + /* input pending */ + ret |= UART_LSR_DR; + } + } + return ret; +} + +int +l1_serial_in_polled(void) +{ + int ch; + if (!ia64_sn_console_getc(&ch)) + return ch; + else + return 0; +} +#endif /* CONFIG_KDB */ Index: 2.6.x-xfs/drivers/serial/8250_early.c =================================================================== --- 2.6.x-xfs.orig/drivers/serial/8250_early.c 2005-12-05 09:56:15.587093669 +1100 +++ 2.6.x-xfs/drivers/serial/8250_early.c 2006-02-28 11:26:53.556769920 +1100 @@ -35,6 +35,13 @@ #include #include + +#ifdef CONFIG_KDB +#include + +static int kdb_serial_line = -1; +#endif /* CONFIG_KDB */ + struct early_uart_device { struct uart_port port; char options[16]; /* e.g., 115200n8 */ @@ -191,6 +198,31 @@ if ((err = parse_options(device, options)) < 0) return err; + +#ifdef CONFIG_KDB + /* + * Remember the line number of the first serial + * console. We'll make this the kdb serial console too. + */ + if (console && kdb_serial_line == -1) { + kdb_serial_line = console->index; + kdb_serial.io_type = device->port.iotype; + switch (device->port.iotype) { + case SERIAL_IO_MEM: +#ifdef SERIAL_IO_MEM32 + case SERIAL_IO_MEM32: +#endif + kdb_serial.iobase = (unsigned long)(device->port.membase); + kdb_serial.ioreg_shift = device->port.regshift; + break; + default: + kdb_serial.iobase = device->port.iobase; + kdb_serial.ioreg_shift = 0; + break; + } + } +#endif /* CONFIG_KDB */ + init_port(device); return 0; } Index: 2.6.x-xfs/drivers/usb/host/ohci-hcd.c =================================================================== --- 2.6.x-xfs.orig/drivers/usb/host/ohci-hcd.c 2006-02-06 11:08:00.020924142 +1100 +++ 2.6.x-xfs/drivers/usb/host/ohci-hcd.c 2006-02-28 11:26:53.558722779 +1100 @@ -17,6 +17,7 @@ * * History: * + * 2005/06/23 CONFIG_KDB_USB support. (ayoung@sgi.com) * 2004/03/24 LH7A404 support (Durgesh Pattamatta & Marc Singer) * 2004/02/04 use generic dma_* functions instead of pci_* (dsaxena@plexity.net) * 2003/02/24 show registers in sysfs (Kevin Brosius) @@ -867,6 +868,53 @@ /*-------------------------------------------------------------------------*/ +#ifdef CONFIG_KDB_USB + +static void +ohci_kdb_poll (void * __ohci, struct urb *urb) +{ + struct ohci_hcd *ohci; + struct ohci_regs * regs; + + /* + * NOTE - we use the ohci_hcd from the urb rather than the + * __ohci parameter (which is NULL anyway). This ensures + * that we will process the proper controller for the urb. + */ + + if (!urb) /* can happen if no keyboard attached */ + return; + + ohci = (struct ohci_hcd *) hcd_to_ohci(urb->dev->bus->hcpriv); + regs = ohci->regs; + + /* if the urb is not currently in progress resubmit it */ + if (urb->status != -EINPROGRESS) { + + if (usb_submit_urb (urb, SLAB_ATOMIC)) + return; + + /* make sure the HC registers are set correctly */ + writel (OHCI_INTR_WDH, ®s->intrenable); + writel (OHCI_INTR_WDH, ®s->intrstatus); + writel (OHCI_INTR_MIE, ®s->intrenable); + + // flush those pci writes + (void) readl (&ohci->regs->control); + } + + if (ohci->hcca->done_head) { + dl_done_list_kdb (ohci, urb); + writel (OHCI_INTR_WDH, ®s->intrstatus); + // flush the pci write + (void) readl (&ohci->regs->control); + } +} + +#endif /* CONFIG_KDB_USB */ + +/*-------------------------------------------------------------------------*/ + #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC MODULE_AUTHOR (DRIVER_AUTHOR); Index: 2.6.x-xfs/drivers/usb/host/ohci-pci.c =================================================================== --- 2.6.x-xfs.orig/drivers/usb/host/ohci-pci.c 2005-12-05 09:56:16.226653785 +1100 +++ 2.6.x-xfs/drivers/usb/host/ohci-pci.c 2006-02-28 11:26:53.558722779 +1100 @@ -18,6 +18,10 @@ #error "This file is PCI bus glue. CONFIG_PCI must be defined." #endif +#ifdef CONFIG_KDB_USB +#include +#endif + /*-------------------------------------------------------------------------*/ static int @@ -98,6 +102,11 @@ ohci_stop (hcd); return ret; } + +#ifdef CONFIG_KDB_USB + kdb_usb_infos.poll_func = ohci_kdb_poll; + kdb_usb_infos.uhci = NULL; /* not used */ +#endif return 0; } Index: 2.6.x-xfs/drivers/usb/host/ohci-q.c =================================================================== --- 2.6.x-xfs.orig/drivers/usb/host/ohci-q.c 2005-06-20 16:55:32.315687217 +1000 +++ 2.6.x-xfs/drivers/usb/host/ohci-q.c 2006-02-28 11:26:53.559699208 +1100 @@ -1114,3 +1114,65 @@ td = td_next; } } + + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_KDB_USB +static void +dl_done_list_kdb (struct ohci_hcd *ohci, struct urb *kdburb) +{ + struct td *td = dl_reverse_done_list (ohci); + + while (td) { + struct td *td_next = td->next_dl_td; + struct urb *urb = td->urb; + urb_priv_t *urb_priv = urb->hcpriv; + struct ed *ed = td->ed; + + if (urb != kdburb) { + td = td_next; + continue; + } + + /* update URB's length and status from TD */ + td_done (ohci, urb, td); + urb_priv->td_cnt++; + + /* If all this urb's TDs are done, just resubmit it */ + if (urb_priv->td_cnt == urb_priv->length) { + urb->actual_length = 0; + urb->status = -EINPROGRESS; + td_submit_urb (ohci, urb); + } + + /* clean schedule: unlink EDs that are no longer busy */ + if (list_empty (&ed->td_list)) { + if (ed->state == ED_OPER) + start_ed_unlink (ohci, ed); + + /* ... reenabling halted EDs only after fault cleanup */ + } else if ((ed->hwINFO & cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE)) + == cpu_to_hc32 (ohci, ED_SKIP)) { + td = list_entry (ed->td_list.next, struct td, td_list); + if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) { + ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP); + /* ... hc may need waking-up */ + switch (ed->type) { + case PIPE_CONTROL: + ohci_writel (ohci, OHCI_CLF, + &ohci->regs->cmdstatus); + break; + case PIPE_BULK: + ohci_writel (ohci, OHCI_BLF, + &ohci->regs->cmdstatus); + break; + } + } + } + + td = td_next; + } +} + +#endif /* CONFIG_KDB_USB */ Index: 2.6.x-xfs/drivers/usb/input/hid-core.c =================================================================== --- 2.6.x-xfs.orig/drivers/usb/input/hid-core.c 2006-02-20 11:15:25.608980942 +1100 +++ 2.6.x-xfs/drivers/usb/input/hid-core.c 2006-02-28 11:26:53.561652068 +1100 @@ -44,6 +44,10 @@ #define DRIVER_DESC "USB HID core driver" #define DRIVER_LICENSE "GPL" +#ifdef CONFIG_KDB_USB +#include +#endif + static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; /* @@ -1861,6 +1865,12 @@ if (!hid) return; +#ifdef CONFIG_KDB_USB + /* Unlink the KDB USB struct */ + if (hid->urbin == kdb_usb_infos.urb) + memset(&kdb_usb_infos, 0, sizeof(kdb_usb_infos)); +#endif + usb_set_intfdata(intf, NULL); usb_kill_urb(hid->urbin); usb_kill_urb(hid->urbout); @@ -1933,6 +1943,15 @@ printk(": USB HID v%x.%02x %s [%s] on %s\n", hid->version >> 8, hid->version & 0xff, c, hid->name, path); +#ifdef CONFIG_KDB_USB + /* Initialization of the KDB structure */ + if (!strcmp(c, "Keyboard")) { + kdb_usb_infos.urb = hid->urbin; + kdb_usb_infos.buffer = hid->inbuf; + kdb_usb_infos.reset_timer = NULL; + } +#endif + return 0; } Index: 2.6.x-xfs/drivers/usb/input/usbkbd.c =================================================================== --- 2.6.x-xfs.orig/drivers/usb/input/usbkbd.c 2006-02-06 11:08:00.025806284 +1100 +++ 2.6.x-xfs/drivers/usb/input/usbkbd.c 2006-02-28 11:26:53.562628497 +1100 @@ -82,6 +82,10 @@ dma_addr_t leds_dma; }; +#ifdef CONFIG_KDB_USB +#include +#endif + static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs) { struct usb_kbd *kbd = urb->context; @@ -297,6 +301,13 @@ usb_fill_int_urb(kbd->irq, dev, pipe, kbd->new, (maxp > 8 ? 8 : maxp), usb_kbd_irq, kbd, endpoint->bInterval); + +#ifdef CONFIG_KDB_USB + /* Init the KDB structure */ + kdb_usb_infos.urb = kbd->irq; + kdb_usb_infos.buffer = kbd->new; + kdb_usb_infos.reset_timer = NULL; +#endif kbd->irq->transfer_dma = kbd->new_dma; kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -329,6 +340,11 @@ struct usb_kbd *kbd = usb_get_intfdata (intf); usb_set_intfdata(intf, NULL); +#ifdef CONFIG_KDB_USB + /* Unlink the KDB USB struct */ + if (kbd && kbd->irq == kdb_usb_infos.urb) + memset(&kdb_usb_infos, 0, sizeof(kdb_usb_infos)); +#endif /* CONFIG_KDB_USB */ if (kbd) { usb_kill_urb(kbd->irq); input_unregister_device(kbd->dev); Index: 2.6.x-xfs/fs/proc/proc_misc.c =================================================================== --- 2.6.x-xfs.orig/fs/proc/proc_misc.c 2006-02-13 14:38:32.960309050 +1100 +++ 2.6.x-xfs/fs/proc/proc_misc.c 2006-02-28 11:26:53.504042718 +1100 @@ -206,6 +206,106 @@ #undef K } +#ifdef CONFIG_KDB +#include +#include +/* Like meminfo_read_proc() but without the locks and using kdb_printf() */ +void +kdb_meminfo_read_proc(void) +{ + struct sysinfo i; + struct page_state ps; + unsigned long inactive; + unsigned long active; + unsigned long free; + unsigned long committed; + unsigned long allowed; + struct vmalloc_info vmi; + + get_page_state(&ps); + get_zone_counts(&active, &inactive, &free); + +/* + * display in kilobytes. + */ +#define K(x) ((x) << (PAGE_SHIFT - 10)) + si_meminfo(&i); + kdb_si_swapinfo(&i); + committed = atomic_read(&vm_committed_space); + allowed = ((totalram_pages - hugetlb_total_pages()) + * sysctl_overcommit_ratio / 100) + total_swap_pages; + + get_vmalloc_info(&vmi); + + kdb_printf( + "MemTotal: %8lu kB\n" + "MemFree: %8lu kB\n" + "Buffers: %8lu kB\n", + K(i.totalram), + K(i.freeram), + K(i.bufferram) + ); + kdb_printf( + "Cached: %8lu kB\n" + "SwapCached: %8lu kB\n" + "Active: %8lu kB\n", + K(get_page_cache_size()-total_swapcache_pages-i.bufferram), + K(total_swapcache_pages), + K(active) + ); + kdb_printf( + "Inactive: %8lu kB\n" + "HighTotal: %8lu kB\n" + "HighFree: %8lu kB\n", + K(inactive), + K(i.totalhigh), + K(i.freehigh) + ); + kdb_printf( + "LowTotal: %8lu kB\n" + "LowFree: %8lu kB\n" + "SwapTotal: %8lu kB\n", + K(i.totalram-i.totalhigh), + K(i.freeram-i.freehigh), + K(i.totalswap) + ); + kdb_printf( + "SwapFree: %8lu kB\n" + "Dirty: %8lu kB\n" + "Writeback: %8lu kB\n", + K(i.freeswap), + K(ps.nr_dirty), + K(ps.nr_writeback) + ); + kdb_printf( + "Mapped: %8lu kB\n" + "Slab: %8lu kB\n" + "CommitLimit: %8lu kB\n", + K(ps.nr_mapped), + K(ps.nr_slab), + K(allowed) + ); + kdb_printf( + "Committed_AS: %8lu kB\n" + "PageTables: %8lu kB\n" + "VmallocTotal: %8lu kB\n", + K(committed), + K(ps.nr_page_table_pages), + VMALLOC_TOTAL >> 10 + ); + kdb_printf( + "VmallocUsed: %8lu kB\n" + "VmallocChunk: %8lu kB\n", + vmi.used >> 10, + vmi.largest_chunk >> 10 + ); + +#ifdef CONFIG_HUGETLBFS + kdb_hugetlb_report_meminfo(); +#endif +} +#endif /* CONFIG_KDB */ + extern struct seq_operations fragmentation_op; static int fragmentation_open(struct inode *inode, struct file *file) { Index: 2.6.x-xfs/fs/proc/mmu.c =================================================================== --- 2.6.x-xfs.orig/fs/proc/mmu.c 2005-06-20 16:55:33.291273654 +1000 +++ 2.6.x-xfs/fs/proc/mmu.c 2006-02-28 11:26:53.554817060 +1100 @@ -31,6 +31,10 @@ #include #include "internal.h" +#ifdef CONFIG_KDB +#include +#endif + void get_vmalloc_info(struct vmalloc_info *vmi) { struct vm_struct *vma; @@ -47,6 +51,9 @@ prev_end = VMALLOC_START; +#ifdef CONFIG_KDB + if (!KDB_IS_RUNNING()) +#endif read_lock(&vmlist_lock); for (vma = vmlist; vma; vma = vma->next) { @@ -72,6 +79,9 @@ if (VMALLOC_END - prev_end > vmi->largest_chunk) vmi->largest_chunk = VMALLOC_END - prev_end; +#ifdef CONFIG_KDB + if (!KDB_IS_RUNNING()) +#endif read_unlock(&vmlist_lock); } } Index: 2.6.x-xfs/include/linux/console.h =================================================================== --- 2.6.x-xfs.orig/include/linux/console.h 2005-06-20 16:55:33.932875545 +1000 +++ 2.6.x-xfs/include/linux/console.h 2006-02-28 11:26:53.505019148 +1100 @@ -119,7 +119,12 @@ /* Some debug stub to catch some of the obvious races in the VT code */ #if 1 +#ifdef CONFIG_KDB +#include +#define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && !oops_in_progress && !atomic_read(&kdb_event)) +#else /* !CONFIG_KDB */ #define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && !oops_in_progress) +#endif /* CONFIG_KDB */ #else #define WARN_CONSOLE_UNLOCKED() #endif Index: 2.6.x-xfs/include/linux/dis-asm.h =================================================================== --- 2.6.x-xfs.orig/include/linux/dis-asm.h 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/include/linux/dis-asm.h 2006-02-28 11:26:53.506972007 +1100 @@ -0,0 +1,316 @@ +/* Interface between the opcode library and its callers. + Written by Cygnus Support, 1993. + + The opcode library (libopcodes.a) provides instruction decoders for + a large variety of instruction sets, callable with an identical + interface, for making instruction-processing programs more independent + of the instruction set being processed. */ + +/* Hacked by Scott Lurndal at SGI (02/1999) for linux kernel debugger */ +/* Upgraded to cygnus CVS Keith Owens 30 Oct 2000 */ + +#ifndef DIS_ASM_H +#define DIS_ASM_H + +#ifdef __cplusplus +extern "C" { +#endif + + /* + * Misc definitions + */ +#ifndef PARAMS +#define PARAMS(x) x +#endif +#define PTR void * +#define FILE int +#if !defined(NULL) +#define NULL 0 +#endif + +#define abort() dis_abort(__LINE__) + +static inline void +dis_abort(int line) +{ + panic("Aborting disassembler @ line %d\n", line); +} + +#include +#include +#define xstrdup(string) ({ char *res = kdb_strdup(string, GFP_ATOMIC); if (!res) BUG(); res; }) +#if 0 /* CONFIG_KDB */ +#define xmalloc(size) ({ void *res = kmalloc(size, GFP_ATOMIC); if (!res) BUG(); res; }) +#define free(address) kfree(address) +#else +#define xmalloc(size) ({ void *res = debug_kmalloc(size, GFP_ATOMIC); if (!res) BUG(); res; }) +#define free(address) debug_kfree(address) +#endif + +#if 0 /* CONFIG_KDB */ +#include +#else +#include +#endif + +typedef int (*fprintf_ftype) PARAMS((PTR, const char*, ...)); + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2 /* Two data references in instruction */ +}; + +/* This struct is passed into the instruction decoding routine, + and is passed back out into each callback. The various fields are used + for conveying information from your main routine into your callbacks, + for passing information into the instruction decoders (such as the + addresses of the callback functions), or for passing information + back from the instruction decoders to their callers. + + It must be initialized before it is first passed; this can be done + by hand, or using one of the initialization macros below. */ + +typedef struct disassemble_info { + fprintf_ftype fprintf_func; + fprintf_ftype fprintf_dummy; + PTR stream; + PTR application_data; + + /* Target description. We could replace this with a pointer to the bfd, + but that would require one. There currently isn't any such requirement + so to avoid introducing one we record these explicitly. */ + /* The bfd_flavour. This can be bfd_target_unknown_flavour. */ + enum bfd_flavour flavour; + /* The bfd_arch value. */ + enum bfd_architecture arch; + /* The bfd_mach value. */ + unsigned long mach; + /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */ + enum bfd_endian endian; + + /* An array of pointers to symbols either at the location being disassembled + or at the start of the function being disassembled. The array is sorted + so that the first symbol is intended to be the one used. The others are + present for any misc. purposes. This is not set reliably, but if it is + not NULL, it is correct. */ + asymbol **symbols; + /* Number of symbols in array. */ + int num_symbols; + + /* For use by the disassembler. + The top 16 bits are reserved for public use (and are documented here). + The bottom 16 bits are for the internal use of the disassembler. */ + unsigned long flags; +#define INSN_HAS_RELOC 0x80000000 + PTR private_data; + + /* Function used to get bytes to disassemble. MEMADDR is the + address of the stuff to be disassembled, MYADDR is the address to + put the bytes in, and LENGTH is the number of bytes to read. + INFO is a pointer to this struct. + Returns an errno value or 0 for success. */ + int (*read_memory_func) + PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, + struct disassemble_info *info)); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and + MEMADDR is the address that we were trying to read. INFO is a + pointer to this struct. */ + void (*memory_error_func) + PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info)); + + /* Function called to print ADDR. */ + void (*print_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info *info)); + + /* Function called to determine if there is a symbol at the given ADDR. + If there is, the function returns 1, otherwise it returns 0. + This is used by ports which support an overlay manager where + the overlay number is held in the top part of an address. In + some circumstances we want to include the overlay number in the + address, (normally because there is a symbol associated with + that address), but sometimes we want to mask out the overlay bits. */ + int (* symbol_at_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info * info)); + + /* These are for buffer_read_memory. */ + bfd_byte *buffer; + bfd_vma buffer_vma; + unsigned int buffer_length; + + /* This variable may be set by the instruction decoder. It suggests + the number of bytes objdump should display on a single line. If + the instruction decoder sets this, it should always set it to + the same value in order to get reasonable looking output. */ + int bytes_per_line; + + /* the next two variables control the way objdump displays the raw data */ + /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */ + /* output will look like this: + 00: 00000000 00000000 + with the chunks displayed according to "display_endian". */ + int bytes_per_chunk; + enum bfd_endian display_endian; + + /* Number of octets per incremented target address + Normally one, but some DSPs have byte sizes of 16 or 32 bits + */ + unsigned int octets_per_byte; + + /* Results from instruction decoders. Not all decoders yet support + this information. This info is set each time an instruction is + decoded, and is only valid for the last such instruction. + + To determine whether this decoder supports this information, set + insn_info_valid to 0, decode an instruction, then check it. */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + + /* Command line options specific to the target disassembler. */ + char * disassembler_options; + +} disassemble_info; + + +/* Standard disassemblers. Disassemble one instruction at the given + target address. Return number of bytes processed. */ +typedef int (*disassembler_ftype) + PARAMS((bfd_vma, disassemble_info *)); + +extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386_att PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386_intel PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ia64 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i370 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68hc11 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68hc12 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); +extern disassembler_ftype arc_get_disassembler PARAMS ((int, int)); +extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i860 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_shl PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_fr30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m32r PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mcore PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10200 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*)); +extern disassembler_ftype cris_get_disassembler PARAMS ((bfd *)); +extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_d30v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_vax PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic54x PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic80 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_pj PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_avr PARAMS ((bfd_vma, disassemble_info*)); + +extern void print_arm_disassembler_options PARAMS ((FILE *)); +extern void parse_arm_disassembler_option PARAMS ((char *)); +extern int get_arm_regname_num_options PARAMS ((void)); +extern int set_arm_regname_option PARAMS ((int)); +extern int get_arm_regnames PARAMS ((int, const char **, const char **, const char ***)); + +/* Fetch the disassembler for a given BFD, if that support is available. */ +extern disassembler_ftype disassembler PARAMS ((bfd *)); + +/* Document any target specific options available from the disassembler. */ +extern void disassembler_usage PARAMS ((FILE *)); + + +/* This block of definitions is for particular callers who read instructions + into a buffer before calling the instruction decoder. */ + +/* Here is a function which callers may wish to use for read_memory_func. + It gets bytes from a buffer. */ +extern int buffer_read_memory + PARAMS ((bfd_vma, bfd_byte *, unsigned int, struct disassemble_info *)); + +/* This function goes with buffer_read_memory. + It prints a message using info->fprintf_func and info->stream. */ +extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *)); + + +/* Just print the address in hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ +extern void generic_print_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Always true. */ +extern int generic_symbol_at_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Macro to initialize a disassemble_info struct. This should be called + by all applications creating such a struct. */ +#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).flavour = bfd_target_unknown_flavour, \ + (INFO).arch = bfd_arch_unknown, \ + (INFO).mach = 0, \ + (INFO).endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).octets_per_byte = 1, \ + INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) + +/* Call this macro to initialize only the internal variables for the + disassembler. Architecture dependent things such as byte order, or machine + variant are not touched by this macro. This makes things much easier for + GDB which must initialize these things separately. */ + +#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).fprintf_func = (fprintf_ftype)(FPRINTF_FUNC), \ + (INFO).stream = (PTR)(STREAM), \ + (INFO).symbols = NULL, \ + (INFO).num_symbols = 0, \ + (INFO).buffer = NULL, \ + (INFO).buffer_vma = 0, \ + (INFO).buffer_length = 0, \ + (INFO).read_memory_func = buffer_read_memory, \ + (INFO).memory_error_func = perror_memory, \ + (INFO).print_address_func = generic_print_address, \ + (INFO).symbol_at_address_func = generic_symbol_at_address, \ + (INFO).flags = 0, \ + (INFO).bytes_per_line = 0, \ + (INFO).bytes_per_chunk = 0, \ + (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).insn_info_valid = 0 + +#ifdef __cplusplus +}; +#endif + +#endif /* ! defined (DIS_ASM_H) */ Index: 2.6.x-xfs/include/linux/kdb.h =================================================================== --- 2.6.x-xfs.orig/include/linux/kdb.h 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/include/linux/kdb.h 2006-02-28 11:26:53.507948437 +1100 @@ -0,0 +1,170 @@ +#ifndef _KDB_H +#define _KDB_H + +/* + * Kernel Debugger Architecture Independent Global Headers + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2000 Stephane Eranian + */ + +#include +#include +#include +#include + +/* These are really private, but they must be defined before including + * asm-$(ARCH)/kdb.h, so make them public and put them here. + */ +extern int kdb_getuserarea_size(void *, unsigned long, size_t); +extern int kdb_putuserarea_size(unsigned long, void *, size_t); + +#include + +#define KDB_MAJOR_VERSION 4 +#define KDB_MINOR_VERSION 4 +#define KDB_TEST_VERSION "" + +/* + * kdb_initial_cpu is initialized to -1, and is set to the cpu + * number whenever the kernel debugger is entered. + */ +extern volatile int kdb_initial_cpu; +#ifdef CONFIG_KDB +#define KDB_IS_RUNNING() (kdb_initial_cpu != -1) +#else +#define KDB_IS_RUNNING() (0) +#endif /* CONFIG_KDB */ +extern atomic_t kdb_event; + +/* + * kdb_on + * + * Defines whether kdb is on or not. Default value + * is set by CONFIG_KDB_OFF. Boot with kdb=on/off/on-nokey + * or echo "[012]" > /proc/sys/kernel/kdb to change it. + */ +extern int kdb_on; + +#if defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_SGI_L1_CONSOLE) +/* + * kdb_serial.iobase is initialized to zero, and is set to the I/O + * address of the serial port when the console is setup in + * serial_console_setup. + */ +extern struct kdb_serial { + int io_type; + unsigned long iobase; + unsigned long ioreg_shift; +} kdb_serial; +#endif + +/* + * kdb_diemsg + * + * Contains a pointer to the last string supplied to the + * kernel 'die' panic function. + */ +extern const char *kdb_diemsg; + +#define KDB_FLAG_EARLYKDB (1 << 0) /* set from boot parameter kdb=early */ +#define KDB_FLAG_CATASTROPHIC (1 << 1) /* A catastrophic event has occurred */ +#define KDB_FLAG_CMD_INTERRUPT (1 << 2) /* Previous command was interrupted */ +#define KDB_FLAG_NOIPI (1 << 3) /* Do not send IPIs */ +#define KDB_FLAG_ONLY_DO_DUMP (1 << 4) /* Only do a dump, used when kdb is off */ +#define KDB_FLAG_NO_CONSOLE (1 << 5) /* No console is available, kdb is disabled */ +#define KDB_FLAG_RECOVERY (1 << 6) /* kdb is being entered for an error which has been recovered */ + +extern volatile int kdb_flags; /* Global flags, see kdb_state for per cpu state */ + +extern void kdb_save_flags(void); +extern void kdb_restore_flags(void); + +#define KDB_FLAG(flag) (kdb_flags & KDB_FLAG_##flag) +#define KDB_FLAG_SET(flag) ((void)(kdb_flags |= KDB_FLAG_##flag)) +#define KDB_FLAG_CLEAR(flag) ((void)(kdb_flags &= ~KDB_FLAG_##flag)) + +/* + * External entry point for the kernel debugger. The pt_regs + * at the time of entry are supplied along with the reason for + * entry to the kernel debugger. + */ + +typedef enum { + KDB_REASON_CALL = 1, /* Call kdb() directly - regs should be valid */ + KDB_REASON_FAULT, /* Kernel fault - regs valid */ + KDB_REASON_BREAK, /* Breakpoint inst. - regs valid */ + KDB_REASON_DEBUG, /* Debug Fault - regs valid */ + KDB_REASON_OOPS, /* Kernel Oops - regs valid */ + KDB_REASON_SWITCH, /* CPU switch - regs valid*/ + KDB_REASON_ENTER, /* KDB_ENTER() trap/fault - regs valid */ + KDB_REASON_ENTER_SLAVE, /* KDB_ENTER_SLAVE() trap/fault - regs valid */ + KDB_REASON_KEYBOARD, /* Keyboard entry - regs valid */ + KDB_REASON_NMI, /* Non-maskable interrupt; regs valid */ + KDB_REASON_WATCHDOG, /* Watchdog interrupt; regs valid */ + KDB_REASON_RECURSE, /* Recursive entry to kdb; regs probably valid */ + KDB_REASON_SILENT, /* Silent entry/exit to kdb; regs invalid */ + KDB_REASON_CALL_PRESET, /* Same as KDB_REASON_CALL but kdb_process_running has been preset */ +} kdb_reason_t; + +#ifdef CONFIG_KDB +extern asmlinkage int kdb(kdb_reason_t, int, struct pt_regs *); +#else +#define kdb(reason,error_code,frame) (0) +#endif + +/* Mainly used by kdb code, but this function is sometimes used + * by hacked debug code so make it generally available, not private. + */ +extern void kdb_printf(const char *,...) + __attribute__ ((format (printf, 1, 2))); +typedef void (*kdb_printf_t)(const char *, ...) + __attribute__ ((format (printf, 1, 2))); +extern void kdb_init(void); + +#if defined(CONFIG_SMP) +/* + * Kernel debugger non-maskable IPI handler. + */ +extern int kdb_ipi(struct pt_regs *, void (*ack_interrupt)(void)); +extern void smp_kdb_stop(void); +#else /* CONFIG_SMP */ +#define smp_kdb_stop() +#endif /* CONFIG_SMP */ + +/* + * Interface from general kernel to enable any hardware + * error reporting mechanisms. Such as the Intel Machine + * Check Architecture, for example. + */ +extern void kdb_enablehwfault(void); + +#ifdef CONFIG_KDB_USB +#include + +struct kdb_usb_exchange { + void *uhci; /* pointer to the UHCI structure */ + struct urb *urb; /* pointer to the URB */ + unsigned char *buffer; /* pointer to buffer */ + void (*poll_func)(void *, struct urb *); /* pointer to the polling function */ + void (*reset_timer)(void); /* pointer to the reset timer function */ +}; +extern struct kdb_usb_exchange kdb_usb_infos; /* KDB common structure */ +#endif /* CONFIG_KDB_USB */ + +static inline +int kdb_process_cpu(const struct task_struct *p) +{ + unsigned int cpu = p->thread_info->cpu; + if (cpu > NR_CPUS) + cpu = 0; + return cpu; +} + +extern const char kdb_serial_str[]; + +#endif /* !_KDB_H */ Index: 2.6.x-xfs/include/linux/kdbprivate.h =================================================================== --- 2.6.x-xfs.orig/include/linux/kdbprivate.h 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/include/linux/kdbprivate.h 2006-02-28 11:26:53.509901296 +1100 @@ -0,0 +1,506 @@ +#ifndef _KDBPRIVATE_H +#define _KDBPRIVATE_H + +/* + * Kernel Debugger Architecture Independent Private Headers + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + */ + + +#include +#include +#include + + /* + * Kernel Debugger Error codes. Must not overlap with command codes. + */ + +#define KDB_NOTFOUND (-1) +#define KDB_ARGCOUNT (-2) +#define KDB_BADWIDTH (-3) +#define KDB_BADRADIX (-4) +#define KDB_NOTENV (-5) +#define KDB_NOENVVALUE (-6) +#define KDB_NOTIMP (-7) +#define KDB_ENVFULL (-8) +#define KDB_ENVBUFFULL (-9 ) +#define KDB_TOOMANYBPT (-10) +#define KDB_TOOMANYDBREGS (-11) +#define KDB_DUPBPT (-12) +#define KDB_BPTNOTFOUND (-13) +#define KDB_BADMODE (-14) +#define KDB_BADINT (-15) +#define KDB_INVADDRFMT (-16) +#define KDB_BADREG (-17) +#define KDB_BADCPUNUM (-18) +#define KDB_BADLENGTH (-19) +#define KDB_NOBP (-20) +#define KDB_BADADDR (-21) + + /* + * Kernel Debugger Command codes. Must not overlap with error codes. + */ +#define KDB_CMD_GO (-1001) +#define KDB_CMD_CPU (-1002) +#define KDB_CMD_SS (-1003) +#define KDB_CMD_SSB (-1004) + + /* + * Internal debug flags + */ +#define KDB_DEBUG_FLAG_BT 0x0001 /* Stack traceback debug */ +#define KDB_DEBUG_FLAG_BP 0x0002 /* Breakpoint subsystem debug */ +#define KDB_DEBUG_FLAG_LBR 0x0004 /* Print last branch register */ +#define KDB_DEBUG_FLAG_AR 0x0008 /* Activation record, generic */ +#define KDB_DEBUG_FLAG_ARA 0x0010 /* Activation record, arch specific */ +/* KDB_DEBUG_FLAG_CALLBACK 0x0020 WAS Event callbacks to kdb */ +#define KDB_DEBUG_FLAG_STATE 0x0040 /* State flags */ +#define KDB_DEBUG_FLAG_MASK 0xffff /* All debug flags */ +#define KDB_DEBUG_FLAG_SHIFT 16 /* Shift factor for dbflags */ + +#define KDB_DEBUG(flag) (kdb_flags & (KDB_DEBUG_FLAG_##flag << KDB_DEBUG_FLAG_SHIFT)) +#define KDB_DEBUG_STATE(text,value) if (KDB_DEBUG(STATE)) kdb_print_state(text, value) + +typedef enum { + KDB_REPEAT_NONE = 0, /* Do not repeat this command */ + KDB_REPEAT_NO_ARGS, /* Repeat the command without arguments */ + KDB_REPEAT_WITH_ARGS, /* Repeat the command including its arguments */ +} kdb_repeat_t; + +typedef int (*kdb_func_t)(int, const char **, const char **, struct pt_regs *); + + /* + * Symbol table format returned by kallsyms. + */ + +typedef struct __ksymtab { + unsigned long value; /* Address of symbol */ + const char *mod_name; /* Module containing symbol or "kernel" */ + unsigned long mod_start; + unsigned long mod_end; + const char *sec_name; /* Section containing symbol */ + unsigned long sec_start; + unsigned long sec_end; + const char *sym_name; /* Full symbol name, including any version */ + unsigned long sym_start; + unsigned long sym_end; + } kdb_symtab_t; +extern int kallsyms_symbol_next(char *prefix_name, int flag); +extern int kallsyms_symbol_complete(char *prefix_name, int max_len); + + /* + * Exported Symbols for kernel loadable modules to use. + */ +extern int kdb_register(char *, kdb_func_t, char *, char *, short); +extern int kdb_register_repeat(char *, kdb_func_t, char *, char *, short, kdb_repeat_t); +extern int kdb_unregister(char *); + +extern int kdb_getarea_size(void *, unsigned long, size_t); +extern int kdb_putarea_size(unsigned long, void *, size_t); + +/* Like get_user and put_user, kdb_getarea and kdb_putarea take variable + * names, not pointers. The underlying *_size functions take pointers. + */ +#define kdb_getarea(x,addr) kdb_getarea_size(&(x), addr, sizeof((x))) +#define kdb_putarea(addr,x) kdb_putarea_size(addr, &(x), sizeof((x))) + +extern int kdb_getphysword(unsigned long *word, + unsigned long addr, size_t size); +extern int kdb_getword(unsigned long *, unsigned long, size_t); +extern int kdb_putword(unsigned long, unsigned long, size_t); + +extern int kdbgetularg(const char *, unsigned long *); +extern char *kdbgetenv(const char *); +extern int kdbgetintenv(const char *, int *); +extern int kdbgetaddrarg(int, const char**, int*, unsigned long *, + long *, char **, struct pt_regs *); +extern int kdbgetsymval(const char *, kdb_symtab_t *); +extern int kdbnearsym(unsigned long, kdb_symtab_t *); +extern char *kdb_read(char *buffer, size_t bufsize); +extern char *kdb_strdup(const char *str, int type); +extern void kdb_symbol_print(kdb_machreg_t, const kdb_symtab_t *, unsigned int); + + /* + * Do we have a set of registers? + */ + +#define KDB_NULL_REGS(regs) \ + (regs == (struct pt_regs *)NULL ? kdb_printf("%s: null regs - should never happen\n", __FUNCTION__), 1 : 0) + + /* + * Routine for debugging the debugger state. + */ + +extern void kdb_print_state(const char *, int); + + /* + * Per cpu kdb state. A cpu can be under kdb control but outside kdb, + * for example when doing single step. + */ +volatile extern int kdb_state[ /*NR_CPUS*/ ]; +#define KDB_STATE_KDB 0x00000001 /* Cpu is inside kdb */ +#define KDB_STATE_LEAVING 0x00000002 /* Cpu is leaving kdb */ +#define KDB_STATE_CMD 0x00000004 /* Running a kdb command */ +#define KDB_STATE_KDB_CONTROL 0x00000008 /* This cpu is under kdb control */ +#define KDB_STATE_HOLD_CPU 0x00000010 /* Hold this cpu inside kdb */ +#define KDB_STATE_DOING_SS 0x00000020 /* Doing ss command */ +#define KDB_STATE_DOING_SSB 0x00000040 /* Doing ssb command, DOING_SS is also set */ +#define KDB_STATE_SSBPT 0x00000080 /* Install breakpoint after one ss, independent of DOING_SS */ +#define KDB_STATE_REENTRY 0x00000100 /* Valid re-entry into kdb */ +#define KDB_STATE_SUPPRESS 0x00000200 /* Suppress error messages */ +#define KDB_STATE_LONGJMP 0x00000400 /* longjmp() data is available */ +#define KDB_STATE_GO_SWITCH 0x00000800 /* go is switching back to initial cpu */ +#define KDB_STATE_PRINTF_LOCK 0x00001000 /* Holds kdb_printf lock */ +#define KDB_STATE_WAIT_IPI 0x00002000 /* Waiting for kdb_ipi() NMI */ +#define KDB_STATE_RECURSE 0x00004000 /* Recursive entry to kdb */ +#define KDB_STATE_IP_ADJUSTED 0x00008000 /* Restart IP has been adjusted */ +#define KDB_STATE_GO1 0x00010000 /* go only releases one cpu */ +#define KDB_STATE_KEYBOARD 0x00020000 /* kdb entered via keyboard on this cpu */ +#define KDB_STATE_ARCH 0xff000000 /* Reserved for arch specific use */ + +#define KDB_STATE_CPU(flag,cpu) (kdb_state[cpu] & KDB_STATE_##flag) +#define KDB_STATE_SET_CPU(flag,cpu) ((void)(kdb_state[cpu] |= KDB_STATE_##flag)) +#define KDB_STATE_CLEAR_CPU(flag,cpu) ((void)(kdb_state[cpu] &= ~KDB_STATE_##flag)) + +#define KDB_STATE(flag) KDB_STATE_CPU(flag,smp_processor_id()) +#define KDB_STATE_SET(flag) KDB_STATE_SET_CPU(flag,smp_processor_id()) +#define KDB_STATE_CLEAR(flag) KDB_STATE_CLEAR_CPU(flag,smp_processor_id()) + + /* + * kdb_nextline + * + * Contains the current line number on the screen. Used + * to handle the built-in pager (LINES env variable) + */ +extern volatile int kdb_nextline; + + /* + * Breakpoint state + * + * Each active and inactive breakpoint is represented by + * an instance of the following data structure. + */ + +typedef struct _kdb_bp { + bfd_vma bp_addr; /* Address breakpoint is present at */ + kdb_machinst_t bp_inst; /* Replaced instruction */ + + unsigned int bp_free:1; /* This entry is available */ + + unsigned int bp_enabled:1; /* Breakpoint is active in register */ + unsigned int bp_global:1; /* Global to all processors */ + + unsigned int bp_hardtype:1; /* Uses hardware register */ + unsigned int bp_forcehw:1; /* Force hardware register */ + unsigned int bp_installed:1; /* Breakpoint is installed */ + unsigned int bp_delay:1; /* Do delayed bp handling */ + unsigned int bp_delayed:1; /* Delayed breakpoint */ + + int bp_cpu; /* Cpu # (if bp_global == 0) */ + kdbhard_bp_t bp_template; /* Hardware breakpoint template */ + kdbhard_bp_t *bp_hard; /* Hardware breakpoint structure */ + int bp_adjust; /* Adjustment to PC for real instruction */ +} kdb_bp_t; + + /* + * Breakpoint handling subsystem global variables + */ +extern kdb_bp_t kdb_breakpoints[/* KDB_MAXBPT */]; + + /* + * Breakpoint architecture dependent functions. Must be provided + * in some form for all architectures. + */ +extern void kdba_initbp(void); +extern void kdba_printbp(kdb_bp_t *); +extern kdbhard_bp_t *kdba_allocbp(kdbhard_bp_t *, int *); +extern void kdba_freebp(kdbhard_bp_t *); +extern int kdba_parsebp(int, const char**, int *, kdb_bp_t*); +extern char *kdba_bptype(kdbhard_bp_t *); +extern void kdba_setsinglestep(struct pt_regs *); +extern void kdba_clearsinglestep(struct pt_regs *); + + /* + * Adjust instruction pointer architecture dependent function. Must be + * provided in some form for all architectures. + */ +extern void kdba_adjust_ip(kdb_reason_t, int, struct pt_regs *); + + /* + * KDB-only global function prototypes. + */ +extern void kdb_id1(unsigned long); +extern void kdb_id_init(void); + + /* + * Architecture dependent function to enable any + * processor machine check exception handling modes. + */ +extern void kdba_enable_mce(void); + +extern void kdba_enable_lbr(void); +extern void kdba_disable_lbr(void); +extern void kdba_print_lbr(void); + + /* + * Initialization functions. + */ +extern void kdba_init(void); +extern void kdb_io_init(void); + + /* + * Architecture specific function to read a string. + */ +typedef int (*get_char_func)(void); +extern get_char_func poll_funcs[]; + + /* + * Data for a single activation record on stack. + */ + +typedef struct __kdb_activation_record { + kdb_machreg_t start; /* -> start of activation record */ + kdb_machreg_t end; /* -> end+1 of activation record */ + kdb_machreg_t ret; /* Return address to caller */ + kdb_machreg_t oldfp; /* Frame pointer for caller's frame */ + kdb_machreg_t fp; /* Frame pointer for callee's frame */ + kdb_machreg_t arg0; /* -> First argument on stack (in previous ar) */ + unsigned long locals; /* Bytes allocated for local variables */ + unsigned long regs; /* Bytes allocated for saved registers */ + unsigned long args; /* Bytes allocated for arguments (in previous ar) */ + unsigned long setup; /* Bytes allocated for setup data */ +} kdb_ar_t; + + /* + * General Stack Traceback functions. + */ + +#if defined(__i386__) || defined(__x86_64__) +extern int kdb_get_next_ar(kdb_machreg_t, kdb_machreg_t, + kdb_machreg_t, kdb_machreg_t, + kdb_machreg_t, + kdb_ar_t *, kdb_symtab_t *); +#endif + + /* + * Architecture specific Stack Traceback functions. + */ + +struct task_struct; + +extern int kdba_bt_address(kdb_machreg_t, int); +extern int kdba_bt_process(const struct task_struct *, int); +extern int kdba_prologue(const kdb_symtab_t *, kdb_machreg_t, + kdb_machreg_t, kdb_machreg_t, kdb_machreg_t, + int, kdb_ar_t *); + /* + * KDB Command Table + */ + +typedef struct _kdbtab { + char *cmd_name; /* Command name */ + kdb_func_t cmd_func; /* Function to execute command */ + char *cmd_usage; /* Usage String for this command */ + char *cmd_help; /* Help message for this command */ + short cmd_flags; /* Parsing flags */ + short cmd_minlen; /* Minimum legal # command chars required */ + kdb_repeat_t cmd_repeat; /* Does command auto repeat on enter? */ +} kdbtab_t; + + /* + * External command function declarations + */ + +extern int kdb_id(int, const char **, const char **, struct pt_regs *); +extern int kdb_bt(int, const char **, const char **, struct pt_regs *); + + /* + * External utility function declarations + */ +extern char* kdb_getstr(char *, size_t, char *); + + /* + * Register contents manipulation + */ +extern int kdba_getregcontents(const char *, struct pt_regs *, kdb_machreg_t *); +extern int kdba_setregcontents(const char *, struct pt_regs *, kdb_machreg_t); +extern int kdba_dumpregs(struct pt_regs *, const char *, const char *); +extern int kdba_setpc(struct pt_regs *, kdb_machreg_t); +extern kdb_machreg_t kdba_getpc(struct pt_regs *); + + /* + * Debug register handling. + */ +extern void kdba_installdbreg(kdb_bp_t*); +extern void kdba_removedbreg(kdb_bp_t*); + + /* + * Breakpoint handling - External interfaces + */ +extern void kdb_initbptab(void); +extern void kdb_bp_install_global(struct pt_regs *); +extern void kdb_bp_install_local(struct pt_regs *); +extern void kdb_bp_remove_global(void); +extern void kdb_bp_remove_local(void); + + /* + * Breakpoint handling - Internal to kdb_bp.c/kdba_bp.c + */ +extern int kdba_installbp(struct pt_regs *regs, kdb_bp_t *); +extern int kdba_removebp(kdb_bp_t *); + + +typedef enum { + KDB_DB_BPT, /* Breakpoint */ + KDB_DB_SS, /* Single-step trap */ + KDB_DB_SSB, /* Single step to branch */ + KDB_DB_SSBPT, /* Single step over breakpoint */ + KDB_DB_NOBPT /* Spurious breakpoint */ +} kdb_dbtrap_t; + +extern kdb_dbtrap_t kdba_db_trap(struct pt_regs *, int); /* DEBUG trap/fault handler */ +extern kdb_dbtrap_t kdba_bp_trap(struct pt_regs *, int); /* Breakpoint trap/fault hdlr */ + + /* + * Interrupt Handling + */ +typedef unsigned long kdb_intstate_t; + +extern void kdba_disableint(kdb_intstate_t *); +extern void kdba_restoreint(kdb_intstate_t *); + + /* + * SMP and process stack manipulation routines. + */ +extern int kdba_ipi(struct pt_regs *, void (*)(void)); +extern int kdba_main_loop(kdb_reason_t, kdb_reason_t, int, kdb_dbtrap_t, struct pt_regs *); +extern int kdb_main_loop(kdb_reason_t, kdb_reason_t, int, kdb_dbtrap_t, struct pt_regs *); + + /* + * General Disassembler interfaces + */ +extern int kdb_dis_fprintf(PTR, const char *, ...) __attribute__ ((format (printf, 2, 3))); +extern int kdb_dis_fprintf_dummy(PTR, const char *, ...) __attribute__ ((format (printf, 2, 3))); +extern disassemble_info kdb_di; + + /* + * Architecture Dependent Disassembler interfaces + */ +extern int kdba_id_printinsn(kdb_machreg_t, disassemble_info *); +extern int kdba_id_parsemode(const char *, disassemble_info*); +extern void kdba_id_init(disassemble_info *); +extern void kdba_check_pc(kdb_machreg_t *); + + /* + * Miscellaneous functions and data areas + */ +extern char *kdb_cmds[]; +extern void kdb_syslog_data(char *syslog_data[]); +extern unsigned long kdb_task_state_string(const char *); +extern char kdb_task_state_char (const struct task_struct *); +extern unsigned long kdb_task_state(const struct task_struct *p, unsigned long mask); +extern void kdb_ps_suppressed(void); +extern void kdb_ps1(const struct task_struct *p); +extern int kdb_parse(const char *cmdstr, struct pt_regs *regs); +extern void kdb_print_nameval(const char *name, unsigned long val); +extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info, int seqno); +#ifdef CONFIG_SWAP +extern void kdb_si_swapinfo(struct sysinfo *); +#else +#include +#define kdb_si_swapinfo(x) si_swapinfo(x) +#endif +extern void kdb_meminfo_read_proc(void); +#ifdef CONFIG_HUGETLB_PAGE +extern void kdb_hugetlb_report_meminfo(void); +#endif /* CONFIG_HUGETLB_PAGE */ +extern const char *kdb_walk_kallsyms(loff_t *pos); + + /* + * Architecture Dependant Local Processor setup & cleanup interfaces + */ +extern void kdba_local_arch_setup(void); +extern void kdba_local_arch_cleanup(void); + + /* + * Defines for kdb_symbol_print. + */ +#define KDB_SP_SPACEB 0x0001 /* Space before string */ +#define KDB_SP_SPACEA 0x0002 /* Space after string */ +#define KDB_SP_PAREN 0x0004 /* Parenthesis around string */ +#define KDB_SP_VALUE 0x0008 /* Print the value of the address */ +#define KDB_SP_SYMSIZE 0x0010 /* Print the size of the symbol */ +#define KDB_SP_NEWLINE 0x0020 /* Newline after string */ +#define KDB_SP_DEFAULT (KDB_SP_VALUE|KDB_SP_PAREN) + +/* Save data about running processes */ + +struct kdb_running_process { + struct task_struct *p; + struct pt_regs *regs; + int seqno; /* kdb sequence number */ + int irq_depth; /* irq count */ + struct kdba_running_process arch; /* arch dependent save data */ +}; + +extern struct kdb_running_process kdb_running_process[/* NR_CPUS */]; + +extern void kdb_save_running(struct pt_regs *); +extern void kdb_unsave_running(struct pt_regs *); +extern struct task_struct *kdb_curr_task(int); + +/* Incremented each time the main kdb loop is entered on the initial cpu, + * it gives some indication of how old the saved data is. + */ +extern int kdb_seqno; + +#ifdef MODULE +#define kdb_module_init(fn) module_init(fn) +#define kdb_module_exit(fn) module_exit(fn) +#else /* !MODULE */ +extern initcall_t __kdb_initcall_start, __kdb_initcall_end; +#define kdb_module_init(fn) \ + static initcall_t __kdb_initcall_##fn __attribute_used__ __attribute__ ((__section__ (".kdb_initcall.init"))) = fn; +#define kdb_module_exit(fn) \ + static exitcall_t __kdb_exitcall_##fn __attribute_used__ __attribute__ ((__section__ (".kdb_exitcall.exit"))) = fn; +#endif /* MODULE */ + +#define kdb_task_has_cpu(p) (task_curr(p)) +extern void kdb_runqueue(unsigned long cpu, kdb_printf_t xxx_printf); + +/* Simplify coexistence with NPTL */ +#define kdb_do_each_thread(g, p) do_each_thread(g, p) +#define kdb_while_each_thread(g, p) while_each_thread(g, p) + +#define GFP_KDB (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) + +extern void *debug_kmalloc(size_t size, int flags); +extern void debug_kfree(const void *); + +extern void kdb_initsupport(void); + +extern void kdba_set_current_task(const struct task_struct *); +extern const struct task_struct *kdb_current_task; +extern struct pt_regs *kdb_current_regs; + +/* Functions to safely read and write kernel areas. The {to,from}_xxx + * addresses are not necessarily valid, these functions must check for + * validity. If the arch already supports get and put routines with suitable + * validation and/or recovery on invalid addresses then use those routines, + * otherwise check it yourself. + */ + +extern int kdba_putarea_size(unsigned long to_xxx, void *from, size_t size); +extern int kdba_getarea_size(void *to, unsigned long from_xxx, size_t size); +extern int kdba_verify_rw(unsigned long addr, size_t size); + +#ifndef KDB_RUNNING_PROCESS_ORIGINAL +#define KDB_RUNNING_PROCESS_ORIGINAL kdb_running_process +#endif + +#endif /* !_KDBPRIVATE_H */ Index: 2.6.x-xfs/include/linux/sysctl.h =================================================================== --- 2.6.x-xfs.orig/include/linux/sysctl.h 2006-02-28 10:56:53.201817517 +1100 +++ 2.6.x-xfs/include/linux/sysctl.h 2006-02-28 11:26:53.510877726 +1100 @@ -147,6 +147,7 @@ KERN_SETUID_DUMPABLE=69, /* int: behaviour of dumps for setuid core */ KERN_SPIN_RETRY=70, /* int: number of spinlock retries */ KERN_ACPI_VIDEO_FLAGS=71, /* int: flags for setting up video after ACPI sleep */ + KERN_KDB=72, /* int: kdb on/off */ }; Index: 2.6.x-xfs/init/main.c =================================================================== --- 2.6.x-xfs.orig/init/main.c 2006-02-13 14:38:33.066739793 +1100 +++ 2.6.x-xfs/init/main.c 2006-02-28 11:26:53.511854155 +1100 @@ -58,6 +58,10 @@ #include #endif +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ + /* * This is one of the first .c files built. Error out early if we have compiler * trouble. @@ -156,6 +160,26 @@ extern struct obs_kernel_param __setup_start[], __setup_end[]; +#ifdef CONFIG_KDB +static int __init kdb_setup(char *str) +{ + if (strcmp(str, "on") == 0) { + kdb_on = 1; + } else if (strcmp(str, "on-nokey") == 0) { + kdb_on = 2; + } else if (strcmp(str, "off") == 0) { + kdb_on = 0; + } else if (strcmp(str, "early") == 0) { + kdb_on = 1; + kdb_flags |= KDB_FLAG_EARLYKDB; + } else + printk("kdb flag %s not recognised\n", str); + return 0; +} + +__setup("kdb=", kdb_setup); +#endif /* CONFIG_KDB */ + static int __init obsolete_checksetup(char *line) { struct obs_kernel_param *p; @@ -518,6 +542,14 @@ pgtable_cache_init(); prio_tree_init(); anon_vma_init(); + +#ifdef CONFIG_KDB + kdb_init(); + if (KDB_FLAG(EARLYKDB)) { + KDB_ENTER(); + } +#endif /* CONFIG_KDB */ + #ifdef CONFIG_X86 if (efi_enabled) efi_enter_virtual_mode(); Index: 2.6.x-xfs/kdb/ChangeLog =================================================================== --- 2.6.x-xfs.orig/kdb/ChangeLog 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/ChangeLog 2006-02-28 11:26:53.515759874 +1100 @@ -0,0 +1,1338 @@ +2006-02-28 Nathan Scott + + * kdb v4.4-2.6.16-rc5-common-1. + +2006-02-20 Nathan Scott + + * kdb v4.4-2.6.16-rc4-common-1. + +2006-02-06 Keith Owens + + * Change CONFIG_CRASH_DUMP to CONFIG_LKCD. + * Remove obsolete kdb_notifier_list. + * kdb v4.4-2.6.16-rc2-common-2. + +2006-02-06 Keith Owens + + * Add xpcusers command. Dean Nelson, SGI. + * kdb v4.4-2.6.16-rc2-common-1. + +2006-02-02 Keith Owens + + * Check if we have a console before using it for KDB. + * kdb v4.4-2.6.16-rc1-common-3. + +2006-02-01 Keith Owens + + * Add option 'R' to the pid command to reset to the original task. + * Include 'pid R' in archkdb* commands to reset up the original failing + task. Users may have switched to other cpus and/or tasks before + issuing archkdb. + * Compile fix for kdbm_pg.c on i386. + * kdb v4.4-2.6.16-rc1-common-2. + +2006-01-18 Keith Owens + + * kdb v4.4-2.6.16-rc1-common-1. + +2006-01-11 Keith Owens + + * Plug a timing race between KDB_ENTER_SLAVE and KDB_ENTER, and allow + the cpu command to switch to a slave cpu. + * KDB_REASON_SILENT now waits for other cpus, to avoid spurious NMI + events that were seen on some Xeon systems. + * kdb v4.4-2.6.15-common-3. + +2006-01-08 Keith Owens + + * kdb mainline invokes DIE_KDEBUG_ENTER and DIE_KDEBUG_LEAVE via + notify_die. + * Move xpc debug support from xpc to mainline kdb. + * kdbm_cm.c: check if file_lock_operations or lock_manager_operations + are set before dereferencing them. Felix Blyakher, SGI. + * kdb v4.4-2.6.15-common-2. + +2006-01-04 Keith Owens + + * Print all buffers on a page in inode pages and update formatting to be + legible, too. David Chinner, SGI. + * Update page flags in kdbm_pg. + * Remove inline from *.c files. + * kdb v4.4-2.6.15-common-1. + +2005-12-25 Keith Owens + + * kdb v4.4-2.6.15-rc7-common-1. + +2005-12-20 Keith Owens + + * kdb v4.4-2.6.15-rc6-common-1. + +2005-12-10 Keith Owens + + * Update mapping of flags to strings in kdbm_pg.c and kdbm_vm.c. + * kdb v4.4-2.6.15-rc5-common-3. + +2005-12-06 Keith Owens + + * Add RECOVERY flag to global KDB flags. + * Add kdb_{save,restore}_flags. + * kdb v4.4-2.6.15-rc5-common-2. + +2005-12-05 Keith Owens + + * kdb v4.4-2.6.15-rc5-common-1. + +2005-12-02 Keith Owens + + * kdbm_vm.c: offsets of page macros should be unsigned long. Reported + by Dean Nelson, SGI. + * kdb v4.4-2.6.15-rc4-common-1. + +2005-11-30 Keith Owens + + * New follow_page() API. + * kdb v4.4-2.6.15-rc3-common-1. + +2005-11-21 Keith Owens + + * kdb v4.4-2.6.15-rc2-common-1. + +2005-11-15 Keith Owens + + * kdb v4.4-2.6.15-rc1-common-1. + +2005-11-15 Keith Owens + + * Allow kdb_printf() to be used outside kdb, in preemptible context. + * Build with CONFIG_SWAP=n. Reported by Leo Yuriev. + * kdb v4.4-2.6.14-common-2. + +2005-10-28 Keith Owens + + * kdb v4.4-2.6.14-common-1. + +2005-10-21 Keith Owens + + * kdb v4.4-2.6.14-rc5-common-1. + +2005-10-11 Keith Owens + + * Handle removal of USB keyboard. Aaron Young, SGI. + * kdb v4.4-2.6.14-rc4-common-1. + +2005-10-05 Keith Owens + + * Extend kdb_notifier_list() codes to include dumping. + * Use emergency_restart() for reboot, it can be called from interrupt + context, unlike machine_restart(). + * kdb v4.4-2.6.14-rc3-common-1. + +2005-09-21 Keith Owens + + * Support kdb_current_task in register display and modify commands. + * Document what changes kdb's notion of the current task. + * Update rd documentation for IA64. + * Move some definictions to kdbprivate.h and remove some unused symbol + exports. + * kdb v4.4-2.6.14-rc2-common-1. + +2005-09-20 Keith Owens + + * Document IA64 handlers command. + * Add more fields to the task command. + * Cope with MCA/INIT handlers in the ps command. + * Namespace cleanup, delete unused exports, make some functions static. + * Add a kdb_notifier_list callback when kdb is about to reboot the + system. + * kdb v4.4-2.6.14-rc1-common-1. + +2005-08-29 Keith Owens + + * kdb v4.4-2.6.13-common-1. + +2005-08-24 Keith Owens + + * kdb v4.4-2.6.13-rc7-common-1. + +2005-08-08 Keith Owens + + * kdb v4.4-2.6.13-rc6-common-1. + +2005-08-02 Keith Owens + + * Print more fields from filp, dentry. + * Add kdb=on-nokey to suppress kdb entry from the keyboard. + * kdb v4.4-2.6.13-rc5-common-1. + +2005-07-30 Keith Owens + + * kdb v4.4-2.6.13-rc4-common-1. + +2005-07-26 Keith Owens + + * Fix compile problem with CONFIG_USB_KBD. + * kdb v4.4-2.6.13-rc3-common-3. + +2005-07-22 Keith Owens + + * The asmlinkage kdb() patch was lost during packaging. Reinstate it. + * kdb v4.4-2.6.13-rc3-common-2. + +2005-07-19 Keith Owens + + * Add support for USB keyboard (OHCI only). Aaron Young, SGI. + * kdb v4.4-2.6.13-rc3-common-1. + +2005-07-08 Keith Owens + + * kdb v4.4-2.6.13-rc2-common-1. + +2005-07-01 Keith Owens + + * Make kdb() asmlinkage to avoid problems with CONFIG_REGPARM. + * Change some uses of smp_processor_id() to be preempt safe. + * Use DEFINE_SPINLOCK(). + * kdb v4.4-2.6.13-rc1-common-1. + +2005-06-18 Keith Owens + + * kdb v4.4-2.6.12-common-1. + +2005-06-08 Keith Owens + + * Correct early exit from bd *. + * kdb v4.4-2.6.12-rc6-common-1. + +2005-05-25 Keith Owens + + * Delete Documentation/kdb/dump.txt. lkcd now has reasonable + integration with kdb. + * kdb v4.4-2.6.12-rc5-common-1. + +2005-05-08 Keith Owens + + * kdb v4.4-2.6.12-rc4-common-1. + +2005-04-21 Keith Owens + + * Add rpte command (find the pte for a physical page). + * kdb v4.4-2.6.12-rc3-common-1. + +2005-04-06 Keith Owens + + * Add rq and rqa commands. John Hawkes, SGI. + * kdb v4.4-2.6.12-rc2-common-1. + +2005-03-29 Keith Owens + + * Use register_sysctl_table() instead of patching kernel/sysctl.c. + * Non-ASCII characters are not printable. + * kdb v4.4-2.6.12-rc1-common-1. + +2005-03-15 Keith Owens + + * More coexistence patches for lkcd. Jason Uhlenkott, SGI. + * kdb v4.4-2.6.11-common-3. + +2005-03-08 Keith Owens + + * Coexistence patches for lkcd. Jason Uhlenkott, SGI. + * kdb v4.4-2.6.11-common-2. + +2005-03-03 Keith Owens + + * Add kdb to drivers/serial/8250_early.c. Francois Wellenreiter, Bull. + * kdb v4.4-2.6.11-common-1. + +2005-02-14 Keith Owens + + * kdb v4.4-2.6.11-rc4-common-1. + +2005-02-08 Keith Owens + + * kdb v4.4-2.6.11-rc3-bk4-common-1. + +2005-02-03 Keith Owens + + * Print more superblock fields. Nathan Scott, SGI. + * Remove kallsyms correction for modules, Linus took it. + * kdb v4.4-2.6.11-rc3-common-1. + +2005-01-27 Keith Owens + + * Add bio command. Nathan Scott, SGI. + * kdb v4.4-2.6.11-rc2-common-1. + +2005-01-20 Keith Owens + + * Include kallsyms correction for modules until Linus takes it. + * kdb v4.4-2.6.11-rc1-bk7-common-1. + +2005-01-12 Keith Owens + + * kallsyms now supports all symbols properly, remove kdb patch. + * Add last ditch allocator for debugging. + * Update kdb_meminfo_read_proc() for vmalloc changes. + * Update kdbm_vm.c for 4 level page tables. + * kdb v4.4-2.6.11-rc1-common-1. + +2004-12-25 Keith Owens + + * Add kobject command. + * Ignore low addresses and large offsets in kdbnearsym(). + * Console updates for sn2 simulator. + * kdb v4.4-2.6.10-common-1. + +2004-12-07 Keith Owens + + * kdb v4.4-2.6.10-rc3-common-1. + +2004-11-23 Keith Owens + + * Remove warning message from kdb_get_one_user_page(), it was too noisy. + * kdb v4.4-2.6.10-rc2-common-1. + +2004-11-02 Keith Owens + + * Build with kdb patch applied but CONFIG_KDB=n. + * kdb v4.4-2.6.10-rc1-common-2. + +2004-10-29 Keith Owens + + * Handle new compression scheme for kallsyms. + * Handle move of DEAD and ZOMBIE for task->state to task->exit_state. + * Tweak the concept of a valid kernel address to get all symbols, + including the symbols in the ia64 gate page. + * kdb v4.4-2.6.10-rc1-common-1. + +2004-10-21 Keith Owens + + * Handle variable size for the kernel log buffer. + * kdb v4.4-2.6.9-common-2. + +2004-10-19 Keith Owens + + * kdb v4.4-2.6.9-common-1. + +2004-10-12 Keith Owens + + * kdb v4.4-2.6.9-rc4-common-1. + +2004-10-01 Keith Owens + + * kdb v4.4-2.6.9-rc3-common-1. + +2004-09-30 Keith Owens + + * Add stackdepth command to Documentation/kdb/kdb.mm. stackdepth is + only supported on i386 and ia64 at the moment. + * Skip kdbm_pg memmap build on x86_64. Scott Lurndal, 3leafnetworks. + * Export kdb_serial_str for modular I/O. Bryan Cardillo, UPenn. + * Reinstate tab completion for symbols. + * kdb v4.4-2.6.9-rc2-common-2. + +2004-09-14 Keith Owens + + * Add task states C (traCed) and E (dEad). + * kdb v4.4-2.6.9-rc2-common-1. + +2004-08-27 Keith Owens + + * kdb v4.4-2.6.9-rc1-common-1. + +2004-08-14 Keith Owens + + * kdb v4.4-2.6.8-common-1. + +2004-08-12 Keith Owens + + * kdb v4.4-2.6.8-rc4-common-1. + +2004-08-05 Keith Owens + + * Mark kdb_initcall as __attribute_used__ for newer gcc. + * kdb v4.4-2.6.8-rc3-common-2. + +2004-08-04 Keith Owens + + * Add mdp (memory display physical) comnmand. + Ananth N Mavinakayanahalli, IBM. + * kdb v4.4-2.6.8-rc3-common-1. + +2004-07-18 Keith Owens + + * Patch for new sn_console. Erik Jacobson. SGI. + * kdb v4.4-2.6.8-rc2-common-1. + +2004-07-12 Keith Owens + + * Convert kdbm_task to standard cpumask_t. + * Document '*' (all breakpoints) option on bd/be/bc commands. + * kdb v4.4-2.6.8-rc1-common-1. + +2004-06-30 Keith Owens + + * Common changes to help the x86-64 port. + * kdb v4.4-2.6.7-common-3. + +2004-06-20 Keith Owens + + * Move kdb includes in mm/swapfile.c to reduce conflicts with other + SGI patches. + * kdb v4.4-2.6.7-common-2. + +2004-06-16 Keith Owens + + * kdb v4.4-2.6.7-common-1. + +2004-06-09 Keith Owens + + * kdb v4.4-2.6.7-rc3-common-1. + +2004-06-09 Keith Owens + + * Namespace clean up. Mark code/variables as static when it is only + used in one file, delete dead code/variables. + * Saved interrupt state requires long, not int. + * kdb v4.4-2.6.7-rc2-common-3. + +2004-06-08 Keith Owens + + * Whitespace clean up, no code changes. + * kdb v4.4-2.6.7-rc2-common-2. + +2004-06-07 Keith Owens + + * kdb v4.4-2.6.7-rc2-common-1. + +2004-06-06 Keith Owens + + * Avoid recursion problems in kdb_init(). + * Add standard archkdb commands. + * Add per_cpu command. + * Move kdb_{get,put}userarea_size definitions to linux/kdb.h. + * kdb v4.4-2.6.6-common-2. + +2004-05-23 Keith Owens + + * Shrink the output from the cpu command. + * Add cpu state 'I', the cpu is idle. + * Add cpu state '+', some kdb data is available but the cpu is not + responding. + * Do not print tasks in state I or M by default in ps and bta commands. + * Add states I (idle task) and M (sleeping system daemon) to ps and + bta commands. + * Delete unused variables. + * Move private kdb fields from kdb.h to kdbprivate.h. + * Print 'for keyboard entry' for the special cases when KDB_ENTER() is + used to get registers. + * Move bfd.h and ansidecl.h from arch/$(ARCH)/kdb to include/asm-$(ARCH) + and remove -I arch/$(ARCH)/kdb. + * dmesg command now prints from either the start or end of dmesg, or at + an arbitrary point in the middle of the kernel log buffer. + * Sensible string dump for multi byte md commands. + * 'page' command handles ia64 correctly. + * Show some activity when waiting for cpus to enter kdb. + * Change the KDB entry code to KDB. + * Allow comment commands, starting with '#'. + * Commands defined using defcmd from kdb_cmds are not printed as they + are entered, use defcmd with no parameters to print all the defined + commands. + * Add summary command. + * Update copyright notices. + * Zero suppression on md command. + * Make set NOSECT=1 the default. + * PPC64 uses OF-stdout instead of console. Ananth N Mavinakayanahalli. + * kdb v4.4-2.6.6-common-1. + +2004-05-10 Keith Owens + + * kdb v4.3-2.6.6-common-1. + +2004-05-06 Keith Owens + + * kdb v4.3-2.6.6-rc3-common-1. + +2004-05-06 Keith Owens + + * kdb v4.3-2.6.6-rc2-common-1. + +2004-04-30 Keith Owens + + * Rewrite inode_pages command for new radix code in struct page. + * kdb v4.3-2.6.6-rc1-common-1. + +2004-04-11 Keith Owens + + * Unlock sn_sal_lock before entering kdb from sn_serial. + * kdb v4.3-2.6.5-common-2. + +2004-04-05 Keith Owens + + * kdb v4.3-2.6.5-common-1. + +2004-03-22 Keith Owens + + * kdb v4.3-2.6.5-rc2-common-1. + +2004-03-12 Keith Owens + + * More work to avoid spurious messages from WARN_CONSOLE_UNLOCKED(). + * bh command bug fixes. Nathan Scott. + * kdb v4.3-2.6.4-common-1. + +2004-03-06 Keith Owens + + * Set KDB_IS_RUNNING() during kdb_init to avoid spurious messages from + WARN_CONSOLE_UNLOCKED(). + * Correct loss of symbol names in kdbnearsym. + * kdb v4.3-2.6.4-rc2-common-1. + +2004-02-29 Keith Owens + + * kdb v4.3-2.6.4-rc1-common-1. + +2004-02-21 Keith Owens + + * Correct build of kdb_cmds when using a separate object directory and + make it quiet. j-nomura (NEC), Keith Owens. + * kdb v4.3-2.6.3-common-2. + +2004-02-18 Keith Owens + + * kdb v4.3-2.6.3-common-1. + +2004-02-17 Keith Owens + + * Remove WAR for incorrect console registration patch. + * kdb v4.3-2.6.3-rc4-common-1. + +2004-02-17 Keith Owens + + * Convert longjmp buffers from static to dynamic allocation, for large + cpu counts. + * Tweak kdbm_task for SMP/UP. + * Reconcile with kdb-v4.3 2.4.25-rc1-common-1. + * Simplify coexistence with NPTL patches. + * Support kill command on new scheduler. + * Do not refetch data when printing a value as characters. + * Document the pid command. + * Work around 2.6 kallsyms 'feature'. + * Upgrade to 2.6.3-rc3. + * WAR for incorrect console registration patch. + * kdb v4.3-2.6.3-rc3-common-1. + +2003-12-03 Keith Owens + + * Reconcile 2.6-test versions from Xavier Bru (Bull), Greg Banks (SGI), + Jim Houston (Concurrent Computer Corp). + * Reconcile with kdb v4.3-2.4.23-common-2. + * Clean up CONFIG_KDB changes to {scripts,kernel}/kallsyms.c. + * Correct handling of kdb command line arguments. + * Make hooks into module code less intrusive. + * Delete kdb_active_task, not required with O(1) scheduler. + * Port kdbm_task.c from 2.4. + * Disable debug check in exit.c::next_thread() when kdb is running. + * Remove "only bh_disable when interrupts are set". BH must be disabled + in kdb to prevent deadlock on breakpoints in interrupt handlers. + * Add kdb to drivers/char/sn_serial.c. + * kdb v4.3-2.6.0-test11-common-1. + +2003-11-11 Xavier Bru + * Merge to 2.6.0-test9 +2003-10-17 Xavier Bru + * fix NUll ptr in kdb_ps at early prompt. +2003-10-14 Xavier Bru + * fix NUll ptr in kdb_ps when cpu not present. +2003-10-06 Xavier Bru + * Merge to 2.6.0-test5 + * fix compile error with CONFIG_MODULES not set. + +2003-09-08 Xavier Bru + * Merge to 2.6.0-test4 + +2003-07-10 Xavier Bru + + * Merge kdb v4.3 to 2.5.72 ia64 + * don't call local_bh_enable() with interrupts masked. + +2003-04-07 Xavier Bru + + * Merge kdb v4.1 to 2.5.64 ia64 + * new kernel parameters support + * new module format + * new kallsyms support + +2003-12-02 Keith Owens + + * Use correct page alignment in kdb_get_one_user_page(). + Prasanna S Panchamukhi, IBM. + * Split pte command into pte -m and pte -p. Dean Roe, SGI. + * kdb v4.3-2.4.23-common-2. + +2003-12-01 Keith Owens + + * kdb v4.3-2.4.23-common-1. + +2003-11-11 Keith Owens + + * Make KDB for USB keyboards build. Peter T. Breuer. + * Do not use USB keyboard if it has not been probed. + * kdb v4.3-2.4.23-rc1-common-1. + +2003-10-10 Keith Owens + + * Sync with XFS 2.4.22 tree. + * kdb v4.3-2.4.22-common-2. + +2003-08-29 Keith Owens + + * kdb v4.3-2.4.22-common-1. + +2003-07-27 Keith Owens + + * kdb v4.3-2.4.22-pre8-common-8. + +2003-07-20 Keith Owens + + * Make kdb_serial_str a common constant, the same for all consoles. + * Support SGI L1 console. + * kdb v4.3-2.4.21-common-8. + +2003-07-14 Keith Owens + + * Correct ll command. + * kdb v4.3-2.4.21-common-7. + +2003-07-08 Keith Owens + + * Export more kdb symbols. Vamsi Krishna S., IBM. + * kdb v4.3-2.4.21-common-6. + +2003-07-07 Keith Owens + + * Tweak 'waiting for cpus' message. + * kdb v4.3-2.4.21-common-5. + +2003-07-07 Keith Owens + + * 2.4.21-ia64-030702 patches common code that affects kdb. Workaround + this nuisance. + * kdb v4.3-2.4.21-common-4. + +2003-06-24 Keith Owens + + * Add task and sigset commands. Mark Goodwin, SGI. + * kdb v4.3-2.4.21-common-3. + +2003-06-23 Keith Owens + + * Sync with XFS 2.4.21 tree. + * kdb v4.3-2.4.21-common-2. + +2003-06-20 Keith Owens + + * kdb v4.3-2.4.21-common-1. + +2003-06-20 Keith Owens + + * More details on vm command, add vmp and pte commands. + Dean Nelson, Dean Roe, SGI. + * YAO1SCF (Yet Another O(1) Scheduler Coexistence Fix). + * Changes to common code to build on sparc. Tom Duffy. + * Move Tom Duffy's changes to drivers/sbus from the sparc64 + patch to the common patch to keep all the serial changes + together. + * Changes to common code to build on Xscale. Eddie Dong, Intel. + * Remove CROSS_COMPILE_INC. + * Remove obsolete boot parameter 'kdb', long since replaced by + 'kdb=on'. + * Remove obsolete kdb_eframe_t casts. + * Add CONFIG_KDB_CONTINUE_CATASTROPHIC. + * Wait a short interval for cpus to join kdb before proceeding. + * Automatically enable sysrq for sr command. + * Correct double free of kdb_printf lock, spotted by Richard Sanders. + * Add optional cpu parameter to btc command. + * kdb v4.3-2.4.20-common-1. + +2003-05-02 Keith Owens + + * Some architectures have problems with the initial empty kallsyms + section so revert to three kallsyms passes. + * Flush buffered input at startup and at 'more' prompt. + * Only print 'more' prompt when longjmp data is available. + * Print more data for buffers and inodes. + * Disable kill command when O(1) scheduler is installed, the code + needs to be redone for O(1). + * The kernel has an undocumented assumption that enable_bh() is + always called with interrupts enabled, make it so. + * Print trailing punctuation even for symbols that are not in kernel. + * Add read/write access to user pages. Vamsi Krishna S., IBM + * Rename cpu_is_online to cpu_online, as in 2.5. + * O(1) scheduler removes init_task so kdb maintains its own list of + active tasks. + * Delete btp 0 option, it needed init_tasks. + * Clean up USB keyboard support. Steven Dake. + * Sync with XFS 2.4.20 tree. + * kdb v4.2-2.4.20-common-1. + +2003-04-04 Keith Owens + + * Remove one kallsyms pass. + * Automatic detection of O(1) scheduler. + * Rename cpu_online to cpu_is_online. + * Workarounds for scheduler bugs. + * Tweak algorithm for detecting if cpu process data is available. + * Add 'kill' command. Sonic Zhang, Keith Owens. + * kdb v4.1-2.4.20-common-1. + +2003-03-16 Keith Owens + + * Each cpu saves its state as it enters kdb or before it enters code + which cannot call kdb. + * Allow btp on process 0 for a specified cpu. + * Add btt command, backtrace given a struct task address. + * btc command no longer switches cpus, instead it uses the saved data. + * bta shows the idle task on each cpu as well as real tasks, the idle + task could be handling an interrupt. + * ps command shows the idle task on each cpu. + * ps checks that the saved data for a cpu matches the process running on + that cpu and warns about stale saved data or no saved data at all. + * Remove special cases for i386 backtrace from common code and simplify + common bt code. + * Clean up kdb interaction with CONFIG_SERIAL_CONSOLE. + * Do not automatically repeat commands after the user typed 'q'. + * O(1) scheduler patch changes the process cpu field but does not set + any indicator that O(1) is being used. Adjust kdb_process_cpu() by + hand after applying O(1). + * Add kdb_print_nameval() to common code. + * Convert tests of cpu_online_map to cpu_online() macro. + * module.h needs errno.h when compiling with CONFIG_MODULES=n. + * Correct duplicate breakpoint handling. + * Do not try to send IPI during a catastrophic error, send_ipi can hang + and take kdb with it. + * kdb memmap command is i386 only, restrict it. + * Add large block device (LBD) support from XFS tree. Eric Sandeen. + * kdb v4.0-2.4.20-common-1. + +2003-02-03 Keith Owens + + * Register kdb commands early. + * Decode oops via kallsyms if it is available. + * Update copyright notices to 2003. + * Add defcmd/endefcmd to allow users to package their own macros. + * kdb commands that fail are ignored when prefixed with '-'. + * Add selection options to bta command. + * Add btc command (switch to each cpu and backtrace). + * Do real time detection of dead cpus. + * Clear ip adjusted flag when leaving kdb. + * Clean up ps command. + * Print ps output for each task when backtracing. + * Bump to version v3.0 to reduce confusion between kdb and kernel + version numbers. + * Add kdba_local_arch_setup/kdba_local_arch_cleanup to correct + keyboard freeze. Ashish Kalra. + * Refuse multiple breakpoints at the same address. + * Add fl (file_lock) command, from XFS development tree. + * Correct inode_pages, from XFS development tree. + * Add command history and editing. Sonic Zhang. + * Extend command history and editing to handle vt100 escape sequences. + * Allow tab completion at start of line. + * Touch nmi watchdog on long running bta and btc commands. + * Clean up ps output and standardize with bta codes. + * Correctly handle escaped characters in commands. + * Update man pages for btc and command history/editing. + * kdb v3.0-2.4.20-common-1. + +2002-11-29 Keith Owens + + * Upgrade to 2.4.20. + * Correct Documentation/kdb/kdb_sr.man. + * Remove leading zeroes from pids, they are decimal, not octal. + * kdb v2.5-2.4.20-common-1. + +2002-11-14 Keith Owens + + * Upgrade to 2.4.20-rc1. + * kdb v2.5-2.4.20-rc1-common-1. + +2002-11-14 Keith Owens + + * Fix processing with O(1) scheduler. + * 'go' switches back to initial cpu first. + * 'go
' only allowed on initial cpu. + * 'go' installs the global breakpoints from the initial cpu before + releasing the other cpus. + * If 'go' has to single step over a breakpoint then it single steps just + the initial cpu, installs the global breakpoints then releases the + other cpus. + * General clean up of handling for breakpoints and single stepping over + software breakpoints. + * Add kdb_notifier_block so other code can tell when kdb is in control. + * kdb v2.5-2.4.19-common-1. + +2002-11-02 Keith Owens + + * Correct build without CONFIG_KDB. + * kdb v2.4-2.4.19-common-3. + +2002-11-01 Keith Owens + + * Minimize differences from 2.5.44. + * kdb v2.4-2.4.19-common-2. + +2002-10-31 Keith Owens + + * Add defcmd/endefcmd feature. + * Remove kdb_eframe_t. + * Clear bp data before using. + * Sanity check if we have pt_regs. + * Force LINES > 1. + * Remove special case for KDB_REASON_PANIC, use KDB_ENTER() instead. + * Remove kdba_getcurrentframe(). + * Coexist with O(1) scheduler. + * Add lines option to dmesg, speed up dmesg. + * kdb v2.4-2.4.19-common-1. + +2002-10-17 Keith Owens + + * Add selection critera to ps and bta commands. + * kdb v2.3-2.4.19-common-4. + +2002-10-07 Keith Owens + + * New man page, Documentation/kdb/kdb_sr.man. + +2002-10-04 Keith Owens + + * Minimize differences between patches for 2.4 and 2.5 kernels. + * Add Configure.help for CONFIG_KDB_USB. + * Reduce stack usage. + * kdb v2.3-2.4.19-common-3. + +2002-08-10 Keith Owens + + * Replace kdb_port with kdb_serial to support memory mapped I/O. + David Mosberger. + * kdb v2.3-2.4.19-common-2. + +2002-08-07 Keith Owens + + * Upgrade to 2.4.19. + * Remove individual SGI copyrights, the general SGI copyright applies. + * Handle md0. Reported by Hugh Dickins, different fix by Keith Owens. + * Use page_address() in kdbm_pg.c. Hugh Dickins. + * Remove debugging printk from kdbm_pg.c. Hugh Dickins. + * Move breakpoint address verification into arch dependent code. + * Dynamically resize kdb command table as required. + * Common code to support USB keyboard. Sebastien Lelarge. + * kdb v2.3-2.4.19-common-1. + +2002-07-09 Keith Owens + + * Upgrade to 2.4.19-rc1. + * Add dmesg command. + * Clean up copyrights, Eric Sandeen. + * kdb v2.2-2.4.19-rc1-common-1. + +2002-06-14 Keith Owens + + * Upgrade to 2.4.19-pre10. + * Sync with XFS. + * kdb v2.1-2.4.19-pre10-common-1. + +2002-04-09 Keith Owens + + * Upgrade to 2.4.19-pre6. + * kdb v2.1-2.4.19-pre6-common-1. + +2002-03-18 Keith Owens + + * Syntax check mdWcN commands. + +2002-03-01 Keith Owens + + * Sync with XFS 2.4.18. + * kdb v2.1-2.4.18-common-2. + +2002-02-26 Keith Owens + + * Upgrade to 2.4.18. + * Add Paul Dorwin (IBM) magicpoint slides on using kdb as + Documentation/kdb/slides. + * kdb v2.1-2.4.18-common-1. + +2002-01-23 Keith Owens + + * Sync with XFS pagebuf changes. + * kdb v2.1-2.4.17-common-2. + +2002-01-18 Keith Owens + + * Ignore single stepping during panic. + * Remove kdba_getword, kdba_putword. Replace with kdb_getword, + kdb_putword that rely on copy_xx_user. The new functions return + an error code, like copy_xx_user. + * New functions kdb_getarea, kdb_putarea for copying areas of data + such as structures. These functions also return an error code. + * Change all common code to use the new functions. + * bp command checks that it can read and write the word at the + breakpoint before accepting the address. + * Break points are now set FIFO and cleared LIFO so overlapping + entries give sensible results. + * Verify address before disassembling code. + * Common changes for sparc64. Ethan Solomita, Tom Duffy. + * Remove ss , never supported. + * Remove kallsyms entries from arch vmlinux.lds files. + * Specify which commands auto repeat. + * kdb v2.1-2.4.17-common-1. + +2002-01-07 Keith Owens + + * Remove console semaphore code, not good in interrupt. + * Remove fragment of ia64 patch that had crept into kdb. + * Release as kdb v2.0-2.4.17-common-3. + +2002-01-04 Keith Owens + + * Sync xfs <-> kdb common code. + +2001-12-22 Keith Owens + + * Upgrade to 2.4.17. + * Clean up ifdef CONFIG_KDB. + * Add ifdef CONFIG_KDB around include kdb.h. + * Delete dummy kdb.h files for unsupported architectures. + * Delete arch i386 and ia64 specific files. This changelog now + applies to kdb common code only. + * Release as kdb v2.0-2.4.17-common-1. + +2001-12-03 Keith Owens + + * Upgrade to 2.4.16. + * Add include/asm-um/kdb.h stub to allow XFS to be tested under UML. + * Check if an interrupt frame on i386 came from user space. + * Out of scope bug fix in kdb_id.c. Ethan Solomita. + * Changes to common code to support sparc64. Ethan Solomita. + * Change GFP_KERNEL to GFP_ATOMIC in disasm. Ethan Solomita. + +2001-11-16 Keith Owens + + * Upgrade to 2.4.15-pre5. + * Wrap () around #define expressions with unary operators. + +2001-11-13 Keith Owens + + * Upgrade to 2.4.15-pre4. + * kbdm_pg.c patch from Hugh Dickins. + +2001-11-07 Keith Owens + + * Upgrade to 2.4.14-ia64-011105. + * Change name of l1 serial I/O routine, add ia64 init command. SGI. + * Sync kdbm_pg with XFS. + +2001-11-06 Keith Owens + + * Upgrade to kernel 2.4.14. + +2001-11-02 Keith Owens + + * Sync kdbm_pg.c with XFS. + +2001-10-24 Keith Owens + + * Upgrade to kernel 2.4.13. + +2001-10-14 Keith Owens + + * More use of TMPPREFIX in top level Makefile to speed up NFS compiles. + + * Correct repeat calculations in md/mds commands. + +2001-10-10 Keith Owens + + * Copy bfd.h and ansidecl.h to arch/$(ARCH)/kdb, remove dependecies on + user space includes. + + * Update kdb v1.9 to kernel 2.4.11. + +2001-10-01 Keith Owens + + * Update kdb v1.9 to kernel 2.4.11-pre1 and 2.4.10-ac1. + + * Correct loop in kdb_parse, reported by Tachino Nobuhiro. + +2001-09-25 Keith Owens + + * Update kdb v1.8 to kernel 2.4.10. + + * kdbm_pg patch from Hugh Dickens. + + * DProbes patch from Bharata B Rao. + + * mdWcn and mmW patch from Vamsi Krishna S. + + * i386 disasm layout patch from Jean-Marc Saffroy. + + * Work around for 64 bit binutils, Simon Munton. + + * kdb.mm doc correction by Chris Pascoe. + + * Enter repeats the last command, IA64 disasm only prints one + instruction. Don Dugger. + + * Allow kdb/modules to be linked into vmlinux. + + * Remove obsolete code from kdb/modules/kdbm_{pg,vm}.c. + + * Warn when commands are entered at more prompt. + + * Add MODULE_AUTHOR, DESCRIPTION, LICENSE. + + * Release as kdb v1.9. + +2001-02-27 Keith Owens + + * Update kdb v1.8 to kernel 2.4.2, sync kdb/modules with XFS. + + * Hook into panic() call. + +2000-12-18 Keith Owens + + * Update kdb v1.7 to kernel 2.4.0-test13-pre3, sync kdb/modules with + XFS. + +2000-11-18 Keith Owens + + * Update to kernel 2.4.0-test11-pre7, including forward port of + bug fixes from WIP 2.4.0-test9 tree. + + * Update to Cygnus CVS trees for disassembly code. + + * Bump to kdb v1.6. + +2000-10-19 Keith Owens + + * Update to kernel 2.4.0-test10-pre4. + +2000-10-15 Keith Owens + + * kdb/kdbmain.c (kdb_parse): Correctly handle blank input. + + * kdb/kdbmain.c (kdb_local, kdb): Reason SILENT can have NULL regs. + +2000-10-13 Keith Owens + + * kdb/kdbmain.c: Reduce CMD_LEN to avoid overflowing kdb_printf buffer. + +2000-10-11 Keith Owens + + * kdb/kdbmain.c (kdb): Test for userspace breakpoints before driving + other cpus into kdb. Speeds up gdb and avoids SMP race. + + * arch/i386/kdb/kdba_io.c (get_serial_char, get_kbd_char): Ignore + unprintable characters. + + * arch/i386/kdb/kdba_io.c (kdba_read): Better handling of buffer size. + +2000-10-04 Keith Owens + + * arch/i386/kdb/kdba_bt.c (kdba_bt_process): Verify that esp is inside + task_struct. Original patch by Mike Galbraith. + + * kdb/kdb_io.c (kdb_getstr): Reset output line counter, remove + unnecessary prompts. + + * arch/i386/kdb/kdbasupport.c (kdb_getregcontents): Change " cs" to + "xcs", ditto ss, ds, es. gdb2kdb does not like leading spaces. + + * include/asm-xxx/kdb.h: Add dummy kdb.h for all architectures except + ix86. This allows #include to appear in arch independent + code without causing compile errors. + + * kdb/modules/kdbm_pg: Sync with XFS. + +2000-10-03 Keith Owens + + * kdb/kdb_io.c (kdb_read): Ignore NMI while waiting for input. + + * kdb/kdb_io.c, kdb/Makefile: Export kdb_read. + +2000-10-02 Keith Owens + + * arch/i386/kernel/smpboot.c (do_boot_cpu): Set nmi_watchdog_source to 2 + to avoid premature NMI oops during cpu bring up. We have to assume that + a box with more than 1 cpu has a working IO-APIC. + + * Documentation/kdb/{kdb.mm,kdb_md.man}: Add mdr command. + + * kdb/kdbmain.c (kdb_md): Add mdr command. + + * Release as kdb v1.5 against 2.4.0-test9-pre8. + + * arch/i386/kdb/kdba_io.c, arch/i386/kdb/kdbasupport.c, kdb/kdbmain.c, + kdb/kdb_io.c, kdb/kdb_id.c: Remove zero initializers for static + variables. + +2000-09-28 Keith Owens + + * various: Add nmi_watchdog_source, 1 local APIC, 2 IO-APIC. + Test nmi_watchdog_source instead of nr_ioapics so UP works on SMP hardware. + + * arch/i386/kernel/io_apic.c: Rename setup_nmi to setup_nmi_io for clarity. + + * kdb/kdbmain.c (kdb_parse): Only set NO_WATCHDOG if it was already set. + + * kdb/kdbmain.c (kdb): Clear NO_WATCHDOG on all exit paths. + + * include/linux/kdb.h: Add KDB_REASON_SILENT. + + * kdb/kdbmain.c (kdb_local): Treat reason SILENT as immediate 'go'. + + * kdb/kdbmain.c (kdb_init): Invoke kdb with reason SILENT to instantiate + any breakpoints on boot cpu. + + * arch/i386/kernel/smpboot.c (smp_callin): Invoke kdb with reason SILENT + to instantiate any global breakpoints on this cpu. + + * kdb/kdb_cmds: Remove comment that said initial commands only worked on + boot cpu. + +2000-09-27 Keith Owens + + * arch/i386/kernel/msr.c: Move {rd,wr}msr_eio to include/asm-i386/apic.h. + + * include/asm-i386/apic.h: Define NMI interfaces. + + * kernel/sysctl.c (kern_table): + * kernel/sysctl.c (do_proc_set_nmi_watchdog): + Add /proc/sys/kernel/nmi_watchdog. + + * arch/i386/kernel/apic.c: New routines set_nmi_counter_local, + setup_apic_nmi_watchdog. + + * arch/i386/kernel/traps.c: New routine set_nmi_watchdog(). Call apic + routines to set/clear local apic timer. + +2000-09-26 Keith Owens + + * include/linux/sysctl.h (enum): Add NMI_WATCHDOG. + + * arch/i386/kernel/traps.c (nmi_watchdog_tick): Check nmi_watchdog is + still on. + + * arch/i386/config.in: Add CONFIG_UP_NMI_WATCHDOG. + + * Documentation/Configure.help: Add CONFIG_UP_NMI_WATCHDOG. + + * Documentation/nmi_watchdog.txt: Update for UP NMI watchdog. + +2000-09-25 Keith Owens + + * arch/i386/kernel/apic.c (init_apic_mappings): + * arch/i386/kernel/io_apic.c (IO_APIC_init_uniprocessor): + Merge Keir Fraser's local APIC for uniprocessors patch. + +2000-09-24 Keith Owens + + * Various: Declare initialization routines as __init. + + * Makefile: Define and export AWK. + + * kdb/Makefile: Generate gen-kdb_cmds.c from kdb/kdb_cmds. + + * kdb/kdbmain.c (kdb_init): Call new routine kdb_cmds_init to execute + whatever the user put in kdb/kdb_cmds. + + * arch/i386/kdb/kdba_bt.c (kdba_bt_stack): New parameter to + indicate if esp in regs is known to be valid or not. + + * kdb/kdb_bp.c, arch/i386/kdb/kdba_bp.c: More trace prints for + breakpoint handling. + + * arch/i386/kdb/kdba_bp.c (kdba_installbp): Finally found and fixed the + annoying breakpoint bug where breakpoints where not always installed + after 'go'. + + * Documentation/kdb: Update man pages kdb.mm, kdb_env.man, kdb_ss.man. + + * Released as kdb-v1.5-beta1-2.4.0-test8. + + * Sync to 2.4.0-test9-pre6 and release as kdb-v1.5-beta1-2.4.0-test9-pre6. + +2000-09-23 Keith Owens + + * arch/i386/kdb/kdbasupport.c (kdba_getregcontents): New pseudo + registers cesp and ceflags to help with debugging the debugger. + + * kdb/kdbmain.c (kdb_local, kdb): Add KDB_REASON_RECURSE. Add + environment variable RECURSE. Add code to cope with some types of + recursion. + + * kdb/kdbmain.c (kdb), arch/i386/kdba/kdba_bp.c: Add + kdba_clearsinglestep. + +2000-09-22 Keith Owens + + * drivers/video/vgacon.c (write_vga): No cli() if kdb is running, avoid + console deadlock. + + * arch/i386/kernel/irq.c (get_irqlock): Warn if kdb is running, may hang. + + * include/linux/kdb.h: Define KDB_IS_RUNNING as (0) if no CONFIG_KDB. + + * arch/i386/kdb/kdba_bt.c (kdba_bt_stack): Do not attempt a backtrace if + the code segment is not in the kernel. + + * kdb/modules: Change modules from MX_OBJS to M_OBJS. Remove EXPORT_NOSYMBOLS. + +2000-09-21 Keith Owens + + * arch/i386/kernel/i386_ksyms.c: Move EXPORT_SYMBOLS for kdb to kdb/kdbmain.c. + + * kdb/Makefile: Change kdb/kdbmain.o from O_OBJS to OX_OBJS. + + * arch/i386/kernel/smp.c: Remove some #ifdef CONFIG_KDB. Remove kdbprivate.h. + + * include/linux/kdb.h: Add kdb_print_state. Add KDB_STATE_WAIT_IPI. + + * kdb/kdbmain.c (kdb): Only mark cpu as leaving if it is in KDB state. Maintain + WAIT_IPI state so a cpu is only driven through NMI once. + + * arch/i386/kernel/smp.c (smp_kdb_stop): All state fiddling moved to kdb(). + +2000-09-20 Keith Owens + + * include/linux/kdb.h: #define kdb() as (0) if kdb is not configured. + + * arch/i386/kernel/traps.c: Remove some #ifdef CONFIG_KDB. + + * include/linux/kdbprivate.h: Move per cpu state to kdb.h. + + * include/linux/kdb.h: Add KDB_STATE_NO_WATCHDOG, KDB_STATE_PRINTF_LOCK. + Rename KDB_DEBUG_xxx to KDB_DEBUG_FLAG_xxx. Clean up debug flag + definitions. + + * arch/i386/kernel/traps.c (nmi_watchdog_tick): Check no watchdog. + + * kdb/kdbmain.c (kdb): Set no watchdog in normal kdb code. + + * kdb/kdbmain.c (kdb_parse): Allow watchdog in commands. + + * kdb/kdb_io.c (kdb_printf): No watchdog during printing. Clean up lock handling. + + * kdb/kdbmain.c (kdb_set): Clean up debug flag handling. + +2000-09-19 Juan J. Quintela + + * kdb/arch/i386/kdb/kdba_io.c: Allow kdb to compile without CONFIG_VT and/or + serial console. + +2000-09-19 Keith Owens + + * include/linux/kdb.h: Define KDB_DEBUG_STATE(). + + * kdb/kdbmain.c (kdb): Add kdb_print_state(), calls to KDB_DEBUG_STATE(). + +2000-09-16 Keith Owens + + * Move to finer grained control over individual processors in kdb with + per cpu kdb state. Needed to allow ss[b] to only release one processor, + previously ss[b] released all processors. Also need to recover from + errors inside kdb commands, e.g. oops in kdbm_pg code. + + * various: + Move global flags KDB_FLAG_SSB, KDB_FLAG_SUPRESS, KDB_FLAG_FAULT, + KDB_FLAG_SS, KDB_FLAG_SSBPT, kdb_active, to per cpu state and macros + KDB_STATE(xxx). + Replace kdb_flags & KDB_FLAG_xxx with KDB_FLAG(xxx). + Replace kdb_flags & KDB_DEBUG_xxx with KDB_DEBUG(xxx). + Replace specific tests with wrapper KDB_IS_RUNNING(). + + * various: Remove #ifdef CONFIG_SMP from kdb code wherever + possible. Simplifies the code and makes it much more readable. + + * arch/i386/kdb/kdbasupport.c (kdb_setjmp): Record if we have reliable + longjmp data instead of assuming it is always set. + + * various: Replace smp_kdb_wait with per cpu state, HOLD_CPU. + + * init/main.c : Replace #ifdef KDB_DEBUG with KDB_DEBUG(CALLBACK). + + * include/linux/kdbprivate.h: Separate command return codes from error + codes. Add more detailed command codes. + + * arch/i386/kernel/traps.c (die): Change spin_lock_irq to + spin_lock_irqsave. Why did I do this? + + * kdb/kdbmain.c (kdb_parse): Set per cpu flag CMD before executing kdb + command. More detailed return codes for commands that affect + processors. + + * kdb/kdbmain.c (kdb_previous_event): New, check if any processors are + still executing the previous kdb event. Removes a race window where a + second event could enter kdb before the first had completely ended. + + * kdb/kdbmain.c (kdb): Document all the concurrency conditions and how + kdb handles them. ss[b] now releases only the current cpu. Do not set + breakpoints when releasing for ss[b]. Recover from errors in kdb + commands. Check that we have reliable longjmp data before using it. + + * various: Update return code documentation. + + * kdb/kdb_bp.c (kdb_ss): Separate ss and ssb return codes. + + * kdb/kdbsupport.c (kdb_ipi): Finer grained algorithm for deciding + whether to call send a stop signal to a cpu. + + * arch/i386/kdb/kdba_bp.c (kdba_db_trap): Separate ss and ssb return + codes. Reinstall delayed software breakpoints per cpu instead of + globally. Changed algorithm for handling ss[b]. + + * arch/i386/kdb/kdba_bp.c (kdba_bp_trap): Match software breakpoints per + cpu instead of globally. + + * include/linux/kdb.h: Bump version to kdb v1.5. + +2000-09-16 Keith Owens + + * kernel/sysctl.c (kern_table): add /proc/sys/kernel/kdb. + + * init/main.c (parse_options): add boot flags kdb=on, kdb=off, + kdb=early. + + * include/linux/sysctl.h (enum): add KERN_KDB. + + * drivers/char/serial.c (receive_chars): check kdb_on. + + * drivers/char/keyboard.c (handle_scancode): check kdb_on. + + * arch/i386/kernel/traps.c (nmi_watchdog_tick): check kdb_on. + + * arch/i386/config.in: add CONFIG_KDB_OFF. + + * Documentation/Configure.help: add CONFIG_KDB_OFF. + + * kdb/kdbmain.c: add kdb_initial_cpu, kdb_on. + + * kdb/kdbmain.c (kdb): check kdb_on, set kdb_initial_cpu. + + * kdb/kdbmain.c (kdb_init): add Keith Owens to kdb banner. + + * kdb/kdb_io.c (kdb_printf): serialize kdb_printf output. + + * kdb/kdb_bt.c (kdb_bt): check environment variable BTAPROMPT. + + * kdb/kdbsupport.c (kdb_ipi): ignore NMI for kdb_initial_cpu. + + * kdb/modules/kdbm_pg.c (kdbm_page): merge updates from 2.4.0-test5-xfs. + + * kdb/kdb_bt.man: add btp, bta, BTAPROMPT. + + * kdb/kdb.mm: add CONFIG_KDB_OFF, boot flags, btp, bta. + + * include/linux/kdbprivate.h: add kdb_initial_cpu. + + * include/linux/kdb.h: add kdb_on, bump version to kdb v1.4. Index: 2.6.x-xfs/kdb/Makefile =================================================================== --- 2.6.x-xfs.orig/kdb/Makefile 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/Makefile 2006-02-28 11:26:53.516736304 +1100 @@ -0,0 +1,28 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. +# + +obj-y := kdb_bt.o kdb_bp.o kdb_id.o kdbsupport.o gen-kdb_cmds.o kdbmain.o kdb_io.o + +subdir-$(CONFIG_KDB_MODULES) := modules +obj-y += $(addsuffix /built-in.o, $(subdir-y)) + +clean-files := gen-kdb_cmds.c + +override CFLAGS := $(CFLAGS:%-pg=% ) + +quiet_cmd_gen-kdb = GENKDB $@ + cmd_gen-kdb = $(AWK) 'BEGIN {print "\#include "} \ + /^\#/{next} \ + /^[ \t]*$$/{next} \ + {gsub(/"/, "\\\"", $$0); \ + print "static __initdata char kdb_cmd" cmds++ "[] = \"" $$0 "\\n\";"} \ + END {print "char __initdata *kdb_cmds[] = {"; for (i = 0; i < cmds; ++i) {print " kdb_cmd" i ","}; print(" 0\n};");}' \ + $(filter-out %/Makefile,$^) > $@ + +$(obj)/gen-kdb_cmds.c: $(src)/kdb_cmds $(wildcard $(TOPDIR)/arch/$(ARCH)/kdb/kdb_cmds) $(src)/Makefile + $(call cmd,gen-kdb) Index: 2.6.x-xfs/kdb/kdb_bp.c =================================================================== --- 2.6.x-xfs.orig/kdb/kdb_bp.c 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/kdb_bp.c 2006-02-28 11:26:53.517712733 +1100 @@ -0,0 +1,623 @@ +/* + * Kernel Debugger Architecture Independent Breakpoint Handler + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Table of kdb_breakpoints + */ +kdb_bp_t kdb_breakpoints[KDB_MAXBPT]; + +/* + * kdb_bp_install_global + * + * Install global kdb_breakpoints prior to returning from the + * kernel debugger. This allows the kdb_breakpoints to be set + * upon functions that are used internally by kdb, such as + * printk(). + * + * Parameters: + * regs Execution frame. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + * This function is only called once per kdb session. + */ + +void +kdb_bp_install_global(struct pt_regs *regs) +{ + int i; + + for(i=0; i=0; i--) { + if (KDB_DEBUG(BP)) { + kdb_printf("kdb_bp_remove_global bp %d bp_enabled %d bp_global %d\n", + i, kdb_breakpoints[i].bp_enabled, kdb_breakpoints[i].bp_global); + } + if (kdb_breakpoints[i].bp_enabled + && kdb_breakpoints[i].bp_global) { + kdba_removebp(&kdb_breakpoints[i]); + } + } +} + + +/* + * kdb_bp_remove_local + * + * Remove local kdb_breakpoints upon entry to the kernel debugger. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdb_bp_remove_local(void) +{ + int i; + + for(i=KDB_MAXBPT-1; i>=0; i--) { + if (KDB_DEBUG(BP)) { + kdb_printf("kdb_bp_remove_local bp %d bp_enabled %d bp_global %d cpu %d bp_cpu %d\n", + i, kdb_breakpoints[i].bp_enabled, kdb_breakpoints[i].bp_global, + smp_processor_id(), kdb_breakpoints[i].bp_cpu); + } + if (kdb_breakpoints[i].bp_enabled + && kdb_breakpoints[i].bp_cpu == smp_processor_id() + && !kdb_breakpoints[i].bp_global){ + kdba_removebp(&kdb_breakpoints[i]); + } + } +} + +/* + * kdb_printbp + * + * Internal function to format and print a breakpoint entry. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +static void +kdb_printbp(kdb_bp_t *bp, int i) +{ + if (bp->bp_forcehw) { + kdb_printf("Forced "); + } + + if (!bp->bp_template.bph_free) { + kdb_printf("%s ", kdba_bptype(&bp->bp_template)); + } else { + kdb_printf("Instruction(i) "); + } + + kdb_printf("BP #%d at ", i); + kdb_symbol_print(bp->bp_addr, NULL, KDB_SP_DEFAULT); + + if (bp->bp_enabled) { + kdba_printbp(bp); + if (bp->bp_global) + kdb_printf(" globally"); + else + kdb_printf(" on cpu %d", bp->bp_cpu); + if (bp->bp_adjust) + kdb_printf(" adjust %d", bp->bp_adjust); + } else { + kdb_printf("\n is disabled"); + } + + kdb_printf("\n"); +} + +/* + * kdb_bp + * + * Handle the bp, and bpa commands. + * + * [bp|bpa|bph] [DATAR|DATAW|IO [length]] + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + * + * bp Set breakpoint. Only use hardware assist if necessary. + * bpa Set breakpoint on all cpus, only use hardware regs if necessary + * bph Set breakpoint - force hardware register + * bpha Set breakpoint on all cpus, force hardware register + */ + +static int +kdb_bp(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i, bpno; + kdb_bp_t *bp, *bp_check; + int diag; + int free; + kdb_machreg_t addr; + char *symname = NULL; + long offset = 0ul; + int nextarg; + int hardware; + int global; + + if (argc == 0) { + /* + * Display breakpoint table + */ + for(bpno=0,bp=kdb_breakpoints; bpnobp_free) continue; + + kdb_printbp(bp, bpno); + } + + return 0; + } + + global = ((strcmp(argv[0], "bpa") == 0) + || (strcmp(argv[0], "bpha") == 0)); + hardware = ((strcmp(argv[0], "bph") == 0) + || (strcmp(argv[0], "bpha") == 0)); + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, &symname, regs); + if (diag) + return diag; + if (!addr) + return KDB_BADINT; + + /* + * Allocate a new bp structure + */ + free = KDB_MAXBPT; + for(bpno=0,bp=kdb_breakpoints; bpnobp_free) { + break; + } + } + + if (bpno == KDB_MAXBPT) + return KDB_TOOMANYBPT; + + memset(bp, 0, sizeof(*bp)); + bp->bp_free = 1; + kdba_check_pc(&addr); + for(i=0,bp_check=kdb_breakpoints; ibp_free && bp_check->bp_addr == addr) { + kdb_printf("You already have a breakpoint at " kdb_bfd_vma_fmt0 "\n", addr); + return KDB_DUPBPT; + } + } + bp->bp_addr = addr; + bp->bp_free = 0; + + bp->bp_forcehw = hardware; + if (KDB_DEBUG(BP)) + kdb_printf("kdb_bp: forcehw is %d hardware is %d\n", bp->bp_forcehw, hardware); + + /* + * Handle architecture dependent parsing + */ + diag = kdba_parsebp(argc, argv, &nextarg, bp); + if (diag) { + return diag; + } + + bp->bp_enabled = 1; + bp->bp_global = 1; /* Most breakpoints are global */ + + if (hardware && !global) { + bp->bp_global = 0; + bp->bp_cpu = smp_processor_id(); + } + + /* + * Allocate a hardware breakpoint. If one is not available, + * disable the breakpoint, but leave it in the breakpoint + * table. When the breakpoint is re-enabled (via 'be'), we'll + * attempt to allocate a hardware register for it. + */ + if (!bp->bp_template.bph_free) { + bp->bp_hard = kdba_allocbp(&bp->bp_template, &diag); + if (diag) { + bp->bp_enabled = 0; + return diag; + } + bp->bp_hardtype = 1; + } + + kdb_printbp(bp, bpno); + + return 0; +} + +/* + * kdb_bc + * + * Handles the 'bc', 'be', and 'bd' commands + * + * [bd|bc|be] + * [bd|bc|be] * + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + */ + +#define KDBCMD_BC 0 +#define KDBCMD_BE 1 +#define KDBCMD_BD 2 + +static int +kdb_bc(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdb_machreg_t addr; + kdb_bp_t *bp = 0; + int lowbp = KDB_MAXBPT; + int highbp = 0; + int done = 0; + int i; + int diag; + int cmd; /* KDBCMD_B? */ + + if (strcmp(argv[0], "be") == 0) { + cmd = KDBCMD_BE; + } else if (strcmp(argv[0], "bd") == 0) { + cmd = KDBCMD_BD; + } else + cmd = KDBCMD_BC; + + if (argc != 1) + return KDB_ARGCOUNT; + + if (strcmp(argv[1], "*") == 0) { + lowbp = 0; + highbp = KDB_MAXBPT; + } else { + diag = kdbgetularg(argv[1], &addr); + if (diag) + return diag; + + /* + * For addresses less than the maximum breakpoint number, + * assume that the breakpoint number is desired. + */ + if (addr < KDB_MAXBPT) { + bp = &kdb_breakpoints[addr]; + lowbp = highbp = addr; + highbp++; + } else { + for(i=0, bp=kdb_breakpoints; ibp_addr == addr) { + lowbp = highbp = i; + highbp++; + break; + } + } + } + } + + /* + * Now operate on the set of breakpoints matching the input + * criteria (either '*' for all, or an individual breakpoint). + */ + for(bp=&kdb_breakpoints[lowbp], i=lowbp; + i < highbp; + i++, bp++) { + if (bp->bp_free) + continue; + + done++; + + switch (cmd) { + case KDBCMD_BC: + if (bp->bp_hardtype) { + kdba_freebp(bp->bp_hard); + bp->bp_hard = 0; + bp->bp_hardtype = 0; + } + + bp->bp_enabled = 0; + bp->bp_global = 0; + + kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " cleared\n", + i, bp->bp_addr); + + bp->bp_addr = 0; + bp->bp_free = 1; + + break; + case KDBCMD_BE: + /* + * Allocate a hardware breakpoint. If one is not + * available, don't enable the breakpoint. + */ + if (!bp->bp_template.bph_free + && !bp->bp_hardtype) { + bp->bp_hard = kdba_allocbp(&bp->bp_template, &diag); + if (diag) { + bp->bp_enabled = 0; + return diag; + } + bp->bp_hardtype = 1; + } + + bp->bp_enabled = 1; + + kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " enabled", + i, bp->bp_addr); + + kdb_printf("\n"); + break; + case KDBCMD_BD: + if (!bp->bp_enabled) + break; + + /* + * Since this breakpoint is now disabled, we can + * give up the hardware register which is allocated + * to it. + */ + if (bp->bp_hardtype) { + kdba_freebp(bp->bp_hard); + bp->bp_hard = 0; + bp->bp_hardtype = 0; + } + + bp->bp_enabled = 0; + + kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " disabled\n", + i, bp->bp_addr); + + break; + } + if (bp->bp_delay && (cmd == KDBCMD_BC || cmd == KDBCMD_BD)) { + bp->bp_delay = 0; + KDB_STATE_CLEAR(SSBPT); + } + } + + return (!done)?KDB_BPTNOTFOUND:0; +} + +/* + * kdb_ss + * + * Process the 'ss' (Single Step) and 'ssb' (Single Step to Branch) + * commands. + * + * ss + * ssb + * + * Parameters: + * argc Argument count + * argv Argument vector + * envp Environment vector + * regs Registers at time of entry to kernel debugger + * Outputs: + * None. + * Returns: + * KDB_CMD_SS[B] for success, a kdb error if failure. + * Locking: + * None. + * Remarks: + * + * Set the arch specific option to trigger a debug trap after the next + * instruction. + * + * For 'ssb', set the trace flag in the debug trap handler + * after printing the current insn and return directly without + * invoking the kdb command processor, until a branch instruction + * is encountered. + */ + +static int +kdb_ss(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int ssb = 0; + + ssb = (strcmp(argv[0], "ssb") == 0); + if (argc != 0) + return KDB_ARGCOUNT; + + if (!regs) { + kdb_printf("%s: pt_regs not available\n", __FUNCTION__); + return KDB_BADREG; + } + + /* + * Set trace flag and go. + */ + KDB_STATE_SET(DOING_SS); + if (ssb) + KDB_STATE_SET(DOING_SSB); + + kdba_setsinglestep(regs); /* Enable single step */ + + if (ssb) + return KDB_CMD_SSB; + return KDB_CMD_SS; +} + +/* + * kdb_initbptab + * + * Initialize the breakpoint table. Register breakpoint commands. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void __init +kdb_initbptab(void) +{ + int i; + kdb_bp_t *bp; + + /* + * First time initialization. + */ + memset(&kdb_breakpoints, '\0', sizeof(kdb_breakpoints)); + + for (i=0, bp=kdb_breakpoints; ibp_free = 1; + /* + * The bph_free flag is architecturally required. It + * is set by architecture-dependent code to false (zero) + * in the event a hardware breakpoint register is required + * for this breakpoint. + * + * The rest of the template is reserved to the architecture + * dependent code and _must_ not be touched by the architecture + * independent code. + */ + bp->bp_template.bph_free = 1; + } + + kdb_register_repeat("bp", kdb_bp, "[]", "Set/Display breakpoints", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("bl", kdb_bp, "[]", "Display breakpoints", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("bpa", kdb_bp, "[]", "Set/Display global breakpoints", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("bph", kdb_bp, "[]", "Set hardware breakpoint", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("bpha", kdb_bp, "[]", "Set global hardware breakpoint", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("bc", kdb_bc, "", "Clear Breakpoint", 0, KDB_REPEAT_NONE); + kdb_register_repeat("be", kdb_bc, "", "Enable Breakpoint", 0, KDB_REPEAT_NONE); + kdb_register_repeat("bd", kdb_bc, "", "Disable Breakpoint", 0, KDB_REPEAT_NONE); + + kdb_register_repeat("ss", kdb_ss, "", "Single Step", 1, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("ssb", kdb_ss, "", "Single step to branch/call", 0, KDB_REPEAT_NO_ARGS); + /* + * Architecture dependent initialization. + */ + kdba_initbp(); +} Index: 2.6.x-xfs/kdb/kdb_bt.c =================================================================== --- 2.6.x-xfs.orig/kdb/kdb_bt.c 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/kdb_bt.c 2006-02-28 11:26:53.518689163 +1100 @@ -0,0 +1,182 @@ +/* + * Kernel Debugger Architecture Independent Stack Traceback + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * kdb_bt + * + * This function implements the 'bt' command. Print a stack + * traceback. + * + * bt [] (addr-exp is for alternate stacks) + * btp Kernel stack for + * btt Kernel stack for task structure at + * bta [DRSTCZEUIMA] All useful processes, optionally filtered by state + * btc [] The current process on one cpu, default is all cpus + * + * address expression refers to a return address on the stack. It + * is expected to be preceeded by a frame pointer. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Backtrack works best when the code uses frame pointers. But + * even without frame pointers we should get a reasonable trace. + * + * mds comes in handy when examining the stack to do a manual + * traceback. + */ + +static int +kdb_bt1(const struct task_struct *p, unsigned long mask, int argcount, int btaprompt) +{ + int diag; + char buffer[2]; + /* FIXME: use kdb_verify_area */ + if (kdb_getarea(buffer[0], (unsigned long)p) || + kdb_getarea(buffer[0], (unsigned long)(p+1)-1)) + return KDB_BADADDR; + if (!kdb_task_state(p, mask)) + return 0; + kdb_printf("Stack traceback for pid %d\n", p->pid); + kdb_ps1(p); + diag = kdba_bt_process(p, argcount); + if (btaprompt) { + kdb_getstr(buffer, sizeof(buffer), "Enter to end, to continue:"); + if (buffer[0] == 'q') { + kdb_printf("\n"); + return 1; + } + } + touch_nmi_watchdog(); + return 0; +} + +int +kdb_bt(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int argcount = 5; + int btaprompt = 1; + int nextarg; + unsigned long addr; + long offset; + + kdbgetintenv("BTARGS", &argcount); /* Arguments to print */ + kdbgetintenv("BTAPROMPT", &btaprompt); /* Prompt after each proc in bta */ + + if (strcmp(argv[0], "bta") == 0) { + struct task_struct *g, *p; + unsigned long cpu; + unsigned long mask = kdb_task_state_string(argc ? argv[1] : NULL); + if (argc == 0) + kdb_ps_suppressed(); + /* Run the active tasks first */ + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (!cpu_online(cpu)) + continue; + p = kdb_curr_task(cpu); + if (kdb_bt1(p, mask, argcount, btaprompt)) + return 0; + } + /* Now the inactive tasks */ + kdb_do_each_thread(g, p) { + if (task_curr(p)) + continue; + if (kdb_bt1(p, mask, argcount, btaprompt)) + return 0; + } kdb_while_each_thread(g, p); + } else if (strcmp(argv[0], "btp") == 0) { + struct task_struct *p; + unsigned long pid; + if (argc != 1) + return KDB_ARGCOUNT; + if ((diag = kdbgetularg((char *)argv[1], &pid))) + return diag; + if ((p = find_task_by_pid(pid))) { + kdba_set_current_task(p); + return kdb_bt1(p, ~0UL, argcount, 0); + } + kdb_printf("No process with pid == %ld found\n", pid); + return 0; + } else if (strcmp(argv[0], "btt") == 0) { + unsigned long addr; + if (argc != 1) + return KDB_ARGCOUNT; + if ((diag = kdbgetularg((char *)argv[1], &addr))) + return diag; + kdba_set_current_task((struct task_struct *)addr); + return kdb_bt1((struct task_struct *)addr, ~0UL, argcount, 0); + } else if (strcmp(argv[0], "btc") == 0) { + unsigned long cpu = ~0; + struct kdb_running_process *krp; + const struct task_struct *save_current_task = kdb_current_task; + char buf[80]; + if (argc > 1) + return KDB_ARGCOUNT; + if (argc == 1 && (diag = kdbgetularg((char *)argv[1], &cpu))) + return diag; + /* Recursive use of kdb_parse, do not use argv after this point */ + argv = NULL; + if (cpu != ~0) { + krp = kdb_running_process + cpu; + if (cpu >= NR_CPUS || !krp->seqno || !cpu_online(cpu)) { + kdb_printf("no process for cpu %ld\n", cpu); + return 0; + } + sprintf(buf, "btt 0x%p\n", krp->p); + kdb_parse(buf, regs); + return 0; + } + kdb_printf("btc: cpu status: "); + kdb_parse("cpu\n", regs); + for (cpu = 0, krp = kdb_running_process; cpu < NR_CPUS; ++cpu, ++krp) { + if (!cpu_online(cpu) || !krp->seqno) + continue; + sprintf(buf, "btt 0x%p\n", krp->p); + kdb_parse(buf, regs); + touch_nmi_watchdog(); + } + kdba_set_current_task(save_current_task); + return 0; + } else { + if (argc) { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, + &offset, NULL, regs); + if (diag) + return diag; + return kdba_bt_address(addr, argcount); + } else { + return kdb_bt1(kdb_current_task, ~0UL, argcount, 0); + } + } + + /* NOTREACHED */ + return 0; +} Index: 2.6.x-xfs/kdb/kdb_cmds =================================================================== --- 2.6.x-xfs.orig/kdb/kdb_cmds 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/kdb_cmds 2006-02-28 11:26:53.519665593 +1100 @@ -0,0 +1,32 @@ +# Initial commands for kdb, alter to suit your needs. +# These commands are executed in kdb_init() context, no SMP, no +# processes. Commands that require process data (including stack or +# registers) are not reliable this early. set and bp commands should +# be safe. Global breakpoint commands affect each cpu as it is booted. + +# Standard debugging information for first level support, just type archkdb +# or archkdbcpu or archkdbshort at the kdb prompt. + +defcmd archkdb "" "First line arch debugging" + set BTSYMARG 1 + set BTARGS 5 + pid R + -archkdbcommon + -bta +endefcmd + +defcmd archkdbcpu "" "archkdb with only tasks on cpus" + set BTSYMARG 1 + set BTARGS 5 + pid R + -archkdbcommon + -btc +endefcmd + +defcmd archkdbshort "" "archkdb with less detailed backtrace" + set BTSYMARG 0 + set BTARGS 0 + pid R + -archkdbcommon + -bta +endefcmd Index: 2.6.x-xfs/kdb/kdb_id.c =================================================================== --- 2.6.x-xfs.orig/kdb/kdb_id.c 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/kdb_id.c 2006-02-28 11:26:53.519665593 +1100 @@ -0,0 +1,239 @@ +/* + * Kernel Debugger Architecture Independent Instruction Disassembly + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +disassemble_info kdb_di; + +/* + * kdb_id + * + * Handle the id (instruction display) command. + * + * id [] + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + */ + +int +kdb_id(int argc, const char **argv, const char **envp, struct pt_regs* regs) +{ + kdb_machreg_t pc; + int icount; + int diag; + int i; + char *mode; + int nextarg; + long offset = 0; + static kdb_machreg_t lastpc; + struct disassemble_info *dip = &kdb_di; + char lastbuf[50]; + unsigned long word; + + if (argc != 1) { + if (lastpc == 0) { + return KDB_ARGCOUNT; + } else { + sprintf(lastbuf, "0x%lx", lastpc); + argv[1] = lastbuf; + argc = 1; + } + } + + + /* + * Fetch PC. First, check to see if it is a symbol, if not, + * try address. + */ + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &pc, &offset, NULL, regs); + if (diag) + return diag; + kdba_check_pc(&pc); + if (kdb_getarea(word, pc)) + return(0); + + /* + * Number of lines to display + */ + diag = kdbgetintenv("IDCOUNT", &icount); + if (diag) + return diag; + + dip->fprintf_dummy = kdb_dis_fprintf; + + mode = kdbgetenv("IDMODE"); + diag = kdba_id_parsemode(mode, dip); + if (diag) { + return diag; + } + + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_SPARC64 +#include +#else +static struct console *kdbcons; +#endif + +#ifdef CONFIG_PPC64 +#include +#endif + +#define CMD_BUFLEN 256 +char kdb_prompt_str[CMD_BUFLEN]; + +/* + * kdb_read + * + * This function reads a string of characters, terminated by + * a newline, or by reaching the end of the supplied buffer, + * from the current kernel debugger console device. + * Parameters: + * buffer - Address of character buffer to receive input characters. + * bufsize - size, in bytes, of the character buffer + * Returns: + * Returns a pointer to the buffer containing the received + * character string. This string will be terminated by a + * newline character. + * Locking: + * No locks are required to be held upon entry to this + * function. It is not reentrant - it relies on the fact + * that while kdb is running on any one processor all other + * processors will be spinning at the kdb barrier. + * Remarks: + * + * Davidm asks, why doesn't kdb use the console abstraction; + * here are some reasons: + * - you cannot debug the console abstraction with kdb if + * kdb uses it. + * - you rely on the correct functioning of the abstraction + * in the presence of general system failures. + * - You must acquire the console spinlock thus restricting + * the usability - what if the kernel fails with the spinlock + * held - one still wishes to debug such situations. + * - How about debugging before the console(s) are registered? + * - None of the current consoles (sercons, vt_console_driver) + * have read functions defined. + * - The standard pc keyboard and terminal drivers are interrupt + * driven. We cannot enable interrupts while kdb is active, + * so the standard input functions cannot be used by kdb. + * + * An implementation could be improved by removing the need for + * lock acquisition - just keep a 'struct console *kdbconsole;' global + * variable which refers to the preferred kdb console. + * + * The bulk of this function is architecture dependent. + * + * The buffer size must be >= 2. A buffer size of 2 means that the caller only + * wants a single key. + * + * An escape key could be the start of a vt100 control sequence such as \e[D + * (left arrow) or it could be a character in its own right. The standard + * method for detecting the difference is to wait for 2 seconds to see if there + * are any other characters. kdb is complicated by the lack of a timer service + * (interrupts are off), by multiple input sources and by the need to sometimes + * return after just one key. Escape sequence processing has to be done as + * states in the polling loop. + */ + +char * +kdb_read(char *buffer, size_t bufsize) +{ + char *cp = buffer; + char *bufend = buffer+bufsize-2; /* Reserve space for newline and null byte */ + + char *lastchar; + char *p_tmp; + char tmp; + static char tmpbuffer[CMD_BUFLEN]; + int len = strlen(buffer); + int len_tmp; + int tab=0; + int count; + int i; + int diag, dtab_count; + +#define ESCAPE_UDELAY 1000 +#define ESCAPE_DELAY 2*1000000/ESCAPE_UDELAY /* 2 seconds worth of udelays */ + char escape_data[5]; /* longest vt100 escape sequence is 4 bytes */ + char *ped = escape_data; + int escape_delay = 0; + get_char_func *f, *f_escape = NULL; + + diag = kdbgetintenv("DTABCOUNT",&dtab_count); + if (diag) + dtab_count = 30; + + if (len > 0 ) { + cp += len; + if (*(buffer+len-1) == '\n') + cp--; + } + + lastchar = cp; + *cp = '\0'; + kdb_printf("%s", buffer); + + for (;;) { + int key; + for (f = &poll_funcs[0]; ; ++f) { + if (*f == NULL) { + /* Reset NMI watchdog once per poll loop */ + touch_nmi_watchdog(); + f = &poll_funcs[0]; + } + if (escape_delay == 2) { + *ped = '\0'; + ped = escape_data; + --escape_delay; + } + if (escape_delay == 1) { + key = *ped++; + if (!*ped) + --escape_delay; + break; + } + key = (*f)(); + if (key == -1) { + if (escape_delay) { + udelay(ESCAPE_UDELAY); + --escape_delay; + } + continue; + } + if (bufsize <= 2) { + if (key == '\r') + key = '\n'; + kdb_printf("%c", key); + *buffer++ = key; + *buffer = '\0'; + return buffer; + } + if (escape_delay == 0 && key == '\e') { + escape_delay = ESCAPE_DELAY; + ped = escape_data; + f_escape = f; + } + if (escape_delay) { + *ped++ = key; + if (f_escape != f) { + escape_delay = 2; + continue; + } + if (ped - escape_data == 1) { + /* \e */ + continue; + } + else if (ped - escape_data == 2) { + /* \e */ + if (key != '[') + escape_delay = 2; + continue; + } else if (ped - escape_data == 3) { + /* \e[ */ + int mapkey = 0; + switch (key) { + case 'A': mapkey = 16; break; /* \e[A, up arrow */ + case 'B': mapkey = 14; break; /* \e[B, down arrow */ + case 'C': mapkey = 6; break; /* \e[C, right arrow */ + case 'D': mapkey = 2; break; /* \e[D, left arrow */ + case '1': /* dropthrough */ + case '3': /* dropthrough */ + case '4': mapkey = -1; break; /* \e[<1,3,4>], may be home, del, end */ + } + if (mapkey != -1) { + if (mapkey > 0) { + escape_data[0] = mapkey; + escape_data[1] = '\0'; + } + escape_delay = 2; + } + continue; + } else if (ped - escape_data == 4) { + /* \e[<1,3,4> */ + int mapkey = 0; + if (key == '~') { + switch (escape_data[2]) { + case '1': mapkey = 1; break; /* \e[1~, home */ + case '3': mapkey = 4; break; /* \e[3~, del */ + case '4': mapkey = 5; break; /* \e[4~, end */ + } + } + if (mapkey > 0) { + escape_data[0] = mapkey; + escape_data[1] = '\0'; + } + escape_delay = 2; + continue; + } + } + break; /* A key to process */ + } + + if (key != 9) + tab = 0; + switch (key) { + case 8: /* backspace */ + if (cp > buffer) { + if (cp < lastchar) { + memcpy(tmpbuffer, cp, lastchar - cp); + memcpy(cp-1, tmpbuffer, lastchar - cp); + } + *(--lastchar) = '\0'; + --cp; + kdb_printf("\b%s \r", cp); + tmp = *cp; + *cp = '\0'; + kdb_printf(kdb_prompt_str); + kdb_printf("%s", buffer); + *cp = tmp; + } + break; + case 13: /* enter */ + *lastchar++ = '\n'; + *lastchar++ = '\0'; + kdb_printf("\n"); + return buffer; + case 4: /* Del */ + if(cp < lastchar) { + memcpy(tmpbuffer, cp+1, lastchar - cp -1); + memcpy(cp, tmpbuffer, lastchar - cp -1); + *(--lastchar) = '\0'; + kdb_printf("%s \r", cp); + tmp = *cp; + *cp = '\0'; + kdb_printf(kdb_prompt_str); + kdb_printf("%s", buffer); + *cp = tmp; + } + break; + case 1: /* Home */ + if(cp > buffer) { + kdb_printf("\r"); + kdb_printf(kdb_prompt_str); + cp = buffer; + } + break; + case 5: /* End */ + if(cp < lastchar) { + kdb_printf("%s", cp); + cp = lastchar; + } + break; + case 2: /* Left */ + if (cp > buffer) { + kdb_printf("\b"); + --cp; + } + break; + case 14: /* Down */ + memset(tmpbuffer, ' ', strlen(kdb_prompt_str)+(lastchar-buffer)); + *(tmpbuffer+strlen(kdb_prompt_str)+(lastchar-buffer)) = '\0'; + kdb_printf("\r%s\r", tmpbuffer); + *lastchar = (char)key; + *(lastchar+1) = '\0'; + return lastchar; + case 6: /* Right */ + if (cp < lastchar) { + kdb_printf("%c", *cp); + ++cp; + } + break; + case 16: /* Up */ + memset(tmpbuffer, ' ', strlen(kdb_prompt_str)+(lastchar-buffer)); + *(tmpbuffer+strlen(kdb_prompt_str)+(lastchar-buffer)) = '\0'; + kdb_printf("\r%s\r", tmpbuffer); + *lastchar = (char)key; + *(lastchar+1) = '\0'; + return lastchar; + case 9: /* Tab */ + if (tab < 2) + ++tab; + p_tmp = buffer; + while(*p_tmp==' ') p_tmp++; + if (p_tmp<=cp) { + memcpy(tmpbuffer, p_tmp, cp-p_tmp); + *(tmpbuffer + (cp-p_tmp)) = '\0'; + p_tmp = strrchr(tmpbuffer, ' '); + if (p_tmp) + ++p_tmp; + else + p_tmp = tmpbuffer; + len = strlen(p_tmp); + count = kallsyms_symbol_complete(p_tmp, sizeof(tmpbuffer) - (p_tmp - tmpbuffer)); + if (tab == 2) { + if (count > 0) { + kdb_printf("\n%d symbols are found.", count); + if(count>dtab_count) { + count=dtab_count; + kdb_printf(" But only first %d symbols will be printed.\nYou can change the environment variable DTABCOUNT.", count); + } + kdb_printf("\n"); + for(i=0;i=dtab_count)kdb_printf("..."); + kdb_printf("\n"); + kdb_printf(kdb_prompt_str); + kdb_printf("%s", buffer); + } + } + else { + if (count > 0) { + len_tmp = strlen(p_tmp); + strncpy(p_tmp+len_tmp,cp, lastchar-cp+1); + len_tmp = strlen(p_tmp); + strncpy(cp, p_tmp+len, len_tmp-len+1); + len = len_tmp - len; + kdb_printf("%s", cp); + cp+=len; + lastchar+=len; + } + } + kdb_nextline = 1; /* reset output line number */ + } + break; + default: + if (key >= 32 &&lastchar < bufend) { + if (cp < lastchar) { + memcpy(tmpbuffer, cp, lastchar - cp); + memcpy(cp+1, tmpbuffer, lastchar - cp); + } + *(++lastchar) = '\0'; + *cp = key; + kdb_printf("%s\r", cp); + ++cp; + tmp = *cp; + *cp = '\0'; + kdb_printf(kdb_prompt_str); + kdb_printf("%s", buffer); + *cp = tmp; + } + break; + } + } +} + +/* + * kdb_getstr + * + * Print the prompt string and read a command from the + * input device. + * + * Parameters: + * buffer Address of buffer to receive command + * bufsize Size of buffer in bytes + * prompt Pointer to string to use as prompt string + * Returns: + * Pointer to command buffer. + * Locking: + * None. + * Remarks: + * For SMP kernels, the processor number will be + * substituted for %d, %x or %o in the prompt. + */ + +char * +kdb_getstr(char *buffer, size_t bufsize, char *prompt) +{ + if(prompt && kdb_prompt_str!=prompt) + strncpy(kdb_prompt_str, prompt, CMD_BUFLEN); + kdb_printf(kdb_prompt_str); + kdb_nextline = 1; /* Prompt and input resets line number */ + return kdb_read(buffer, bufsize); +} + +/* + * kdb_input_flush + * + * Get rid of any buffered console input. + * + * Parameters: + * none + * Returns: + * nothing + * Locking: + * none + * Remarks: + * Call this function whenever you want to flush input. If there is any + * outstanding input, it ignores all characters until there has been no + * data for approximately half a second. + */ + +#define FLUSH_UDELAY 100 +#define FLUSH_DELAY 500000/FLUSH_UDELAY /* 0.5 seconds worth of udelays */ + +static void +kdb_input_flush(void) +{ + get_char_func *f; + int flush_delay = 1; + while (flush_delay--) { + touch_nmi_watchdog(); + for (f = &poll_funcs[0]; *f; ++f) { + if ((*f)() != -1) { + flush_delay = FLUSH_DELAY; + break; + } + } + if (flush_delay) + udelay(FLUSH_UDELAY); + } +} + +/* + * kdb_printf + * + * Print a string to the output device(s). + * + * Parameters: + * printf-like format and optional args. + * Returns: + * 0 + * Locking: + * None. + * Remarks: + * use 'kdbcons->write()' to avoid polluting 'log_buf' with + * kdb output. + */ + +static char kdb_buffer[256]; /* A bit too big to go on stack */ + +void +kdb_printf(const char *fmt, ...) +{ + va_list ap; + int diag; + int linecount; + int logging, saved_loglevel = 0; + int do_longjmp = 0; + int got_printf_lock = 0; + struct console *c = console_drivers; + static DEFINE_SPINLOCK(kdb_printf_lock); + + preempt_disable(); + /* Serialize kdb_printf if multiple cpus try to write at once. + * But if any cpu goes recursive in kdb, just print the output, + * even if it is interleaved with any other text. + */ + if (!KDB_STATE(PRINTF_LOCK)) { + KDB_STATE_SET(PRINTF_LOCK); + spin_lock(&kdb_printf_lock); + got_printf_lock = 1; + atomic_inc(&kdb_event); + } + + diag = kdbgetintenv("LINES", &linecount); + if (diag || linecount <= 1) + linecount = 22; + + diag = kdbgetintenv("LOGGING", &logging); + if (diag) + logging = 0; + + va_start(ap, fmt); + vsnprintf(kdb_buffer, sizeof(kdb_buffer), fmt, ap); + va_end(ap); + + /* + * Write to all consoles. + */ +#ifdef CONFIG_SPARC64 + if (c == NULL) + prom_printf("%s", kdb_buffer); + else +#endif + +#ifdef CONFIG_PPC64 + if (udbg_write) + udbg_write(kdb_buffer, strlen(kdb_buffer)); + else +#endif + + while (c) { + c->write(c, kdb_buffer, strlen(kdb_buffer)); + c = c->next; + } + if (logging) { + saved_loglevel = console_loglevel; + console_loglevel = 0; + printk("%s", kdb_buffer); + } + + if (KDB_STATE(LONGJMP) && strchr(kdb_buffer, '\n')) + kdb_nextline++; + + if (kdb_nextline == linecount) { + char buf1[16]=""; +#if defined(CONFIG_SMP) + char buf2[32]; +#endif + char *moreprompt; + + /* Watch out for recursion here. Any routine that calls + * kdb_printf will come back through here. And kdb_read + * uses kdb_printf to echo on serial consoles ... + */ + kdb_nextline = 1; /* In case of recursion */ + + /* + * Pause until cr. + */ + moreprompt = kdbgetenv("MOREPROMPT"); + if (moreprompt == NULL) { + moreprompt = "more> "; + } + +#if defined(CONFIG_SMP) + if (strchr(moreprompt, '%')) { + sprintf(buf2, moreprompt, get_cpu()); + put_cpu(); + moreprompt = buf2; + } +#endif + + kdb_input_flush(); + c = console_drivers; +#ifdef CONFIG_SPARC64 + if (c == NULL) + prom_printf("%s", moreprompt); + else +#endif + +#ifdef CONFIG_PPC64 + if (udbg_write) + udbg_write(moreprompt, strlen(moreprompt)); + else +#endif + + while (c) { + c->write(c, moreprompt, strlen(moreprompt)); + c = c->next; + } + + if (logging) + printk("%s", moreprompt); + + kdb_read(buf1, 2); /* '2' indicates to return immediately after getting one key. */ + kdb_nextline = 1; /* Really set output line 1 */ + + if ((buf1[0] == 'q') || (buf1[0] == 'Q')) { + do_longjmp = 1; + KDB_FLAG_SET(CMD_INTERRUPT); /* command was interrupted */ + kdb_printf("\n"); + } + else if (buf1[0] && buf1[0] != '\n') { + kdb_printf("\nOnly 'q' or 'Q' are processed at more prompt, input ignored\n"); + } + kdb_input_flush(); + } + + if (logging) { + console_loglevel = saved_loglevel; + } + if (KDB_STATE(PRINTF_LOCK) && got_printf_lock) { + got_printf_lock = 0; + spin_unlock(&kdb_printf_lock); + KDB_STATE_CLEAR(PRINTF_LOCK); + atomic_dec(&kdb_event); + } + preempt_enable(); + if (do_longjmp) +#ifdef KDB_HAVE_LONGJMP + kdba_longjmp(&kdbjmpbuf[smp_processor_id()], 1) +#endif /* KDB_HAVE_LONGJMP */ + ; +} + +/* + * kdb_io_init + * + * Initialize kernel debugger output environment. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * Select a console device. + */ + +void __init +kdb_io_init(void) +{ +#ifndef CONFIG_SPARC64 /* we don't register serial consoles in time */ + /* + * Select a console. + */ + struct console *c = console_drivers; + + while (c) { + if ((c->flags & CON_CONSDEV)) { + kdbcons = c; + break; + } + c = c->next; + } + + if (kdbcons == NULL) { + printk(KERN_ERR "kdb: Initialization failed - no console. kdb is disabled.\n"); + KDB_FLAG_SET(NO_CONSOLE); + kdb_on = 0; + } + kdb_input_flush(); +#endif + return; +} + +EXPORT_SYMBOL(kdb_read); Index: 2.6.x-xfs/kdb/kdbmain.c =================================================================== --- 2.6.x-xfs.orig/kdb/kdbmain.c 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/kdbmain.c 2006-02-28 11:26:53.532359178 +1100 @@ -0,0 +1,4013 @@ +/* + * Kernel Debugger Architecture Independent Main Code + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2000 Stephane Eranian + * Xscale (R) modifications copyright (C) 2003 Intel Corporation. + */ + +/* + * Updated for Xscale (R) architecture support + * Eddie Dong 8 Jan 03 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_LKCD) || defined(CONFIG_LKCD_MODULE) +#include +#endif + +#include +#include + +/* + * Kernel debugger state flags + */ +volatile int kdb_flags; +atomic_t kdb_event; + +/* + * kdb_lock protects updates to kdb_initial_cpu. Used to + * single thread processors through the kernel debugger. + */ +static DEFINE_SPINLOCK(kdb_lock); +volatile int kdb_initial_cpu = -1; /* cpu number that owns kdb */ +int kdb_seqno = 2; /* how many times kdb has been entered */ + +volatile int kdb_nextline = 1; +static volatile int kdb_new_cpu; /* Which cpu to switch to */ + +volatile int kdb_state[NR_CPUS]; /* Per cpu state */ + +const struct task_struct *kdb_current_task; +struct pt_regs *kdb_current_regs; + +#ifdef CONFIG_KDB_OFF +int kdb_on = 0; /* Default is off */ +#else +int kdb_on = 1; /* Default is on */ +#endif /* CONFIG_KDB_OFF */ + +const char *kdb_diemsg; +static int kdb_go_count; +#ifdef CONFIG_KDB_CONTINUE_CATASTROPHIC +static unsigned int kdb_continue_catastrophic = CONFIG_KDB_CONTINUE_CATASTROPHIC; +#else +static unsigned int kdb_continue_catastrophic = 0; +#endif + +#ifdef KDB_HAVE_LONGJMP + /* + * Must have a setjmp buffer per CPU. Switching cpus will + * cause the jump buffer to be setup for the new cpu, and + * subsequent switches (and pager aborts) will use the + * appropriate per-processor values. + */ +kdb_jmp_buf *kdbjmpbuf; +#endif /* KDB_HAVE_LONGJMP */ + + /* + * kdb_commands describes the available commands. + */ +static kdbtab_t *kdb_commands; +static int kdb_max_commands; + +typedef struct _kdbmsg { + int km_diag; /* kdb diagnostic */ + char *km_msg; /* Corresponding message text */ +} kdbmsg_t; + +#define KDBMSG(msgnum, text) \ + { KDB_##msgnum, text } + +static kdbmsg_t kdbmsgs[] = { + KDBMSG(NOTFOUND,"Command Not Found"), + KDBMSG(ARGCOUNT, "Improper argument count, see usage."), + KDBMSG(BADWIDTH, "Illegal value for BYTESPERWORD use 1, 2, 4 or 8, 8 is only allowed on 64 bit systems"), + KDBMSG(BADRADIX, "Illegal value for RADIX use 8, 10 or 16"), + KDBMSG(NOTENV, "Cannot find environment variable"), + KDBMSG(NOENVVALUE, "Environment variable should have value"), + KDBMSG(NOTIMP, "Command not implemented"), + KDBMSG(ENVFULL, "Environment full"), + KDBMSG(ENVBUFFULL, "Environment buffer full"), + KDBMSG(TOOMANYBPT, "Too many breakpoints defined"), +#ifdef CONFIG_CPU_XSCALE + KDBMSG(TOOMANYDBREGS, "More breakpoints than ibcr registers defined"), +#else + KDBMSG(TOOMANYDBREGS, "More breakpoints than db registers defined"), +#endif + KDBMSG(DUPBPT, "Duplicate breakpoint address"), + KDBMSG(BPTNOTFOUND, "Breakpoint not found"), + KDBMSG(BADMODE, "Invalid IDMODE"), + KDBMSG(BADINT, "Illegal numeric value"), + KDBMSG(INVADDRFMT, "Invalid symbolic address format"), + KDBMSG(BADREG, "Invalid register name"), + KDBMSG(BADCPUNUM, "Invalid cpu number"), + KDBMSG(BADLENGTH, "Invalid length field"), + KDBMSG(NOBP, "No Breakpoint exists"), + KDBMSG(BADADDR, "Invalid address"), +}; +#undef KDBMSG + +static const int __nkdb_err = sizeof(kdbmsgs) / sizeof(kdbmsg_t); + + +/* + * Initial environment. This is all kept static and local to + * this file. We don't want to rely on the memory allocation + * mechanisms in the kernel, so we use a very limited allocate-only + * heap for new and altered environment variables. The entire + * environment is limited to a fixed number of entries (add more + * to __env[] if required) and a fixed amount of heap (add more to + * KDB_ENVBUFSIZE if required). + */ + +static char *__env[] = { +#if defined(CONFIG_SMP) + "PROMPT=[%d]kdb> ", + "MOREPROMPT=[%d]more> ", +#else + "PROMPT=kdb> ", + "MOREPROMPT=more> ", +#endif + "RADIX=16", + "LINES=24", + "COLUMNS=80", + "MDCOUNT=8", /* lines of md output */ + "BTARGS=5", /* 5 possible args in bt */ + KDB_PLATFORM_ENV, + "DTABCOUNT=30", + "NOSECT=1", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, +}; + +static const int __nenv = (sizeof(__env) / sizeof(char *)); + +/* + * kdb_serial_str is the sequence that the user must enter on a serial + * console to invoke kdb. It can be a single character such as "\001" + * (control-A) or multiple characters such as "\eKDB". NOTE: All except the + * last character are passed through to the application reading from the serial + * console. + * + * I tried to make the sequence a CONFIG_ option but most of CML1 cannot cope + * with '\' in strings. CML2 would have been able to do it but we lost CML2. + * KAO. + */ +const char kdb_serial_str[] = "\eKDB"; +EXPORT_SYMBOL(kdb_serial_str); + +struct task_struct * +kdb_curr_task(int cpu) +{ + struct task_struct *p = curr_task(cpu); +#ifdef _TIF_MCA_INIT + struct kdb_running_process *krp = kdb_running_process + cpu; + if ((p->thread_info->flags & _TIF_MCA_INIT) && krp->p) + p = krp->p; +#endif + return p; +} + +/* + * kdbgetenv + * + * This function will return the character string value of + * an environment variable. + * + * Parameters: + * match A character string representing an environment variable. + * Outputs: + * None. + * Returns: + * NULL No environment variable matches 'match' + * char* Pointer to string value of environment variable. + * Locking: + * No locking considerations required. + * Remarks: + */ +char * +kdbgetenv(const char *match) +{ + char **ep = __env; + int matchlen = strlen(match); + int i; + + for(i=0; i<__nenv; i++) { + char *e = *ep++; + + if (!e) continue; + + if ((strncmp(match, e, matchlen) == 0) + && ((e[matchlen] == '\0') + ||(e[matchlen] == '='))) { + char *cp = strchr(e, '='); + return (cp ? ++cp :""); + } + } + return NULL; +} + +/* + * kdballocenv + * + * This function is used to allocate bytes for environment entries. + * + * Parameters: + * match A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of the env variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. Must be called with all + * processors halted. + * Remarks: + * We use a static environment buffer (envbuffer) to hold the values + * of dynamically generated environment variables (see kdb_set). Buffer + * space once allocated is never free'd, so over time, the amount of space + * (currently 512 bytes) will be exhausted if env variables are changed + * frequently. + */ +static char * +kdballocenv(size_t bytes) +{ +#define KDB_ENVBUFSIZE 512 + static char envbuffer[KDB_ENVBUFSIZE]; + static int envbufsize; + char *ep = (char *)0; + + if ((KDB_ENVBUFSIZE - envbufsize) >= bytes) { + ep = &envbuffer[envbufsize]; + envbufsize += bytes; + } + return ep; +} + +/* + * kdbgetulenv + * + * This function will return the value of an unsigned long-valued + * environment variable. + * + * Parameters: + * match A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of the env variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +static int +kdbgetulenv(const char *match, unsigned long *value) +{ + char *ep; + + ep = kdbgetenv(match); + if (!ep) return KDB_NOTENV; + if (strlen(ep) == 0) return KDB_NOENVVALUE; + + *value = simple_strtoul(ep, 0, 0); + + return 0; +} + +/* + * kdbgetintenv + * + * This function will return the value of an integer-valued + * environment variable. + * + * Parameters: + * match A character string representing an integer-valued env variable + * Outputs: + * *value the integer representation of the environment variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetintenv(const char *match, int *value) { + unsigned long val; + int diag; + + diag = kdbgetulenv(match, &val); + if (!diag) { + *value = (int) val; + } + return diag; +} + +/* + * kdbgetularg + * + * This function will convert a numeric string + * into an unsigned long value. + * + * Parameters: + * arg A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of arg. + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetularg(const char *arg, unsigned long *value) +{ + char *endp; + unsigned long val; + + val = simple_strtoul(arg, &endp, 0); + + if (endp == arg) { + /* + * Try base 16, for us folks too lazy to type the + * leading 0x... + */ + val = simple_strtoul(arg, &endp, 16); + if (endp == arg) + return KDB_BADINT; + } + + *value = val; + + return 0; +} + +/* + * kdb_set + * + * This function implements the 'set' command. Alter an existing + * environment variable or create a new one. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_set(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + char *ep; + size_t varlen, vallen; + + /* + * we can be invoked two ways: + * set var=value argv[1]="var", argv[2]="value" + * set var = value argv[1]="var", argv[2]="=", argv[3]="value" + * - if the latter, shift 'em down. + */ + if (argc == 3) { + argv[2] = argv[3]; + argc--; + } + + if (argc != 2) + return KDB_ARGCOUNT; + + /* + * Check for internal variables + */ + if (strcmp(argv[1], "KDBDEBUG") == 0) { + unsigned int debugflags; + char *cp; + + debugflags = simple_strtoul(argv[2], &cp, 0); + if (cp == argv[2] || debugflags & ~KDB_DEBUG_FLAG_MASK) { + kdb_printf("kdb: illegal debug flags '%s'\n", + argv[2]); + return 0; + } + kdb_flags = (kdb_flags & ~(KDB_DEBUG_FLAG_MASK << KDB_DEBUG_FLAG_SHIFT)) + | (debugflags << KDB_DEBUG_FLAG_SHIFT); + + return 0; + } + + /* + * Tokenizer squashed the '=' sign. argv[1] is variable + * name, argv[2] = value. + */ + varlen = strlen(argv[1]); + vallen = strlen(argv[2]); + ep = kdballocenv(varlen + vallen + 2); + if (ep == (char *)0) + return KDB_ENVBUFFULL; + + sprintf(ep, "%s=%s", argv[1], argv[2]); + + ep[varlen+vallen+1]='\0'; + + for(i=0; i<__nenv; i++) { + if (__env[i] + && ((strncmp(__env[i], argv[1], varlen)==0) + && ((__env[i][varlen] == '\0') + || (__env[i][varlen] == '=')))) { + __env[i] = ep; + return 0; + } + } + + /* + * Wasn't existing variable. Fit into slot. + */ + for(i=0; i<__nenv-1; i++) { + if (__env[i] == (char *)0) { + __env[i] = ep; + return 0; + } + } + + return KDB_ENVFULL; +} + +/* + * kdbgetaddrarg + * + * This function is responsible for parsing an + * address-expression and returning the value of + * the expression, symbol name, and offset to the caller. + * + * The argument may consist of a numeric value (decimal or + * hexidecimal), a symbol name, a register name (preceeded + * by the percent sign), an environment variable with a numeric + * value (preceeded by a dollar sign) or a simple arithmetic + * expression consisting of a symbol name, +/-, and a numeric + * constant value (offset). + * + * Parameters: + * argc - count of arguments in argv + * argv - argument vector + * *nextarg - index to next unparsed argument in argv[] + * regs - Register state at time of KDB entry + * Outputs: + * *value - receives the value of the address-expression + * *offset - receives the offset specified, if any + * *name - receives the symbol name, if any + * *nextarg - index to next unparsed argument in argv[] + * + * Returns: + * zero is returned on success, a kdb diagnostic code is + * returned on error. + * + * Locking: + * No locking requirements. + * + * Remarks: + * + */ + +int +kdbgetaddrarg(int argc, const char **argv, int *nextarg, + kdb_machreg_t *value, long *offset, + char **name, struct pt_regs *regs) +{ + kdb_machreg_t addr; + long off = 0; + int positive; + int diag; + int found = 0; + char *symname; + char symbol = '\0'; + char *cp; + kdb_symtab_t symtab; + + /* + * Process arguments which follow the following syntax: + * + * symbol | numeric-address [+/- numeric-offset] + * %register + * $environment-variable + */ + + if (*nextarg > argc) { + return KDB_ARGCOUNT; + } + + symname = (char *)argv[*nextarg]; + + /* + * If there is no whitespace between the symbol + * or address and the '+' or '-' symbols, we + * remember the character and replace it with a + * null so the symbol/value can be properly parsed + */ + if ((cp = strpbrk(symname, "+-")) != NULL) { + symbol = *cp; + *cp++ = '\0'; + } + + if (symname[0] == '$') { + diag = kdbgetulenv(&symname[1], &addr); + if (diag) + return diag; + } else if (symname[0] == '%') { + diag = kdba_getregcontents(&symname[1], kdb_current_regs, &addr); + if (diag) + return diag; + } else { + found = kdbgetsymval(symname, &symtab); + if (found) { + addr = symtab.sym_start; + } else { + diag = kdbgetularg(argv[*nextarg], &addr); + if (diag) + return diag; + } + } + + if (!found) + found = kdbnearsym(addr, &symtab); + + (*nextarg)++; + + if (name) + *name = symname; + if (value) + *value = addr; + if (offset && name && *name) + *offset = addr - symtab.sym_start; + + if ((*nextarg > argc) + && (symbol == '\0')) + return 0; + + /* + * check for +/- and offset + */ + + if (symbol == '\0') { + if ((argv[*nextarg][0] != '+') + && (argv[*nextarg][0] != '-')) { + /* + * Not our argument. Return. + */ + return 0; + } else { + positive = (argv[*nextarg][0] == '+'); + (*nextarg)++; + } + } else + positive = (symbol == '+'); + + /* + * Now there must be an offset! + */ + if ((*nextarg > argc) + && (symbol == '\0')) { + return KDB_INVADDRFMT; + } + + if (!symbol) { + cp = (char *)argv[*nextarg]; + (*nextarg)++; + } + + diag = kdbgetularg(cp, &off); + if (diag) + return diag; + + if (!positive) + off = -off; + + if (offset) + *offset += off; + + if (value) + *value += off; + + return 0; +} + +static void +kdb_cmderror(int diag) +{ + int i; + + if (diag >= 0) { + kdb_printf("no error detected\n"); + return; + } + + for(i=0; i<__nkdb_err; i++) { + if (kdbmsgs[i].km_diag == diag) { + kdb_printf("diag: %d: %s\n", diag, kdbmsgs[i].km_msg); + return; + } + } + + kdb_printf("Unknown diag %d\n", -diag); +} + +/* + * kdb_defcmd, kdb_defcmd2 + * + * This function implements the 'defcmd' command which defines one + * command as a set of other commands, terminated by endefcmd. + * kdb_defcmd processes the initial 'defcmd' command, kdb_defcmd2 + * is invoked from kdb_parse for the following commands until + * 'endefcmd'. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +struct defcmd_set { + int count; + int usable; + char *name; + char *usage; + char *help; + char **command; +}; +static struct defcmd_set *defcmd_set; +static int defcmd_set_count; +static int defcmd_in_progress; + +/* Forward references */ +static int kdb_exec_defcmd(int argc, const char **argv, const char **envp, struct pt_regs *regs); + +static int +kdb_defcmd2(const char *cmdstr, const char *argv0) +{ + struct defcmd_set *s = defcmd_set + defcmd_set_count - 1; + char **save_command = s->command; + if (strcmp(argv0, "endefcmd") == 0) { + defcmd_in_progress = 0; + if (!s->count) + s->usable = 0; + if (s->usable) + kdb_register(s->name, kdb_exec_defcmd, s->usage, s->help, 0); + return 0; + } + if (!s->usable) + return KDB_NOTIMP; + s->command = kmalloc((s->count + 1) * sizeof(*(s->command)), GFP_KDB); + if (!s->command) { + kdb_printf("Could not allocate new kdb_defcmd table for %s\n", cmdstr); + s->usable = 0; + return KDB_NOTIMP; + } + memcpy(s->command, save_command, s->count * sizeof(*(s->command))); + s->command[s->count++] = kdb_strdup(cmdstr, GFP_KDB); + kfree(save_command); + return 0; +} + +static int +kdb_defcmd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct defcmd_set *save_defcmd_set = defcmd_set, *s; + if (defcmd_in_progress) { + kdb_printf("kdb: nested defcmd detected, assuming missing endefcmd\n"); + kdb_defcmd2("endefcmd", "endefcmd"); + } + if (argc == 0) { + int i; + for (s = defcmd_set; s < defcmd_set + defcmd_set_count; ++s) { + kdb_printf("defcmd %s \"%s\" \"%s\"\n", s->name, s->usage, s->help); + for (i = 0; i < s->count; ++i) + kdb_printf("%s", s->command[i]); + kdb_printf("endefcmd\n"); + } + return 0; + } + if (argc != 3) + return KDB_ARGCOUNT; + defcmd_set = kmalloc((defcmd_set_count + 1) * sizeof(*defcmd_set), GFP_KDB); + if (!defcmd_set) { + kdb_printf("Could not allocate new defcmd_set entry for %s\n", argv[1]); + defcmd_set = save_defcmd_set; + return KDB_NOTIMP; + } + memcpy(defcmd_set, save_defcmd_set, defcmd_set_count * sizeof(*defcmd_set)); + kfree(save_defcmd_set); + s = defcmd_set + defcmd_set_count; + memset(s, 0, sizeof(*s)); + s->usable = 1; + s->name = kdb_strdup(argv[1], GFP_KDB); + s->usage = kdb_strdup(argv[2], GFP_KDB); + s->help = kdb_strdup(argv[3], GFP_KDB); + if (s->usage[0] == '"') { + strcpy(s->usage, s->usage+1); + s->usage[strlen(s->usage)-1] = '\0'; + } + if (s->help[0] == '"') { + strcpy(s->help, s->help+1); + s->help[strlen(s->help)-1] = '\0'; + } + ++defcmd_set_count; + defcmd_in_progress = 1; + return 0; +} + +/* + * kdb_exec_defcmd + * + * Execute the set of commands associated with this defcmd name. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_exec_defcmd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i, ret; + struct defcmd_set *s; + if (argc != 0) + return KDB_ARGCOUNT; + for (s = defcmd_set, i = 0; i < defcmd_set_count; ++i, ++s) { + if (strcmp(s->name, argv[0]) == 0) + break; + } + if (i == defcmd_set_count) { + kdb_printf("kdb_exec_defcmd: could not find commands for %s\n", argv[0]); + return KDB_NOTIMP; + } + for (i = 0; i < s->count; ++i) { + /* Recursive use of kdb_parse, do not use argv after this point */ + argv = NULL; + kdb_printf("[%s]kdb> %s\n", s->name, s->command[i]); + if ((ret = kdb_parse(s->command[i], regs))) + return ret; + } + return 0; +} + +/* Command history */ +#define KDB_CMD_HISTORY_COUNT 32 +#define CMD_BUFLEN 200 /* kdb_printf: max printline size == 256 */ +static unsigned int cmd_head=0, cmd_tail=0; +static unsigned int cmdptr; +static char cmd_hist[KDB_CMD_HISTORY_COUNT][CMD_BUFLEN]; +static char cmd_cur[CMD_BUFLEN]; + +/* + * kdb_parse + * + * Parse the command line, search the command table for a + * matching command and invoke the command function. + * This function may be called recursively, if it is, the second call + * will overwrite argv and cbuf. It is the caller's responsibility to + * save their argv if they recursively call kdb_parse(). + * + * Parameters: + * cmdstr The input command line to be parsed. + * regs The registers at the time kdb was entered. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + * Limited to 20 tokens. + * + * Real rudimentary tokenization. Basically only whitespace + * is considered a token delimeter (but special consideration + * is taken of the '=' sign as used by the 'set' command). + * + * The algorithm used to tokenize the input string relies on + * there being at least one whitespace (or otherwise useless) + * character between tokens as the character immediately following + * the token is altered in-place to a null-byte to terminate the + * token string. + */ + +#define MAXARGC 20 + +int +kdb_parse(const char *cmdstr, struct pt_regs *regs) +{ + static char *argv[MAXARGC]; + static int argc = 0; + static char cbuf[CMD_BUFLEN+2]; + const char *cp; + char *cpp, quoted; + kdbtab_t *tp; + int i, escaped, ignore_errors = 0; + + /* + * First tokenize the command string. + */ + cp = cmdstr; + + if (KDB_FLAG(CMD_INTERRUPT)) { + /* Previous command was interrupted, newline must not repeat the command */ + KDB_FLAG_CLEAR(CMD_INTERRUPT); + argc = 0; /* no repeat */ + } + + if (*cp != '\n' && *cp != '\0') { + argc = 0; + cpp = cbuf; + while (*cp) { + /* skip whitespace */ + while (isspace(*cp)) cp++; + if ((*cp == '\0') || (*cp == '\n') || (*cp == '#' && !defcmd_in_progress)) + break; + if (cpp >= cbuf + CMD_BUFLEN) { + kdb_printf("kdb_parse: command buffer overflow, command ignored\n%s\n", cmdstr); + return KDB_NOTFOUND; + } + if (argc >= MAXARGC - 1) { + kdb_printf("kdb_parse: too many arguments, command ignored\n%s\n", cmdstr); + return KDB_NOTFOUND; + } + argv[argc++] = cpp; + escaped = 0; + quoted = '\0'; + /* Copy to next unquoted and unescaped whitespace or '=' */ + while (*cp && *cp != '\n' && (escaped || quoted || !isspace(*cp))) { + if (cpp >= cbuf + CMD_BUFLEN) + break; + if (escaped) { + escaped = 0; + *cpp++ = *cp++; + continue; + } + if (*cp == '\\') { + escaped = 1; + ++cp; + continue; + } + if (*cp == quoted) { + quoted = '\0'; + } else if (*cp == '\'' || *cp == '"') { + quoted = *cp; + } + if ((*cpp = *cp++) == '=' && !quoted) + break; + ++cpp; + } + *cpp++ = '\0'; /* Squash a ws or '=' character */ + } + } + if (!argc) + return 0; + if (defcmd_in_progress) { + int result = kdb_defcmd2(cmdstr, argv[0]); + if (!defcmd_in_progress) { + argc = 0; /* avoid repeat on endefcmd */ + *(argv[0]) = '\0'; + } + return result; + } + if (argv[0][0] == '-' && argv[0][1] && (argv[0][1] < '0' || argv[0][1] > '9')) { + ignore_errors = 1; + ++argv[0]; + } + + for(tp=kdb_commands, i=0; i < kdb_max_commands; i++,tp++) { + if (tp->cmd_name) { + /* + * If this command is allowed to be abbreviated, + * check to see if this is it. + */ + + if (tp->cmd_minlen + && (strlen(argv[0]) <= tp->cmd_minlen)) { + if (strncmp(argv[0], + tp->cmd_name, + tp->cmd_minlen) == 0) { + break; + } + } + + if (strcmp(argv[0], tp->cmd_name)==0) { + break; + } + } + } + + /* + * If we don't find a command by this name, see if the first + * few characters of this match any of the known commands. + * e.g., md1c20 should match md. + */ + if (i == kdb_max_commands) { + for(tp=kdb_commands, i=0; i < kdb_max_commands; i++,tp++) { + if (tp->cmd_name) { + if (strncmp(argv[0], + tp->cmd_name, + strlen(tp->cmd_name))==0) { + break; + } + } + } + } + + if (i < kdb_max_commands) { + int result; + KDB_STATE_SET(CMD); + result = (*tp->cmd_func)(argc-1, + (const char**)argv, + (const char**)__env, + regs); + if (result && ignore_errors && result > KDB_CMD_GO) + result = 0; + KDB_STATE_CLEAR(CMD); + switch (tp->cmd_repeat) { + case KDB_REPEAT_NONE: + argc = 0; + if (argv[0]) + *(argv[0]) = '\0'; + break; + case KDB_REPEAT_NO_ARGS: + argc = 1; + if (argv[1]) + *(argv[1]) = '\0'; + break; + case KDB_REPEAT_WITH_ARGS: + break; + } + return result; + } + + /* + * If the input with which we were presented does not + * map to an existing command, attempt to parse it as an + * address argument and display the result. Useful for + * obtaining the address of a variable, or the nearest symbol + * to an address contained in a register. + */ + { + kdb_machreg_t value; + char *name = NULL; + long offset; + int nextarg = 0; + + if (kdbgetaddrarg(0, (const char **)argv, &nextarg, + &value, &offset, &name, regs)) { + return KDB_NOTFOUND; + } + + kdb_printf("%s = ", argv[0]); + kdb_symbol_print(value, NULL, KDB_SP_DEFAULT); + kdb_printf("\n"); + return 0; + } +} + + +static int +handle_ctrl_cmd(char *cmd) +{ +#define CTRL_P 16 +#define CTRL_N 14 + + /* initial situation */ + if (cmd_head == cmd_tail) return 0; + + switch(*cmd) { + case CTRL_P: + if (cmdptr != cmd_tail) + cmdptr = (cmdptr-1) % KDB_CMD_HISTORY_COUNT; + strncpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN); + return 1; + case CTRL_N: + if (cmdptr != cmd_head) + cmdptr = (cmdptr+1) % KDB_CMD_HISTORY_COUNT; + strncpy(cmd_cur, cmd_hist[cmdptr], CMD_BUFLEN); + return 1; + } + return 0; +} + +/* + * kdb_do_dump + * + * Call the dump() function if the kernel is configured for LKCD. + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * None. dump() may or may not return. + * Locking: + * none. + * Remarks: + */ + +static void +kdb_do_dump(struct pt_regs *regs) +{ +#if defined(CONFIG_LKCD) || defined(CONFIG_LKCD_MODULE) + kdb_printf("Forcing dump (if configured)\n"); + console_loglevel = 8; /* to see the dump messages */ + dump("kdb_do_dump", regs); +#endif +} + +/* + * kdb_reboot + * + * This function implements the 'reboot' command. Reboot the system + * immediately. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Shouldn't return from this function. + */ + +static int +kdb_reboot(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + emergency_restart(); + kdb_printf("Hmm, kdb_reboot did not reboot, spinning here\n"); + while (1) {}; + /* NOTREACHED */ + return 0; +} + +/* + * kdb_local + * + * The main code for kdb. This routine is invoked on a specific + * processor, it is not global. The main kdb() routine ensures + * that only one processor at a time is in this routine. This + * code is called with the real reason code on the first entry + * to a kdb session, thereafter it is called with reason SWITCH, + * even if the user goes back to the original cpu. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * regs The exception frame at time of fault/breakpoint. NULL + * for reason SILENT, otherwise valid. + * db_result Result code from the break or debug point. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * KDB_CMD_GO User typed 'go'. + * KDB_CMD_CPU User switched to another cpu. + * KDB_CMD_SS Single step. + * KDB_CMD_SSB Single step until branch. + * Locking: + * none + * Remarks: + * none + */ + +extern char kdb_prompt_str[]; + +static int +kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs, kdb_dbtrap_t db_result) +{ + char *cmdbuf; + int diag; + struct task_struct *kdb_current = kdb_curr_task(smp_processor_id()); + + /* If kdb has been entered for an event which has been/will be + * recovered then silently return. We have to get this far into kdb in + * order to synchronize all the cpus, typically only one cpu (monarch) + * knows that the event is recoverable but the other cpus (slaves) may + * also be driven into kdb before that decision is made by the monarch. + * + * To pause in kdb even for recoverable events, 'set RECOVERY_PAUSE 1' + */ + KDB_DEBUG_STATE("kdb_local 1", reason); + if (reason == KDB_REASON_ENTER + && KDB_FLAG(RECOVERY) + && !KDB_FLAG(CATASTROPHIC)) { + int recovery_pause = 0; + kdbgetintenv("RECOVERY_PAUSE", &recovery_pause); + if (recovery_pause == 0) + reason = KDB_REASON_SILENT; + else + kdb_printf("%s: Recoverable error detected but" + " RECOVERY_PAUSE is set, staying in KDB\n", + __FUNCTION__); + } + + KDB_DEBUG_STATE("kdb_local 2", reason); + kdb_go_count = 0; + if (reason != KDB_REASON_DEBUG && + reason != KDB_REASON_SILENT) { + kdb_printf("\nEntering kdb (current=0x%p, pid %d) ", kdb_current, kdb_current->pid); +#if defined(CONFIG_SMP) + kdb_printf("on processor %d ", smp_processor_id()); +#endif + } + + switch (reason) { + case KDB_REASON_DEBUG: + { + /* + * If re-entering kdb after a single step + * command, don't print the message. + */ + switch(db_result) { + case KDB_DB_BPT: + kdb_printf("\nEntering kdb (0x%p) ", kdb_current); +#if defined(CONFIG_SMP) + kdb_printf("on processor %d ", smp_processor_id()); +#endif + kdb_printf("due to Debug @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); + break; + case KDB_DB_SSB: + /* + * In the midst of ssb command. Just return. + */ + KDB_DEBUG_STATE("kdb_local 3", reason); + return KDB_CMD_SSB; /* Continue with SSB command */ + + break; + case KDB_DB_SS: + break; + case KDB_DB_SSBPT: + KDB_DEBUG_STATE("kdb_local 4", reason); + return 1; /* kdba_db_trap did the work */ + default: + kdb_printf("kdb: Bad result from kdba_db_trap: %d\n", + db_result); + break; + } + + } + break; + case KDB_REASON_FAULT: + break; + case KDB_REASON_ENTER: + if (KDB_STATE(KEYBOARD)) + kdb_printf("due to Keyboard Entry\n"); + else + kdb_printf("due to KDB_ENTER()\n"); + break; + case KDB_REASON_KEYBOARD: + KDB_STATE_SET(KEYBOARD); + kdb_printf("due to Keyboard Entry\n"); + break; + case KDB_REASON_ENTER_SLAVE: /* drop through, slaves only get released via cpu switch */ + case KDB_REASON_SWITCH: + kdb_printf("due to cpu switch\n"); + if (KDB_STATE(GO_SWITCH)) { + KDB_STATE_CLEAR(GO_SWITCH); + KDB_DEBUG_STATE("kdb_local 5", reason); + return KDB_CMD_GO; + } + break; + case KDB_REASON_CALL: + if (!regs) + kdb_printf("kdb() called with no registers, restricted function"); + kdb_printf("\n"); + break; + case KDB_REASON_OOPS: + kdb_printf("Oops: %s\n", kdb_diemsg); + kdb_printf("due to oops @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); + kdba_dumpregs(regs, NULL, NULL); + break; + case KDB_REASON_NMI: + kdb_printf("due to NonMaskable Interrupt @ " kdb_machreg_fmt "\n", + kdba_getpc(regs)); + kdba_dumpregs(regs, NULL, NULL); + break; + case KDB_REASON_WATCHDOG: + kdb_printf("due to WatchDog Interrupt @ " kdb_machreg_fmt "\n", + kdba_getpc(regs)); + kdba_dumpregs(regs, NULL, NULL); + break; + case KDB_REASON_BREAK: + kdb_printf("due to Breakpoint @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); + /* + * Determine if this breakpoint is one that we + * are interested in. + */ + if (db_result != KDB_DB_BPT) { + kdb_printf("kdb: error return from kdba_bp_trap: %d\n", db_result); + KDB_DEBUG_STATE("kdb_local 6", reason); + return 0; /* Not for us, dismiss it */ + } + break; + case KDB_REASON_RECURSE: + kdb_printf("due to Recursion @ " kdb_machreg_fmt "\n", kdba_getpc(regs)); + break; + case KDB_REASON_SILENT: + KDB_DEBUG_STATE("kdb_local 7", reason); + return KDB_CMD_GO; /* Silent entry, silent exit */ + break; + default: + kdb_printf("kdb: unexpected reason code: %d\n", reason); + KDB_DEBUG_STATE("kdb_local 8", reason); + return 0; /* Not for us, dismiss it */ + } + + kdba_local_arch_setup(); + + kdba_set_current_task(kdb_current); + + while (1) { + /* + * Initialize pager context. + */ + kdb_nextline = 1; + KDB_STATE_CLEAR(SUPPRESS); +#ifdef KDB_HAVE_LONGJMP + /* + * Use kdba_setjmp/kdba_longjmp to break out of + * the pager early and to attempt to recover from kdb errors. + */ + KDB_STATE_CLEAR(LONGJMP); + if (kdbjmpbuf) { + if (kdba_setjmp(&kdbjmpbuf[smp_processor_id()])) { + /* Command aborted (usually in pager) */ + continue; + } + else + KDB_STATE_SET(LONGJMP); + } +#endif /* KDB_HAVE_LONGJMP */ + + cmdbuf = cmd_cur; + *cmdbuf = '\0'; + *(cmd_hist[cmd_head])='\0'; + + if (KDB_FLAG(ONLY_DO_DUMP)) { + /* kdb is off but a catastrophic error requires a dump. + * Take the dump and reboot. + * Turn on logging so the kdb output appears in the log + * buffer in the dump. + */ + const char *setargs[] = { "set", "LOGGING", "1" }; + kdb_set(2, setargs, NULL, regs); + kdb_do_dump(regs); + kdb_reboot(0, NULL, NULL, regs); + /*NOTREACHED*/ + } + +do_full_getstr: +#if defined(CONFIG_SMP) + snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"), smp_processor_id()); +#else + snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT")); +#endif + if (defcmd_in_progress) + strncat(kdb_prompt_str, "[defcmd]", CMD_BUFLEN); + + /* + * Fetch command from keyboard + */ + cmdbuf = kdb_getstr(cmdbuf, CMD_BUFLEN, kdb_prompt_str); + if (*cmdbuf != '\n') { + if (*cmdbuf < 32) { + if(cmdptr == cmd_head) { + strncpy(cmd_hist[cmd_head], cmd_cur, CMD_BUFLEN); + *(cmd_hist[cmd_head]+strlen(cmd_hist[cmd_head])-1) = '\0'; + } + if(!handle_ctrl_cmd(cmdbuf)) + *(cmd_cur+strlen(cmd_cur)-1) = '\0'; + cmdbuf = cmd_cur; + goto do_full_getstr; + } + else + strncpy(cmd_hist[cmd_head], cmd_cur, CMD_BUFLEN); + + cmd_head = (cmd_head+1) % KDB_CMD_HISTORY_COUNT; + if (cmd_head == cmd_tail) cmd_tail = (cmd_tail+1) % KDB_CMD_HISTORY_COUNT; + + } + + cmdptr = cmd_head; + diag = kdb_parse(cmdbuf, regs); + if (diag == KDB_NOTFOUND) { + kdb_printf("Unknown kdb command: '%s'\n", cmdbuf); + diag = 0; + } + if (diag == KDB_CMD_GO + || diag == KDB_CMD_CPU + || diag == KDB_CMD_SS + || diag == KDB_CMD_SSB) + break; + + if (diag) + kdb_cmderror(diag); + } + + kdba_local_arch_cleanup(); + + KDB_DEBUG_STATE("kdb_local 9", diag); + return diag; +} + + +/* + * kdb_print_state + * + * Print the state data for the current processor for debugging. + * + * Inputs: + * text Identifies the debug point + * value Any integer value to be printed, e.g. reason code. + * Returns: + * None. + * Locking: + * none + * Remarks: + * none + */ + +void kdb_print_state(const char *text, int value) +{ + kdb_printf("state: %s cpu %d value %d initial %d state %x\n", + text, smp_processor_id(), value, kdb_initial_cpu, kdb_state[smp_processor_id()]); +} + +/* + * kdb_previous_event + * + * Return a count of cpus that are leaving kdb, i.e. the number + * of processors that are still handling the previous kdb event. + * + * Inputs: + * None. + * Returns: + * Count of cpus in previous event. + * Locking: + * none + * Remarks: + * none + */ + +static int +kdb_previous_event(void) +{ + int i, leaving = 0; + for (i = 0; i < NR_CPUS; ++i) { + if (KDB_STATE_CPU(LEAVING, i)) + ++leaving; + } + return leaving; +} + +/* + * kdb_wait_for_cpus + * + * Invoked once at the start of a kdb event, from the controlling cpu. Wait a + * short period for the other cpus to enter kdb state. + * + * Inputs: + * none + * Returns: + * none + * Locking: + * none + * Remarks: + * none + */ + +int kdb_wait_for_cpus_secs = 10; /* may be modified by ia64 MCA timeout */ + +static void +kdb_wait_for_cpus(void) +{ +#ifdef CONFIG_SMP + int online = 0, kdb_data = 0, prev_kdb_data = 0, i, time; + mdelay(100); + for (time = 0; time < kdb_wait_for_cpus_secs; ++time) { + online = 0; + kdb_data = 0; + for (i = 0; i < NR_CPUS; ++i) { + if (cpu_online(i)) { + ++online; + if (kdb_running_process[i].seqno >= kdb_seqno - 1) + ++kdb_data; + } + } + if (online == kdb_data) + break; + if (prev_kdb_data != kdb_data) { + kdb_nextline = 0; /* no prompt yet */ + kdb_printf(" %d out of %d cpus in kdb, waiting for the rest, timeout in %d second(s)\n", + kdb_data, online, kdb_wait_for_cpus_secs - time); + prev_kdb_data = kdb_data; + } + touch_nmi_watchdog(); + mdelay(1000); + if (time % 4 == 0) + kdb_printf("."); + } + if (time) { + int wait = online - kdb_data; + if (wait == 0) + kdb_printf("All cpus are now in kdb\n"); + else + kdb_printf("%d cpu%s not in kdb, %s state is unknown\n", + wait, + wait == 1 ? " is" : "s are", + wait == 1 ? "its" : "their"); + } +#endif /* CONFIG_SMP */ +} + +/* + * kdb_main_loop + * + * The main kdb loop. After initial setup and assignment of the controlling + * cpu, all cpus are in this loop. One cpu is in control and will issue the kdb + * prompt, the others will spin until 'go' or cpu switch. + * + * To get a consistent view of the kernel stacks for all processes, this routine + * is invoked from the main kdb code via an architecture specific routine. + * kdba_main_loop is responsible for making the kernel stacks consistent for all + * processes, there should be no difference between a blocked process and a + * running process as far as kdb is concerned. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * reason2 kdb's current reason code. Initially error but can change + * acording to kdb state. + * db_result Result code from break or debug point. + * regs The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT then regs is NULL, otherwise it + * should always be valid. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * Locking: + * none + * Remarks: + * none + */ + +int +kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, + kdb_dbtrap_t db_result, struct pt_regs *regs) +{ + int result = 1; + /* Stay in kdb() until 'go', 'ss[b]' or an error */ + while (1) { + /* + * All processors except the one that is in control + * will spin here. + */ + KDB_DEBUG_STATE("kdb_main_loop 1", reason); + while (KDB_STATE(HOLD_CPU)) { + /* state KDB is turned off by kdb_cpu to see if the + * other cpus are still live, each cpu in this loop + * turns it back on. + */ + if (!KDB_STATE(KDB)) { + KDB_STATE_SET(KDB); + } + } + KDB_STATE_CLEAR(SUPPRESS); + KDB_DEBUG_STATE("kdb_main_loop 2", reason); + if (KDB_STATE(LEAVING)) + break; /* Another cpu said 'go' */ + + kdb_wait_for_cpus(); + /* Still using kdb, this processor is in control */ + result = kdb_local(reason2, error, regs, db_result); + KDB_DEBUG_STATE("kdb_main_loop 3", result); + + if (result == KDB_CMD_CPU) { + /* Cpu switch, hold the current cpu, release the target one. */ + reason2 = KDB_REASON_SWITCH; + KDB_STATE_SET(HOLD_CPU); + KDB_STATE_CLEAR_CPU(HOLD_CPU, kdb_new_cpu); + continue; + } + + if (result == KDB_CMD_SS) { + KDB_STATE_SET(DOING_SS); + break; + } + + if (result == KDB_CMD_SSB) { + KDB_STATE_SET(DOING_SS); + KDB_STATE_SET(DOING_SSB); + break; + } + + if (result && result != 1 && result != KDB_CMD_GO) + kdb_printf("\nUnexpected kdb_local return code %d\n", result); + + KDB_DEBUG_STATE("kdb_main_loop 4", reason); + break; + } + if (KDB_STATE(DOING_SS)) + KDB_STATE_CLEAR(SSBPT); + return result; +} + +/* + * kdb + * + * This function is the entry point for the kernel debugger. It + * provides a command parser and associated support functions to + * allow examination and control of an active kernel. + * + * This function may be invoked directly from any + * point in the kernel by calling with reason == KDB_REASON_CALL + * + * The breakpoint trap code should invoke this function with + * one of KDB_REASON_BREAK (int 03) or KDB_REASON_DEBUG (debug register) + * + * the die_if_kernel function should invoke this function with + * KDB_REASON_OOPS. + * + * The kernel fault handler should invoke this function with + * reason == KDB_REASON_FAULT and error == trap vector #. + * + * In single step mode, one cpu is released to run without + * breakpoints. Interrupts and NMI are reset to their original values, + * the cpu is allowed to do one instruction which causes a trap + * into kdb with KDB_REASON_DEBUG. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * regs The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT then regs is NULL, otherwise it + * should always be valid. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * Locking: + * none + * Remarks: + * No assumptions of system state. This function may be invoked + * with arbitrary locks held. It will stop all other processors + * in an SMP environment, disable all interrupts and does not use + * the operating systems keyboard driver. + * + * This code is reentrant but only for cpu switch. Any other + * reentrancy is an error, although kdb will attempt to recover. + * + * At the start of a kdb session the initial processor is running + * kdb() and the other processors can be doing anything. When the + * initial processor calls smp_kdb_stop() the other processors are + * driven through kdb_ipi which calls kdb() with reason SWITCH. + * That brings all processors into this routine, one with a "real" + * reason code, the other with SWITCH. + * + * Because the other processors are driven via smp_kdb_stop(), + * they enter here from the NMI handler. Until the other + * processors exit from here and exit from kdb_ipi, they will not + * take any more NMI requests. The initial cpu will still take NMI. + * + * Multiple race and reentrancy conditions, each with different + * advoidance mechanisms. + * + * Two cpus hit debug points at the same time. + * + * kdb_lock and kdb_initial_cpu ensure that only one cpu gets + * control of kdb. The others spin on kdb_initial_cpu until + * they are driven through NMI into kdb_ipi. When the initial + * cpu releases the others from NMI, they resume trying to get + * kdb_initial_cpu to start a new event. + * + * A cpu is released from kdb and starts a new event before the + * original event has completely ended. + * + * kdb_previous_event() prevents any cpu from entering + * kdb_initial_cpu state until the previous event has completely + * ended on all cpus. + * + * An exception occurs inside kdb. + * + * kdb_initial_cpu detects recursive entry to kdb and attempts + * to recover. The recovery uses longjmp() which means that + * recursive calls to kdb never return. Beware of assumptions + * like + * + * ++depth; + * kdb(); + * --depth; + * + * If the kdb call is recursive then longjmp takes over and + * --depth is never executed. + * + * NMI handling. + * + * NMI handling is tricky. The initial cpu is invoked by some kdb event, + * this event could be NMI driven but usually is not. The other cpus are + * driven into kdb() via kdb_ipi which uses NMI so at the start the other + * cpus will not accept NMI. Some operations such as SS release one cpu + * but hold all the others. Releasing a cpu means it drops back to + * whatever it was doing before the kdb event, this means it drops out of + * kdb_ipi and hence out of NMI status. But the software watchdog uses + * NMI and we do not want spurious watchdog calls into kdb. kdba_read() + * resets the watchdog counters in its input polling loop, when a kdb + * command is running it is subject to NMI watchdog events. + * + * Another problem with NMI handling is the NMI used to drive the other + * cpus into kdb cannot be distinguished from the watchdog NMI. State + * flag WAIT_IPI indicates that a cpu is waiting for NMI via kdb_ipi, + * if not set then software NMI is ignored by kdb_ipi. + * + * Cpu switching. + * + * All cpus are in kdb (or they should be), all but one are + * spinning on KDB_STATE(HOLD_CPU). Only one cpu is not in + * HOLD_CPU state, only that cpu can handle commands. + * + * Go command entered. + * + * If necessary, go will switch to the initial cpu first. If the event + * was caused by a software breakpoint (assumed to be global) that + * requires single-step to get over the breakpoint then only release the + * initial cpu, after the initial cpu has single-stepped the breakpoint + * then release the rest of the cpus. If SSBPT is not required then + * release all the cpus at once. + */ + +asmlinkage int +kdb(kdb_reason_t reason, int error, struct pt_regs *regs) +{ + kdb_intstate_t int_state; /* Interrupt state */ + kdb_reason_t reason2 = reason; + int result = 0; /* Default is kdb did not handle it */ + int ss_event; + kdb_dbtrap_t db_result=KDB_DB_NOBPT; + preempt_disable(); + atomic_inc(&kdb_event); + + switch(reason) { + case KDB_REASON_OOPS: + case KDB_REASON_NMI: + case KDB_REASON_WATCHDOG: + KDB_FLAG_SET(CATASTROPHIC); /* kernel state is dubious now */ + break; + default: + break; + } + if (kdb_continue_catastrophic > 2) { + kdb_printf("kdb_continue_catastrophic is out of range, setting to 2\n"); + kdb_continue_catastrophic = 2; + } + if (!kdb_on && KDB_FLAG(CATASTROPHIC) && kdb_continue_catastrophic == 2) { + KDB_FLAG_SET(ONLY_DO_DUMP); + } + if (!kdb_on && !KDB_FLAG(ONLY_DO_DUMP)) + goto out; + + KDB_DEBUG_STATE("kdb 1", reason); + KDB_STATE_CLEAR(SUPPRESS); + + /* Filter out userspace breakpoints first, no point in doing all + * the kdb smp fiddling when it is really a gdb trap. + * Save the single step status first, kdba_db_trap clears ss status. + * kdba_b[dp]_trap sets SSBPT if required. + */ + ss_event = KDB_STATE(DOING_SS) || KDB_STATE(SSBPT); +#ifdef CONFIG_CPU_XSCALE + if ( KDB_STATE(A_XSC_ICH) ) { + /* restore changed I_BIT */ + KDB_STATE_CLEAR(A_XSC_ICH); + kdba_restore_retirq(regs, KDB_STATE(A_XSC_IRQ)); + if ( !ss_event ) { + kdb_printf("Stranger!!! Why IRQ bit is changed====\n"); + } + } +#endif + if (reason == KDB_REASON_BREAK) { + db_result = kdba_bp_trap(regs, error); /* Only call this once */ + } + if (reason == KDB_REASON_DEBUG) { + db_result = kdba_db_trap(regs, error); /* Only call this once */ + } + + if ((reason == KDB_REASON_BREAK || reason == KDB_REASON_DEBUG) + && db_result == KDB_DB_NOBPT) { + KDB_DEBUG_STATE("kdb 2", reason); + goto out; /* Not one of mine */ + } + + /* Turn off single step if it was being used */ + if (ss_event) { + kdba_clearsinglestep(regs); + /* Single step after a breakpoint removes the need for a delayed reinstall */ + if (reason == KDB_REASON_BREAK || reason == KDB_REASON_DEBUG) + KDB_STATE_CLEAR(SSBPT); + } + + /* kdb can validly reenter but only for certain well defined conditions */ + if (reason == KDB_REASON_DEBUG + && !KDB_STATE(HOLD_CPU) + && ss_event) + KDB_STATE_SET(REENTRY); + else + KDB_STATE_CLEAR(REENTRY); + + /* Wait for previous kdb event to completely exit before starting + * a new event. + */ + while (kdb_previous_event()) + ; + KDB_DEBUG_STATE("kdb 3", reason); + + /* + * If kdb is already active, print a message and try to recover. + * If recovery is not possible and recursion is allowed or + * forced recursion without recovery is set then try to recurse + * in kdb. Not guaranteed to work but it makes an attempt at + * debugging the debugger. + */ + if (reason != KDB_REASON_SWITCH) { + if (KDB_IS_RUNNING() && !KDB_STATE(REENTRY)) { + int recover = 1; + unsigned long recurse = 0; + kdb_printf("kdb: Debugger re-entered on cpu %d, new reason = %d\n", + smp_processor_id(), reason); + /* Should only re-enter from released cpu */ + + if (KDB_STATE(HOLD_CPU)) { + kdb_printf(" Strange, cpu %d should not be running\n", smp_processor_id()); + recover = 0; + } + if (!KDB_STATE(CMD)) { + kdb_printf(" Not executing a kdb command\n"); + recover = 0; + } + if (!KDB_STATE(LONGJMP)) { + kdb_printf(" No longjmp available for recovery\n"); + recover = 0; + } + kdbgetulenv("RECURSE", &recurse); + if (recurse > 1) { + kdb_printf(" Forced recursion is set\n"); + recover = 0; + } + if (recover) { + kdb_printf(" Attempting to abort command and recover\n"); +#ifdef KDB_HAVE_LONGJMP + kdba_longjmp(&kdbjmpbuf[smp_processor_id()], 0); +#endif + } + if (recurse) { + if (KDB_STATE(RECURSE)) { + kdb_printf(" Already in recursive mode\n"); + } else { + kdb_printf(" Attempting recursive mode\n"); + KDB_STATE_SET(RECURSE); + KDB_STATE_SET(REENTRY); + reason2 = KDB_REASON_RECURSE; + recover = 1; + } + } + if (!recover) { + kdb_printf(" Cannot recover, allowing event to proceed\n"); + /*temp*/ + while (KDB_IS_RUNNING()) + cpu_relax(); + goto out; + } + } + } else if (!KDB_IS_RUNNING()) { + kdb_printf("kdb: CPU switch without kdb running, I'm confused\n"); + goto out; + } + + /* + * Disable interrupts, breakpoints etc. on this processor + * during kdb command processing + */ + KDB_STATE_SET(KDB); + if (!ss_event) { + /* bh not re-enabled during single step */ + local_bh_disable(); + } + kdba_disableint(&int_state); + if (!KDB_STATE(KDB_CONTROL)) { + kdb_bp_remove_local(); + kdba_disable_lbr(); + KDB_STATE_SET(KDB_CONTROL); + } + else if (KDB_DEBUG(LBR)) + kdba_print_lbr(); + + /* + * If not entering the debugger due to CPU switch or single step + * reentry, serialize access here. + * The processors may race getting to this point - if, + * for example, more than one processor hits a breakpoint + * at the same time. We'll serialize access to kdb here - + * other processors will loop here, and the NMI from the stop + * IPI will take them into kdb as switch candidates. Once + * the initial processor releases the debugger, the rest of + * the processors will race for it. + * + * The above describes the normal state of affairs, where two or more + * cpus that are entering kdb at the "same" time are assumed to be for + * separate events. However some processes such as ia64 MCA/INIT will + * drive all the cpus into error processing at the same time. For that + * case, all of the cpus entering kdb at the "same" time are really a + * single event. + * + * That case is handled by the use of KDB_ENTER by one cpu (the + * monarch) and KDB_ENTER_SLAVE on the other cpus (the slaves). + * KDB_ENTER_SLAVE maps to KDB_REASON_ENTER_SLAVE. The slave events + * will be treated as if they had just responded to the kdb IPI, i.e. + * as if they were KDB_REASON_SWITCH. + * + * Because of races across multiple cpus, ENTER_SLAVE can occur before + * the main ENTER. Hold up ENTER_SLAVE here until the main ENTER + * arrives. + */ + + if (reason == KDB_REASON_ENTER_SLAVE) { + spin_lock(&kdb_lock); + while (!KDB_IS_RUNNING()) { + spin_unlock(&kdb_lock); + while (!KDB_IS_RUNNING()) + cpu_relax(); + spin_lock(&kdb_lock); + } + reason = KDB_REASON_SWITCH; + KDB_STATE_SET(HOLD_CPU); + spin_unlock(&kdb_lock); + } + + if (reason == KDB_REASON_SWITCH || KDB_STATE(REENTRY)) + ; /* drop through */ + else { + KDB_DEBUG_STATE("kdb 4", reason); + spin_lock(&kdb_lock); + while (KDB_IS_RUNNING() || kdb_previous_event()) { + spin_unlock(&kdb_lock); + while (KDB_IS_RUNNING() || kdb_previous_event()) + cpu_relax(); + spin_lock(&kdb_lock); + } + KDB_DEBUG_STATE("kdb 5", reason); + + kdb_initial_cpu = smp_processor_id(); + ++kdb_seqno; + spin_unlock(&kdb_lock); + notify_die(DIE_KDEBUG_ENTER, "KDEBUG ENTER", regs, error, 0, 0); + } + + if (smp_processor_id() == kdb_initial_cpu + && !KDB_STATE(REENTRY)) { + KDB_STATE_CLEAR(HOLD_CPU); + KDB_STATE_CLEAR(WAIT_IPI); + /* + * Remove the global breakpoints. This is only done + * once from the initial processor on initial entry. + */ + kdb_bp_remove_global(); + + /* + * If SMP, stop other processors. The other processors + * will enter kdb() with KDB_REASON_SWITCH and spin in + * kdb_main_loop(). + */ + KDB_DEBUG_STATE("kdb 6", reason); + if (NR_CPUS > 1) { + int i; + for (i = 0; i < NR_CPUS; ++i) { + if (!cpu_online(i)) + continue; + if (i != kdb_initial_cpu) { + KDB_STATE_SET_CPU(HOLD_CPU, i); + KDB_STATE_SET_CPU(WAIT_IPI, i); + } + } + KDB_DEBUG_STATE("kdb 7", reason); + smp_kdb_stop(); + KDB_DEBUG_STATE("kdb 8", reason); + } + } + + if (KDB_STATE(GO1)) { + kdb_bp_remove_global(); /* They were set for single-step purposes */ + KDB_STATE_CLEAR(GO1); + reason = KDB_REASON_SILENT; /* Now silently go */ + } + + /* Set up a consistent set of process stacks before talking to the user */ + KDB_DEBUG_STATE("kdb 9", result); + result = kdba_main_loop(reason, reason2, error, db_result, regs); + + KDB_DEBUG_STATE("kdb 10", result); + kdba_adjust_ip(reason2, error, regs); + KDB_STATE_CLEAR(LONGJMP); + KDB_DEBUG_STATE("kdb 11", result); + /* go which requires single-step over a breakpoint must only release + * one cpu. + */ + if (result == KDB_CMD_GO && KDB_STATE(SSBPT)) + KDB_STATE_SET(GO1); + + if (smp_processor_id() == kdb_initial_cpu && + !KDB_STATE(DOING_SS) && + !KDB_STATE(RECURSE)) { + /* + * (Re)install the global breakpoints. This is only done + * once from the initial processor on go. + */ + KDB_DEBUG_STATE("kdb 12", reason); + kdb_bp_install_global(regs); + if (!KDB_STATE(GO1)) { + /* + * Release all other cpus which will see KDB_STATE(LEAVING) is set. + */ + int i; + for (i = 0; i < NR_CPUS; ++i) { + if (KDB_STATE_CPU(KDB, i)) + KDB_STATE_SET_CPU(LEAVING, i); + KDB_STATE_CLEAR_CPU(WAIT_IPI, i); + KDB_STATE_CLEAR_CPU(HOLD_CPU, i); + } + /* Wait until all the other processors leave kdb */ + while (kdb_previous_event() != 1) + ; + notify_die(DIE_KDEBUG_LEAVE, "KDEBUG LEAVE", regs, error, 0, 0); + kdb_initial_cpu = -1; /* release kdb control */ + KDB_DEBUG_STATE("kdb 13", reason); + } + } + + KDB_DEBUG_STATE("kdb 14", result); + kdba_restoreint(&int_state); +#ifdef CONFIG_CPU_XSCALE + if ( smp_processor_id() == kdb_initial_cpu && + ( KDB_STATE(SSBPT) | KDB_STATE(DOING_SS) ) + ) { + kdba_setsinglestep(regs); + // disable IRQ in stack frame + KDB_STATE_SET(A_XSC_ICH); + if ( kdba_disable_retirq(regs) ) { + KDB_STATE_SET(A_XSC_IRQ); + } + else { + KDB_STATE_CLEAR(A_XSC_IRQ); + } + } +#endif + + /* Only do this work if we are really leaving kdb */ + if (!(KDB_STATE(DOING_SS) || KDB_STATE(SSBPT) || KDB_STATE(RECURSE))) { + KDB_DEBUG_STATE("kdb 15", result); + kdb_bp_install_local(regs); + kdba_enable_lbr(); + __local_bh_enable(); + KDB_STATE_CLEAR(KDB_CONTROL); + } + + KDB_DEBUG_STATE("kdb 16", result); + KDB_FLAG_CLEAR(CATASTROPHIC); + KDB_STATE_CLEAR(IP_ADJUSTED); /* Re-adjust ip next time in */ + KDB_STATE_CLEAR(KEYBOARD); + KDB_STATE_CLEAR(KDB); /* Main kdb state has been cleared */ + KDB_STATE_CLEAR(RECURSE); + KDB_STATE_CLEAR(LEAVING); /* No more kdb work after this */ + KDB_DEBUG_STATE("kdb 17", reason); +out: + atomic_dec(&kdb_event); + preempt_enable(); + return result != 0; +} + +/* + * kdb_mdr + * + * This function implements the guts of the 'mdr' command. + * + * mdr , + * + * Inputs: + * addr Start address + * count Number of bytes + * Outputs: + * None. + * Returns: + * Always 0. Any errors are detected and printed by kdb_getarea. + * Locking: + * none. + * Remarks: + */ + +static int +kdb_mdr(kdb_machreg_t addr, unsigned int count) +{ + unsigned char c; + while (count--) { + if (kdb_getarea(c, addr)) + return 0; + kdb_printf("%02x", c); + addr++; + } + kdb_printf("\n"); + return 0; +} + +/* + * kdb_md + * + * This function implements the 'md', 'md1', 'md2', 'md4', 'md8' + * 'mdr' and 'mds' commands. + * + * md|mds [ [ []]] + * mdWcN [ [ []]] + * where W = is the width (1, 2, 4 or 8) and N is the count. + * for eg., md1c20 reads 20 bytes, 1 at a time. + * mdr , + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static void +kdb_md_line(const char *fmtstr, kdb_machreg_t addr, + int symbolic, int nosect, int bytesperword, + int num, int repeat, int phys) +{ + /* print just one line of data */ + kdb_symtab_t symtab; + char cbuf[32]; + char *c = cbuf; + int i; + unsigned long word; + + memset(cbuf, '\0', sizeof(cbuf)); + if (phys) + kdb_printf("phys " kdb_machreg_fmt0 " ", addr); + else + kdb_printf(kdb_machreg_fmt0 " ", addr); + + for (i = 0; i < num && repeat--; i++) { + if (phys) { + if (kdb_getphysword(&word, addr, bytesperword)) + break; + } else if (kdb_getword(&word, addr, bytesperword)) + break; + kdb_printf(fmtstr, word); + if (symbolic) + kdbnearsym(word, &symtab); + else + memset(&symtab, 0, sizeof(symtab)); + if (symtab.sym_name) { + kdb_symbol_print(word, &symtab, 0); + if (!nosect) { + kdb_printf("\n"); + kdb_printf(" %s %s " + kdb_machreg_fmt " " kdb_machreg_fmt " " kdb_machreg_fmt, + symtab.mod_name, + symtab.sec_name, + symtab.sec_start, + symtab.sym_start, + symtab.sym_end); + } + addr += bytesperword; + } else { + union { + u64 word; + unsigned char c[8]; + } wc; + unsigned char *cp; +#ifdef __BIG_ENDIAN + cp = wc.c + 8 - bytesperword; +#else + cp = wc.c; +#endif + wc.word = word; +#define printable_char(c) ({unsigned char __c = c; isascii(__c) && isprint(__c) ? __c : '.';}) + switch (bytesperword) { + case 8: + *c++ = printable_char(*cp++); + *c++ = printable_char(*cp++); + *c++ = printable_char(*cp++); + *c++ = printable_char(*cp++); + addr += 4; + case 4: + *c++ = printable_char(*cp++); + *c++ = printable_char(*cp++); + addr += 2; + case 2: + *c++ = printable_char(*cp++); + addr++; + case 1: + *c++ = printable_char(*cp++); + addr++; + break; + } +#undef printable_char + } + } + kdb_printf("%*s %s\n", (int)((num-i)*(2*bytesperword + 1)+1), " ", cbuf); +} + +static int +kdb_md(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + static kdb_machreg_t last_addr; + static int last_radix, last_bytesperword, last_repeat; + int radix = 16, mdcount = 8, bytesperword = sizeof(kdb_machreg_t), repeat; + int nosect = 0; + char fmtchar, fmtstr[64]; + kdb_machreg_t addr; + unsigned long word; + long offset = 0; + int symbolic = 0; + int valid = 0; + int phys = 0; + + kdbgetintenv("MDCOUNT", &mdcount); + kdbgetintenv("RADIX", &radix); + kdbgetintenv("BYTESPERWORD", &bytesperword); + + /* Assume 'md ' and start with environment values */ + repeat = mdcount * 16 / bytesperword; + + if (strcmp(argv[0], "mdr") == 0) { + if (argc != 2) + return KDB_ARGCOUNT; + valid = 1; + } else if (isdigit(argv[0][2])) { + bytesperword = (int)(argv[0][2] - '0'); + if (bytesperword == 0) { + bytesperword = last_bytesperword; + if (bytesperword == 0) { + bytesperword = 4; + } + } + last_bytesperword = bytesperword; + repeat = mdcount * 16 / bytesperword; + if (!argv[0][3]) + valid = 1; + else if (argv[0][3] == 'c' && argv[0][4]) { + char *p; + repeat = simple_strtoul(argv[0]+4, &p, 10); + mdcount = ((repeat * bytesperword) + 15) / 16; + valid = !*p; + } + last_repeat = repeat; + } else if (strcmp(argv[0], "md") == 0) + valid = 1; + else if (strcmp(argv[0], "mds") == 0) + valid = 1; + else if (strcmp(argv[0], "mdp") == 0) { + phys = valid = 1; + } + if (!valid) + return KDB_NOTFOUND; + + if (argc == 0) { + if (last_addr == 0) + return KDB_ARGCOUNT; + addr = last_addr; + radix = last_radix; + bytesperword = last_bytesperword; + repeat = last_repeat; + mdcount = ((repeat * bytesperword) + 15) / 16; + } + + if (argc) { + kdb_machreg_t val; + int diag, nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + if (argc > nextarg+2) + return KDB_ARGCOUNT; + + if (argc >= nextarg) { + diag = kdbgetularg(argv[nextarg], &val); + if (!diag) { + mdcount = (int) val; + repeat = mdcount * 16 / bytesperword; + } + } + if (argc >= nextarg+1) { + diag = kdbgetularg(argv[nextarg+1], &val); + if (!diag) + radix = (int) val; + } + } + + if (strcmp(argv[0], "mdr") == 0) { + return kdb_mdr(addr, mdcount); + } + + switch (radix) { + case 10: + fmtchar = 'd'; + break; + case 16: + fmtchar = 'x'; + break; + case 8: + fmtchar = 'o'; + break; + default: + return KDB_BADRADIX; + } + + last_radix = radix; + + if (bytesperword > sizeof(kdb_machreg_t)) + return KDB_BADWIDTH; + + switch (bytesperword) { + case 8: + sprintf(fmtstr, "%%16.16l%c ", fmtchar); + break; + case 4: + sprintf(fmtstr, "%%8.8l%c ", fmtchar); + break; + case 2: + sprintf(fmtstr, "%%4.4l%c ", fmtchar); + break; + case 1: + sprintf(fmtstr, "%%2.2l%c ", fmtchar); + break; + default: + return KDB_BADWIDTH; + } + + last_repeat = repeat; + last_bytesperword = bytesperword; + + if (strcmp(argv[0], "mds") == 0) { + symbolic = 1; + /* Do not save these changes as last_*, they are temporary mds + * overrides. + */ + bytesperword = sizeof(kdb_machreg_t); + repeat = mdcount; + kdbgetintenv("NOSECT", &nosect); + } + + /* Round address down modulo BYTESPERWORD */ + + addr &= ~(bytesperword-1); + + while (repeat > 0) { + unsigned long a; + int n, z, num = (symbolic ? 1 : (16 / bytesperword)); + + for (a = addr, z = 0; z < repeat; a += bytesperword, ++z) { + if (phys) { + if (kdb_getphysword(&word, a, bytesperword) + || word) + break; + } else if (kdb_getword(&word, a, bytesperword) || word) + break; + } + n = min(num, repeat); + kdb_md_line(fmtstr, addr, symbolic, nosect, bytesperword, num, repeat, phys); + addr += bytesperword * n; + repeat -= n; + z = (z + num - 1) / num; + if (z > 2) { + int s = num * (z-2); + kdb_printf(kdb_machreg_fmt0 "-" kdb_machreg_fmt0 " zero suppressed\n", + addr, addr + bytesperword * s - 1); + addr += bytesperword * s; + repeat -= s; + } + } + last_addr = addr; + + return 0; +} + +/* + * kdb_mm + * + * This function implements the 'mm' command. + * + * mm address-expression new-value + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * mm works on machine words, mmW works on bytes. + */ + +static int +kdb_mm(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + kdb_machreg_t addr; + long offset = 0; + unsigned long contents; + int nextarg; + int width; + + if (argv[0][2] && !isdigit(argv[0][2])) + return KDB_NOTFOUND; + + if (argc < 2) { + return KDB_ARGCOUNT; + } + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + return diag; + + if (nextarg > argc) + return KDB_ARGCOUNT; + + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &contents, NULL, NULL, regs))) + return diag; + + if (nextarg != argc + 1) + return KDB_ARGCOUNT; + + width = argv[0][2] ? (argv[0][2] - '0') : (sizeof(kdb_machreg_t)); + if ((diag = kdb_putword(addr, contents, width))) + return diag; + + kdb_printf(kdb_machreg_fmt " = " kdb_machreg_fmt "\n", addr, contents); + + return 0; +} + +/* + * kdb_go + * + * This function implements the 'go' command. + * + * go [address-expression] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * KDB_CMD_GO for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_go(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdb_machreg_t addr; + int diag; + int nextarg; + long offset; + + if (argc == 1) { + if (smp_processor_id() != kdb_initial_cpu) { + kdb_printf("go
must be issued from the initial cpu, do cpu %d first\n", kdb_initial_cpu); + return KDB_ARGCOUNT; + } + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, + &addr, &offset, NULL, regs); + if (diag) + return diag; + + kdba_setpc(regs, addr); + } else if (argc) + return KDB_ARGCOUNT; + + diag = KDB_CMD_GO; + if (KDB_FLAG(CATASTROPHIC)) { + kdb_printf("Catastrophic error detected\n"); + kdb_printf("kdb_continue_catastrophic=%d, ", + kdb_continue_catastrophic); + if (kdb_continue_catastrophic == 0 && kdb_go_count++ == 0) { + kdb_printf("type go a second time if you really want to continue\n"); + return 0; + } + if (kdb_continue_catastrophic == 2) { + kdb_do_dump(regs); + kdb_printf("forcing reboot\n"); + kdb_reboot(0, NULL, NULL, regs); + } + kdb_printf("attempting to continue\n"); + } + if (smp_processor_id() != kdb_initial_cpu) { + char buf[80]; + kdb_printf("go was not issued from initial cpu, switching back to cpu %d\n", kdb_initial_cpu); + sprintf(buf, "cpu %d\n", kdb_initial_cpu); + /* Recursive use of kdb_parse, do not use argv after this point */ + argv = NULL; + diag = kdb_parse(buf, regs); + if (diag == KDB_CMD_CPU) + KDB_STATE_SET_CPU(GO_SWITCH, kdb_initial_cpu); + } + return diag; +} + +/* + * kdb_rd + * + * This function implements the 'rd' command. + * + * rd display all general registers. + * rd c display all control registers. + * rd d display all debug registers. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_rd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + if (argc == 0) { + return kdba_dumpregs(kdb_current_regs, NULL, NULL); + } + + if (argc > 2) { + return KDB_ARGCOUNT; + } + + return kdba_dumpregs(kdb_current_regs, argv[1], argc==2 ? argv[2]: NULL); +} + +/* + * kdb_rm + * + * This function implements the 'rm' (register modify) command. + * + * rm register-name new-contents + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Currently doesn't allow modification of control or + * debug registers, nor does it allow modification + * of model-specific registers (MSR). + */ + +static int +kdb_rm(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int ind = 0; + kdb_machreg_t contents; + + if (argc != 2) { + return KDB_ARGCOUNT; + } + + /* + * Allow presence or absence of leading '%' symbol. + */ + + if (argv[1][0] == '%') + ind = 1; + + diag = kdbgetularg(argv[2], &contents); + if (diag) + return diag; + + diag = kdba_setregcontents(&argv[1][ind], kdb_current_regs, contents); + if (diag) + return diag; + + return 0; +} + +#if defined(CONFIG_MAGIC_SYSRQ) +/* + * kdb_sr + * + * This function implements the 'sr' (SYSRQ key) command which + * interfaces to the soi-disant MAGIC SYSRQ functionality. + * + * sr + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * None. + */ +static int +kdb_sr(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + extern int sysrq_enabled; + if (argc != 1) { + return KDB_ARGCOUNT; + } + if (!sysrq_enabled) { + kdb_printf("Auto activating sysrq\n"); + sysrq_enabled = 1; + } + + handle_sysrq(*argv[1], regs, 0); + + return 0; +} +#endif /* CONFIG_MAGIC_SYSRQ */ + +/* + * kdb_ef + * + * This function implements the 'regs' (display exception frame) + * command. This command takes an address and expects to find + * an exception frame at that address, formats and prints it. + * + * regs address-expression + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Not done yet. + */ + +static int +kdb_ef(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + kdb_machreg_t addr; + long offset; + int nextarg; + + if (argc == 1) { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + return kdba_dumpregs((struct pt_regs *)addr, NULL, NULL); + } + + return KDB_ARGCOUNT; +} + +#if defined(CONFIG_MODULES) +extern struct list_head *kdb_modules; +extern void free_module(struct module *); + +/* modules using other modules */ +struct module_use +{ + struct list_head list; + struct module *module_which_uses; +}; + +/* + * kdb_lsmod + * + * This function implements the 'lsmod' command. Lists currently + * loaded kernel modules. + * + * Mostly taken from userland lsmod. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * + */ + +static int +kdb_lsmod(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct module *mod; + + if (argc != 0) + return KDB_ARGCOUNT; + + kdb_printf("Module Size modstruct Used by\n"); + list_for_each_entry(mod, kdb_modules, list) { + + kdb_printf("%-20s%8lu 0x%p ", mod->name, + mod->core_size, (void *)mod); +#ifdef CONFIG_MODULE_UNLOAD + kdb_printf("%4d ", module_refcount(mod)); +#endif + if (mod->state == MODULE_STATE_GOING) + kdb_printf(" (Unloading)"); + else if (mod->state == MODULE_STATE_COMING) + kdb_printf(" (Loading)"); + else + kdb_printf(" (Live)"); + +#ifdef CONFIG_MODULE_UNLOAD + { + struct module_use *use; + kdb_printf(" [ "); + list_for_each_entry(use, &mod->modules_which_use_me, list) + kdb_printf("%s ", use->module_which_uses->name); + kdb_printf("]\n"); + } +#endif + } + + return 0; +} + +#endif /* CONFIG_MODULES */ + +/* + * kdb_env + * + * This function implements the 'env' command. Display the current + * environment variables. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_env(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + + for(i=0; i<__nenv; i++) { + if (__env[i]) { + kdb_printf("%s\n", __env[i]); + } + } + + if (KDB_DEBUG(MASK)) + kdb_printf("KDBFLAGS=0x%x\n", kdb_flags); + + return 0; +} + +/* + * kdb_dmesg + * + * This function implements the 'dmesg' command to display the contents + * of the syslog buffer. + * + * dmesg [lines] [adjust] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * None. + */ + +static int +kdb_dmesg(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + char *syslog_data[4], *start, *end, c = '\0', *p; + int diag, logging, logsize, lines = 0, adjust = 0, n; + + if (argc > 2) + return KDB_ARGCOUNT; + if (argc) { + char *cp; + lines = simple_strtol(argv[1], &cp, 0); + if (*cp) + lines = 0; + if (argc > 1) { + adjust = simple_strtoul(argv[2], &cp, 0); + if (*cp || adjust < 0) + adjust = 0; + } + } + + /* disable LOGGING if set */ + diag = kdbgetintenv("LOGGING", &logging); + if (!diag && logging) { + const char *setargs[] = { "set", "LOGGING", "0" }; + kdb_set(2, setargs, envp, regs); + } + + /* syslog_data[0,1] physical start, end+1. syslog_data[2,3] logical start, end+1. */ + kdb_syslog_data(syslog_data); + if (syslog_data[2] == syslog_data[3]) + return 0; + logsize = syslog_data[1] - syslog_data[0]; + start = syslog_data[2]; + end = syslog_data[3]; +#define KDB_WRAP(p) (((p - syslog_data[0]) % logsize) + syslog_data[0]) + for (n = 0, p = start; p < end; ++p) { + if ((c = *KDB_WRAP(p)) == '\n') + ++n; + } + if (c != '\n') + ++n; + if (lines < 0) { + if (adjust >= n) + kdb_printf("buffer only contains %d lines, nothing printed\n", n); + else if (adjust - lines >= n) + kdb_printf("buffer only contains %d lines, last %d lines printed\n", + n, n - adjust); + if (adjust) { + for (; start < end && adjust; ++start) { + if (*KDB_WRAP(start) == '\n') + --adjust; + } + if (start < end) + ++start; + } + for (p = start; p < end && lines; ++p) { + if (*KDB_WRAP(p) == '\n') + ++lines; + } + end = p; + } else if (lines > 0) { + int skip = n - (adjust + lines); + if (adjust >= n) { + kdb_printf("buffer only contains %d lines, nothing printed\n", n); + skip = n; + } else if (skip < 0) { + lines += skip; + skip = 0; + kdb_printf("buffer only contains %d lines, first %d lines printed\n", + n, lines); + } + for (; start < end && skip; ++start) { + if (*KDB_WRAP(start) == '\n') + --skip; + } + for (p = start; p < end && lines; ++p) { + if (*KDB_WRAP(p) == '\n') + --lines; + } + end = p; + } + /* Do a line at a time (max 200 chars) to reduce protocol overhead */ + c = '\n'; + while (start != end) { + char buf[201], *p = buf; + while (start < end && (c = *KDB_WRAP(start)) && (p - buf) < sizeof(buf)-1) { + ++start; + *p++ = c; + if (c == '\n') + break; + } + *p = '\0'; + kdb_printf("%s", buf); + } + if (c != '\n') + kdb_printf("\n"); + + return 0; +} + +/* + * kdb_cpu + * + * This function implements the 'cpu' command. + * + * cpu [] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * KDB_CMD_CPU for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * All cpu's should be spinning in kdb(). However just in case + * a cpu did not take the smp_kdb_stop NMI, check that a cpu + * entered kdb() before passing control to it. + */ + +static void +kdb_cpu_status(void) +{ + int i, start_cpu, first_print = 1; + char state, prev_state = '?'; + + kdb_printf("Currently on cpu %d\n", smp_processor_id()); + kdb_printf("Available cpus: "); + for (start_cpu = -1, i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + state = 'F'; /* cpu is offline */ + else { + struct kdb_running_process *krp = kdb_running_process+i; + if (KDB_STATE_CPU(KDB, i)) { + state = ' '; /* cpu is responding to kdb */ + if (kdb_task_state_char(krp->p) == 'I') + state = 'I'; /* running the idle task */ + } else if (krp->seqno && krp->p && krp->seqno >= kdb_seqno - 1) + state = '+'; /* some kdb data, but not responding */ + else + state = '*'; /* no kdb data */ + } + if (state != prev_state) { + if (prev_state != '?') { + if (!first_print) + kdb_printf(", "); + first_print = 0; + kdb_printf("%d", start_cpu); + if (start_cpu < i-1) + kdb_printf("-%d", i-1); + if (prev_state != ' ') + kdb_printf("(%c)", prev_state); + } + prev_state = state; + start_cpu = i; + } + } + /* print the trailing cpus, ignoring them if they are all offline */ + if (prev_state != 'F') { + if (!first_print) + kdb_printf(", "); + kdb_printf("%d", start_cpu); + if (start_cpu < i-1) + kdb_printf("-%d", i-1); + if (prev_state != ' ') + kdb_printf("(%c)", prev_state); + } + kdb_printf("\n"); +} + +static int +kdb_cpu(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long cpunum; + int diag, i; + + /* ask the other cpus if they are still active */ + for (i=0; i NR_CPUS) + || !cpu_online(cpunum) + || !KDB_STATE_CPU(KDB, cpunum)) + return KDB_BADCPUNUM; + + kdb_new_cpu = cpunum; + + /* + * Switch to other cpu + */ + return KDB_CMD_CPU; +} + +/* The user may not realize that ps/bta with no parameters does not print idle + * or sleeping system daemon processes, so tell them how many were suppressed. + */ +void +kdb_ps_suppressed(void) +{ + int idle = 0, daemon = 0; + unsigned long mask_I = kdb_task_state_string("I"), + mask_M = kdb_task_state_string("M"); + unsigned long cpu; + const struct task_struct *p, *g; + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (!cpu_online(cpu)) + continue; + p = kdb_curr_task(cpu); + if (kdb_task_state(p, mask_I)) + ++idle; + } + kdb_do_each_thread(g, p) { + if (kdb_task_state(p, mask_M)) + ++daemon; + } kdb_while_each_thread(g, p); + if (idle || daemon) { + if (idle) + kdb_printf("%d idle process%s (state I)%s", + idle, idle == 1 ? "" : "es", + daemon ? " and " : ""); + if (daemon) + kdb_printf("%d sleeping system daemon (state M) process%s", + daemon, daemon == 1 ? "" : "es"); + kdb_printf(" suppressed\n"); + } +} + +/* + * kdb_ps + * + * This function implements the 'ps' command which shows + * a list of the active processes. + * + * ps [DRSTCZEUIMA] All processes, optionally filtered by state + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +void +kdb_ps1(const struct task_struct *p) +{ + struct kdb_running_process *krp = kdb_running_process + kdb_process_cpu(p); + kdb_printf("0x%p %8d %8d %d %4d %c 0x%p %c%s\n", + (void *)p, p->pid, p->parent->pid, + kdb_task_has_cpu(p), kdb_process_cpu(p), + kdb_task_state_char(p), + (void *)(&p->thread), + p == kdb_curr_task(smp_processor_id()) ? '*': ' ', + p->comm); + if (kdb_task_has_cpu(p)) { + if (!krp->seqno || !krp->p) + kdb_printf(" Error: no saved data for this cpu\n"); + else { + if (krp->seqno < kdb_seqno - 1) + kdb_printf(" Warning: process state is stale\n"); + if (krp->p != p) + kdb_printf(" Error: does not match running process table (0x%p)\n", krp->p); + } + } +} + +static int +kdb_ps(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct task_struct *g, *p; + unsigned long mask, cpu; + + if (argc == 0) + kdb_ps_suppressed(); + kdb_printf("%-*s Pid Parent [*] cpu State %-*s Command\n", + (int)(2*sizeof(void *))+2, "Task Addr", + (int)(2*sizeof(void *))+2, "Thread"); + mask = kdb_task_state_string(argc ? argv[1] : NULL); + /* Run the active tasks first */ + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (!cpu_online(cpu)) + continue; + p = kdb_curr_task(cpu); + if (kdb_task_state(p, mask)) + kdb_ps1(p); + } + kdb_printf("\n"); + /* Now the real tasks */ + kdb_do_each_thread(g, p) { + if (kdb_task_state(p, mask)) + kdb_ps1(p); + } kdb_while_each_thread(g, p); + + return 0; +} + +/* + * kdb_pid + * + * This function implements the 'pid' command which switches + * the currently active process. + * + * pid [ | R] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + + +static int +kdb_pid(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct task_struct *p; + unsigned long val; + int diag; + + if (argc > 1) + return KDB_ARGCOUNT; + + if (argc) { + if (strcmp(argv[1], "R") == 0) { + p = KDB_RUNNING_PROCESS_ORIGINAL[kdb_initial_cpu].p; + } else { + diag = kdbgetularg(argv[1], &val); + if (diag) + return KDB_BADINT; + + p = find_task_by_pid((pid_t)val); + if (!p) { + kdb_printf("No task with pid=%d\n", (pid_t)val); + return 0; + } + } + + kdba_set_current_task(p); + } + + kdb_printf("KDB current process is %s(pid=%d)\n", kdb_current_task->comm, + kdb_current_task->pid); + + return 0; +} + +/* + * kdb_ll + * + * This function implements the 'll' command which follows a linked + * list and executes an arbitrary command for each element. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_ll(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + kdb_machreg_t addr; + long offset = 0; + kdb_machreg_t va; + unsigned long linkoffset; + int nextarg; + const char *command; + + if (argc != 3) { + return KDB_ARGCOUNT; + } + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + diag = kdbgetularg(argv[2], &linkoffset); + if (diag) + return diag; + + /* + * Using the starting address as + * the first element in the list, and assuming that + * the list ends with a null pointer. + */ + + va = addr; + if (!(command = kdb_strdup(argv[3], GFP_KDB))) { + kdb_printf("%s: cannot duplicate command\n", __FUNCTION__); + return 0; + } + /* Recursive use of kdb_parse, do not use argv after this point */ + argv = NULL; + + while (va) { + char buf[80]; + + sprintf(buf, "%s " kdb_machreg_fmt "\n", command, va); + diag = kdb_parse(buf, regs); + if (diag) + return diag; + + addr = va + linkoffset; + if (kdb_getword(&va, addr, sizeof(va))) + return 0; + } + kfree(command); + + return 0; +} + +/* + * kdb_help + * + * This function implements the 'help' and '?' commands. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_help(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdbtab_t *kt; + + kdb_printf("%-15.15s %-20.20s %s\n", "Command", "Usage", "Description"); + kdb_printf("----------------------------------------------------------\n"); + for(kt=kdb_commands; kt->cmd_name; kt++) { + kdb_printf("%-15.15s %-20.20s %s\n", kt->cmd_name, + kt->cmd_usage, kt->cmd_help); + } + return 0; +} + +extern int kdb_wake_up_process(struct task_struct * p); + +/* + * kdb_kill + * + * This function implements the 'kill' commands. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_kill(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + long sig, pid; + char *endp; + struct task_struct *p; + struct siginfo info; + + if (argc!=2) + return KDB_ARGCOUNT; + + sig = simple_strtol(argv[1], &endp, 0); + if (*endp) + return KDB_BADINT; + if (sig >= 0 ) { + kdb_printf("Invalid signal parameter.<-signal>\n"); + return 0; + } + sig=-sig; + + pid = simple_strtol(argv[2], &endp, 0); + if (*endp) + return KDB_BADINT; + if (pid <=0 ) { + kdb_printf("Process ID must be large than 0.\n"); + return 0; + } + + /* Find the process. */ + if (!(p = find_task_by_pid(pid))) { + kdb_printf("The specified process isn't found.\n"); + return 0; + } + p = p->group_leader; + info.si_signo = sig; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = pid; /* use same capabilities as process being signalled */ + info.si_uid = 0; /* kdb has root authority */ + kdb_send_sig_info(p, &info, kdb_seqno); + return 0; +} + +struct kdb_tm { + int tm_sec; /* seconds */ + int tm_min; /* minutes */ + int tm_hour; /* hours */ + int tm_mday; /* day of the month */ + int tm_mon; /* month */ + int tm_year; /* year */ +}; + +static void +kdb_gmtime(struct timespec *tv, struct kdb_tm *tm) +{ + /* This will work from 1970-2099, 2100 is not a leap year */ + static int mon_day[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + memset(tm, 0, sizeof(*tm)); + tm->tm_sec = tv->tv_sec % (24 * 60 * 60); + tm->tm_mday = tv->tv_sec / (24 * 60 * 60) + (2 * 365 + 1); /* shift base from 1970 to 1968 */ + tm->tm_min = tm->tm_sec / 60 % 60; + tm->tm_hour = tm->tm_sec / 60 / 60; + tm->tm_sec = tm->tm_sec % 60; + tm->tm_year = 68 + 4*(tm->tm_mday / (4*365+1)); + tm->tm_mday %= (4*365+1); + mon_day[1] = 29; + while (tm->tm_mday >= mon_day[tm->tm_mon]) { + tm->tm_mday -= mon_day[tm->tm_mon]; + if (++tm->tm_mon == 12) { + tm->tm_mon = 0; + ++tm->tm_year; + mon_day[1] = 28; + } + } + ++tm->tm_mday; +} + +/* + * Most of this code has been lifted from kernel/timer.c::sys_sysinfo(). + * I cannot call that code directly from kdb, it has an unconditional + * cli()/sti() and calls routines that take locks which can stop the debugger. + */ + +static void +kdb_sysinfo(struct sysinfo *val) +{ + struct timespec uptime; + do_posix_clock_monotonic_gettime(&uptime); + memset(val, 0, sizeof(*val)); + val->uptime = uptime.tv_sec; + val->loads[0] = avenrun[0]; + val->loads[1] = avenrun[1]; + val->loads[2] = avenrun[2]; + val->procs = nr_threads-1; + si_meminfo(val); + kdb_si_swapinfo(val); + + return; +} + +/* + * kdb_summary + * + * This function implements the 'summary' command. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_summary(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + extern struct timespec xtime; + extern struct timezone sys_tz; + struct kdb_tm tm; + struct sysinfo val; + + if (argc) + return KDB_ARGCOUNT; + + kdb_printf("sysname %s\n", system_utsname.sysname); + kdb_printf("release %s\n", system_utsname.release); + kdb_printf("version %s\n", system_utsname.version); + kdb_printf("machine %s\n", system_utsname.machine); + kdb_printf("nodename %s\n", system_utsname.nodename); + kdb_printf("domainname %s\n", system_utsname.domainname); + + kdb_gmtime(&xtime, &tm); + kdb_printf("date %04d-%02d-%02d %02d:%02d:%02d tz_minuteswest %d\n", + 1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, + sys_tz.tz_minuteswest); + + kdb_sysinfo(&val); + kdb_printf("uptime "); + if (val.uptime > (24*60*60)) { + int days = val.uptime / (24*60*60); + val.uptime %= (24*60*60); + kdb_printf("%d day%s ", days, days == 1 ? "" : "s"); + } + kdb_printf("%02ld:%02ld\n", val.uptime/(60*60), (val.uptime/60)%60); + + /* lifted from fs/proc/proc_misc.c::loadavg_read_proc() */ + +#define LOAD_INT(x) ((x) >> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) + kdb_printf("load avg %ld.%02ld %ld.%02ld %ld.%02ld\n", + LOAD_INT(val.loads[0]), LOAD_FRAC(val.loads[0]), + LOAD_INT(val.loads[1]), LOAD_FRAC(val.loads[1]), + LOAD_INT(val.loads[2]), LOAD_FRAC(val.loads[2])); + kdb_printf("\n"); +#undef LOAD_INT +#undef LOAD_FRAC + + kdb_meminfo_read_proc(); /* in fs/proc/proc_misc.c */ + + return 0; +} + +/* + * kdb_per_cpu + * + * This function implements the 'per_cpu' command. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +static int +kdb_per_cpu(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + char buf[256], fmtstr[64]; + kdb_symtab_t symtab; + cpumask_t suppress = CPU_MASK_NONE; + int cpu, diag; + unsigned long addr, val, bytesperword = 0, whichcpu = ~0UL; + + if (argc < 1 || argc > 3) + return KDB_ARGCOUNT; + + snprintf(buf, sizeof(buf), "per_cpu__%s", argv[1]); + if (!kdbgetsymval(buf, &symtab)) { + kdb_printf("%s is not a per_cpu variable\n", argv[1]); + return KDB_BADADDR; + } + if (argc >=2 && (diag = kdbgetularg(argv[2], &bytesperword))) + return diag; + if (!bytesperword) + bytesperword = sizeof(kdb_machreg_t); + else if (bytesperword > sizeof(kdb_machreg_t)) + return KDB_BADWIDTH; + sprintf(fmtstr, "%%0%dlx ", (int)(2*bytesperword)); + if (argc >= 3) { + if ((diag = kdbgetularg(argv[3], &whichcpu))) + return diag; + if (!cpu_online(whichcpu)) { + kdb_printf("cpu %ld is not online\n", whichcpu); + return KDB_BADCPUNUM; + } + } + + /* Most architectures use __per_cpu_offset[cpu], some use + * __per_cpu_offset(cpu), smp has no __per_cpu_offset. + */ +#ifdef __per_cpu_offset +#define KDB_PCU(cpu) __per_cpu_offset(cpu) +#else +#ifdef CONFIG_SMP +#define KDB_PCU(cpu) __per_cpu_offset[cpu] +#else +#define KDB_PCU(cpu) 0 +#endif +#endif + + for_each_online_cpu(cpu) { + if (whichcpu != ~0UL && whichcpu != cpu) + continue; + addr = symtab.sym_start + KDB_PCU(cpu); + if ((diag = kdb_getword(&val, addr, bytesperword))) { + kdb_printf("%5d " kdb_bfd_vma_fmt0 " - unable to read, diag=%d\n", + cpu, addr, diag); + continue; + } +#ifdef CONFIG_SMP + if (!val) { + cpu_set(cpu, suppress); + continue; + } +#endif /* CONFIG_SMP */ + kdb_printf("%5d ", cpu); + kdb_md_line(fmtstr, addr, + bytesperword == sizeof(kdb_machreg_t), + 1, bytesperword, 1, 1, 0); + } + if (cpus_weight(suppress) == 0) + return 0; + kdb_printf("Zero suppressed cpu(s):"); + for (cpu = first_cpu(suppress); cpu < NR_CPUS; cpu = next_cpu(cpu, suppress)) { + kdb_printf(" %d", cpu); + if (cpu == NR_CPUS-1 || next_cpu(cpu, suppress) != cpu + 1) + continue; + while (cpu < NR_CPUS && next_cpu(cpu, suppress) == cpu + 1) + ++cpu; + kdb_printf("-%d", cpu); + } + kdb_printf("\n"); + +#undef KDB_PCU + + return 0; +} + + +/* + * kdb_register_repeat + * + * This function is used to register a kernel debugger command. + * + * Inputs: + * cmd Command name + * func Function to execute the command + * usage A simple usage string showing arguments + * help A simple help string describing command + * repeat Does the command auto repeat on enter? + * Outputs: + * None. + * Returns: + * zero for success, one if a duplicate command. + * Locking: + * none. + * Remarks: + * + */ + +#define kdb_command_extend 50 /* arbitrary */ +int +kdb_register_repeat(char *cmd, + kdb_func_t func, + char *usage, + char *help, + short minlen, + kdb_repeat_t repeat) +{ + int i; + kdbtab_t *kp; + + /* + * Brute force method to determine duplicates + */ + for (i=0, kp=kdb_commands; icmd_name && (strcmp(kp->cmd_name, cmd)==0)) { + kdb_printf("Duplicate kdb command registered: '%s'\n", + cmd); + return 1; + } + } + + /* + * Insert command into first available location in table + */ + for (i=0, kp=kdb_commands; icmd_name == NULL) { + break; + } + } + + if (i >= kdb_max_commands) { + kdbtab_t *new = kmalloc((kdb_max_commands + kdb_command_extend) * sizeof(*new), GFP_KDB); + if (!new) { + kdb_printf("Could not allocate new kdb_command table\n"); + return 1; + } + if (kdb_commands) { + memcpy(new, kdb_commands, kdb_max_commands * sizeof(*new)); + kfree(kdb_commands); + } + memset(new + kdb_max_commands, 0, kdb_command_extend * sizeof(*new)); + kdb_commands = new; + kp = kdb_commands + kdb_max_commands; + kdb_max_commands += kdb_command_extend; + } + + kp->cmd_name = cmd; + kp->cmd_func = func; + kp->cmd_usage = usage; + kp->cmd_help = help; + kp->cmd_flags = 0; + kp->cmd_minlen = minlen; + kp->cmd_repeat = repeat; + + return 0; +} + +/* + * kdb_register + * + * Compatibility register function for commands that do not need to + * specify a repeat state. Equivalent to kdb_register_repeat with + * KDB_REPEAT_NONE. + * + * Inputs: + * cmd Command name + * func Function to execute the command + * usage A simple usage string showing arguments + * help A simple help string describing command + * Outputs: + * None. + * Returns: + * zero for success, one if a duplicate command. + * Locking: + * none. + * Remarks: + * + */ + +int +kdb_register(char *cmd, + kdb_func_t func, + char *usage, + char *help, + short minlen) +{ + return kdb_register_repeat(cmd, func, usage, help, minlen, KDB_REPEAT_NONE); +} + +/* + * kdb_unregister + * + * This function is used to unregister a kernel debugger command. + * It is generally called when a module which implements kdb + * commands is unloaded. + * + * Inputs: + * cmd Command name + * Outputs: + * None. + * Returns: + * zero for success, one command not registered. + * Locking: + * none. + * Remarks: + * + */ + +int +kdb_unregister(char *cmd) +{ + int i; + kdbtab_t *kp; + + /* + * find the command. + */ + for (i=0, kp=kdb_commands; icmd_name && (strcmp(kp->cmd_name, cmd)==0)) { + kp->cmd_name = NULL; + return 0; + } + } + + /* + * Couldn't find it. + */ + return 1; +} + +/* + * kdb_inittab + * + * This function is called by the kdb_init function to initialize + * the kdb command table. It must be called prior to any other + * call to kdb_register_repeat. + * + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + */ + +static void __init +kdb_inittab(void) +{ + int i; + kdbtab_t *kp; + initcall_t *call; + + for(i=0, kp=kdb_commands; i < kdb_max_commands; i++,kp++) { + kp->cmd_name = NULL; + } + + kdb_register_repeat("md", kdb_md, "", "Display Memory Contents, also mdWcN, e.g. md8c1", 1, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("mdr", kdb_md, " ", "Display Raw Memory", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("mdp", kdb_md, " ", "Display Physical Memory", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("mds", kdb_md, "", "Display Memory Symbolically", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("mm", kdb_mm, " ", "Modify Memory Contents", 0, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("id", kdb_id, "", "Display Instructions", 1, KDB_REPEAT_NO_ARGS); + kdb_register_repeat("go", kdb_go, "[]", "Continue Execution", 1, KDB_REPEAT_NONE); + kdb_register_repeat("rd", kdb_rd, "", "Display Registers", 1, KDB_REPEAT_NONE); + kdb_register_repeat("rm", kdb_rm, " ", "Modify Registers", 0, KDB_REPEAT_NONE); + kdb_register_repeat("ef", kdb_ef, "", "Display exception frame", 0, KDB_REPEAT_NONE); + kdb_register_repeat("bt", kdb_bt, "[]", "Stack traceback", 1, KDB_REPEAT_NONE); + kdb_register_repeat("btp", kdb_bt, "", "Display stack for process ", 0, KDB_REPEAT_NONE); + kdb_register_repeat("bta", kdb_bt, "[DRSTCZEUIMA]", "Display stack all processes", 0, KDB_REPEAT_NONE); + kdb_register_repeat("btc", kdb_bt, "", "Backtrace current process on each cpu", 0, KDB_REPEAT_NONE); + kdb_register_repeat("btt", kdb_bt, "", "Backtrace process given its struct task address", 0, KDB_REPEAT_NONE); + kdb_register_repeat("ll", kdb_ll, " ", "Execute cmd for each element in linked list", 0, KDB_REPEAT_NONE); + kdb_register_repeat("env", kdb_env, "", "Show environment variables", 0, KDB_REPEAT_NONE); + kdb_register_repeat("set", kdb_set, "", "Set environment variables", 0, KDB_REPEAT_NONE); + kdb_register_repeat("help", kdb_help, "", "Display Help Message", 1, KDB_REPEAT_NONE); + kdb_register_repeat("?", kdb_help, "", "Display Help Message", 0, KDB_REPEAT_NONE); + kdb_register_repeat("cpu", kdb_cpu, "","Switch to new cpu", 0, KDB_REPEAT_NONE); + kdb_register_repeat("ps", kdb_ps, "", "Display active task list", 0, KDB_REPEAT_NONE); + kdb_register_repeat("pid", kdb_pid, "", "Switch to another task", 0, KDB_REPEAT_NONE); + kdb_register_repeat("reboot", kdb_reboot, "", "Reboot the machine immediately", 0, KDB_REPEAT_NONE); +#if defined(CONFIG_MODULES) + kdb_register_repeat("lsmod", kdb_lsmod, "", "List loaded kernel modules", 0, KDB_REPEAT_NONE); +#endif +#if defined(CONFIG_MAGIC_SYSRQ) + kdb_register_repeat("sr", kdb_sr, "", "Magic SysRq key", 0, KDB_REPEAT_NONE); +#endif + kdb_register_repeat("dmesg", kdb_dmesg, "[lines]", "Display syslog buffer", 0, KDB_REPEAT_NONE); + kdb_register_repeat("defcmd", kdb_defcmd, "name \"usage\" \"help\"", "Define a set of commands, down to endefcmd", 0, KDB_REPEAT_NONE); + kdb_register_repeat("kill", kdb_kill, "<-signal> ", "Send a signal to a process", 0, KDB_REPEAT_NONE); + kdb_register_repeat("summary", kdb_summary, "", "Summarize the system", 4, KDB_REPEAT_NONE); + kdb_register_repeat("per_cpu", kdb_per_cpu, "", "Display per_cpu variables", 3, KDB_REPEAT_NONE); + + /* Any kdb commands that are not in the base code but are required + * earlier than normal initcall processing. + */ + call = &__kdb_initcall_start; + while (call < &__kdb_initcall_end) { + (*call)(); + call++; + }; +} + +/* + * kdb_cmd_init + * + * This function is called by the kdb_init function to execute any + * commands defined in kdb_cmds. + * + * Inputs: + * Commands in *kdb_cmds[]; + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + */ + +static void __init +kdb_cmd_init(void) +{ + int i, diag; + for (i = 0; kdb_cmds[i]; ++i) { + if (!defcmd_in_progress) + kdb_printf("kdb_cmd[%d]: %s", i, kdb_cmds[i]); + diag = kdb_parse(kdb_cmds[i], NULL); + if (diag) + kdb_printf("command failed, kdb diag %d\n", diag); + } + if (defcmd_in_progress) { + kdb_printf("Incomplete 'defcmd' set, forcing endefcmd\n"); + kdb_parse("endefcmd", NULL); + } +} + +/* + * kdb_panic + * + * Invoked via the panic_notifier_list. + * + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * Zero. + * Locking: + * None. + * Remarks: + * When this function is called from panic(), the other cpus have already + * been stopped. + * + */ + +static int +kdb_panic(struct notifier_block *self, unsigned long command, void *ptr) +{ + KDB_FLAG_SET(CATASTROPHIC); /* kernel state is dubious now */ + KDB_ENTER(); + return 0; +} + +static struct notifier_block kdb_block = { kdb_panic, NULL, 0 }; + +#ifdef CONFIG_SYSCTL +static int proc_do_kdb(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp, loff_t *ppos) +{ + if (KDB_FLAG(NO_CONSOLE) && write) { + printk(KERN_ERR "kdb has no working console and has switched itself off\n"); + return -EINVAL; + } + return proc_dointvec(table, write, filp, buffer, lenp, ppos); +} + +static ctl_table kdb_kern_table[] = { + { + .ctl_name = KERN_KDB, + .procname = "kdb", + .data = &kdb_on, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_do_kdb, + }, + {} +}; + +static ctl_table kdb_root_table[] = { + { + .ctl_name = CTL_KERN, + .procname = "kernel", + .mode = 0555, + .child = kdb_kern_table, + }, + {} +}; +#endif /* CONFIG_SYSCTL */ + +/* + * kdb_init + * + * Initialize the kernel debugger environment. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +void __init +kdb_init(void) +{ + kdb_initial_cpu = smp_processor_id(); + /* + * This must be called before any calls to kdb_printf. + */ + kdb_io_init(); + + kdb_inittab(); /* Initialize Command Table */ + kdb_initbptab(); /* Initialize Breakpoint Table */ + kdb_id_init(); /* Initialize Disassembler */ + kdb_initsupport(); /* Initialize support routines */ + kdba_init(); /* Architecture Dependent Initialization */ + + /* + * Use printk() to get message in log_buf[]; + */ + printk("kdb version %d.%d%s by Keith Owens, Scott Lurndal. "\ + "Copyright SGI, All Rights Reserved\n", + KDB_MAJOR_VERSION, KDB_MINOR_VERSION, KDB_TEST_VERSION); + + kdb_cmd_init(); /* Preset commands from kdb_cmds */ + kdb_initial_cpu = -1; /* Avoid recursion problems */ + kdb(KDB_REASON_SILENT, 0, 0); /* Activate any preset breakpoints on boot cpu */ + kdb_initial_cpu = smp_processor_id(); + notifier_chain_register(&panic_notifier_list, &kdb_block); + +#ifdef KDB_HAVE_LONGJMP + kdbjmpbuf = vmalloc(NR_CPUS * sizeof(*kdbjmpbuf)); + if (!kdbjmpbuf) + printk(KERN_ERR "Cannot allocate kdbjmpbuf, no kdb recovery will be possible\n"); +#endif /* KDB_HAVE_LONGJMP */ + + kdb_initial_cpu = -1; +} + +#ifdef CONFIG_SYSCTL +static int __init +kdb_late_init(void) +{ + register_sysctl_table(kdb_root_table, 0); + return 0; +} + +__initcall(kdb_late_init); +#endif + +EXPORT_SYMBOL(kdb_register); +EXPORT_SYMBOL(kdb_register_repeat); +EXPORT_SYMBOL(kdb_unregister); +EXPORT_SYMBOL(kdb_getarea_size); +EXPORT_SYMBOL(kdb_putarea_size); +EXPORT_SYMBOL(kdb_getuserarea_size); +EXPORT_SYMBOL(kdb_putuserarea_size); +EXPORT_SYMBOL(kdbgetularg); +EXPORT_SYMBOL(kdbgetenv); +EXPORT_SYMBOL(kdbgetintenv); +EXPORT_SYMBOL(kdbgetaddrarg); +EXPORT_SYMBOL(kdb); +EXPORT_SYMBOL(kdb_on); +EXPORT_SYMBOL(kdb_seqno); +EXPORT_SYMBOL(kdb_initial_cpu); +EXPORT_SYMBOL(kdbnearsym); +EXPORT_SYMBOL(kdb_printf); +EXPORT_SYMBOL(kdb_symbol_print); +EXPORT_SYMBOL(kdb_running_process); Index: 2.6.x-xfs/kdb/kdbsupport.c =================================================================== --- 2.6.x-xfs.orig/kdb/kdbsupport.c 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/kdbsupport.c 2006-02-28 11:26:53.536264897 +1100 @@ -0,0 +1,1285 @@ +/* + * Kernel Debugger Architecture Independent Support Functions + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. + * 03/02/13 added new 2.5 kallsyms + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#ifdef CONFIG_MODULES +extern struct list_head *kdb_modules; +#endif + +/* + * Symbol table functions. + */ + +/* + * kdbgetsymval + * + * Return the address of the given symbol. + * + * Parameters: + * symname Character string containing symbol name + * symtab Structure to receive results + * Outputs: + * Returns: + * 0 Symbol not found, symtab zero filled + * 1 Symbol mapped to module/symbol/section, data in symtab + * Locking: + * None. + * Remarks: + */ + +int +kdbgetsymval(const char *symname, kdb_symtab_t *symtab) +{ + if (KDB_DEBUG(AR)) + kdb_printf("kdbgetsymval: symname=%s, symtab=%p\n", symname, symtab); + memset(symtab, 0, sizeof(*symtab)); + + if ((symtab->sym_start = kallsyms_lookup_name(symname))) { + if (KDB_DEBUG(AR)) + kdb_printf("kdbgetsymval: returns 1, symtab->sym_start=0x%lx\n", symtab->sym_start); + return 1; + } + if (KDB_DEBUG(AR)) + kdb_printf("kdbgetsymval: returns 0\n"); + return 0; +} + +/* + * kdbnearsym + * + * Return the name of the symbol with the nearest address + * less than 'addr'. + * + * Parameters: + * addr Address to check for symbol near + * symtab Structure to receive results + * Outputs: + * Returns: + * 0 No sections contain this address, symtab zero filled + * 1 Address mapped to module/symbol/section, data in symtab + * Locking: + * None. + * Remarks: + * 2.6 kallsyms has a "feature" where it unpacks the name into a string. + * If that string is reused before the caller expects it then the caller + * sees its string change without warning. To avoid cluttering up the + * main kdb code with lots of kdb_strdup, tests and kfree calls, kdbnearsym + * maintains an LRU list of the last few unique strings. The list is sized + * large enough to hold active strings, no kdb caller of kdbnearsym makes + * more than ~20 later calls before using a saved value. + */ + +int +kdbnearsym(unsigned long addr, kdb_symtab_t *symtab) +{ + int ret = 0; + unsigned long symbolsize; + unsigned long offset; + static char *knt[100]; /* kdb name table, arbitrary size */ +#define knt1_size 128 /* must be >= kallsyms table size */ + char *knt1 = NULL; + + if (KDB_DEBUG(AR)) + kdb_printf("kdbnearsym: addr=0x%lx, symtab=%p\n", addr, symtab); + memset(symtab, 0, sizeof(*symtab)); + + if (addr < 4096) + goto out; + knt1 = debug_kmalloc(knt1_size, GFP_ATOMIC); + if (!knt1) { + kdb_printf("kdbnearsym: addr=0x%lx cannot kmalloc knt1\n", addr); + goto out; + } + symtab->sym_name = kallsyms_lookup(addr, &symbolsize , &offset, (char **)(&symtab->mod_name), knt1); + if (offset > 8*1024*1024) { + symtab->sym_name = NULL; + addr = offset = symbolsize = 0; + } + symtab->sym_start = addr - offset; + symtab->sym_end = symtab->sym_start + symbolsize; + ret = symtab->sym_name != NULL && *(symtab->sym_name) != '\0'; + + if (ret) { + int i; + /* Another 2.6 kallsyms "feature". Sometimes the sym_name is + * set but the buffer passed into kallsyms_lookup is not used, + * so it contains garbage. The caller has to work out which + * buffer needs to be saved. + * + * What was Rusty smoking when he wrote that code? + */ + if (symtab->sym_name != knt1) { + strncpy(knt1, symtab->sym_name, knt1_size); + knt1[knt1_size-1] = '\0'; + } + for (i = 0; i < ARRAY_SIZE(knt); ++i) { + if (knt[i] && strcmp(knt[i], knt1) == 0) + break; + } + if (i >= ARRAY_SIZE(knt)) { + debug_kfree(knt[0]); + memcpy(knt, knt+1, sizeof(knt[0])*(ARRAY_SIZE(knt)-1)); + } else { + debug_kfree(knt1); + knt1 = knt[i]; + memcpy(knt+i, knt+i+1, sizeof(knt[0])*(ARRAY_SIZE(knt)-i-1)); + } + i = ARRAY_SIZE(knt) - 1; + knt[i] = knt1; + symtab->sym_name = knt[i]; + knt1 = NULL; + } + + if (symtab->mod_name == NULL) + symtab->mod_name = "kernel"; + if (KDB_DEBUG(AR)) + kdb_printf("kdbnearsym: returns %d symtab->sym_start=0x%lx, symtab->mod_name=%p, symtab->sym_name=%p (%s)\n", ret, symtab->sym_start, symtab->mod_name, symtab->sym_name, symtab->sym_name); + +out: + debug_kfree(knt1); + return ret; +} + +/* + * kallsyms_symbol_complete + * + * Parameters: + * prefix_name prefix of a symbol name to lookup + * max_len maximum length that can be returned + * Returns: + * Number of symbols which match the given prefix. + * Notes: + * prefix_name is changed to contain the longest unique prefix that + * starts with this prefix (tab completion). + */ + +static char ks_namebuf[KSYM_NAME_LEN+1], ks_namebuf_prev[KSYM_NAME_LEN+1]; + +int kallsyms_symbol_complete(char *prefix_name, int max_len) +{ + loff_t pos = 0; + int prefix_len = strlen(prefix_name), prev_len = 0; + int i, number = 0; + const char *name; + + while ((name = kdb_walk_kallsyms(&pos))) { + if (strncmp(name, prefix_name, prefix_len) == 0) { + strcpy(ks_namebuf, name); + /* Work out the longest name that matches the prefix */ + if (++number == 1) { + prev_len = min_t(int, max_len-1, strlen(ks_namebuf)); + memcpy(ks_namebuf_prev, ks_namebuf, prev_len); + ks_namebuf_prev[prev_len] = '\0'; + } else for (i = 0; i < prev_len; ++i) { + if (ks_namebuf[i] != ks_namebuf_prev[i]) { + prev_len = i; + ks_namebuf_prev[i] = '\0'; + break; + } + } + } + } + if (prev_len > prefix_len) + memcpy(prefix_name, ks_namebuf_prev, prev_len+1); + return number; +} + +/* + * kallsyms_symbol_next + * + * Parameters: + * prefix_name prefix of a symbol name to lookup + * flag 0 means search from the head, 1 means continue search. + * Returns: + * 1 if a symbol matches the given prefix. + * 0 if no string found + */ + +int kallsyms_symbol_next(char *prefix_name, int flag) +{ + int prefix_len = strlen(prefix_name); + static loff_t pos; + const char *name; + + if (!flag) + pos = 0; + + while ((name = kdb_walk_kallsyms(&pos))) { + if (strncmp(name, prefix_name, prefix_len) == 0) { + strncpy(prefix_name, name, strlen(name)+1); + return 1; + } + } + return 0; +} + +#if defined(CONFIG_SMP) +/* + * kdb_ipi + * + * This function is called from the non-maskable interrupt + * handler to handle a kdb IPI instruction. + * + * Inputs: + * regs = Exception frame pointer + * Outputs: + * None. + * Returns: + * 0 - Did not handle NMI + * 1 - Handled NMI + * Locking: + * None. + * Remarks: + * Initially one processor is invoked in the kdb() code. That + * processor sends an ipi which drives this routine on the other + * processors. All this does is call kdb() with reason SWITCH. + * This puts all processors into the kdb() routine and all the + * code for breakpoints etc. is in one place. + * One problem with the way the kdb NMI is sent, the NMI has no + * identification that says it came from kdb. If the cpu's kdb state is + * marked as "waiting for kdb_ipi" then the NMI is treated as coming from + * kdb, otherwise it is assumed to be for another reason and is ignored. + */ + +int +kdb_ipi(struct pt_regs *regs, void (*ack_interrupt)(void)) +{ + /* Do not print before checking and clearing WAIT_IPI, IPIs are + * going all the time. + */ + if (KDB_STATE(WAIT_IPI)) { + /* + * Stopping other processors via smp_kdb_stop(). + */ + if (ack_interrupt) + (*ack_interrupt)(); /* Acknowledge the interrupt */ + KDB_STATE_CLEAR(WAIT_IPI); + KDB_DEBUG_STATE("kdb_ipi 1", 0); + kdb(KDB_REASON_SWITCH, 0, regs); /* Spin in kdb() */ + KDB_DEBUG_STATE("kdb_ipi 2", 0); + return 1; + } + return 0; +} +#endif /* CONFIG_SMP */ + +#if defined(__i386__) || defined(__x86_64__) +void +kdb_enablehwfault(void) +{ + kdba_enable_mce(); +} + +/* + * kdb_get_next_ar + * + * Get the next activation record from the stack. + * + * Inputs: + * arend Last byte +1 of the activation record. sp for the first + * frame, start of callee's activation record otherwise. + * func Start address of function. + * pc Current program counter within this function. pc for + * the first frame, caller's return address otherwise. + * fp Current frame pointer. Register fp for the first + * frame, oldfp otherwise. 0 if not known. + * ss Start of stack for the current process. + * Outputs: + * ar Activation record. + * symtab kallsyms symbol table data for the calling function. + * Returns: + * 1 if ar is usable, 0 if not. + * Locking: + * None. + * Remarks: + * Activation Record format, assuming a stack that grows down + * (KDB_STACK_DIRECTION == -1). + * + * +-----------------------------+ ^ ===================== + * | Return address, frame 3 | | + * +-----------------------------+ | + * | Frame Pointer, frame 3 |>--' + * +-----------------------------+<--. + * | Locals and automatics, | | + * | frame 2. (variable size) | | AR 2 + * +-----------------------------+ | + * | Save registers, | | + * | frame 2. (variable size) | | + * +-----------------------------+ | + * | Arguments to frame 1, | | + * | (variable size) | | + * +-----------------------------+ | ===================== + * | Return address, frame 2 | | + * +-----------------------------+ | + * | Frame Pointer, frame 2 |>--' + * +-----------------------------+<--. + * | Locals and automatics, | | + * | frame 1. (variable size) | | AR 1 + * +-----------------------------+ | + * | Save registers, | | + * | frame 1. (variable size) | | + * +-----------------------------+ | + * | Arguments to frame 0, | | + * | (variable size) | | + * +-----------------------------+ | -- (5) ===================== + * | Return address, frame 1 | | + * +-----------------------------+ | -- (0) + * | Frame Pointer, frame 1 |>--' + * +-----------------------------+ -- (1), (2) + * | Locals and automatics, | + * | frame 0. (variable size) | AR 0 + * +-----------------------------+ -- (3) + * | Save registers, | + * | frame 0. (variable size) | + * +-----------------------------+ -- (4) ===================== + * + * The stack for the top frame can be in one of several states. + * (0) Immediately on entry to the function, stack pointer (sp) is + * here. + * (1) If the function was compiled with frame pointers and the 'push + * fp' instruction has been executed then the pointer to the + * previous frame is on the stack. However there is no guarantee + * that this saved pointer is valid, the calling function might + * not have frame pointers. sp is adjusted by wordsize after + * 'push fp'. + * (2) If the function was compiled with frame pointers and the 'copy + * sp to fp' instruction has been executed then fp points here. + * (3) If the function startup has 'adjust sp by 0xnn bytes' and that + * instruction has been executed then sp has been adjusted by + * 0xnn bytes for local and automatic variables. + * (4) If the function startup has one or more 'push reg' instructions + * and any have been executed then sp has been adjusted by + * wordsize bytes for each register saved. + * + * As the function exits it rewinds the stack, typically to (1) then (0). + * + * The stack entries for the lower frames is normally are in state (5). + * (5) Arguments for the called frame are on to the stack. + * However lower frames can be incomplete if there is an interrupt in + * progress. + * + * An activation record runs from the return address for a function + * through to the return address for the next function or sp, whichever + * comes first. For each activation record we extract :- + * + * start Address of the activation record. + * end Address of the last byte+1 in the activation record. + * ret Return address to caller. + * oldfp Frame pointer to previous frame, 0 if this function was + * not compiled with frame pointers. + * fp Frame pointer for the current frame, 0 if this function + * was not compiled with frame pointers or fp has not been + * set yet. + * arg0 Address of the first argument (in the previous activation + * record). + * locals Bytes allocated to locals and automatics. + * regs Bytes allocated to saved registers. + * args Bytes allocated to arguments (in the previous activation + * record). + * setup Bytes allocated to setup data on stack (return address, + * frame pointer). + * + * Although the kernel might be compiled with frame pointers, we still + * have to assume the worst and validate the frame. Some calls from + * asm code to C code might not use frame pointers. Third party binary + * only modules might be compiled without frame pointers, even when the + * rest of the kernel has frame pointers. Some routines are always + * compiled with frame pointers, even if the overall kernel is not. A + * routine compiled with frame pointers can be called from a routine + * without frame pointers, the previous "frame pointer" is saved on + * stack but it contains garbage. + * + * We check the object code to see if it saved a frame pointer and we + * validate that pointer. Basically frame pointers are hints. + */ + +#define FORCE_ARG(ar,n) (ar)->setup = (ar)->locals = (ar)->regs = \ + (ar)->fp = (ar)->oldfp = (ar)->ret = 0; \ + (ar)->start = (ar)->end - KDB_STACK_DIRECTION*(n)*sizeof(unsigned long); + +int +kdb_get_next_ar(kdb_machreg_t arend, kdb_machreg_t func, + kdb_machreg_t pc, kdb_machreg_t fp, kdb_machreg_t ss, + kdb_ar_t *ar, kdb_symtab_t *symtab) +{ + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: arend=0x%lx func=0x%lx pc=0x%lx fp=0x%lx\n", + arend, func, pc, fp); + } + + memset(ar, 0, sizeof(*ar)); + if (!kdbnearsym(pc, symtab)) { + symtab->sym_name = symtab->sec_name = ""; + symtab->mod_name = "kernel"; + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: callee not in kernel\n"); + } + pc = 0; + } + + if (!kdba_prologue(symtab, pc, arend, fp, ss, 0, ar)) { + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: callee prologue failed\n"); + } + return(0); + } + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: callee activation record\n"); + kdb_printf(" start=0x%lx end=0x%lx ret=0x%lx oldfp=0x%lx fp=0x%lx\n", + ar->start, ar->end, ar->ret, ar->oldfp, ar->fp); + kdb_printf(" locals=%ld regs=%ld setup=%ld\n", + ar->locals, ar->regs, ar->setup); + } + + if (ar->ret) { + /* Run the caller code to get arguments to callee function */ + kdb_symtab_t caller_symtab; + kdb_ar_t caller_ar; + memset(&caller_ar, 0, sizeof(caller_ar)); + if (!kdbnearsym(ar->ret, &caller_symtab)) { + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: caller not in kernel\n"); + } + } else if (kdba_prologue(&caller_symtab, ar->ret, + ar->start, ar->oldfp, ss, 1, &caller_ar)) { + /* some caller data extracted */ ; + } else if (strcmp(symtab->sym_name, "do_exit") == 0) { + /* non-standard caller, force one argument */ + FORCE_ARG(&caller_ar, 1); + } else if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: caller prologue failed\n"); + } + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: caller activation record\n"); + kdb_printf(" start=0x%lx end=0x%lx ret=0x%lx" + " oldfp=0x%lx fp=0x%lx\n", + caller_ar.start, caller_ar.end, caller_ar.ret, + caller_ar.oldfp, caller_ar.fp); + kdb_printf(" locals=%ld regs=%ld args=%ld setup=%ld\n", + caller_ar.locals, caller_ar.regs, + caller_ar.args, caller_ar.setup); + } + if (caller_ar.start) { + ar->args = KDB_STACK_DIRECTION*(caller_ar.end - caller_ar.start) - + (caller_ar.setup + caller_ar.locals + caller_ar.regs); + if (ar->args < 0) + ar->args = 0; + if (ar->args) { + ar->arg0 = ar->start - + KDB_STACK_DIRECTION*(ar->args - sizeof (ar->args)); + if (KDB_DEBUG(AR)) { + kdb_printf(" callee arg0=0x%lx args=%ld\n", + ar->arg0, ar->args); + } + } + } + } + + return(1); +} +#endif /* defined(__i386__) || defined(__x86_64__) */ + +/* + * kdb_symbol_print + * + * Standard method for printing a symbol name and offset. + * Inputs: + * addr Address to be printed. + * symtab Address of symbol data, if NULL this routine does its + * own lookup. + * punc Punctuation for string, bit field. + * Outputs: + * None. + * Returns: + * Always 0. + * Locking: + * none. + * Remarks: + * The string and its punctuation is only printed if the address + * is inside the kernel, except that the value is always printed + * when requested. + */ + +void +kdb_symbol_print(kdb_machreg_t addr, const kdb_symtab_t *symtab_p, unsigned int punc) +{ + kdb_symtab_t symtab, *symtab_p2; + if (symtab_p) { + symtab_p2 = (kdb_symtab_t *)symtab_p; + } + else { + symtab_p2 = &symtab; + kdbnearsym(addr, symtab_p2); + } + if (symtab_p2->sym_name || (punc & KDB_SP_VALUE)) { + ; /* drop through */ + } + else { + return; + } + if (punc & KDB_SP_SPACEB) { + kdb_printf(" "); + } + if (punc & KDB_SP_VALUE) { + kdb_printf(kdb_machreg_fmt0, addr); + } + if (symtab_p2->sym_name) { + if (punc & KDB_SP_VALUE) { + kdb_printf(" "); + } + if (punc & KDB_SP_PAREN) { + kdb_printf("("); + } + if (strcmp(symtab_p2->mod_name, "kernel")) { + kdb_printf("[%s]", symtab_p2->mod_name); + } + kdb_printf("%s", symtab_p2->sym_name); + if (addr != symtab_p2->sym_start) { + kdb_printf("+0x%lx", addr - symtab_p2->sym_start); + } + if (punc & KDB_SP_SYMSIZE) { + kdb_printf("/0x%lx", symtab_p2->sym_end - symtab_p2->sym_start); + } + if (punc & KDB_SP_PAREN) { + kdb_printf(")"); + } + } + if (punc & KDB_SP_SPACEA) { + kdb_printf(" "); + } + if (punc & KDB_SP_NEWLINE) { + kdb_printf("\n"); + } +} + +/* + * kdb_strdup + * + * kdb equivalent of strdup, for disasm code. + * Inputs: + * str The string to duplicate. + * type Flags to kmalloc for the new string. + * Outputs: + * None. + * Returns: + * Address of the new string, NULL if storage could not be allocated. + * Locking: + * none. + * Remarks: + * This is not in lib/string.c because it uses kmalloc which is not + * available when string.o is used in boot loaders. + */ + +char *kdb_strdup(const char *str, int type) +{ + int n = strlen(str)+1; + char *s = kmalloc(n, type); + if (!s) return NULL; + return strcpy(s, str); +} + +/* + * kdb_getarea_size + * + * Read an area of data. The kdb equivalent of copy_from_user, with + * kdb messages for invalid addresses. + * Inputs: + * res Pointer to the area to receive the result. + * addr Address of the area to copy. + * size Size of the area. + * Outputs: + * none. + * Returns: + * 0 for success, < 0 for error. + * Locking: + * none. + */ + +int kdb_getarea_size(void *res, unsigned long addr, size_t size) +{ + int ret = kdba_getarea_size(res, addr, size); + if (ret) { + if (!KDB_STATE(SUPPRESS)) { + kdb_printf("kdb_getarea: Bad address 0x%lx\n", addr); + KDB_STATE_SET(SUPPRESS); + } + ret = KDB_BADADDR; + } + else { + KDB_STATE_CLEAR(SUPPRESS); + } + return(ret); +} + +/* + * kdb_putarea_size + * + * Write an area of data. The kdb equivalent of copy_to_user, with + * kdb messages for invalid addresses. + * Inputs: + * addr Address of the area to write to. + * res Pointer to the area holding the data. + * size Size of the area. + * Outputs: + * none. + * Returns: + * 0 for success, < 0 for error. + * Locking: + * none. + */ + +int kdb_putarea_size(unsigned long addr, void *res, size_t size) +{ + int ret = kdba_putarea_size(addr, res, size); + if (ret) { + if (!KDB_STATE(SUPPRESS)) { + kdb_printf("kdb_putarea: Bad address 0x%lx\n", addr); + KDB_STATE_SET(SUPPRESS); + } + ret = KDB_BADADDR; + } + else { + KDB_STATE_CLEAR(SUPPRESS); + } + return(ret); +} + +/* + * kdb_getphys + * + * Read data from a physical address. Validate the address is in range, + * use kmap_atomic() to get data + * + * Similar to kdb_getarea() - but for phys addresses + * + * Inputs: + * res Pointer to the word to receive the result + * addr Physical address of the area to copy + * size Size of the area + * Outputs: + * none. + * Returns: + * 0 for success, < 0 for error. + * Locking: + * none. + */ +static int kdb_getphys(void *res, unsigned long addr, size_t size) +{ + unsigned long pfn; + void *vaddr; + struct page *page; + + pfn = (addr >> PAGE_SHIFT); + if (!pfn_valid(pfn)) + return 1; + page = pfn_to_page(pfn); + vaddr = kmap_atomic(page, KM_KDB); + memcpy(res, vaddr + (addr & (PAGE_SIZE -1)), size); + kunmap_atomic(vaddr, KM_KDB); + + return 0; +} + +/* + * kdb_getphysword + * + * Inputs: + * word Pointer to the word to receive the result. + * addr Address of the area to copy. + * size Size of the area. + * Outputs: + * none. + * Returns: + * 0 for success, < 0 for error. + * Locking: + * none. + */ +int kdb_getphysword(unsigned long *word, unsigned long addr, size_t size) +{ + int diag; + __u8 w1; + __u16 w2; + __u32 w4; + __u64 w8; + *word = 0; /* Default value if addr or size is invalid */ + + switch (size) { + case 1: + if (!(diag = kdb_getphys(&w1, addr, sizeof(w1)))) + *word = w1; + break; + case 2: + if (!(diag = kdb_getphys(&w2, addr, sizeof(w2)))) + *word = w2; + break; + case 4: + if (!(diag = kdb_getphys(&w4, addr, sizeof(w4)))) + *word = w4; + break; + case 8: + if (size <= sizeof(*word)) { + if (!(diag = kdb_getphys(&w8, addr, sizeof(w8)))) + *word = w8; + break; + } + /* drop through */ + default: + diag = KDB_BADWIDTH; + kdb_printf("kdb_getphysword: bad width %ld\n", (long) size); + } + return(diag); +} + +/* + * kdb_getword + * + * Read a binary value. Unlike kdb_getarea, this treats data as numbers. + * Inputs: + * word Pointer to the word to receive the result. + * addr Address of the area to copy. + * size Size of the area. + * Outputs: + * none. + * Returns: + * 0 for success, < 0 for error. + * Locking: + * none. + */ + +int kdb_getword(unsigned long *word, unsigned long addr, size_t size) +{ + int diag; + __u8 w1; + __u16 w2; + __u32 w4; + __u64 w8; + *word = 0; /* Default value if addr or size is invalid */ + switch (size) { + case 1: + if (!(diag = kdb_getarea(w1, addr))) + *word = w1; + break; + case 2: + if (!(diag = kdb_getarea(w2, addr))) + *word = w2; + break; + case 4: + if (!(diag = kdb_getarea(w4, addr))) + *word = w4; + break; + case 8: + if (size <= sizeof(*word)) { + if (!(diag = kdb_getarea(w8, addr))) + *word = w8; + break; + } + /* drop through */ + default: + diag = KDB_BADWIDTH; + kdb_printf("kdb_getword: bad width %ld\n", (long) size); + } + return(diag); +} + +/* + * kdb_putword + * + * Write a binary value. Unlike kdb_putarea, this treats data as numbers. + * Inputs: + * addr Address of the area to write to.. + * word The value to set. + * size Size of the area. + * Outputs: + * none. + * Returns: + * 0 for success, < 0 for error. + * Locking: + * none. + */ + +int kdb_putword(unsigned long addr, unsigned long word, size_t size) +{ + int diag; + __u8 w1; + __u16 w2; + __u32 w4; + __u64 w8; + switch (size) { + case 1: + w1 = word; + diag = kdb_putarea(addr, w1); + break; + case 2: + w2 = word; + diag = kdb_putarea(addr, w2); + break; + case 4: + w4 = word; + diag = kdb_putarea(addr, w4); + break; + case 8: + if (size <= sizeof(word)) { + w8 = word; + diag = kdb_putarea(addr, w8); + break; + } + /* drop through */ + default: + diag = KDB_BADWIDTH; + kdb_printf("kdb_putword: bad width %ld\n", (long) size); + } + return(diag); +} + +/* + * kdb_task_state_string + * + * Convert a string containing any of the letters DRSTCZEUIMA to a mask + * for the process state field and return the value. If no argument is + * supplied, return the mask that corresponds to environment variable PS, + * DRSTCZEU by default. + * Inputs: + * s String to convert + * Outputs: + * none. + * Returns: + * Mask for process state. + * Locking: + * none. + * Notes: + * The mask folds data from several sources into a single long value, so + * be carefull not to overlap the bits. TASK_* bits are in the LSB, + * special cases like UNRUNNABLE are in the MSB. As of 2.6.10-rc1 there + * is no overlap between TASK_* and EXIT_* but that may not always be + * true, so EXIT_* bits are shifted left 16 bits before being stored in + * the mask. + */ + +#define UNRUNNABLE (1UL << (8*sizeof(unsigned long) - 1)) /* unrunnable is < 0 */ +#define RUNNING (1UL << (8*sizeof(unsigned long) - 2)) +#define IDLE (1UL << (8*sizeof(unsigned long) - 3)) +#define DAEMON (1UL << (8*sizeof(unsigned long) - 4)) + +unsigned long +kdb_task_state_string(const char *s) +{ + long res = 0; + if (!s && !(s = kdbgetenv("PS"))) { + s = "DRSTCZEU"; /* default value for ps */ + } + while (*s) { + switch (*s) { + case 'D': res |= TASK_UNINTERRUPTIBLE; break; + case 'R': res |= RUNNING; break; + case 'S': res |= TASK_INTERRUPTIBLE; break; + case 'T': res |= TASK_STOPPED; break; + case 'C': res |= TASK_TRACED; break; + case 'Z': res |= EXIT_ZOMBIE << 16; break; + case 'E': res |= EXIT_DEAD << 16; break; + case 'U': res |= UNRUNNABLE; break; + case 'I': res |= IDLE; break; + case 'M': res |= DAEMON; break; + case 'A': res = ~0UL; break; + default: + kdb_printf("%s: unknown flag '%c' ignored\n", __FUNCTION__, *s); + break; + } + ++s; + } + return res; +} + +/* + * kdb_task_state_char + * + * Return the character that represents the task state. + * Inputs: + * p struct task for the process + * Outputs: + * none. + * Returns: + * One character to represent the task state. + * Locking: + * none. + */ + +char +kdb_task_state_char (const struct task_struct *p) +{ + int cpu = kdb_process_cpu(p); + struct kdb_running_process *krp = kdb_running_process + cpu; + char state = (p->state == 0) ? 'R' : + (p->state < 0) ? 'U' : + (p->state & TASK_UNINTERRUPTIBLE) ? 'D' : + (p->state & TASK_STOPPED) ? 'T' : + (p->state & TASK_TRACED) ? 'C' : + (p->exit_state & EXIT_ZOMBIE) ? 'Z' : + (p->exit_state & EXIT_DEAD) ? 'E' : + (p->state & TASK_INTERRUPTIBLE) ? 'S' : '?'; + if (p->pid == 0) { + /* Idle task. Is it really idle, apart from the kdb interrupt? */ + if (!kdb_task_has_cpu(p) || krp->irq_depth == 1) { + /* There is a corner case when the idle task takes an + * interrupt and dies in the interrupt code. It has an + * interrupt count of 1 but that did not come from kdb. + * This corner case can only occur on the initial cpu, + * all the others were entered via the kdb IPI. + */ + if (cpu != kdb_initial_cpu || KDB_STATE_CPU(KEYBOARD, cpu)) + state = 'I'; /* idle task */ + } + } + else if (!p->mm && state == 'S') { + state = 'M'; /* sleeping system daemon */ + } + return state; +} + +/* + * kdb_task_state + * + * Return true if a process has the desired state given by the mask. + * Inputs: + * p struct task for the process + * mask mask from kdb_task_state_string to select processes + * Outputs: + * none. + * Returns: + * True if the process matches at least one criteria defined by the mask. + * Locking: + * none. + */ + +unsigned long +kdb_task_state(const struct task_struct *p, unsigned long mask) +{ + char state[] = { kdb_task_state_char(p), '\0' }; + return (mask & kdb_task_state_string(state)) != 0; +} + +struct kdb_running_process kdb_running_process[NR_CPUS]; + +/* + * kdb_save_running + * + * Save the state of a running process. This is invoked on the current + * process on each cpu (assuming the cpu is responding). + * Inputs: + * regs struct pt_regs for the process + * Outputs: + * Updates kdb_running_process[] for this cpu. + * Returns: + * none. + * Locking: + * none. + */ + +void +kdb_save_running(struct pt_regs *regs) +{ + struct kdb_running_process *krp = kdb_running_process + smp_processor_id(); + krp->p = current; + krp->regs = regs; + krp->seqno = kdb_seqno; + krp->irq_depth = hardirq_count() >> HARDIRQ_SHIFT; + kdba_save_running(&(krp->arch), regs); +} + +/* + * kdb_unsave_running + * + * Reverse the effect of kdb_save_running. + * Inputs: + * regs struct pt_regs for the process + * Outputs: + * Updates kdb_running_process[] for this cpu. + * Returns: + * none. + * Locking: + * none. + */ + +void +kdb_unsave_running(struct pt_regs *regs) +{ + struct kdb_running_process *krp = kdb_running_process + smp_processor_id(); + kdba_unsave_running(&(krp->arch), regs); + krp->seqno = 0; +} + + +/* + * kdb_print_nameval + * + * Print a name and its value, converting the value to a symbol lookup + * if possible. + * Inputs: + * name field name to print + * val value of field + * Outputs: + * none. + * Returns: + * none. + * Locking: + * none. + */ + +void +kdb_print_nameval(const char *name, unsigned long val) +{ + kdb_symtab_t symtab; + kdb_printf(" %-11.11s ", name); + if (kdbnearsym(val, &symtab)) + kdb_symbol_print(val, &symtab, KDB_SP_VALUE|KDB_SP_SYMSIZE|KDB_SP_NEWLINE); + else + kdb_printf("0x%lx\n", val); +} + +static struct page * kdb_get_one_user_page(const struct task_struct *tsk, unsigned long start, + int len, int write) +{ + struct mm_struct *mm = tsk->mm; + unsigned int flags; + struct vm_area_struct * vma; + + /* shouldn't cross a page boundary. */ + if ((start & PAGE_MASK) != ((start+len) & PAGE_MASK)) + return NULL; + + /* we need to align start address to the current page boundy, PAGE_ALIGN + * aligns to next page boundry. + * FIXME: What about hugetlb? + */ + start = start & PAGE_MASK; + flags = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD); + + vma = find_extend_vma(mm, start); + + /* may be we can allow access to VM_IO pages inside KDB? */ + if (!vma || (vma->vm_flags & VM_IO) || !(flags & vma->vm_flags)) + return NULL; + + return follow_page(vma, start, write ? FOLL_WRITE : 0); +} + +int kdb_getuserarea_size(void *to, unsigned long from, size_t size) +{ + struct page *page; + void *vaddr; + + page = kdb_get_one_user_page(kdb_current_task, from, size, 0); + if (!page) + return size; + + vaddr = kmap_atomic(page, KM_KDB); + memcpy(to, vaddr+ (from & (PAGE_SIZE - 1)), size); + kunmap_atomic(vaddr, KM_KDB); + + return 0; +} + +int kdb_putuserarea_size(unsigned long to, void *from, size_t size) +{ + struct page *page; + void *vaddr; + + page = kdb_get_one_user_page(kdb_current_task, to, size, 1); + if (!page) + return size; + + vaddr = kmap_atomic(page, KM_KDB); + memcpy(vaddr+ (to & (PAGE_SIZE - 1)), from, size); + kunmap_atomic(vaddr, KM_KDB); + + return 0; +} + +/* Last ditch allocator for debugging, so we can still debug even when the + * GFP_ATOMIC pool has been exhausted. The algorithms are tuned for space + * usage, not for speed. One smallish memory pool, the free chain is always in + * ascending address order to allow coalescing, allocations are done in brute + * force best fit. + */ + +struct debug_alloc_header { + u32 next; /* offset of next header from start of pool */ + u32 size; +}; +#define dah_align 8 + +static u64 debug_alloc_pool_aligned[64*1024/dah_align]; /* 64K pool */ +static char *debug_alloc_pool = (char *)debug_alloc_pool_aligned; +static u32 dah_first; + +/* Locking is awkward. The debug code is called from all contexts, including + * non maskable interrupts. A normal spinlock is not safe in NMI context. Try + * to get the debug allocator lock, if it cannot be obtained after a second + * then give up. If the lock could not be previously obtained on this cpu then + * only try once. + */ +static DEFINE_SPINLOCK(dap_lock); +static +int get_dap_lock(void) +{ + static int dap_locked = -1; + int count; + if (dap_locked == smp_processor_id()) + count = 1; + else + count = 1000; + while (1) { + if (spin_trylock(&dap_lock)) { + dap_locked = -1; + return 1; + } + if (!count--) + break; + udelay(1000); + } + dap_locked = smp_processor_id(); + return 0; +} + +void *debug_kmalloc(size_t size, int flags) +{ + unsigned int rem, h_offset; + struct debug_alloc_header *best, *bestprev, *prev, *h; + void *p = NULL; + if ((p = kmalloc(size, flags))) + return p; + if (!get_dap_lock()) + return NULL; + h = (struct debug_alloc_header *)(debug_alloc_pool + dah_first); + prev = best = bestprev = NULL; + while (1) { + if (h->size >= size && (!best || h->size < best->size)) { + best = h; + bestprev = prev; + } + if (!h->next) + break; + prev = h; + h = (struct debug_alloc_header *)(debug_alloc_pool + h->next); + } + if (!best) + goto out; + rem = (best->size - size) & -dah_align; + /* The pool must always contain at least one header */ + if (best->next == 0 && bestprev == NULL && rem < sizeof(*h)) + goto out; + if (rem >= sizeof(*h)) { + best->size = (size + dah_align - 1) & -dah_align; + h_offset = (char *)best - debug_alloc_pool + sizeof(*best) + best->size; + h = (struct debug_alloc_header *)(debug_alloc_pool + h_offset); + h->size = rem - sizeof(*h); + h->next = best->next; + } else + h_offset = best->next; + if (bestprev) + bestprev->next = h_offset; + else + dah_first = h_offset; + p = best+1; +out: + spin_unlock(&dap_lock); + return p; +} + +void debug_kfree(const void *p) +{ + struct debug_alloc_header *h; + unsigned int h_offset; + if (!p) + return; + if ((char *)p < debug_alloc_pool || + (char *)p >= debug_alloc_pool + sizeof(debug_alloc_pool_aligned)) { + kfree(p); + return; + } + if (!get_dap_lock()) + return; /* memory leak, cannot be helped */ + h = (struct debug_alloc_header *)p - 1; + h_offset = (char *)h - debug_alloc_pool; + if (h_offset < dah_first) { + h->next = dah_first; + dah_first = h_offset; + } else { + struct debug_alloc_header *prev; + prev = (struct debug_alloc_header *)(debug_alloc_pool + dah_first); + while (1) { + if (!prev->next || prev->next > h_offset) + break; + prev = (struct debug_alloc_header *)(debug_alloc_pool + prev->next); + } + if (sizeof(*prev) + prev->size == h_offset) { + prev->size += sizeof(*h) + h->size; + h = prev; + h_offset = (char *)h - debug_alloc_pool; + } else { + h->next = prev->next; + prev->next = h_offset; + } + } + if (h_offset + sizeof(*h) + h->size == h->next) { + struct debug_alloc_header *next; + next = (struct debug_alloc_header *)(debug_alloc_pool + h->next); + h->size += sizeof(*next) + next->size; + h->next = next->next; + } + spin_unlock(&dap_lock); +} + +void kdb_initsupport() +{ + struct debug_alloc_header *h; + h = (struct debug_alloc_header *)debug_alloc_pool; + h->next = 0; + h->size = sizeof(debug_alloc_pool_aligned) - sizeof(*h); + dah_first = 0; +} + +/* Maintain a small stack of kdb_flags to allow recursion without disturbing + * the global kdb state. + */ + +static int kdb_flags_stack[4], kdb_flags_index; + +void +kdb_save_flags(void) +{ + BUG_ON(kdb_flags_index >= ARRAY_SIZE(kdb_flags_stack)); + kdb_flags_stack[kdb_flags_index++] = kdb_flags; +} + +void +kdb_restore_flags(void) +{ + BUG_ON(kdb_flags_index <= 0); + kdb_flags = kdb_flags_stack[--kdb_flags_index]; +} Index: 2.6.x-xfs/kdb/modules/Makefile =================================================================== --- 2.6.x-xfs.orig/kdb/modules/Makefile 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/modules/Makefile 2006-02-28 11:26:53.536264897 +1100 @@ -0,0 +1,16 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (c) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. +# + +obj-$(CONFIG_KDB_MODULES) += kdbm_pg.o kdbm_task.o kdbm_vm.o kdbm_sched.o +ifdef CONFIG_X86 +ifndef CONFIG_X86_64 +obj-$(CONFIG_KDB_MODULES) += kdbm_x86.o +endif +endif +obj-$(CONFIG_KDB_MODULES_XP) += kdbm_xpc.o +CFLAGS_kdbm_vm.o += -I $(srctree)/drivers/scsi Index: 2.6.x-xfs/kdb/modules/kdbm_pg.c =================================================================== --- 2.6.x-xfs.orig/kdb/modules/kdbm_pg.c 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/modules/kdbm_pg.c 2006-02-28 11:26:53.538217756 +1100 @@ -0,0 +1,658 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("SGI"); +MODULE_DESCRIPTION("Debug page information"); +MODULE_LICENSE("GPL"); + +/* Standard Linux page stuff */ + +#ifndef CONFIG_DISCONTIGMEM +/* From include/linux/page_flags.h */ +static char *pg_flag_vals[] = { + "PG_locked", "PG_error", "PG_referenced", "PG_uptodate", + "PG_dirty", "PG_lru", "PG_active", "PG_slab", + "PG_checked", "PG_arch_1", "PG_reserved", "PG_private", + "PG_writeback", "PG_nosave", "PG_compound", "PG_swapcache", + "PG_mappedtodisk", "PG_reclaim", "PG_nosave_free", "PG_uncached", + NULL }; +#endif + +/* From include/linux/buffer_head.h */ +static char *bh_state_vals[] = { + "Uptodate", "Dirty", "Lock", "Req", + "Uptodate_Lock", "Mapped", "New", "Async_read", + "Async_write", "Delay", "Boundary", "Write_EIO", + "Ordered", "Eopnotsupp", "Private", + NULL }; + +/* From include/linux/bio.h */ +static char *bio_flag_vals[] = { + "Uptodate", "RW_block", "EOF", "Seg_valid", + "Cloned", "Bounced", "User_mapped", "Eopnotsupp", + NULL }; + +/* From include/linux/fs.h */ +static char *inode_flag_vals[] = { + "I_DIRTY_SYNC", "I_DIRTY_DATASYNC", "I_DIRTY_PAGES", "I_LOCK", + "I_FREEING", "I_CLEAR", "I_NEW", "I_WILL_FREE", + NULL }; + +static char *map_flags(unsigned long flags, char *mapping[]) +{ + static char buffer[256]; + int index; + int offset = 12; + + buffer[0] = '\0'; + + for (index = 0; flags && mapping[index]; flags >>= 1, index++) { + if (flags & 1) { + if ((offset + strlen(mapping[index]) + 1) >= 80) { + strcat(buffer, "\n "); + offset = 12; + } else if (offset > 12) { + strcat(buffer, " "); + offset++; + } + strcat(buffer, mapping[index]); + offset += strlen(mapping[index]); + } + } + + return (buffer); +} + +static int +kdbm_buffers(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct buffer_head bh; + unsigned long addr; + long offset = 0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(bh, addr))) + return(diag); + + kdb_printf("buffer_head at 0x%lx\n", addr); + kdb_printf(" bno %llu size %d dev 0x%x\n", + (unsigned long long)bh.b_blocknr, + bh.b_size, + bh.b_bdev ? bh.b_bdev->bd_dev : 0); + kdb_printf(" count %d state 0x%lx [%s]\n", + bh.b_count.counter, bh.b_state, + map_flags(bh.b_state, bh_state_vals)); + kdb_printf(" b_data 0x%p\n", + bh.b_data); + kdb_printf(" b_page 0x%p b_this_page 0x%p b_private 0x%p\n", + bh.b_page, bh.b_this_page, bh.b_private); + kdb_printf(" b_end_io "); + if (bh.b_end_io) + kdb_symbol_print(kdba_funcptr_value(bh.b_end_io), NULL, KDB_SP_VALUE); + else + kdb_printf("(NULL)"); + kdb_printf("\n"); + + return 0; +} + +static int +print_biovec(struct bio_vec *vec, int vcount) +{ + struct bio_vec bvec; + unsigned long addr; + int diag; + int i; + + if (vcount < 1 || vcount > BIO_MAX_PAGES) { + kdb_printf(" [skipped iovecs, vcnt is %d]\n", vcount); + return 0; + } + + addr = (unsigned long)vec; + for (i = 0; i < vcount; i++) { + if ((diag = kdb_getarea(bvec, addr))) + return(diag); + addr += sizeof(bvec); + kdb_printf(" [%d] page 0x%p length=%u offset=%u\n", + i, bvec.bv_page, bvec.bv_len, bvec.bv_offset); + } + return 0; +} + +static int +kdbm_bio(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct bio bio; + unsigned long addr; + long offset = 0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(bio, addr))) + return(diag); + + kdb_printf("bio at 0x%lx\n", addr); + kdb_printf(" bno %llu next 0x%p dev 0x%x\n", + (unsigned long long)bio.bi_sector, + bio.bi_next, bio.bi_bdev ? bio.bi_bdev->bd_dev : 0); + kdb_printf(" vcnt %u vec 0x%p rw 0x%lx flags 0x%lx [%s]\n", + bio.bi_vcnt, bio.bi_io_vec, bio.bi_rw, bio.bi_flags, + map_flags(bio.bi_flags, bio_flag_vals)); + print_biovec(bio.bi_io_vec, bio.bi_vcnt); + kdb_printf(" count %d private 0x%p\n", + atomic_read(&bio.bi_cnt), bio.bi_private); + kdb_printf(" bi_end_io "); + if (bio.bi_end_io) + kdb_symbol_print(kdba_funcptr_value(bio.bi_end_io), NULL, KDB_SP_VALUE); + else + kdb_printf("(NULL)"); + kdb_printf("\n"); + + return 0; +} + +#ifndef CONFIG_DISCONTIGMEM +static char *page_flags(unsigned long flags) +{ + return(map_flags(flags, pg_flag_vals)); +} + +static int +kdbm_page(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct page page; + unsigned long addr; + long offset = 0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + +#ifdef __ia64__ + if (rgn_index(addr) == 0) + addr = (unsigned long) &mem_map[addr]; /* assume region 0 is a page index, not an address */ +#else + if (addr < PAGE_OFFSET) + addr = (unsigned long) &mem_map[addr]; +#endif + + if ((diag = kdb_getarea(page, addr))) + return(diag); + + kdb_printf("struct page at 0x%lx\n", addr); + kdb_printf(" addr space 0x%p index %lu (offset 0x%llx)\n", + page.mapping, page.index, + (unsigned long long)page.index << PAGE_CACHE_SHIFT); + kdb_printf(" count %d flags %s\n", + page._count.counter, page_flags(page.flags)); + kdb_printf(" virtual 0x%p\n", page_address((struct page *)addr)); + if (page_has_buffers(&page)) + kdb_printf(" buffers 0x%p\n", page_buffers(&page)); + else + kdb_printf(" private 0x%lx\n", page_private(&page)); + + return 0; +} +#endif /* CONFIG_DISCONTIGMEM */ + +static unsigned long +print_request(unsigned long addr) +{ + struct request rq; + + if (kdb_getarea(rq, addr)) + return(0); + + kdb_printf("struct request at 0x%lx\n", addr); + kdb_printf(" errors %d sector %llu nr_sectors %lu waiting 0x%p\n", + rq.errors, + (unsigned long long)rq.sector, rq.nr_sectors, + rq.waiting); + + kdb_printf(" hsect %llu hnrsect %lu nrseg %u nrhwseg %u currnrsect %u\n", + (unsigned long long)rq.hard_sector, rq.hard_nr_sectors, + rq.nr_phys_segments, rq.nr_hw_segments, + rq.current_nr_sectors); + + return (unsigned long) rq.queuelist.next; +} + +static int +kdbm_request(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + long offset = 0; + unsigned long addr; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + print_request(addr); + return 0; +} + + +static int +kdbm_rqueue(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct request_queue rq; + unsigned long addr, head_addr, next; + long offset = 0; + int nextarg; + int i, diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(rq, addr))) + return(diag); + + kdb_printf("struct request_queue at 0x%lx\n", addr); + i = 0; + next = (unsigned long)rq.queue_head.next; + head_addr = addr + offsetof(struct request_queue, queue_head); + kdb_printf(" request queue: %s\n", next == head_addr ? + "empty" : ""); + while (next != head_addr) { + i++; + next = print_request(next); + } + + if (i) + kdb_printf("%d requests found\n", i); + + return 0; +} + + +static void +do_buffer(unsigned long addr) +{ + struct buffer_head bh; + + if (kdb_getarea(bh, addr)) + return; + + kdb_printf("\tbh 0x%lx bno %8llu [%s]\n", addr, + (unsigned long long)bh.b_blocknr, + map_flags(bh.b_state, bh_state_vals)); +} + +static void +kdbm_show_page(struct page *page, int first) +{ + if (first) + kdb_printf("page_struct index cnt zone nid flags\n"); + kdb_printf("%p%s %6lu %5d %3ld %3ld 0x%lx", + page_address(page), sizeof(void *) == 4 ? " " : "", + page->index, atomic_read(&(page->_count)), + page_zonenum(page), page_to_nid(page), + page->flags & (~0UL >> ZONES_SHIFT)); +#define kdb_page_flags(page, type) if (Page ## type(page)) kdb_printf(" " #type); + kdb_page_flags(page, Locked); + kdb_page_flags(page, Error); + kdb_page_flags(page, Referenced); + kdb_page_flags(page, Uptodate); + kdb_page_flags(page, Dirty); + kdb_page_flags(page, LRU); + kdb_page_flags(page, Active); + kdb_page_flags(page, Slab); + kdb_page_flags(page, Checked); + if (page->flags & (1UL << PG_arch_1)) + kdb_printf(" arch_1"); + kdb_page_flags(page, Reserved); + kdb_page_flags(page, Private); + kdb_page_flags(page, Writeback); + kdb_page_flags(page, Nosave); + kdb_page_flags(page, Compound); + kdb_page_flags(page, SwapCache); + kdb_page_flags(page, MappedToDisk); + kdb_page_flags(page, Reclaim); + kdb_page_flags(page, NosaveFree); + kdb_page_flags(page, Uncached); + + /* PageHighMem is not a flag any more, but treat it as one */ + kdb_page_flags(page, HighMem); + + if (page_has_buffers(page)) { + struct buffer_head *head, *bh; + kdb_printf("\n"); + head = bh = page_buffers(page); + do { + do_buffer((unsigned long) bh); + } while ((bh = bh->b_this_page) != head); + } else if (page_private(page)) { + kdb_printf(" private= 0x%lx", page_private(page)); + } + /* Cannot use page_mapping(page) here, it needs swapper_space which is + * not exported. + */ + if (page->mapping) + kdb_printf(" mapping= %p", page->mapping); + kdb_printf("\n"); +#undef kdb_page_flags +} + +static int +kdbm_inode_pages(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct inode *inode = NULL; + struct address_space *ap = NULL; + unsigned long addr, addr1 = 0; + long offset = 0; + int nextarg; + int diag; + pgoff_t next = 0; + struct page *page; + int first; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + goto out; + + if (argc == 2) { + nextarg = 2; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr1, + &offset, NULL, regs); + if (diag) + goto out; + kdb_printf("Looking for page index 0x%lx ... \n", addr1); + next = addr1; + } + + if (!(inode = kmalloc(sizeof(*inode), GFP_ATOMIC))) { + kdb_printf("kdbm_inode_pages: cannot kmalloc inode\n"); + goto out; + } + if (!(ap = kmalloc(sizeof(*ap), GFP_ATOMIC))) { + kdb_printf("kdbm_inode_pages: cannot kmalloc ap\n"); + goto out; + } + if ((diag = kdb_getarea(*inode, addr))) + goto out; + if (!inode->i_mapping) { + kdb_printf("inode has no mapping\n"); + goto out; + } + if ((diag = kdb_getarea(*ap, (unsigned long) inode->i_mapping))) + goto out; + + /* Run the pages in the radix tree, printing the state of each page */ + first = 1; + while (radix_tree_gang_lookup(&ap->page_tree, (void **)&page, next, 1)) { + kdbm_show_page(page, first); + if (addr1) + break; + first = 0; + next = page->index + 1; + } + +out: + if (inode) + kfree(inode); + if (ap) + kfree(ap); + return diag; +} + +static int +kdbm_inode(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct inode *inode = NULL; + unsigned long addr; + unsigned char *iaddr; + long offset = 0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + goto out; + if (!(inode = kmalloc(sizeof(*inode), GFP_ATOMIC))) { + kdb_printf("kdbm_inode: cannot kmalloc inode\n"); + goto out; + } + if ((diag = kdb_getarea(*inode, addr))) + goto out; + + kdb_printf("struct inode at 0x%lx\n", addr); + + kdb_printf(" i_ino = %lu i_count = %u i_size %Ld\n", + inode->i_ino, atomic_read(&inode->i_count), + inode->i_size); + + kdb_printf(" i_mode = 0%o i_nlink = %d i_rdev = 0x%x\n", + inode->i_mode, inode->i_nlink, + inode->i_rdev); + + kdb_printf(" i_hash.nxt = 0x%p i_hash.pprev = 0x%p\n", + inode->i_hash.next, + inode->i_hash.pprev); + + kdb_printf(" i_list.nxt = 0x%p i_list.prv = 0x%p\n", + list_entry(inode->i_list.next, struct inode, i_list), + list_entry(inode->i_list.prev, struct inode, i_list)); + + kdb_printf(" i_dentry.nxt = 0x%p i_dentry.prv = 0x%p\n", + list_entry(inode->i_dentry.next, struct dentry, d_alias), + list_entry(inode->i_dentry.prev, struct dentry, d_alias)); + + kdb_printf(" i_sb = 0x%p i_op = 0x%p i_data = 0x%lx nrpages = %lu\n", + inode->i_sb, inode->i_op, + addr + offsetof(struct inode, i_data), + inode->i_data.nrpages); + kdb_printf(" i_fop= 0x%p i_flock = 0x%p i_mapping = 0x%p\n", + inode->i_fop, inode->i_flock, inode->i_mapping); + + kdb_printf(" i_flags 0x%x i_state 0x%lx [%s]", + inode->i_flags, inode->i_state, + map_flags(inode->i_state, inode_flag_vals)); + + iaddr = (char *)addr; + iaddr += offsetof(struct inode, u); + + kdb_printf(" fs specific info @ 0x%p\n", iaddr); +out: + if (inode) + kfree(inode); + return diag; +} + +static int +kdbm_sb(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct super_block *sb = NULL; + unsigned long addr; + long offset = 0; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + goto out; + if (!(sb = kmalloc(sizeof(*sb), GFP_ATOMIC))) { + kdb_printf("kdbm_sb: cannot kmalloc sb\n"); + goto out; + } + if ((diag = kdb_getarea(*sb, addr))) + goto out; + + kdb_printf("struct super_block at 0x%lx\n", addr); + kdb_printf(" s_dev 0x%x blocksize 0x%lx\n", sb->s_dev, sb->s_blocksize); + kdb_printf(" s_flags 0x%lx s_root 0x%p\n", sb->s_flags, sb->s_root); + kdb_printf(" s_dirt %d s_dirty.next 0x%p s_dirty.prev 0x%p\n", + sb->s_dirt, sb->s_dirty.next, sb->s_dirty.prev); + kdb_printf(" s_frozen %d s_id [%s]\n", sb->s_frozen, sb->s_id); +out: + if (sb) + kfree(sb); + return diag; +} + + + +#if defined(CONFIG_X86) && !defined(CONFIG_X86_64) +/* According to Steve Lord, this code is ix86 specific. Patches to extend it to + * other architectures will be greatefully accepted. + */ +static int +kdbm_memmap(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct page page; + int i, page_count; + int slab_count = 0; + int dirty_count = 0; + int locked_count = 0; + int page_counts[9]; + int buffered_count = 0; +#ifdef buffer_delay + int delay_count = 0; +#endif + int diag; + unsigned long addr; + + addr = (unsigned long)mem_map; + page_count = max_mapnr; + memset(page_counts, 0, sizeof(page_counts)); + + for (i = 0; i < page_count; i++) { + if ((diag = kdb_getarea(page, addr))) + return(diag); + addr += sizeof(page); + + if (PageSlab(&page)) + slab_count++; + if (PageDirty(&page)) + dirty_count++; + if (PageLocked(&page)) + locked_count++; + if (page._count.counter < 8) + page_counts[page._count.counter]++; + else + page_counts[8]++; + if (page_has_buffers(&page)) { + buffered_count++; +#ifdef buffer_delay + if (buffer_delay(page.buffers)) + delay_count++; +#endif + } + + } + + kdb_printf(" Total pages: %6d\n", page_count); + kdb_printf(" Slab pages: %6d\n", slab_count); + kdb_printf(" Dirty pages: %6d\n", dirty_count); + kdb_printf(" Locked pages: %6d\n", locked_count); + kdb_printf(" Buffer pages: %6d\n", buffered_count); +#ifdef buffer_delay + kdb_printf(" Delalloc pages: %6d\n", delay_count); +#endif + for (i = 0; i < 8; i++) { + kdb_printf(" %d page count: %6d\n", + i, page_counts[i]); + } + kdb_printf(" high page count: %6d\n", page_counts[8]); + return 0; +} +#endif /* CONFIG_X86 && !CONFIG_X86_64 */ + +static int __init kdbm_pg_init(void) +{ +#ifndef CONFIG_DISCONTIGMEM + kdb_register("page", kdbm_page, "", "Display page", 0); +#endif + kdb_register("inode", kdbm_inode, "", "Display inode", 0); + kdb_register("sb", kdbm_sb, "", "Display super_block", 0); + kdb_register("bh", kdbm_buffers, "", "Display buffer", 0); + kdb_register("bio", kdbm_bio, "", "Display bio", 0); + kdb_register("inode_pages", kdbm_inode_pages, "", "Display pages in an inode", 0); + kdb_register("req", kdbm_request, "", "dump request struct", 0); + kdb_register("rqueue", kdbm_rqueue, "", "dump request queue", 0); +#if defined(CONFIG_X86) && !defined(CONFIG_X86_64) + kdb_register("memmap", kdbm_memmap, "", "page table summary", 0); +#endif + + return 0; +} + + +static void __exit kdbm_pg_exit(void) +{ +#ifndef CONFIG_DISCONTIGMEM + kdb_unregister("page"); +#endif + kdb_unregister("inode"); + kdb_unregister("sb"); + kdb_unregister("bh"); + kdb_unregister("bio"); + kdb_unregister("inode_pages"); + kdb_unregister("req"); + kdb_unregister("rqueue"); +#if defined(CONFIG_X86) && !defined(CONFIG_X86_64) + kdb_unregister("memmap"); +#endif +} + +module_init(kdbm_pg_init) +module_exit(kdbm_pg_exit) Index: 2.6.x-xfs/kdb/modules/kdbm_task.c =================================================================== --- 2.6.x-xfs.orig/kdb/modules/kdbm_task.c 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/modules/kdbm_task.c 2006-02-28 11:26:53.539194186 +1100 @@ -0,0 +1,179 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("SGI"); +MODULE_DESCRIPTION("Debug struct task and sigset information"); +MODULE_LICENSE("GPL"); + +static char * +kdb_cpus_allowed_string(struct task_struct *tp) +{ + static char maskbuf[(NR_CPUS + 31) / 32 * 9 + 1]; + if (cpus_full(tp->cpus_allowed)) + strcpy(maskbuf, "ALL"); + else if (cpus_empty(tp->cpus_allowed)) + strcpy(maskbuf, "NONE"); + else if (cpus_weight(tp->cpus_allowed) == 1) + snprintf(maskbuf, sizeof(maskbuf), "ONLY(%d)", first_cpu(tp->cpus_allowed)); + else + cpumask_scnprintf(maskbuf, sizeof(maskbuf), tp->cpus_allowed); + return maskbuf; +} + +static int +kdbm_task(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long addr; + long offset=0; + int nextarg; + int e = 0; + struct task_struct *tp = NULL, *tp1; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((e = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) != 0) + return(e); + + if (!(tp = kmalloc(sizeof(*tp), GFP_ATOMIC))) { + kdb_printf("%s: cannot kmalloc tp\n", __FUNCTION__); + goto out; + } + if ((e = kdb_getarea(*tp, addr))) { + kdb_printf("%s: invalid task address\n", __FUNCTION__); + goto out; + } + + tp1 = (struct task_struct *)addr; + kdb_printf( + "struct task at 0x%lx, pid=%d flags=0x%lx state=%ld comm=\"%s\"\n", + addr, tp->pid, tp->flags, tp->state, tp->comm); + + kdb_printf(" cpu=%d policy=%lu ", kdb_process_cpu(tp), tp->policy); + kdb_printf( + "prio=%d static_prio=%d cpus_allowed=%s", + tp->prio, tp->static_prio, kdb_cpus_allowed_string(tp)); + kdb_printf(" &thread=0x%p\n", &tp1->thread); + + kdb_printf(" need_resched=%d ", + test_tsk_thread_flag(tp, TIF_NEED_RESCHED)); + kdb_printf( + "timestamp=%llu time_slice=%u", + tp->timestamp, tp->time_slice); + kdb_printf(" lock_depth=%d\n", tp->lock_depth); + + kdb_printf( + " fs=0x%p files=0x%p mm=0x%p\n", + tp->fs, tp->files, tp->mm); + + kdb_printf( + " uid=%d euid=%d suid=%d fsuid=%d gid=%d egid=%d sgid=%d fsgid=%d\n", + tp->uid, tp->euid, tp->suid, tp->fsuid, tp->gid, tp->egid, tp->sgid, tp->fsgid); + + kdb_printf( + " user=0x%p\n", + tp->user); + + if (tp->sysvsem.undo_list) + kdb_printf( + " sysvsem.sem_undo refcnt %d proc_list=0x%p\n", + atomic_read(&tp->sysvsem.undo_list->refcnt), + tp->sysvsem.undo_list->proc_list); + + kdb_printf( + " signal=0x%p &blocked=0x%p &pending=0x%p\n", + tp->signal, &tp1->blocked, &tp1->pending); + + kdb_printf( + " utime=%ld stime=%ld cutime=%ld cstime=%ld\n", + tp->utime, tp->stime, + tp->signal ? tp->signal->cutime : 0L, + tp->signal ? tp->signal->cstime : 0L); + + kdb_printf(" thread_info=0x%p\n", tp->thread_info); + kdb_printf(" ti flags=0x%lx\n", (unsigned long)tp->thread_info->flags); + +out: + if (tp) + kfree(tp); + return e; +} + +static int +kdbm_sigset(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + sigset_t *sp = NULL; + unsigned long addr; + long offset=0; + int nextarg; + int e = 0; + int i; + char fmt[32]; + + if (argc != 1) + return KDB_ARGCOUNT; + +#ifndef _NSIG_WORDS + kdb_printf("unavailable on this platform, _NSIG_WORDS not defined.\n"); +#else + nextarg = 1; + if ((e = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) != 0) + return(e); + + if (!(sp = kmalloc(sizeof(*sp), GFP_ATOMIC))) { + kdb_printf("%s: cannot kmalloc sp\n", __FUNCTION__); + goto out; + } + if ((e = kdb_getarea(*sp, addr))) { + kdb_printf("%s: invalid sigset address\n", __FUNCTION__); + goto out; + } + + sprintf(fmt, "[%%d]=0x%%0%dlx ", (int)sizeof(sp->sig[0])*2); + kdb_printf("sigset at 0x%p : ", sp); + for (i=_NSIG_WORDS-1; i >= 0; i--) { + if (i == 0 || sp->sig[i]) { + kdb_printf(fmt, i, sp->sig[i]); + } + } + kdb_printf("\n"); +#endif /* _NSIG_WORDS */ + +out: + if (sp) + kfree(sp); + return e; +} + +static int __init kdbm_task_init(void) +{ + kdb_register("task", kdbm_task, "", "Display task_struct", 0); + kdb_register("sigset", kdbm_sigset, "", "Display sigset_t", 0); + + return 0; +} + +static void __exit kdbm_task_exit(void) +{ + kdb_unregister("task"); + kdb_unregister("sigset"); +} + +kdb_module_init(kdbm_task_init) +kdb_module_exit(kdbm_task_exit) Index: 2.6.x-xfs/kdb/modules/kdbm_vm.c =================================================================== --- 2.6.x-xfs.orig/kdb/modules/kdbm_vm.c 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/modules/kdbm_vm.c 2006-02-28 11:26:53.542123475 +1100 @@ -0,0 +1,845 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("SGI"); +MODULE_DESCRIPTION("Debug VM information"); +MODULE_LICENSE("GPL"); + +struct __vmflags { + unsigned long mask; + char *name; +}; + +static struct __vmflags vmflags[] = { + { VM_READ, "READ" }, + { VM_WRITE, "WRITE" }, + { VM_EXEC, "EXEC" }, + { VM_SHARED, "SHARED" }, + { VM_MAYREAD, "MAYREAD" }, + { VM_MAYWRITE, "MAYWRITE" }, + { VM_MAYEXEC, "MAYEXEC" }, + { VM_MAYSHARE, "MAYSHARE" }, + { VM_GROWSDOWN, "GROWSDOWN" }, + { VM_GROWSUP, "GROWSUP" }, + { VM_SHM, "SHM" }, + { VM_PFNMAP, "PFNMAP" }, + { VM_DENYWRITE, "DENYWRITE" }, + { VM_EXECUTABLE, "EXECUTABLE" }, + { VM_LOCKED, "LOCKED" }, + { VM_IO , "IO " }, + { VM_SEQ_READ , "SEQ_READ " }, + { VM_RAND_READ , "RAND_READ " }, + { VM_DONTCOPY , "DONTCOPY " }, + { VM_DONTEXPAND , "DONTEXPAND " }, + { VM_RESERVED , "RESERVED " }, + { VM_ACCOUNT , "ACCOUNT " }, + { VM_HUGETLB , "HUGETLB " }, + { VM_NONLINEAR , "NONLINEAR " }, + { VM_MAPPED_COPY , "MAPPED_COPY " }, + { VM_INSERTPAGE , "INSERTPAGE " }, + { 0, "" } +}; + +static int +kdbm_print_vm(struct vm_area_struct *vp, unsigned long addr, int verbose_flg) +{ + struct __vmflags *tp; + + kdb_printf("struct vm_area_struct at 0x%lx for %d bytes\n", + addr, (int) sizeof (struct vm_area_struct)); + + kdb_printf("vm_start = 0x%p vm_end = 0x%p\n", (void *) vp->vm_start, + (void *) vp->vm_end); + kdb_printf("vm_page_prot = 0x%lx\n", pgprot_val(vp->vm_page_prot)); + + kdb_printf("vm_flags: "); + for (tp = vmflags; tp->mask; tp++) { + if (vp->vm_flags & tp->mask) { + kdb_printf(" %s", tp->name); + } + } + kdb_printf("\n"); + + if (!verbose_flg) + return 0; + + kdb_printf("vm_mm = 0x%p\n", (void *) vp->vm_mm); + kdb_printf("vm_next = 0x%p\n", (void *) vp->vm_next); + kdb_printf("shared.vm_set.list.next = 0x%p\n", (void *) vp->shared.vm_set.list.next); + kdb_printf("shared.vm_set.list.prev = 0x%p\n", (void *) vp->shared.vm_set.list.prev); + kdb_printf("shared.vm_set.parent = 0x%p\n", (void *) vp->shared.vm_set.parent); + kdb_printf("shared.vm_set.head = 0x%p\n", (void *) vp->shared.vm_set.head); + kdb_printf("anon_vma_node.next = 0x%p\n", (void *) vp->anon_vma_node.next); + kdb_printf("anon_vma_node.prev = 0x%p\n", (void *) vp->anon_vma_node.prev); + kdb_printf("vm_ops = 0x%p\n", (void *) vp->vm_ops); + if (vp->vm_ops != NULL) { + kdb_printf("vm_ops->open = 0x%p\n", vp->vm_ops->open); + kdb_printf("vm_ops->close = 0x%p\n", vp->vm_ops->close); + kdb_printf("vm_ops->nopage = 0x%p\n", vp->vm_ops->nopage); +#ifdef HAVE_VMOP_MPROTECT + kdb_printf("vm_ops->mprotect = 0x%p\n", vp->vm_ops->mprotect); +#endif + } + kdb_printf("vm_pgoff = 0x%lx\n", vp->vm_pgoff); + kdb_printf("vm_file = 0x%p\n", (void *) vp->vm_file); + kdb_printf("vm_private_data = 0x%p\n", vp->vm_private_data); + + return 0; +} + +static int +kdbm_print_vmp(struct vm_area_struct *vp, int verbose_flg) +{ + struct __vmflags *tp; + + if (verbose_flg) { + kdb_printf("0x%lx: ", (unsigned long) vp); + } + + kdb_printf("0x%p 0x%p ", (void *) vp->vm_start, (void *) vp->vm_end); + + for (tp = vmflags; tp->mask; tp++) { + if (vp->vm_flags & tp->mask) { + kdb_printf(" %s", tp->name); + } + } + kdb_printf("\n"); + + return 0; +} + +/* + * kdbm_vm + * + * This function implements the 'vm' command. Print a vm_area_struct. + * + * vm [-v]
Print vm_area_struct at
+ * vmp [-v] Print all vm_area_structs for + */ + +static int +kdbm_vm(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long addr; + long offset = 0; + int nextarg; + int diag; + int verbose_flg = 0; + + if (argc == 2) { + if (strcmp(argv[1], "-v") != 0) { + return KDB_ARGCOUNT; + } + verbose_flg = 1; + } else if (argc != 1) { + return KDB_ARGCOUNT; + } + + if (strcmp(argv[0], "vmp") == 0) { + struct task_struct *g, *tp; + struct vm_area_struct *vp; + pid_t pid; + + if ((diag = kdbgetularg(argv[argc], (unsigned long *) &pid))) + return diag; + + kdb_do_each_thread(g, tp) { + if (tp->pid == pid) { + if (tp->mm != NULL) { + if (verbose_flg) + kdb_printf + ("vm_area_struct "); + kdb_printf + ("vm_start vm_end vm_flags\n"); + vp = tp->mm->mmap; + while (vp != NULL) { + kdbm_print_vmp(vp, verbose_flg); + vp = vp->vm_next; + } + } + return 0; + } + } kdb_while_each_thread(g, tp); + + kdb_printf("No process with pid == %d found\n", pid); + + } else { + struct vm_area_struct v; + + nextarg = argc; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, + NULL, regs)) + || (diag = kdb_getarea(v, addr))) + return (diag); + + kdbm_print_vm(&v, addr, verbose_flg); + } + + return 0; +} + +static int +kdbm_print_pte(pte_t * pte) +{ + kdb_printf("0x%lx (", (unsigned long) pte_val(*pte)); + + if (pte_present(*pte)) { + if (pte_exec(*pte)) + kdb_printf("X"); + if (pte_write(*pte)) + kdb_printf("W"); + if (pte_read(*pte)) + kdb_printf("R"); + if (pte_young(*pte)) + kdb_printf("A"); + if (pte_dirty(*pte)) + kdb_printf("D"); + + } else { + kdb_printf("OFFSET=0x%lx ", swp_offset(pte_to_swp_entry(*pte))); + kdb_printf("TYPE=0x%ulx", swp_type(pte_to_swp_entry(*pte))); + } + + kdb_printf(")"); + + /* final newline is output by caller of kdbm_print_pte() */ + + return 0; +} + +/* + * kdbm_pte + * + * This function implements the 'pte' command. Print all pte_t structures + * that map to the given virtual address range (
through
+ * plus ) for the given process. The default value for nbytes is + * one. + * + * pte -m
[] Print all pte_t structures for + * virtual
in address space + * of which is a pointer to a + * mm_struct + * pte -p
[] Print all pte_t structures for + * virtual
in address space + * of + */ + +static int +kdbm_pte(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long addr; + long offset = 0; + int nextarg; + unsigned long nbytes = 1; + long npgs; + int diag; + int found; + pid_t pid; + struct task_struct *tp; + struct mm_struct *mm, copy_of_mm; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + if (argc < 3 || argc > 4) { + return KDB_ARGCOUNT; + } + + if (strcmp(argv[1], "-p") == 0) { + if ((diag = kdbgetularg(argv[2], (unsigned long *) &pid))) { + return diag; + } + + found = 0; + for_each_process(tp) { + if (tp->pid == pid) { + if (tp->mm != NULL) { + found = 1; + break; + } + kdb_printf("task structure's mm field is NULL\n"); + return 0; + } + } + + if (!found) { + kdb_printf("No process with pid == %d found\n", pid); + return 0; + } + mm = tp->mm; + } else if (strcmp(argv[1], "-m") == 0) { + + + nextarg = 2; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, + NULL, regs)) + || (diag = kdb_getarea(copy_of_mm, addr))) + return (diag); + mm = ©_of_mm; + } else { + return KDB_ARGCOUNT; + } + + if ((diag = kdbgetularg(argv[3], &addr))) { + return diag; + } + + if (argc == 4) { + if ((diag = kdbgetularg(argv[4], &nbytes))) { + return diag; + } + } + + kdb_printf("vaddr pte\n"); + + npgs = ((((addr & ~PAGE_MASK) + nbytes) + ~PAGE_MASK) >> PAGE_SHIFT); + while (npgs-- > 0) { + + kdb_printf("0x%p ", (void *) (addr & PAGE_MASK)); + + pgd = pgd_offset(mm, addr); + if (pgd_present(*pgd)) { + pud = pud_offset(pgd, addr); + if (pud_present(*pud)) { + pmd = pmd_offset(pud, addr); + if (pmd_present(*pmd)) { + pte = pte_offset_map(pmd, addr); + if (pte_present(*pte)) { + kdbm_print_pte(pte); + } + } + } + } + + kdb_printf("\n"); + addr += PAGE_SIZE; + } + + return 0; +} + +/* + * kdbm_rpte + * + * This function implements the 'rpte' command. Print all pte_t structures + * that contain the given physical page range ( through + * plus ) for the given process. The default value for npages is + * one. + * + * rpte -m [] Print all pte_t structures for + * physical page in address space + * of which is a pointer to a + * mm_struct + * rpte -p [] Print all pte_t structures for + * physical page in address space + * of + */ + +static int +kdbm_rpte(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long addr; + unsigned long pfn; + long offset = 0; + int nextarg; + unsigned long npages = 1; + int diag; + int found; + pid_t pid; + struct task_struct *tp; + struct mm_struct *mm, copy_of_mm; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + unsigned long g, u, m, t; + + if (argc < 3 || argc > 4) { + return KDB_ARGCOUNT; + } + + if (strcmp(argv[1], "-p") == 0) { + if ((diag = kdbgetularg(argv[2], (unsigned long *) &pid))) { + return diag; + } + + found = 0; + for_each_process(tp) { + if (tp->pid == pid) { + if (tp->mm != NULL) { + found = 1; + break; + } + kdb_printf("task structure's mm field is NULL\n"); + return 0; + } + } + + if (!found) { + kdb_printf("No process with pid == %d found\n", pid); + return 0; + } + mm = tp->mm; + } else if (strcmp(argv[1], "-m") == 0) { + + + nextarg = 2; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, + NULL, regs)) + || (diag = kdb_getarea(copy_of_mm, addr))) + return (diag); + mm = ©_of_mm; + } else { + return KDB_ARGCOUNT; + } + + if ((diag = kdbgetularg(argv[3], &pfn))) { + return diag; + } + + if (argc == 4) { + if ((diag = kdbgetularg(argv[4], &npages))) { + return diag; + } + } + + /* spaces after vaddr depends on sizeof(unsigned long) */ + kdb_printf("pfn vaddr%*s pte\n", + (int)(2*sizeof(unsigned long) + 2 - 5), " "); + + for (g = 0, pgd = pgd_offset(mm, 0UL); g < PTRS_PER_PGD; ++g, ++pgd) { + if (pgd_none(*pgd) || pgd_bad(*pgd)) + continue; + for (u = 0, pud = pud_offset(pgd, 0UL); u < PTRS_PER_PUD; ++u, ++pud) { + if (pud_none(*pud) || pud_bad(*pud)) + continue; + for (m = 0, pmd = pmd_offset(pud, 0UL); m < PTRS_PER_PMD; ++m, ++pmd) { + if (pmd_none(*pmd) || pmd_bad(*pmd)) + continue; + for (t = 0, pte = pte_offset_map(pmd, 0UL); t < PTRS_PER_PTE; ++t, ++pte) { + if (pte_none(*pte)) + continue; + if (pte_pfn(*pte) < pfn || pte_pfn(*pte) >= (pfn + npages)) + continue; + addr = g << PGDIR_SHIFT; +#ifdef __ia64__ + /* IA64 plays tricks with the pgd mapping to save space. + * This reverses pgd_index(). + */ + { + unsigned long region = g >> (PAGE_SHIFT - 6); + unsigned long l1index = g - (region << (PAGE_SHIFT - 6)); + addr = (region << 61) + (l1index << PGDIR_SHIFT); + } +#endif + addr += (m << PMD_SHIFT) + (t << PAGE_SHIFT); + kdb_printf("0x%-14lx " kdb_bfd_vma_fmt0 " ", + pte_pfn(*pte), addr); + kdbm_print_pte(pte); + kdb_printf("\n"); + } + } + } + } + + return 0; +} + +static int +kdbm_print_dentry(unsigned long daddr) +{ + struct dentry d; + int diag; + char buf[256]; + + kdb_printf("Dentry at 0x%lx\n", daddr); + if ((diag = kdb_getarea(d, (unsigned long)daddr))) + return diag; + + if ((d.d_name.len > sizeof(buf)) || (diag = kdb_getarea_size(buf, (unsigned long)(d.d_name.name), d.d_name.len))) + kdb_printf(" d_name.len = %d d_name.name = 0x%p\n", + d.d_name.len, d.d_name.name); + else + kdb_printf(" d_name.len = %d d_name.name = 0x%p <%.*s>\n", + d.d_name.len, d.d_name.name, + (int)(d.d_name.len), d.d_name.name); + + kdb_printf(" d_count = %d d_flags = 0x%x d_inode = 0x%p\n", + atomic_read(&d.d_count), d.d_flags, d.d_inode); + + kdb_printf(" d_parent = 0x%p\n", d.d_parent); + + kdb_printf(" d_hash.nxt = 0x%p d_hash.prv = 0x%p\n", + d.d_hash.next, d.d_hash.pprev); + + kdb_printf(" d_lru.nxt = 0x%p d_lru.prv = 0x%p\n", + d.d_lru.next, d.d_lru.prev); + + kdb_printf(" d_child.nxt = 0x%p d_child.prv = 0x%p\n", + d.d_u.d_child.next, d.d_u.d_child.prev); + + kdb_printf(" d_subdirs.nxt = 0x%p d_subdirs.prv = 0x%p\n", + d.d_subdirs.next, d.d_subdirs.prev); + + kdb_printf(" d_alias.nxt = 0x%p d_alias.prv = 0x%p\n", + d.d_alias.next, d.d_alias.prev); + + kdb_printf(" d_op = 0x%p d_sb = 0x%p d_fsdata = 0x%p\n", + d.d_op, d.d_sb, d.d_fsdata); + + kdb_printf(" d_iname = %s\n", + d.d_iname); + + if (d.d_inode) { + struct inode i; + kdb_printf("\nInode Entry at 0x%p\n", d.d_inode); + if ((diag = kdb_getarea(i, (unsigned long)d.d_inode))) + return diag; + kdb_printf(" i_mode = 0%o i_nlink = %d i_rdev = 0x%x\n", + i.i_mode, i.i_nlink, i.i_rdev); + + kdb_printf(" i_ino = %ld i_count = %d\n", + i.i_ino, atomic_read(&i.i_count)); + + kdb_printf(" i_hash.nxt = 0x%p i_hash.prv = 0x%p\n", + i.i_hash.next, i.i_hash.pprev); + + kdb_printf(" i_list.nxt = 0x%p i_list.prv = 0x%p\n", + i.i_list.next, i.i_list.prev); + + kdb_printf(" i_dentry.nxt = 0x%p i_dentry.prv = 0x%p\n", + i.i_dentry.next, i.i_dentry.prev); + + } + kdb_printf("\n"); + return 0; +} + +static int +kdbm_filp(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct file f; + int nextarg; + unsigned long addr; + long offset; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(f, addr))) + return diag; + + kdb_printf("File Pointer at 0x%lx\n", addr); + + kdb_printf(" fu_list.nxt = 0x%p fu_list.prv = 0x%p\n", + f.f_u.fu_list.next, f.f_u.fu_list.prev); + + kdb_printf(" f_dentry = 0x%p f_vfsmnt = 0x%p f_op = 0x%p\n", + f.f_dentry, f.f_vfsmnt, f.f_op); + + kdb_printf(" f_count = %d f_flags = 0x%x f_mode = 0x%x\n", + f.f_count.counter, f.f_flags, f.f_mode); + + kdb_printf(" f_pos = %Ld security = 0x%p\n", + f.f_pos, f.f_security); + + kdb_printf(" private_data = 0x%p f_mapping = 0x%p\n\n", + f.private_data, f.f_mapping); + + return kdbm_print_dentry((unsigned long)f.f_dentry); +} + +static int +kdbm_fl(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct file_lock fl; + int nextarg; + unsigned long addr; + long offset; + int diag; + + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(fl, addr))) + return diag; + + kdb_printf("File_lock at 0x%lx\n", addr); + + kdb_printf(" fl_next = 0x%p fl_link.nxt = 0x%p fl_link.prv = 0x%p\n", + fl.fl_next, fl.fl_link.next, fl.fl_link.prev); + kdb_printf(" fl_block.nxt = 0x%p fl_block.prv = 0x%p\n", + fl.fl_block.next, fl.fl_block.prev); + kdb_printf(" fl_owner = 0x%p fl_pid = %d fl_wait = 0x%p\n", + fl.fl_owner, fl.fl_pid, &fl.fl_wait); + kdb_printf(" fl_file = 0x%p fl_flags = 0x%x\n", + fl.fl_file, fl.fl_flags); + kdb_printf(" fl_type = %d fl_start = 0x%llx fl_end = 0x%llx\n", + fl.fl_type, fl.fl_start, fl.fl_end); + + kdb_printf(" file_lock_operations"); + if (fl.fl_ops) + kdb_printf("\n fl_insert = 0x%p fl_remove = 0x%p fl_copy_lock = 0x%p fl_release_private = 0x%p\n", + fl.fl_ops->fl_insert, fl.fl_ops->fl_remove, + fl.fl_ops->fl_copy_lock, fl.fl_ops->fl_release_private); + else + kdb_printf(" empty\n"); + + kdb_printf(" lock_manager_operations"); + if (fl.fl_lmops) + kdb_printf("\n fl_compare_owner = 0x%p fl_notify = 0x%p\n", + fl.fl_lmops->fl_compare_owner, fl.fl_lmops->fl_notify); + else + kdb_printf(" empty\n"); + + kdb_printf(" fl_fasync = 0x%p fl_break 0x%lx\n", + fl.fl_fasync, fl.fl_break_time); + + return 0; +} + + +static int +kdbm_dentry(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int nextarg; + unsigned long addr; + long offset; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + return diag; + + return kdbm_print_dentry(addr); +} + +static int +kdbm_kobject(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct kobject k; + int nextarg; + unsigned long addr; + long offset; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(k, addr))) + return diag; + + + kdb_printf("kobject at 0x%lx\n", addr); + + if (k.k_name) { + char c; + kdb_printf(" k_name 0x%p", k.k_name); + if (kdb_getarea(c, (unsigned long)k.k_name) == 0) + kdb_printf(" '%s'", k.k_name); + kdb_printf("\n"); + } + + if (k.k_name != ((struct kobject *)addr)->name) + kdb_printf(" name '%." __stringify(KOBJ_NAME_LEN) "s'\n", k.k_name); + + kdb_printf(" kref.refcount %d'\n", atomic_read(&k.kref.refcount)); + + kdb_printf(" entry.next = 0x%p entry.prev = 0x%p\n", + k.entry.next, k.entry.prev); + + kdb_printf(" parent = 0x%p kset = 0x%p ktype = 0x%p dentry = 0x%p\n", + k.parent, k.kset, k.ktype, k.dentry); + + return 0; +} + +static int +kdbm_sh(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int nextarg; + unsigned long addr; + long offset = 0L; + struct Scsi_Host sh; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(sh, addr))) + return diag; + + kdb_printf("Scsi_Host at 0x%lx\n", addr); + kdb_printf("host_queue = 0x%p\n", sh.__devices.next); + kdb_printf("ehandler = 0x%p eh_action = 0x%p\n", + sh.ehandler, sh.eh_action); + kdb_printf("host_wait = 0x%p hostt = 0x%p\n", + &sh.host_wait, sh.hostt); + kdb_printf("host_failed = %d host_no = %d resetting = %d\n", + sh.host_failed, sh.host_no, sh.resetting); + kdb_printf("max id/lun/channel = [%d/%d/%d] this_id = %d\n", + sh.max_id, sh.max_lun, sh.max_channel, sh.this_id); + kdb_printf("can_queue = %d cmd_per_lun = %d sg_tablesize = %d u_isa_dma = %d\n", + sh.can_queue, sh.cmd_per_lun, sh.sg_tablesize, sh.unchecked_isa_dma); + kdb_printf("host_blocked = %d reverse_ordering = %d \n", + sh.host_blocked, sh.reverse_ordering); + + return 0; +} + +static int +kdbm_sd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int nextarg; + unsigned long addr; + long offset = 0L; + struct scsi_device *sd = NULL; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + goto out; + if (!(sd = kmalloc(sizeof(*sd), GFP_ATOMIC))) { + kdb_printf("kdbm_sd: cannot kmalloc sd\n"); + goto out; + } + if ((diag = kdb_getarea(*sd, addr))) + goto out; + + kdb_printf("scsi_device at 0x%lx\n", addr); + kdb_printf("next = 0x%p prev = 0x%p host = 0x%p\n", + sd->siblings.next, sd->siblings.prev, sd->host); + kdb_printf("device_busy = %d current_cmnd 0x%p\n", + sd->device_busy, sd->current_cmnd); + kdb_printf("id/lun/chan = [%d/%d/%d] single_lun = %d device_blocked = %d\n", + sd->id, sd->lun, sd->channel, sd->single_lun, sd->device_blocked); + kdb_printf("queue_depth = %d current_tag = %d scsi_level = %d\n", + sd->queue_depth, sd->current_tag, sd->scsi_level); + kdb_printf("%8.8s %16.16s %4.4s\n", sd->vendor, sd->model, sd->rev); +out: + if (sd) + kfree(sd); + return diag; +} + +static int +kdbm_sc(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + int nextarg; + unsigned long addr; + long offset = 0L; + struct scsi_cmnd *sc = NULL; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + goto out; + if (!(sc = kmalloc(sizeof(*sc), GFP_ATOMIC))) { + kdb_printf("kdbm_sc: cannot kmalloc sc\n"); + goto out; + } + if ((diag = kdb_getarea(*sc, addr))) + goto out; + + kdb_printf("scsi_cmnd at 0x%lx\n", addr); + kdb_printf("device = 0x%p next = 0x%p done = 0x%p\n", + sc->device, sc->list.next, sc->done); + kdb_printf("serial_number = %ld retries = %d\n", + sc->serial_number, sc->retries); + kdb_printf("cmd_len = %d old_cmd_len = %d\n", + sc->cmd_len, sc->old_cmd_len); + kdb_printf("cmnd = [%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x]\n", + sc->cmnd[0], sc->cmnd[1], sc->cmnd[2], sc->cmnd[3], sc->cmnd[4], + sc->cmnd[5], sc->cmnd[6], sc->cmnd[7], sc->cmnd[8], sc->cmnd[9], + sc->cmnd[10], sc->cmnd[11]); + kdb_printf("data_cmnd = [%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x]\n", + sc->data_cmnd[0], sc->data_cmnd[1], sc->data_cmnd[2], sc->data_cmnd[3], sc->data_cmnd[4], + sc->data_cmnd[5], sc->data_cmnd[6], sc->data_cmnd[7], sc->data_cmnd[8], sc->data_cmnd[9], + sc->data_cmnd[10], sc->data_cmnd[11]); + kdb_printf("request_buffer = 0x%p request_bufflen = %d\n", + sc->request_buffer, sc->request_bufflen); + kdb_printf("use_sg = %d old_use_sg = %d sglist_len = %d\n", + sc->use_sg, sc->old_use_sg, sc->sglist_len); + kdb_printf("bufflen = %d buffer = 0x%p underflow = %d transfersize = %d\n", + sc->bufflen, sc->buffer, sc->underflow, sc->transfersize); + kdb_printf("tag = %d pid = %ld\n", + sc->tag, sc->pid); + +out: + if (sc) + kfree(sc); + return diag; +} + +static int __init kdbm_vm_init(void) +{ + kdb_register("vm", kdbm_vm, "[-v] ", "Display vm_area_struct", 0); + kdb_register("vmp", kdbm_vm, "[-v] ", "Display all vm_area_struct for ", 0); + kdb_register("pte", kdbm_pte, "( -m | -p ) []", "Display pte_t for mm_struct or pid", 0); + kdb_register("rpte", kdbm_rpte, "( -m | -p ) []", "Find pte_t containing pfn for mm_struct or pid", 0); + kdb_register("dentry", kdbm_dentry, "", "Display interesting dentry stuff", 0); + kdb_register("kobject", kdbm_kobject, "", "Display interesting kobject stuff", 0); + kdb_register("filp", kdbm_filp, "", "Display interesting filp stuff", 0); + kdb_register("fl", kdbm_fl, "", "Display interesting file_lock stuff", 0); + kdb_register("sh", kdbm_sh, "", "Show scsi_host", 0); + kdb_register("sd", kdbm_sd, "", "Show scsi_device", 0); + kdb_register("sc", kdbm_sc, "", "Show scsi_cmnd", 0); + + return 0; +} + +static void __exit kdbm_vm_exit(void) +{ + kdb_unregister("vm"); + kdb_unregister("vmp"); + kdb_unregister("pte"); + kdb_unregister("rpte"); + kdb_unregister("dentry"); + kdb_unregister("kobject"); + kdb_unregister("filp"); + kdb_unregister("fl"); + kdb_unregister("sh"); + kdb_unregister("sd"); + kdb_unregister("sc"); +} + +module_init(kdbm_vm_init) +module_exit(kdbm_vm_exit) Index: 2.6.x-xfs/kdb/modules/kdbm_sched.c =================================================================== --- 2.6.x-xfs.orig/kdb/modules/kdbm_sched.c 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/modules/kdbm_sched.c 2006-02-28 11:26:53.556769920 +1100 @@ -0,0 +1,58 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. + */ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("SGI"); +MODULE_DESCRIPTION("Debug scheduler information"); +MODULE_LICENSE("GPL"); + +static int +kdbm_runqueues(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + unsigned long cpu; + int ret = 0; + + if (argc == 1) { + ret = kdbgetularg((char *)argv[1], &cpu); + if (!ret) { + if (!cpu_online(cpu)) { + kdb_printf("Invalid cpu number\n"); + } else + kdb_runqueue(cpu, kdb_printf); + } + } else if (argc == 0) { + for_each_online_cpu(cpu) + kdb_runqueue(cpu, kdb_printf); + } else { + /* More than one arg */ + kdb_printf("Specify one cpu number\n"); + } + return ret; +} + +static int __init kdbm_sched_init(void) +{ + kdb_register("rq", kdbm_runqueues, "", "Display runqueue for ", 0); + kdb_register("rqa", kdbm_runqueues, "", "Display all runqueues", 0); + return 0; +} + +static void __exit kdbm_sched_exit(void) +{ + kdb_unregister("rq"); + kdb_unregister("rqa"); +} + +module_init(kdbm_sched_init) +module_exit(kdbm_sched_exit) Index: 2.6.x-xfs/kdb/modules/kdbm_xpc.c =================================================================== --- 2.6.x-xfs.orig/kdb/modules/kdbm_xpc.c 2005-11-18 06:05:20.000000000 +1100 +++ 2.6.x-xfs/kdb/modules/kdbm_xpc.c 2006-02-28 11:26:53.565557786 +1100 @@ -0,0 +1,1111 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2006 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * Cross Partition Communication (XPC) kdb support. + * + * This provides kdb commands for debugging XPC. + */ + +#include +#include +#include +#include +#include +#include + + +MODULE_AUTHOR("SGI"); +MODULE_DESCRIPTION("Debug XPC information"); +MODULE_LICENSE("GPL"); + + +static int +kdbm_xpc_down(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + if (xpc_rsvd_page == NULL) { + kdb_printf("Reserved Page has not been initialized.\n"); + + } else if (xpc_kdebug_force_disengage()) { + kdb_printf("Unable to force XPC disengage.\n"); + } + return 0; +} + + +static char * +kdbm_xpc_get_ascii_reason_code(enum xpc_retval reason) +{ + switch (reason) { + case xpcSuccess: return ""; + case xpcNotConnected: return "xpcNotConnected"; + case xpcConnected: return "xpcConnected"; + case xpcRETIRED1: return "xpcRETIRED1"; + case xpcMsgReceived: return "xpcMsgReceived"; + case xpcMsgDelivered: return "xpcMsgDelivered"; + case xpcRETIRED2: return "xpcRETIRED2"; + case xpcNoWait: return "xpcNoWait"; + case xpcRetry: return "xpcRetry"; + case xpcTimeout: return "xpcTimeout"; + case xpcInterrupted: return "xpcInterrupted"; + case xpcUnequalMsgSizes: return "xpcUnequalMsgSizes"; + case xpcInvalidAddress: return "xpcInvalidAddress"; + case xpcNoMemory: return "xpcNoMemory"; + case xpcLackOfResources: return "xpcLackOfResources"; + case xpcUnregistered: return "xpcUnregistered"; + case xpcAlreadyRegistered: return "xpcAlreadyRegistered"; + case xpcPartitionDown: return "xpcPartitionDown"; + case xpcNotLoaded: return "xpcNotLoaded"; + case xpcUnloading: return "xpcUnloading"; + case xpcBadMagic: return "xpcBadMagic"; + case xpcReactivating: return "xpcReactivating"; + case xpcUnregistering: return "xpcUnregistering"; + case xpcOtherUnregistering: return "xpcOtherUnregistering"; + case xpcCloneKThread: return "xpcCloneKThread"; + case xpcCloneKThreadFailed: return "xpcCloneKThreadFailed"; + case xpcNoHeartbeat: return "xpcNoHeartbeat"; + case xpcPioReadError: return "xpcPioReadError"; + case xpcPhysAddrRegFailed: return "xpcPhysAddrRegFailed"; + case xpcBteDirectoryError: return "xpcBteDirectoryError"; + case xpcBtePoisonError: return "xpcBtePoisonError"; + case xpcBteWriteError: return "xpcBteWriteError"; + case xpcBteAccessError: return "xpcBteAccessError"; + case xpcBtePWriteError: return "xpcBtePWriteError"; + case xpcBtePReadError: return "xpcBtePReadError"; + case xpcBteTimeOutError: return "xpcBteTimeOutError"; + case xpcBteXtalkError: return "xpcBteXtalkError"; + case xpcBteNotAvailable: return "xpcBteNotAvailable"; + case xpcBteUnmappedError: return "xpcBteUnmappedError"; + case xpcBadVersion: return "xpcBadVersion"; + case xpcVarsNotSet: return "xpcVarsNotSet"; + case xpcNoRsvdPageAddr: return "xpcNoRsvdPageAddr"; + case xpcInvalidPartid: return "xpcInvalidPartid"; + case xpcLocalPartid: return "xpcLocalPartid"; + case xpcOtherGoingDown: return "xpcOtherGoingDown"; + case xpcSystemGoingDown: return "xpcSystemGoingDown"; + case xpcSystemHalt: return "xpcSystemHalt"; + case xpcSystemReboot: return "xpcSystemReboot"; + case xpcSystemPoweroff: return "xpcSystemPoweroff"; + case xpcDisconnecting: return "xpcDisconnecting"; + case xpcOpenCloseError: return "xpcOpenCloseError"; + case xpcUnknownReason: return "xpcUnknownReason"; + default: return "undefined reason code"; + } +} + + +/* + * Display the reserved page used by XPC. + * + * xpcrp + */ +static int +kdbm_xpc_rsvd_page(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct xpc_rsvd_page *rp = (struct xpc_rsvd_page *) xpc_rsvd_page; + + + if (argc > 0) { + return KDB_ARGCOUNT; + } + + if (rp == NULL) { + kdb_printf("Reserved Page has not been initialized.\n"); + return 0; + } + + kdb_printf("struct xpc_rsvd_page @ (0x%p):\n", (void *) rp); + kdb_printf("\tSAL_signature=0x%lx\n", rp->SAL_signature); + kdb_printf("\tSAL_version=0x%lx\n", rp->SAL_version); + kdb_printf("\tpartid=%d\n", rp->partid); + kdb_printf("\tversion=0x%x %d.%d\n", rp->version, + XPC_VERSION_MAJOR(rp->version), + XPC_VERSION_MINOR(rp->version)); + kdb_printf("\tvars_pa=0x%lx\n", rp->vars_pa); + kdb_printf("\tstamp=0x%lx:0x%lx\n", + rp->stamp.tv_sec, rp->stamp.tv_nsec); + kdb_printf("\tnasids_size=%ld\n", rp->nasids_size); + + return 0; +} + + +static void +kdbm_xpc_print_vars_part(struct xpc_vars_part *vars_part, partid_t partid) +{ + kdb_printf("struct xpc_vars_part @ (0x%p) [partid=%d]:\n", + (void *) vars_part, partid); + kdb_printf("\tmagic=0x%lx ", vars_part->magic); + if (vars_part->magic != 0) { + kdb_printf("%s", (char *) &vars_part->magic); + } + kdb_printf("\n"); + kdb_printf("\tGPs_pa=0x%lx\n", vars_part->GPs_pa); + kdb_printf("\topenclose_args_pa=0x%lx\n", + vars_part->openclose_args_pa); + kdb_printf("\tIPI_amo_pa=0x%lx\n", vars_part->IPI_amo_pa); + kdb_printf("\tIPI_nasid=0x%x\n", vars_part->IPI_nasid); + kdb_printf("\tIPI_phys_cpuid=0x%x\n", vars_part->IPI_phys_cpuid); + kdb_printf("\tnchannels=%d\n", vars_part->nchannels); +} + + +/* + * Display XPC variables. + * + * xpcvars [ ] + * + * no partid - displays xpc_vars structure + * partid=0 - displays all initialized xpc_vars_part structures + * partid=i - displays xpc_vars_part structure for specified + * partition, if initialized + */ +static int +kdbm_xpc_variables(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + int ret; + unsigned long ulong_partid; + partid_t partid; + struct xpc_vars_part *vars_part; + + + if (xpc_rsvd_page == NULL) { + kdb_printf("Reserved Page has not been initialized.\n"); + return 0; + } + DBUG_ON(xpc_vars == NULL); + + if (argc == 0) { + + /* just display the xpc_vars structure */ + + kdb_printf("struct xpc_vars @ (0x%p):\n", (void *) xpc_vars); + kdb_printf("\tversion=0x%x %d.%d\n", xpc_vars->version, + XPC_VERSION_MAJOR(xpc_vars->version), + XPC_VERSION_MINOR(xpc_vars->version)); + kdb_printf("\theartbeat=%ld\n", xpc_vars->heartbeat); + kdb_printf("\theartbeating_to_mask=0x%lx", + xpc_vars->heartbeating_to_mask); + for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + if (xpc_hb_allowed(partid, xpc_vars)) { + kdb_printf(" %d", partid); + } + } + kdb_printf("\n"); + kdb_printf("\theartbeat_offline=0x%lx\n", + xpc_vars->heartbeat_offline); + kdb_printf("\tact_nasid=0x%x\n", xpc_vars->act_nasid); + kdb_printf("\tact_phys_cpuid=0x%x\n", + xpc_vars->act_phys_cpuid); + kdb_printf("\tvars_part_pa=0x%lx\n", xpc_vars->vars_part_pa); + kdb_printf("\tamos_page_pa=0x%lx\n", xpc_vars->amos_page_pa); + kdb_printf("\tamos_page=0x%p\n", (void *) xpc_vars->amos_page); + return 0; + + } else if (argc != 1) { + return KDB_ARGCOUNT; + } + + ret = kdbgetularg(argv[1], (unsigned long *) &ulong_partid); + if (ret) { + return ret; + } + partid = (partid_t) ulong_partid; + if (partid < 0 || partid >= XP_MAX_PARTITIONS) { + kdb_printf("invalid partid\n"); + return KDB_BADINT; + } + + vars_part = (struct xpc_vars_part *) __va(xpc_vars->vars_part_pa); + DBUG_ON(vars_part == NULL); + + if (partid == 0) { + + /* display all initialized xpc_vars_part structure */ + + for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + if (vars_part[partid].magic == 0) { + continue; + } + kdbm_xpc_print_vars_part(&vars_part[partid], partid); + } + + } else { + + /* display specified xpc_vars_part structure */ + + if (vars_part[partid].magic != 0) { + kdbm_xpc_print_vars_part(&vars_part[partid], partid); + } else { + kdb_printf("struct xpc_vars_part for partid %d not " + "initialized\n", partid); + } + } + + return 0; +} + + +static void +kdbm_xpc_print_engaged(char *string, u64 mask, int verbose) +{ + partid_t partid; + + + kdb_printf("%s=0x%lx", string, mask); + + if (verbose) { + partid = 0; + while (mask != 0) { + if (mask & 1UL) { + kdb_printf(" %d", partid); + } + partid++; + mask >>= 1; + } + } + kdb_printf("\n"); +} + + +/* + * Display XPC's 'engaged partitions' and 'disengage request' AMOs. + * + * xpcengaged [ -v ] + * + * -v - verbose mode, displays partition numbers. + */ +static int +kdbm_xpc_engaged(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + int nextarg = 1; + int verbose = 0; + u64 mask; + + + if (argc > 1) { + return KDB_ARGCOUNT; + } + if (argc == 1) { + if (strcmp(argv[nextarg], "-v") != 0) { + return KDB_ARGCOUNT; + } + verbose = 1; + } + + mask = xpc_partition_engaged(-1UL); + kdbm_xpc_print_engaged("engaged partitions", mask, verbose); + + mask = xpc_partition_disengage_requested(-1UL); + kdbm_xpc_print_engaged("disengage request", mask, verbose); + + return 0; +} + + +static void +kdbm_xpc_print_IPI_flags_for_channel(u8 IPI_flags) +{ + if (IPI_flags & XPC_IPI_MSGREQUEST) kdb_printf(" MSGREQUEST"); + if (IPI_flags & XPC_IPI_OPENREPLY) kdb_printf(" OPENREPLY"); + if (IPI_flags & XPC_IPI_OPENREQUEST) kdb_printf(" OPENREQUEST"); + if (IPI_flags & XPC_IPI_CLOSEREPLY) kdb_printf(" CLOSEREPLY"); + if (IPI_flags & XPC_IPI_CLOSEREQUEST) kdb_printf(" CLOSEREQUEST"); +} + + +static void +kdbm_xpc_print_IPI_flags(u64 IPI_amo) +{ + int ch_number; + u8 IPI_flags; + + + for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++) { + + /* get the IPI flags for the specific channel */ + IPI_flags = XPC_GET_IPI_FLAGS(IPI_amo, ch_number); + if (IPI_flags == 0) { + continue; + } + + kdb_printf("\t channel_%d=0x%x", ch_number, IPI_flags); + kdbm_xpc_print_IPI_flags_for_channel(IPI_flags); + kdb_printf("\n"); + } +} + + +static void +kdbm_xpc_print_part(struct xpc_partition *part, partid_t partid) +{ + kdb_printf("xpc_partitions[partid=%d] (0x%p):\n", partid, + (void *) part); + kdb_printf("\tremote_rp_version=0x%x %d.%d\n", part->remote_rp_version, + XPC_VERSION_MAJOR(part->remote_rp_version), + XPC_VERSION_MINOR(part->remote_rp_version)); + kdb_printf("\tremote_rp_stamp=0x%lx:0x%lx\n", + part->remote_rp_stamp.tv_sec, part->remote_rp_stamp.tv_nsec); + kdb_printf("\tremote_rp_pa=0x%lx\n", part->remote_rp_pa); + kdb_printf("\tremote_vars_pa=0x%lx\n", part->remote_vars_pa); + kdb_printf("\tremote_vars_part_pa=0x%lx\n", part->remote_vars_part_pa); + kdb_printf("\tlast_heartbeat=%ld\n", part->last_heartbeat); + kdb_printf("\tremote_amos_page_pa=0x%lx\n", part->remote_amos_page_pa); + kdb_printf("\tremote_act_nasid=0x%x\n", part->remote_act_nasid); + kdb_printf("\tremote_act_phys_cpuid=0x%x\n", + part->remote_act_phys_cpuid); + kdb_printf("\tact_IRQ_rcvd=%d\n", part->act_IRQ_rcvd); + kdb_printf("\tact_state=%d", part->act_state); + switch (part->act_state) { + case XPC_P_INACTIVE: kdb_printf(" INACTIVE\n"); break; + case XPC_P_ACTIVATION_REQ: kdb_printf(" ACTIVATION_REQ\n"); break; + case XPC_P_ACTIVATING: kdb_printf(" ACTIVATING\n"); break; + case XPC_P_ACTIVE: kdb_printf(" ACTIVE\n"); break; + case XPC_P_DEACTIVATING: kdb_printf(" DEACTIVATING\n"); break; + default: kdb_printf(" unknown\n"); + } + kdb_printf("\tremote_vars_version=0x%x %d.%d\n", + part->remote_vars_version, + XPC_VERSION_MAJOR(part->remote_vars_version), + XPC_VERSION_MINOR(part->remote_vars_version)); + kdb_printf("\treactivate_nasid=%d\n", part->reactivate_nasid); + kdb_printf("\treason=%d %s\n", part->reason, + kdbm_xpc_get_ascii_reason_code(part->reason)); + kdb_printf("\treason_line=%d\n", part->reason_line); + + kdb_printf("\tdisengage_request_timeout=0x%lx\n", + part->disengage_request_timeout); + kdb_printf("\t&disengage_request_timer=0x%p\n", + (void *) &part->disengage_request_timer); + + kdb_printf("\tsetup_state=%d", part->setup_state); + switch (part->setup_state) { + case XPC_P_UNSET: kdb_printf(" UNSET\n"); break; + case XPC_P_SETUP: kdb_printf(" SETUP\n"); break; + case XPC_P_WTEARDOWN: kdb_printf(" WTEARDOWN\n"); break; + case XPC_P_TORNDOWN: kdb_printf(" TORNDOWN\n"); break; + default: kdb_printf(" unknown\n"); + } + kdb_printf("\treferences=%d\n", atomic_read(&part->references)); + kdb_printf("\tnchannels=%d\n", part->nchannels); + kdb_printf("\tnchannels_active=%d\n", + atomic_read(&part->nchannels_active)); + kdb_printf("\tnchannels_engaged=%d\n", + atomic_read(&part->nchannels_engaged)); + kdb_printf("\tchannels=0x%p\n", (void *) part->channels); + kdb_printf("\tlocal_GPs=0x%p\n", (void *) part->local_GPs); + kdb_printf("\tremote_GPs=0x%p\n", (void *) part->remote_GPs); + kdb_printf("\tremote_GPs_pa=0x%lx\n", part->remote_GPs_pa); + kdb_printf("\tlocal_openclose_args=0x%p\n", + (void *) part->local_openclose_args); + kdb_printf("\tremote_openclose_args=0x%p\n", + (void *) part->remote_openclose_args); + kdb_printf("\tremote_openclose_args_pa=0x%lx\n", + part->remote_openclose_args_pa); + kdb_printf("\tremote_IPI_nasid=0x%x\n", part->remote_IPI_nasid); + kdb_printf("\tremote_IPI_phys_cpuid=0x%x\n", + part->remote_IPI_phys_cpuid); + kdb_printf("\tremote_IPI_amo_va=0x%p\n", + (void *) part->remote_IPI_amo_va); + kdb_printf("\tlocal_IPI_amo_va=0x%p\n", + (void *) part->local_IPI_amo_va); + kdb_printf("\tlocal_IPI_amo=0x%lx\n", part->local_IPI_amo); + kdbm_xpc_print_IPI_flags(part->local_IPI_amo); + kdb_printf("\tIPI_owner=%s\n", part->IPI_owner); + kdb_printf("\t&dropped_IPI_timer=0x%p\n", + (void *) &part->dropped_IPI_timer); + + kdb_printf("\tchannel_mgr_requests=%d\n", atomic_read(&part-> + channel_mgr_requests)); +} + + +/* + * Display XPC partitions. + * + * xpcpart [ | ] + */ +static int +kdbm_xpc_partitions(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + int ret; + int nextarg = 1; + long offset = 0; + unsigned long addr; + struct xpc_partition *part; + partid_t partid; + + + if (argc > 1) { + return KDB_ARGCOUNT; + + } else if (argc == 1) { + ret = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, + NULL, regs); + if (ret) { + return ret; + } + if (addr > 0 && addr < XP_MAX_PARTITIONS) { + partid = (partid_t) addr; + part = &xpc_partitions[partid]; + } else { + part = (struct xpc_partition *) addr; + partid = part - &xpc_partitions[0]; + if (partid <= 0 || partid >= XP_MAX_PARTITIONS || + part != &xpc_partitions[partid]) { + kdb_printf("invalid partition entry address\n"); + return KDB_BADADDR; + } + } + kdbm_xpc_print_part(part, partid); + + } else { + for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + part = &xpc_partitions[partid]; + if (part->setup_state == XPC_P_UNSET && + part->reason == 0) { + continue; + } + kdbm_xpc_print_part(part, partid); + } + } + return 0; +} + + +static void +kdbm_xpc_print_channel_flags(u32 flags) +{ + kdb_printf("\tflags=0x%x", flags); + + if (flags & XPC_C_WDISCONNECT) kdb_printf(" WDISCONNECT"); + if (flags & XPC_C_DISCONNECTING) kdb_printf(" DISCONNECTING"); + if (flags & XPC_C_DISCONNECTED) kdb_printf(" DISCONNECTED"); + + if (flags & XPC_C_CLOSEREQUEST) kdb_printf(" CLOSEREQUEST"); + if (flags & XPC_C_RCLOSEREQUEST) kdb_printf(" RCLOSEREQUEST"); + if (flags & XPC_C_CLOSEREPLY) kdb_printf(" CLOSEREPLY"); + if (flags & XPC_C_RCLOSEREPLY) kdb_printf(" RCLOSEREPLY"); + + if (flags & XPC_C_CONNECTING) kdb_printf(" CONNECTING"); + if (flags & XPC_C_CONNECTED) kdb_printf(" CONNECTED"); + if (flags & XPC_C_SETUP) kdb_printf(" SETUP"); + + if (flags & XPC_C_OPENREQUEST) kdb_printf(" OPENREQUEST"); + if (flags & XPC_C_ROPENREQUEST) kdb_printf(" ROPENREQUEST"); + if (flags & XPC_C_OPENREPLY) kdb_printf(" OPENREPLY"); + if (flags & XPC_C_ROPENREPLY) kdb_printf(" ROPENREPLY"); + + if (flags & XPC_C_WASCONNECTED) kdb_printf(" WASCONNECTED"); + + kdb_printf("\n"); +} + + +static void +kdbm_xpc_print_channel(struct xpc_channel *ch) +{ + kdb_printf("channel %d (0x%p):\n", ch->number, (void *) ch); + kdb_printf("\tpartid=%d\n", ch->partid); + + kdbm_xpc_print_channel_flags(ch->flags); + + kdb_printf("\treason=%d %s\n", ch->reason, + kdbm_xpc_get_ascii_reason_code(ch->reason)); + kdb_printf("\treason_line=%d\n", ch->reason_line); + kdb_printf("\tnumber=%d\n", ch->number); + kdb_printf("\tmsg_size=%d\n", ch->msg_size); + kdb_printf("\tlocal_nentries=%d\n", ch->local_nentries); + kdb_printf("\tremote_nentries=%d\n", ch->remote_nentries); + kdb_printf("\tlocal_msgqueue=0x%p\n", (void *) ch->local_msgqueue); + kdb_printf("\tremote_msgqueue_pa=0x%lx\n", ch->remote_msgqueue_pa); + kdb_printf("\tremote_msgqueue=0x%p\n", + (void *) ch->remote_msgqueue); + kdb_printf("\treferences=%d\n", atomic_read(&ch->references)); + kdb_printf("\tn_on_msg_allocate_wq=%d\n", + atomic_read(&ch->n_on_msg_allocate_wq)); + kdb_printf("\t&msg_allocate_wq=0x%p\n", + (void *) &ch->msg_allocate_wq); + + kdb_printf("\tdelayed_IPI_flags=0x%x", ch->delayed_IPI_flags); + kdbm_xpc_print_IPI_flags_for_channel(ch->delayed_IPI_flags); + kdb_printf("\n"); + + kdb_printf("\tn_to_notify=%d\n", atomic_read(&ch->n_to_notify)); + kdb_printf("\tnotify_queue=0x%p\n", (void *) ch->notify_queue); + kdb_printf("\tfunc=0x%p\n", (void *) ch->func); + kdb_printf("\tkey=0x%p\n", ch->key); + kdb_printf("\t&msg_to_pull_mutex=0x%p\n", + (void *) &ch->msg_to_pull_mutex); + kdb_printf("\t&wdisconnect_wait=0x%p\n", + (void *) &ch->wdisconnect_wait); + kdb_printf("\tlocal_GP=0x%p (%ld:%ld)\n", (void *) ch->local_GP, + ch->local_GP->get, + ch->local_GP->put); + kdb_printf("\tremote_GP=%ld:%ld\n", ch->remote_GP.get, + ch->remote_GP.put); + kdb_printf("\tw_local_GP=%ld:%ld\n", ch->w_local_GP.get, + ch->w_local_GP.put); + kdb_printf("\tw_remote_GP=%ld:%ld\n", ch->w_remote_GP.get, + ch->w_remote_GP.put); + kdb_printf("\tnext_msg_to_pull=%ld\n", ch->next_msg_to_pull); + kdb_printf("\tkthreads_assigned=%d\n", + atomic_read(&ch->kthreads_assigned)); + kdb_printf("\tkthreads_assigned_limit=%d\n", + ch->kthreads_assigned_limit); + kdb_printf("\tkthreads_idle=%d\n", + atomic_read(&ch->kthreads_idle)); + kdb_printf("\tkthreads_idle_limit=%d\n", ch->kthreads_idle_limit); + kdb_printf("\tkthreads_active=%d\n", + atomic_read(&ch->kthreads_active)); + kdb_printf("\tkthreads_created=%d\n", ch->kthreads_created); + kdb_printf("\t&idle_wq=0x%p\n", (void *) &ch->idle_wq); + + if (ch->flags & XPC_C_CONNECTED) { + kdb_printf("\n\t#of local msg queue entries available =%ld\n", + ch->local_nentries - (ch->w_local_GP.put - + ch->w_remote_GP.get)); + + kdb_printf("\t#of local msgs allocated !sent =%ld\n", + ch->w_local_GP.put - ch->local_GP->put); + kdb_printf("\t#of local msgs allocated sent !ACK'd =%ld\n", + ch->local_GP->put - ch->remote_GP.get); + kdb_printf("\t#of local msgs allocated sent ACK'd !notified =" + "%ld\n", ch->remote_GP.get - ch->w_remote_GP.get); + + kdb_printf("\t#of remote msgs sent !pulled =%ld\n", + ch->w_remote_GP.put - ch->next_msg_to_pull); + kdb_printf("\t#of remote msgs sent !delivered =%ld\n", + ch->next_msg_to_pull - ch->w_local_GP.get); + kdb_printf("\t#of remote msgs sent delivered !received =%ld\n", + ch->w_local_GP.get - ch->local_GP->get); + } +} + + +/* + * Display a XPC partition's channels. + * + * xpcchan | [ ] + */ +static int +kdbm_xpc_channels(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + int ret; + int nextarg = 1; + long offset = 0; + unsigned long addr; + partid_t partid; + struct xpc_partition *part; + int ch_number; + struct xpc_channel *ch; + + + if (argc < 1 || argc > 2) { + return KDB_ARGCOUNT; + } + + ret = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (ret) { + return ret; + } + if (addr > 0 && addr < XP_MAX_PARTITIONS) { + partid = (partid_t) addr; + part = &xpc_partitions[partid]; + if (part->setup_state == XPC_P_UNSET) { + kdb_printf("partition is UNSET\n"); + return 0; + } + if (part->setup_state == XPC_P_TORNDOWN) { + kdb_printf("partition is TORNDOWN\n"); + return 0; + } + + if (argc == 2) { + ret = kdbgetularg(argv[2], + (unsigned long *) &ch_number); + if (ret) { + return ret; + } + if (ch_number < 0 || ch_number >= part->nchannels) { + kdb_printf("invalid channel #\n"); + return KDB_BADINT; + } + kdbm_xpc_print_channel(&part->channels[ch_number]); + } else { + for (ch_number = 0; ch_number < part->nchannels; + ch_number++) { + kdbm_xpc_print_channel(&part-> + channels[ch_number]); + } + } + + } else { + ch = (struct xpc_channel *) addr; + + for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { + part = &xpc_partitions[partid]; + if (part->setup_state != XPC_P_UNSET && + part->setup_state != XPC_P_TORNDOWN && + ch >= part->channels) { + ch_number = ch - part->channels; + if (ch_number < part->nchannels && + ch == &part->channels[ch_number]) { + break; + } + } + } + if (partid == XP_MAX_PARTITIONS) { + kdb_printf("invalid channel address\n"); + return KDB_BADADDR; + } + kdbm_xpc_print_channel(ch); + } + + return 0; +} + + +static void +kdbm_xpc_print_local_msgqueue(struct xpc_channel *ch) +{ + int i; + char *prefix; + struct xpc_msg *msg = ch->local_msgqueue; + s64 w_remote_GP_get = ch->w_remote_GP.get % ch->local_nentries; + s64 remote_GP_get = ch->remote_GP.get % ch->local_nentries; + s64 local_GP_put = ch->local_GP->put % ch->local_nentries; + s64 w_local_GP_put = ch->w_local_GP.put % ch->local_nentries; + + + kdb_printf("local message queue (0x%p):\n\n", (void *) msg); + + for (i = 0; i < ch->local_nentries; i++) { + kdb_printf("0x%p: flags=0x%x number=%ld", (void *) msg, + msg->flags, msg->number); + + prefix = " <--"; + + if (i == w_remote_GP_get) { + kdb_printf("%s w_remote_GP.get", prefix); + prefix = ","; + } + if (i == remote_GP_get) { + kdb_printf("%s remote_GP.get", prefix); + prefix = ","; + } + if (i == local_GP_put) { + kdb_printf("%s local_GP->put", prefix); + prefix = ","; + } + if (i == w_local_GP_put) { + kdb_printf("%s w_local_GP.put", prefix); + } + kdb_printf("\n"); + + msg = (struct xpc_msg *) ((u64) msg + ch->msg_size); + } +} + + +static void +kdbm_xpc_print_remote_msgqueue(struct xpc_channel *ch) +{ + int i; + char *prefix; + struct xpc_msg *msg = ch->remote_msgqueue; + s64 local_GP_get = ch->local_GP->get % ch->remote_nentries; + s64 w_local_GP_get = ch->w_local_GP.get % ch->remote_nentries; + s64 next_msg_to_pull = ch->next_msg_to_pull % ch->remote_nentries; + s64 w_remote_GP_put = ch->w_remote_GP.put % ch->remote_nentries; + s64 remote_GP_put = ch->remote_GP.put % ch->remote_nentries; + + + kdb_printf("cached remote message queue (0x%p):\n\n", (void *) msg); + + for (i = 0; i < ch->remote_nentries; i++) { + kdb_printf("0x%p: flags=0x%x number=%ld", (void *) msg, + msg->flags, msg->number); + + prefix = " <--"; + + if (i == local_GP_get) { + kdb_printf("%s local_GP->get", prefix); + prefix = ","; + } + if (i == w_local_GP_get) { + kdb_printf("%s w_local_GP.get", prefix); + prefix = ","; + } + if (i == next_msg_to_pull) { + kdb_printf("%s next_msg_to_pull", prefix); + prefix = ","; + } + if (i == w_remote_GP_put) { + kdb_printf("%s w_remote_GP.put", prefix); + prefix = ","; + } + if (i == remote_GP_put) { + kdb_printf("%s remote_GP.put", prefix); + } + kdb_printf("\n"); + + msg = (struct xpc_msg *) ((u64) msg + ch->msg_size); + } +} + + +/* + * Display XPC specified message queue. + * + * xpcmque local|remote + */ +static int +kdbm_xpc_msgqueue(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + int ret, ch_number; + unsigned long ulong_partid; + partid_t partid; + struct xpc_partition *part; + struct xpc_channel *ch; + + + if (argc != 3) { + return KDB_ARGCOUNT; + } + + ret = kdbgetularg(argv[1], (unsigned long *) &ulong_partid); + if (ret) { + return ret; + } + partid = (partid_t) ulong_partid; + if (partid <= 0 || partid >= XP_MAX_PARTITIONS) { + kdb_printf("invalid partid\n"); + return KDB_BADINT; + } + + ret = kdbgetularg(argv[2], (unsigned long *) &ch_number); + if (ret) { + return ret; + } + if (ch_number < 0 || ch_number >= XPC_NCHANNELS) { + kdb_printf("invalid channel #\n"); + return KDB_BADINT; + } + + part = &xpc_partitions[partid]; + + if (part->setup_state == XPC_P_UNSET) { + kdb_printf("partition is UNSET\n"); + return 0; + } + if (part->setup_state == XPC_P_TORNDOWN) { + kdb_printf("partition is TORNDOWN\n"); + return 0; + } + + if (ch_number >= part->nchannels) { + kdb_printf("unsupported channel #\n"); + return KDB_BADINT; + } + + ch = &part->channels[ch_number]; + + if (!(ch->flags & XPC_C_SETUP)) { + kdb_printf("message queues are not SETUP\n"); + return 0; + } + + if (strcmp(argv[3], "r") == 0 || strcmp(argv[3], "remote") == 0) { + kdbm_xpc_print_remote_msgqueue(ch); + } else if (strcmp(argv[3], "l") == 0 || strcmp(argv[3], "local") == 0) { + kdbm_xpc_print_local_msgqueue(ch); + } else { + kdb_printf("unknown msg queue selected\n"); + return KDB_BADINT; + } + + return 0; +} + + +static void +kdbm_xpc_print_msg_flags(u8 flags) +{ + kdb_printf("\tflags=0x%x", flags); + + if (flags & XPC_M_INTERRUPT) kdb_printf(" INTERRUPT"); + if (flags & XPC_M_READY) kdb_printf(" READY"); + if (flags & XPC_M_DONE) kdb_printf(" DONE"); + + kdb_printf("\n"); +} + + +/* + * Display XPC message. + * + * xpcmsg + */ +static int +kdbm_xpc_msg(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + int ret, nextarg = argc; + long offset = 0; + unsigned long addr; + struct xpc_msg *msg; + + + if (argc != 1) { + return KDB_ARGCOUNT; + } + + ret = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (ret) { + return ret; + } + + msg = (struct xpc_msg *) addr; + kdb_printf("msg (0x%p):\n", (void *) msg); + kdbm_xpc_print_msg_flags(msg->flags); + kdb_printf("\tnumber=%ld\n", msg->number); + kdb_printf("\t&payload=0x%p\n", (void *) &msg->payload); + + return 0; +} + + +static void +kdbm_xpc_print_notify_queue(struct xpc_channel *ch) +{ + int i; + char *prefix; + struct xpc_notify *notify = ch->notify_queue; + s64 w_remote_GP_get = ch->w_remote_GP.get % ch->local_nentries; + s64 remote_GP_get = ch->remote_GP.get % ch->local_nentries; + s64 local_GP_put = ch->local_GP->put % ch->local_nentries; + s64 w_local_GP_put = ch->w_local_GP.put % ch->local_nentries; + + + kdb_printf("notify queue (0x%p):\n\n", (void *) notify); + + for (i = 0; i < ch->local_nentries; i++) { + kdb_printf("0x%p: type=0x%x", (void *) notify, notify->type); + + if (notify->type == XPC_N_CALL) { + kdb_printf(" CALL func=0x%p key=0x%p", + (void *) notify->func, notify->key); + } + + prefix = " <--"; + + if (i == w_remote_GP_get) { + kdb_printf("%s w_remote_GP.get", prefix); + prefix = ","; + } + if (i == remote_GP_get) { + kdb_printf("%s remote_GP.get", prefix); + prefix = ","; + } + if (i == local_GP_put) { + kdb_printf("%s local_GP->put", prefix); + prefix = ","; + } + if (i == w_local_GP_put) { + kdb_printf("%s w_local_GP.put", prefix); + } + kdb_printf("\n"); + + notify++; + } +} + + +/* + * Display XPC specified notify queue. + * + * xpcnque + */ +static int +kdbm_xpc_notify_queue(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + int ret, ch_number; + unsigned long ulong_partid; + partid_t partid; + struct xpc_partition *part; + struct xpc_channel *ch; + + + if (argc != 2) { + return KDB_ARGCOUNT; + } + + ret = kdbgetularg(argv[1], (unsigned long *) &ulong_partid); + if (ret) { + return ret; + } + partid = (partid_t) ulong_partid; + if (partid <= 0 || partid >= XP_MAX_PARTITIONS) { + kdb_printf("invalid partid\n"); + return KDB_BADINT; + } + + ret = kdbgetularg(argv[2], (unsigned long *) &ch_number); + if (ret) { + return ret; + } + if (ch_number < 0 || ch_number >= XPC_NCHANNELS) { + kdb_printf("invalid channel #\n"); + return KDB_BADINT; + } + + part = &xpc_partitions[partid]; + + if (part->setup_state == XPC_P_UNSET) { + kdb_printf("partition is UNSET\n"); + return 0; + } + if (part->setup_state == XPC_P_TORNDOWN) { + kdb_printf("partition is TORNDOWN\n"); + return 0; + } + + if (ch_number >= part->nchannels) { + kdb_printf("unsupported channel #\n"); + return KDB_BADINT; + } + + ch = &part->channels[ch_number]; + + if (!(ch->flags & XPC_C_SETUP)) { + kdb_printf("notify queue is not SETUP\n"); + return 0; + } + + kdbm_xpc_print_notify_queue(ch); + + return 0; +} + + +static void +kdbm_xpc_print_users(struct xpc_registration *registration, int ch_number) +{ + kdb_printf("xpc_registrations[channel=%d] (0x%p):\n", ch_number, + (void *) registration); + + kdb_printf("\t&mutex=0x%p\n", (void *) ®istration->mutex); + kdb_printf("\tfunc=0x%p\n", (void *) registration->func); + kdb_printf("\tkey=0x%p\n", registration->key); + kdb_printf("\tnentries=%d\n", registration->nentries); + kdb_printf("\tmsg_size=%d\n", registration->msg_size); + kdb_printf("\tassigned_limit=%d\n", registration->assigned_limit); + kdb_printf("\tidle_limit=%d\n", registration->idle_limit); +} + + +/* + * Display current XPC users who have registered via xpc_connect(). + * + * xpcusers [ ] + */ +static int +kdbm_xpc_users(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + int ret; + struct xpc_registration *registration; + int ch_number; + + + if (argc > 1) { + return KDB_ARGCOUNT; + + } else if (argc == 1) { + ret = kdbgetularg(argv[1], (unsigned long *) &ch_number); + if (ret) { + return ret; + } + if (ch_number < 0 || ch_number >= XPC_NCHANNELS) { + kdb_printf("invalid channel #\n"); + return KDB_BADINT; + } + registration = &xpc_registrations[ch_number]; + kdbm_xpc_print_users(registration, ch_number); + + } else { + for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++) { + registration = &xpc_registrations[ch_number]; + + /* if !XPC_CHANNEL_REGISTERED(ch_number) */ + if (registration->func == NULL) { + continue; + } + kdbm_xpc_print_users(registration, ch_number); + } + } + return 0; +} + + +static int __init +kdbm_xpc_register(void) +{ + (void) kdb_register("xpcdown", kdbm_xpc_down, "", + "Mark this partition as being down", 0); + (void) kdb_register("xpcrp", kdbm_xpc_rsvd_page, "", + "Display XPC reserved page", 0); + (void) kdb_register("xpcvars", kdbm_xpc_variables, "[]", + "Display XPC variables", 0); + (void) kdb_register("xpcengaged", kdbm_xpc_engaged, "[-v]", + "Display XPC engaged partitions AMOs", 0); + (void) kdb_register("xpcpart", kdbm_xpc_partitions, "[|" + "]", "Display struct xpc_partition entries", 0); + (void) kdb_register("xpcchan", kdbm_xpc_channels, " | " + "[]", "Display struct xpc_channel entries", 0); + (void) kdb_register("xpcmque", kdbm_xpc_msgqueue, " " + "local|remote", "Display local or remote msg queue", 0); + (void) kdb_register("xpcmsg", kdbm_xpc_msg, "", + "Display struct xpc_msg", 0); + (void) kdb_register("xpcnque", kdbm_xpc_notify_queue, " " + "", "Display notify queue", 0); + (void) kdb_register("xpcusers", kdbm_xpc_users, "[ ]", + "Display struct xpc_registration entries", 0); + return 0; +} + + +static void __exit +kdbm_xpc_unregister(void) +{ + (void) kdb_unregister("xpcdown"); + (void) kdb_unregister("xpcrp"); + (void) kdb_unregister("xpcvars"); + (void) kdb_unregister("xpcengaged"); + (void) kdb_unregister("xpcpart"); + (void) kdb_unregister("xpcchan"); + (void) kdb_unregister("xpcmque"); + (void) kdb_unregister("xpcmsg"); + (void) kdb_unregister("xpcnque"); + (void) kdb_unregister("xpcusers"); +} + + +module_init(kdbm_xpc_register); +module_exit(kdbm_xpc_unregister); + Index: 2.6.x-xfs/kernel/exit.c =================================================================== --- 2.6.x-xfs.orig/kernel/exit.c 2006-02-28 10:56:53.204746804 +1100 +++ 2.6.x-xfs/kernel/exit.c 2006-02-28 11:26:53.544076334 +1100 @@ -5,6 +5,9 @@ */ #include +#ifdef CONFIG_KDB +#include +#endif #include #include #include Index: 2.6.x-xfs/kernel/module.c =================================================================== --- 2.6.x-xfs.orig/kernel/module.c 2006-02-13 14:38:33.074551224 +1100 +++ 2.6.x-xfs/kernel/module.c 2006-02-28 11:26:53.546029193 +1100 @@ -2066,6 +2066,13 @@ return NULL; } +#ifdef CONFIG_KDB +#include +struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ +#else /* !CONFIG_KDB */ +#define KDB_IS_RUNNING() 0 +#endif /* CONFIG_KDB */ + struct module *module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, @@ -2073,7 +2080,8 @@ { struct module *mod; - down(&module_mutex); + if (!KDB_IS_RUNNING()) + down(&module_mutex); list_for_each_entry(mod, &modules, list) { if (symnum < mod->num_symtab) { *value = mod->symtab[symnum].st_value; @@ -2081,12 +2089,14 @@ strncpy(namebuf, mod->strtab + mod->symtab[symnum].st_name, 127); - up(&module_mutex); + if (!KDB_IS_RUNNING()) + up(&module_mutex); return mod; } symnum -= mod->num_symtab; } - up(&module_mutex); + if (!KDB_IS_RUNNING()) + up(&module_mutex); return NULL; } Index: 2.6.x-xfs/kernel/printk.c =================================================================== --- 2.6.x-xfs.orig/kernel/printk.c 2006-02-06 11:08:09.959011256 +1100 +++ 2.6.x-xfs/kernel/printk.c 2006-02-28 11:26:53.547005623 +1100 @@ -356,6 +356,20 @@ return do_syslog(type, buf, len); } +#ifdef CONFIG_KDB +/* kdb dmesg command needs access to the syslog buffer. do_syslog() uses locks + * so it cannot be used during debugging. Just tell kdb where the start and + * end of the physical and logical logs are. This is equivalent to do_syslog(3). + */ +void kdb_syslog_data(char *syslog_data[4]) +{ + syslog_data[0] = log_buf; + syslog_data[1] = log_buf + log_buf_len; + syslog_data[2] = log_buf + log_end - (logged_chars < log_buf_len ? logged_chars : log_buf_len); + syslog_data[3] = log_buf + log_end; +} +#endif /* CONFIG_KDB */ + /* * Call the console drivers on a range of log_buf */ Index: 2.6.x-xfs/kernel/sched.c =================================================================== --- 2.6.x-xfs.orig/kernel/sched.c 2006-02-20 11:15:25.706624012 +1100 +++ 2.6.x-xfs/kernel/sched.c 2006-02-28 11:26:53.549934912 +1100 @@ -6121,7 +6121,7 @@ #endif /* CONFIG_MAGIC_SYSRQ */ -#ifdef CONFIG_IA64 +#if defined(CONFIG_IA64) || defined(CONFIG_KDB) /* * These functions are only useful for the IA64 MCA handling. * @@ -6164,3 +6164,80 @@ } #endif + +#ifdef CONFIG_KDB + +#include + +static void +kdb_prio(char *name, prio_array_t *array, kdb_printf_t xxx_printf) +{ + int pri; + + xxx_printf(" %s nr_active:%d bitmap: 0x%lx 0x%lx 0x%lx\n", + name, array->nr_active, + array->bitmap[0], array->bitmap[1], array->bitmap[2]); + + pri = sched_find_first_bit(array->bitmap); + if (pri != MAX_PRIO) { + xxx_printf(" bitmap priorities:"); + while (pri != MAX_PRIO) { + xxx_printf(" %d", pri); + pri++; + pri = find_next_bit(array->bitmap, MAX_PRIO, pri); + } + xxx_printf("\n"); + } + + for (pri = 0; pri < MAX_PRIO; pri++) { + int printed_hdr = 0; + struct list_head *head, *curr; + + head = array->queue + pri; + curr = head->next; + while(curr != head) { + task_t *task; + if (!printed_hdr) { + xxx_printf(" queue at priority=%d\n", pri); + printed_hdr = 1; + } + task = list_entry(curr, task_t, run_list); + xxx_printf(" 0x%p %d %s time_slice:%d\n", + task, task->pid, task->comm, + task->time_slice); + curr = curr->next; + } + } +} + +/* This code must be in sched.c because struct runqueue is only defined in this + * source. To allow most of kdb to be modular, this code cannot call any kdb + * functions directly, any external functions that it needs must be passed in + * as parameters. + */ + +void +kdb_runqueue(unsigned long cpu, kdb_printf_t xxx_printf) +{ + struct runqueue *rq; + + rq = cpu_rq(cpu); + + xxx_printf("CPU%ld lock:%s curr:0x%p(%d)(%s)", + cpu, (spin_is_locked(&rq->lock))?"LOCKED":"free", + rq->curr, rq->curr->pid, rq->curr->comm); + if (rq->curr == rq->idle) + xxx_printf(" is idle"); + xxx_printf("\n "); +#ifdef CONFIG_SMP + xxx_printf(" cpu_load:%lu %lu %lu", + rq->cpu_load[0], rq->cpu_load[1], rq->cpu_load[2]); +#endif + xxx_printf(" nr_running:%lu nr_switches:%llu\n", + rq->nr_running, rq->nr_switches); + kdb_prio("active", rq->active, xxx_printf); + kdb_prio("expired", rq->expired, xxx_printf); +} +EXPORT_SYMBOL(kdb_runqueue); + +#endif /* CONFIG_KDB */ Index: 2.6.x-xfs/kernel/signal.c =================================================================== --- 2.6.x-xfs.orig/kernel/signal.c 2006-02-13 14:38:33.081386226 +1100 +++ 2.6.x-xfs/kernel/signal.c 2006-02-28 11:26:53.551887771 +1100 @@ -2754,3 +2754,52 @@ __alignof__(struct sigqueue), SLAB_PANIC, NULL, NULL); } + +#ifdef CONFIG_KDB +#include +/* + * kdb_send_sig_info + * + * Allows kdb to send signals without exposing signal internals. + * + * Inputs: + * t task + * siginfo signal information + * seqno current kdb sequence number (avoid including kdbprivate.h) + * Outputs: + * None. + * Returns: + * None. + * Locking: + * Checks if the required locks are available before calling the main + * signal code, to avoid kdb deadlocks. + * Remarks: + */ +void +kdb_send_sig_info(struct task_struct *t, struct siginfo *info, int seqno) +{ + static struct task_struct *kdb_prev_t; + static int kdb_prev_seqno; + int sig, new_t; + if (!spin_trylock(&t->sighand->siglock)) { + kdb_printf("Can't do kill command now.\n" + "The sigmask lock is held somewhere else in kernel, try again later\n"); + return; + } + spin_unlock(&t->sighand->siglock); + new_t = kdb_prev_t != t || kdb_prev_seqno != seqno; + kdb_prev_t = t; + kdb_prev_seqno = seqno; + if (t->state != TASK_RUNNING && new_t) { + kdb_printf("Process is not RUNNING, sending a signal from kdb risks deadlock\n" + "on the run queue locks. The signal has _not_ been sent.\n" + "Reissue the kill command if you want to risk the deadlock.\n"); + return; + } + sig = info->si_signo; + if (send_sig_info(sig, info, t)) + kdb_printf("Fail to deliver Signal %d to process %d.\n", sig, t->pid); + else + kdb_printf("Signal %d is sent to process %d.\n", sig, t->pid); +} +#endif /* CONFIG_KDB */ Index: 2.6.x-xfs/kernel/kallsyms.c =================================================================== --- 2.6.x-xfs.orig/kernel/kallsyms.c 2005-12-05 09:56:23.004038162 +1100 +++ 2.6.x-xfs/kernel/kallsyms.c 2006-02-28 11:26:53.555793490 +1100 @@ -419,3 +419,25 @@ __initcall(kallsyms_init); EXPORT_SYMBOL(__print_symbol); + +#ifdef CONFIG_KDB +#include +#include + +const char *kdb_walk_kallsyms(loff_t *pos) +{ + static struct kallsym_iter kdb_walk_kallsyms_iter; + if (*pos == 0) { + memset(&kdb_walk_kallsyms_iter, 0, sizeof(kdb_walk_kallsyms_iter)); + reset_iter(&kdb_walk_kallsyms_iter, 0); + } + while (1) { + if (!update_iter(&kdb_walk_kallsyms_iter, *pos)) + return NULL; + ++*pos; + /* Some debugging symbols have no name. Ignore them. */ + if (kdb_walk_kallsyms_iter.name[0]) + return kdb_walk_kallsyms_iter.name; + } +} +#endif /* CONFIG_KDB */ Index: 2.6.x-xfs/mm/hugetlb.c =================================================================== --- 2.6.x-xfs.orig/mm/hugetlb.c 2006-02-20 11:15:25.710529735 +1100 +++ 2.6.x-xfs/mm/hugetlb.c 2006-02-28 11:26:53.552864201 +1100 @@ -240,6 +240,23 @@ nid, free_huge_pages_node[nid]); } +#ifdef CONFIG_KDB +#include +#include +/* Like hugetlb_report_meminfo() but using kdb_printf() */ +void +kdb_hugetlb_report_meminfo(void) +{ + kdb_printf( + "HugePages_Total: %5lu\n" + "HugePages_Free: %5lu\n" + "Hugepagesize: %5lu kB\n", + nr_huge_pages, + free_huge_pages, + HPAGE_SIZE/1024); +} +#endif /* CONFIG_KDB */ + int is_hugepage_mem_enough(size_t size) { return (size + ~HPAGE_MASK)/HPAGE_SIZE <= free_huge_pages; Index: 2.6.x-xfs/mm/swapfile.c =================================================================== --- 2.6.x-xfs.orig/mm/swapfile.c 2006-02-06 11:08:09.992209818 +1100 +++ 2.6.x-xfs/mm/swapfile.c 2006-02-28 11:26:53.553840631 +1100 @@ -14,6 +14,10 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#include +#endif /* CONFIG_KDB */ #include #include #include @@ -1636,6 +1640,24 @@ spin_unlock(&swap_lock); } +#ifdef CONFIG_KDB +/* Like si_swapinfo() but without the locks */ +void kdb_si_swapinfo(struct sysinfo *val) +{ + unsigned int i; + unsigned long nr_to_be_unused = 0; + + for (i = 0; i < nr_swapfiles; i++) { + if (!(swap_info[i].flags & SWP_USED) || + (swap_info[i].flags & SWP_WRITEOK)) + continue; + nr_to_be_unused += swap_info[i].inuse_pages; + } + val->freeswap = nr_swap_pages + nr_to_be_unused; + val->totalswap = total_swap_pages + nr_to_be_unused; +} +#endif /* CONFIG_KDB */ + /* * Verify that a swap entry is valid and increment its swap map count. * %diffstat Documentation/kdb/kdb.mm | 492 +++++ Documentation/kdb/kdb_bp.man | 197 ++ Documentation/kdb/kdb_bt.man | 223 ++ Documentation/kdb/kdb_env.man | 46 Documentation/kdb/kdb_ll.man | 134 + Documentation/kdb/kdb_md.man | 136 + Documentation/kdb/kdb_ps.man | 96 + Documentation/kdb/kdb_rd.man | 170 + Documentation/kdb/kdb_sr.man | 68 Documentation/kdb/kdb_ss.man | 109 + Documentation/kdb/slides | 1382 ++++++++++++++ Makefile | 1 drivers/char/keyboard.c | 10 drivers/serial/8250.c | 49 drivers/serial/8250_early.c | 32 drivers/serial/sn_console.c | 73 drivers/usb/host/ohci-hcd.c | 48 drivers/usb/host/ohci-pci.c | 9 drivers/usb/host/ohci-q.c | 62 drivers/usb/input/hid-core.c | 19 drivers/usb/input/usbkbd.c | 16 fs/proc/mmu.c | 10 fs/proc/proc_misc.c | 100 + include/linux/console.h | 5 include/linux/dis-asm.h | 316 +++ include/linux/kdb.h | 170 + include/linux/kdbprivate.h | 506 +++++ include/linux/sysctl.h | 1 init/main.c | 32 kdb/ChangeLog | 1338 ++++++++++++++ kdb/Makefile | 28 kdb/kdb_bp.c | 623 ++++++ kdb/kdb_bt.c | 182 + kdb/kdb_cmds | 32 kdb/kdb_id.c | 239 ++ kdb/kdb_io.c | 649 ++++++ kdb/kdbmain.c | 4013 ++++++++++++++++++++++++++++++++++++++++++ kdb/kdbsupport.c | 1285 +++++++++++++ kdb/modules/Makefile | 16 kdb/modules/kdbm_pg.c | 658 ++++++ kdb/modules/kdbm_sched.c | 58 kdb/modules/kdbm_task.c | 179 + kdb/modules/kdbm_vm.c | 845 ++++++++ kdb/modules/kdbm_xpc.c | 1111 +++++++++++ kernel/exit.c | 3 kernel/kallsyms.c | 22 kernel/module.c | 16 kernel/printk.c | 14 kernel/sched.c | 79 kernel/signal.c | 49 mm/hugetlb.c | 17 mm/swapfile.c | 22 52 files changed, 15986 insertions(+), 4 deletions(-)