%patch Index: 2.4.x-xfs/Documentation/Configure.help =================================================================== --- 2.4.x-xfs.orig/Documentation/Configure.help Mon Nov 22 12:29:59 2004 +++ 2.4.x-xfs/Documentation/Configure.help Mon Nov 22 12:30:27 2004 @@ -22366,6 +22366,90 @@ keys are documented in . Don't say Y unless you really know what this hack does. +Kernel Debugging support +CONFIG_KDB + This option provides a built-in kernel debugger. The built-in + kernel debugger contains commands which allow memory to be examined, + instructions to be disassembled and breakpoints to be set. For details, + see Documentation/kdb/kdb.mm and the manual pages kdb_bt, kdb_ss, etc. + Kdb can also be used via the serial port. Set up the system to + have a serial console (see Documentation/serial-console.txt). + The Control-A key sequence on the serial port will cause the + kernel debugger to be entered with input from the serial port and + output to the serial console. Selecting this option will + automatically set CONFIG_KALLSYMS. If unsure, say N. + +KDB modules +CONFIG_KDB_MODULES + KDB can be extended by adding your own modules, in directory + kdb/modules. This option selects the way that these modules should + be compiled, as free standing modules (select M) or built into the + kernel (select Y). If unsure say M. + +KDB off by default +CONFIG_KDB_OFF + Normally kdb is activated by default, as long as CONFIG_KDB is set. + If you want to ship a kernel with kdb support but only have kdb + turned on when the user requests it then select this option. When + compiled with CONFIG_KDB_OFF, kdb ignores all events unless you boot + with kdb=on or you echo "1" > /proc/sys/kernel/kdb. This option also + works in reverse, if kdb is normally activated, you can boot with + kdb=off or echo "0" > /proc/sys/kernel/kdb to deactivate kdb. If + unsure, say N. + +KDB continues after catastrophic errors +CONFIG_KDB_CONTINUE_CATASTROPHIC + This integer controls the behaviour of kdb when the kernel gets a + catastrophic error, i.e. for a panic, oops, NMI or other watchdog + tripping. CONFIG_KDB_CONTINUE_CATASTROPHIC interacts with + /proc/sys/kernel/kdb and CONFIG_DUMP (if your kernel has the LKCD + patch). + + When KDB is active (/proc/sys/kernel/kdb == 1) and a catastrophic + error occurs, nothing extra happens until you type 'go'. + + CONFIG_KDB_CONTINUE_CATASTROPHIC == 0 (default). The first time + you type 'go', kdb warns you. The second time you type 'go', KDB + tries to continue - no guarantees that the kernel is still usable. + + CONFIG_KDB_CONTINUE_CATASTROPHIC == 1. KDB tries to continue - no + guarantees that the kernel is still usable. + + CONFIG_KDB_CONTINUE_CATASTROPHIC == 2. If your kernel has the LKCD + patch and LKCD is configured to take a dump then KDB forces a dump. + Whether or not a dump is taken, KDB forces a reboot. + + When KDB is not active (/proc/sys/kernel/kdb == 0) and a catastrophic + error occurs, the following steps are automatic, no human + intervention is required. + + CONFIG_KDB_CONTINUE_CATASTROPHIC == 0 (default) or 1. KDB attempts + to continue - no guarantees that the kernel is still usable. + + CONFIG_KDB_CONTINUE_CATASTROPHIC == 2. If your kernel has the LKCD + patch and LKCD is configured to take a dump then KDB automatically + forces a dump. Whether or not a dump is taken, KDB forces a + reboot. + + If you are not sure, say 0. Read Documentation/kdb/dump.txt before + setting to 2. + +Support for USB Keyboard in KDB +CONFIG_KDB_USB + If you want to use kdb from a USB keyboard then say Y here. If you + say N then kdb can only be used from a PC (AT) keyboard or a serial + console. + +Load all symbols for debugging +CONFIG_KALLSYMS + Normally only exported symbols are available to modules. For + debugging you may want all symbols, not just the exported ones. If + you say Y here then extra data is added to the kernel and modules, + this data lists all the non-stack symbols in the kernel or module + and can be used by any debugger. You need modutils >= 2.3.11 to use + this option. See "man kallsyms" for the data format, it adds 10-20% + to the size of the kernel and the loaded modules. If unsure, say N. + ISDN support CONFIG_ISDN ISDN ("Integrated Services Digital Networks", called RNIS in France) Index: 2.4.x-xfs/Documentation/kdb/dump.txt =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/dump.txt Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/dump.txt Mon Nov 22 12:30:27 2004 @@ -0,0 +1,364 @@ +Interaction between KDB and LKCD. + +Executive summary: Do not select CONFIG_KDB_CONTINUE_CATASTROPHIC=2 or +use KDB command 'sr c' without first patching LKCD to use KDB data. + +Both KDB and LKCD try to stop all the other cpus, so the system is not +changing while it is being debugged or dumped. KDB will cope with cpus +that cannot be stopped, some versions of LKCD will just hang. In +particular, when LKCD is invoked from KDB, LKCD will attempt to stop +the other cpus again and may hang. + +Some versions of LKCD detect that other cpus are not responding and +ignore them. This is almost as bad, the data is changing while it is +being dumped. Also the method used to avoid hung cpus has been known +to cause oops when LKCD has finished dumping. + +LKCD does not know about several special cases on IA64, including INIT +and MCA backtraces, interrupt handlers, out of line code etc. LKCD +cannot capture cpu state on any cpu that is not responding to OS +interrupts, which means that any cpu that is spinning in a disabled +loop cannot be debugged. Any cpu that calls into SAL for MCA +rendezvous cannot be debugged. Even when LKCD captures IA64 state, the +user space lcrash code cannot unwind through any assembler code, which +rules out all the interesting cases. + +KDB knows far more than LKCD about architecture peculiarities, stack +formats, interrupt handling etc. The methods used by KDB to stop the +other processors and capture their state are far more reliable than +those used by LKCD. KDB can capture INIT and MCA data on IA64, as well +as save the state of cpus before they enter SAL. + +Rather than duplicating the complex KDB code in LKCD, LKCD can be +patched to use the information that has already been captured by KDB. +Obviously this only works when LKCD is invoked from KDB. If you invoke +LKCD directly from the console with SysRq-c or the dump() function is +called from code outside KDB then you get the old and broken LKCD +processing. Because lcrash uses the old unwind algorithm which cannot +unwind through IA64 assembler code, KDB kludges the saved state into +something that the old unwind algorithm can cope with. Calling LKCD +from KDB gives you a clean dump, but you have to patch LKCD first. + +There are two ways to invoke LKCD from KDB. One way is manual, using +the KDB 'sr c' command. This is identical to doing SysRq-C from the +console except that it goes through KDB first, so LKCD can use the data +that KDB has captured. Obviously 'sr c' requires human intervention +and KDB must be on, it is up to the person doing the debugging if they +want to take a dump. + +The second way is to set CONFIG_KDB_CONTINUE_CATASTROPHIC=2. With this +setting, you automatically get a dump for catastrophic errors. A +catastrophic error is a panic, oops, NMI or other watchdog tripping, +INIT and MCA events on IA64. CONFIG_KDB_CONTINUE_CATASTROPHIC=2 has no +effect on debugging events such as break points, single step etc. so it +does not interfere with manual debugging. + +When CONFIG_KDB_CONTINUE_CATASTROPHIC=2 and KDB is on, a catastrophic +error will drop into KDB to allow manual debugging, typing 'go' will +take a dump and force a reboot. With this setting and KDB is off, KDB +detects a catastrophic error, does enough processing to capture the +state, takes a dump and forces a reboot - all automatic with no human +intervention. + +For unattended and clean LKCD dumps, patch LKCD to use KDB data. Use + CONFIG_DUMP=y + CONFIG_KDB=y + CONFIG_KDB_OFF=y + CONFIG_KDB_CONTINUE_CATASTROPHIC=2 + +If you want human intervention before taking a dump, use + CONFIG_DUMP=y + CONFIG_KDB=y + CONFIG_KDB_OFF=n + CONFIG_KDB_CONTINUE_CATASTROPHIC=2 + + +The following are indicative patches against lkcd 4.1, kernel 2.4.20. +You may have to to modify the patches for other kernels or other +versions of lkcd. + +diff -urp lkcd/drivers/dump/dump_base.c lkcd/drivers/dump/dump_base.c +--- lkcd/drivers/dump/dump_base.c Thu May 1 13:10:12 2003 ++++ lkcd/drivers/dump/dump_base.c Fri Jun 20 12:28:16 2003 +@@ -207,6 +207,9 @@ + #include + #include + #include ++#ifdef CONFIG_KDB ++#include ++#endif + + /* + * ----------------------------------------------------------------------- +@@ -852,6 +855,13 @@ dump_silence_system(void) + unsigned int stage = 0; + int cpu = smp_processor_id(); + ++#ifdef CONFIG_KDB ++ if (KDB_IS_RUNNING()) { ++ /* kdb is in control, the system is already silenced */ ++ printk(KERN_ALERT "LKCD entered from KDB\n"); ++ } ++#endif /* CONFIG_KDB */ ++ + if (in_interrupt()) { + printk(KERN_ALERT "Dumping from interrupt handler !\n"); + printk(KERN_ALERT "Uncertain scenario - but will try my best\n"); +@@ -861,6 +871,9 @@ dump_silence_system(void) + * another approach + */ + } + /* see if there's something to do before we re-enable interrupts */ ++#ifdef CONFIG_KDB ++ if (!KDB_IS_RUNNING()) ++#endif /* CONFIG_KDB */ + (void)__dump_silence_system(stage); + +@@ -905,6 +918,9 @@ dump_silence_system(void) + + /* now increment the stage and do stuff after interrupts are enabled */ + stage++; ++#ifdef CONFIG_KDB ++ if (!KDB_IS_RUNNING()) ++#endif /* CONFIG_KDB */ + (void)__dump_silence_system(stage); + + /* time to leave */ +diff -urp lkcd/drivers/dump/dump_i386.c lkcd/drivers/dump/dump_i386.c +--- lkcd/drivers/dump/dump_i386.c Tue Jul 9 07:14:11 2002 ++++ lkcd/drivers/dump/dump_i386.c Fri Jun 20 12:29:12 2003 +@@ -27,6 +27,10 @@ + #include + #include + #include ++#ifdef CONFIG_KDB ++#include ++#include ++#endif /* CONFIG_KDB */ + + static int alloc_dha_stack(void) + { +@@ -119,6 +123,31 @@ save_other_cpu_states(void) + { + int i; + ++#ifdef CONFIG_KDB ++ if (KDB_IS_RUNNING()) { ++ /* invoked from kdb, which has already saved all the state */ ++ int cpu; ++ struct kdb_running_process *krp; ++ for (cpu = 0, krp = kdb_running_process; cpu < smp_num_cpus; ++cpu, ++krp) { ++ if (krp->seqno < kdb_seqno - 1 || ++ !krp->regs || ++ !krp->p || ++ kdb_process_cpu(krp->p) != cpu) { ++ printk(KERN_WARNING "No KDB data for cpu %d, it will not be in the LKCD dump\n", cpu); ++ continue; ++ } ++ if (cpu == smp_processor_id()) ++ continue; /* dumped by save_this_cpu_state */ ++ // kdb_printf("%s: cpu %d task %p regs %p\n", __FUNCTION__, cpu, krp->p, krp->regs); ++ save_this_cpu_state(cpu, krp->regs, krp->p); ++ } ++ return; ++ } ++ printk(KERN_WARNING "This kernel supports KDB but LKCD was invoked directly, not via KDB.\n"); ++ printk(KERN_WARNING "Falling back to the old and broken LKCD method of getting data from all cpus,\n"); ++ printk(KERN_WARNING "do not be surprised if LKCD hangs.\n"); ++#endif /* CONFIG_KDB */ ++ + if (smp_num_cpus > 1) { + atomic_set(&waiting_for_dump_ipi, smp_num_cpus-1); + for (i = 0; i < NR_CPUS; i++) +diff -urp lkcd/drivers/dump/dump_ia64.c lkcd/drivers/dump/dump_ia64.c +--- lkcd/drivers/dump/dump_ia64.c Tue Jul 9 07:14:11 2002 ++++ lkcd/drivers/dump/dump_ia64.c Fri Jun 20 12:31:41 2003 +@@ -30,6 +30,10 @@ + #include + #include + #include ++#ifdef CONFIG_KDB ++#include ++#include ++#endif /* CONFIG_KDB */ + + extern unsigned long irq_affinity[]; + +@@ -75,6 +79,12 @@ save_this_cpu_state(int cpu, struct pt_r + + if (tsk && dump_header_asm.dha_stack[cpu]) { + memcpy((void*)dump_header_asm.dha_stack[cpu], tsk, THREAD_SIZE); ++#ifdef CONFIG_KDB ++ if (KDB_IS_RUNNING()) { ++ static void kludge_for_broken_lcrash(int); ++ kludge_for_broken_lcrash(cpu); ++ } ++#endif /* CONFIG_KDB */ + } + return; + } +@@ -107,6 +117,32 @@ save_other_cpu_states(void) + { + int i; + ++#ifdef CONFIG_KDB ++ if (KDB_IS_RUNNING()) { ++ /* invoked from kdb, which has already saved all the state */ ++ int cpu; ++ struct kdb_running_process *krp; ++ for (cpu = 0, krp = kdb_running_process; cpu < smp_num_cpus; ++cpu, ++krp) { ++ if (krp->seqno < kdb_seqno - 1 || ++ !krp->regs || ++ !krp->arch.sw || ++ !krp->p || ++ kdb_process_cpu(krp->p) != cpu) { ++ printk(KERN_WARNING "No KDB data for cpu %d, it will not be in the LKCD dump\n", cpu); ++ continue; ++ } ++ if (cpu == smp_processor_id()) ++ continue; /* dumped by save_this_cpu_state */ ++ // kdb_printf("%s: cpu %d task %p regs %p\n", __FUNCTION__, cpu, krp->p, krp->regs); ++ save_this_cpu_state(cpu, krp->regs, krp->p); ++ } ++ return; ++ } ++ printk(KERN_WARNING "This kernel supports KDB but LKCD was invoked directly, not via KDB.\n"); ++ printk(KERN_WARNING "Falling back to the old and broken LKCD method of getting data from all cpus,\n"); ++ printk(KERN_WARNING "do not be surprised if LKCD hangs.\n"); ++#endif /* CONFIG_KDB */ ++ + if (smp_num_cpus > 1) { + atomic_set(&waiting_for_dump_ipi, smp_num_cpus-1); + for (i = 0; i < NR_CPUS; i++) +@@ -380,3 +416,131 @@ void * __dump_memcpy(void * dest, const + } + return(vp); + } ++ ++#ifdef CONFIG_KDB ++/* ++ * lcrash is broken. It incorrectly assumes that all tasks are blocked, it ++ * assumes that all code is built by gcc (and therefore it cannot unwind through ++ * assembler code), it assumes that there is only one pt_regs at the base of the ++ * stack (where user space entered the kernel). Dumping from kdb (or any ++ * interrupt context) breaks all those assumptions, resulting in a good dump ++ * that lcrash cannot get any useful backtraces from. ++ * ++ * The real fix is to correct lcrash, using libunwind. That is not going to ++ * happen any time soon, so this kludge takes the kdb data and reformats it to ++ * suit the broken lcrash code. The task state is unwound past the interrupt ++ * frame (pt_regs) before kdb, then a switch_stack is synthesized in place of ++ * the pt_regs, using the unwound data. ksp is changed to point to this ++ * switch_stack, making it look like the task is blocked with no interrupt. ++ * ++ * This will not work when the interrupt occurred in a leaf function, with no ++ * save of b0. But the old unwind code in lcrash cannot cope with that either, ++ * so no change. ++ */ ++ ++static inline void * ++kludge_copy_addr(int cpu, void *addr, struct task_struct *p) ++{ ++ return (char *)addr - (char *)p + (char *)(dump_header_asm.dha_stack[cpu]); ++} ++ ++static void ++kludge_for_broken_lcrash(int cpu) ++{ ++ struct kdb_running_process *krp = kdb_running_process + cpu; ++ struct task_struct *p, *p_copy; ++ struct switch_stack *sw, *sw_copy, *sw_new; ++ struct pt_regs *regs; ++ struct unw_frame_info info; ++ kdb_symtab_t symtab; ++ kdb_machreg_t sp; ++ int count, i; ++ char nat; ++ ++ if (krp->seqno < kdb_seqno - 1 || ++ !krp->regs || ++ user_mode(krp->regs) || ++ !krp->arch.sw || ++ !krp->p || ++ kdb_process_cpu(krp->p) != cpu) ++ return; ++ p = krp->p; ++ regs = krp->regs; ++ sw = krp->arch.sw; ++#if 0 ++ { ++ char buf[80]; ++ sprintf(buf, "btc %d\n", cpu); ++ kdb_parse(buf, regs); ++ } ++#endif ++ ++ unw_init_frame_info(&info, p, sw); ++ count = 0; ++ do { ++ unw_get_sp(&info, &sp); ++ // kdb_printf("sp 0x%lx regs 0x%lx\n", sp, regs); ++ } while (sp < (kdb_machreg_t)regs && unw_unwind(&info) >= 0 && count++ < 200); ++ if (count >= 200) { ++ printk(KERN_WARNING "Unwind for process %d on cpu %d looped\n", p->pid, cpu); ++ return; ++ } ++ ++ /* Must not touch the real stack data, kludge the data using the copies ++ * in dump_header_asm. ++ */ ++ p_copy = kludge_copy_addr(cpu, p, p); ++ sw_new = (struct switch_stack *)((u64)(regs + 1) + 16) - 1; ++ sw_copy = kludge_copy_addr(cpu, sw_new, p); ++ // kdb_printf("p_copy 0x%p sw_new 0x%p sw_copy 0x%p\n", p_copy, sw_new, sw_copy); ++ memset(sw_copy, 0, sizeof(*sw_copy)); ++ ++ sw_copy->caller_unat = sw->caller_unat; ++ unw_access_ar(&info, UNW_AR_FPSR, &sw_copy->ar_fpsr, 0); ++ for (i = 2; i <= 5; ++i) ++ unw_access_fr(&info, i, &sw_copy->f2 + i - 2, 0); ++ for (i = 10; i <= 31; ++i) ++ unw_access_fr(&info, i, &sw_copy->f10 + i - 10, 0); ++ for (i = 4; i <= 7; ++i) ++ unw_access_gr(&info, i, &sw_copy->r4 + i - 4, &nat, 0); ++ for (i = 0; i <= 5; ++i) ++ unw_access_br(&info, i, &sw_copy->b0 + i, 0); ++ sw_copy->ar_pfs = *info.cfm_loc; ++ unw_access_ar(&info, UNW_AR_LC, &sw_copy->ar_lc, 0); ++ unw_access_ar(&info, UNW_AR_UNAT, &sw_copy->ar_unat, 0); ++ unw_access_ar(&info, UNW_AR_RNAT, &sw_copy->ar_rnat, 0); ++ /* FIXME: unwind.c returns the original bspstore, not the value that ++ * matches the current unwind state. Calculate our own value for the ++ * modified bspstore. This should work but does not ++ * unw_access_ar(&info, UNW_AR_BSPSTORE, &sw_copy->ar_bspstore, 0); ++ */ ++ sw_copy->ar_bspstore = (unsigned long)ia64_rse_skip_regs((unsigned long *)info.bsp, (*info.cfm_loc >> 7) & 0x7f); ++ unw_access_pr(&info, &sw_copy->pr, 0); ++ ++ /* lcrash cannot unwind through the new spinlock contention code and it ++ * is too important a case to ignore. So the kludge extracts the ++ * calling IP before saving the data. ++ */ ++ if (kdbnearsym(regs->cr_iip, &symtab) && ++ strncmp(symtab.sym_name, "ia64_spinlock_contention", 24) == 0) ++ unw_get_rp(&info, &sw_copy->b0); ++ ++ p_copy->thread.ksp = (__u64)sw_new - 16; ++ dump_header_asm.dha_smp_regs[cpu] = *((struct pt_regs *)((unsigned long)p + THREAD_SIZE) - 1); ++#if 0 ++ { ++ /* debug. Destructive overwrite of task, then bt the result in kdb to ++ * validate the modified task. ++ */ ++ char buf[80]; ++ memcpy(p, p_copy, THREAD_SIZE); ++ krp->regs = NULL; ++ krp->arch.sw = sw_new; ++ sprintf(buf, "btc %d\n", cpu); ++ kdb_parse(buf, NULL); ++ while(1){}; ++ } ++#endif ++} ++ ++#endif /* CONFIG_KDB */ Index: 2.4.x-xfs/Documentation/kdb/kdb.mm =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/kdb.mm Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/kdb.mm Mon Nov 22 12:30:27 2004 @@ -0,0 +1,414 @@ +.TH KDB 8 "February 9, 2004" +.hy 0 +.SH NAME +Built-in Kernel Debugger for Linux - v4.3 +.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 still supported but +is deprecated. +.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 \fBControl-A\fP key sequence 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 consoel driver is still usable. +.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 +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. +.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 +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. +mdr Display raw memory contents +mds Display memory contents symbolically +mm Modify memory contents, words +mmW Modify memory contents, bytes +pid Change the default process context +ps Display process status +reboot Reboot the machine +rd Display register contents +rm Modify register contents +rmmod Remove a module +sections List information on all known sections +set Add/change environment variable +sr Invoke SysReq commands +ss Single step a cpu +ssb Single step a cpu until a branch instruction +.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. +.I cpu +followed by a number will switch to that cpu, you cannot switch to +a cpu marked '*'. +This command is only available if the kernel was configured for SMP. +.TP 8 +dmesg [lines] +Displays the last set of system messages from the kernel buffer. If +kdb logging is on, it is disabled by dmesg and is left as disabled. +If lines is specified, only dump the last 'lines' from the buffer, 0 +dumps all lines. +.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 +.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 +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 +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. +.TP 8 +ps +Display 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. +Without any parameters, \fBps\fP displays all processes. +If a parameter is specified, it is a single string consisting of the +letters D, R, S, T, Z and U, 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. +\fBps\ RD\fR displays only tasks that are running or are in an +uninterruptible sleep. +The states are\ :- +.P +.DS +.TS +box, center; +l | l +l | l. +D Uninterruptible sleep +R Running +S Interruptible sleep +T Traced or stopped +Z Zombie +U Unrunnable +.TE +.DE +.P +.TP 8 +reboot +Reboot the system, with no attempt to do a clean close down. +.TP 8 +rmmod +Internal command to remove a module. +This does not use any user space services, however it calls the module +cleanup routine and that routine may try to use kernel services. +Because kdb runs disabled there is no guarantee that the module cleanup +routine will succeed, there is a real risk of the routine hanging and +taking kdb with it. +Use the +.I rmmod +command with extreme care. +.TP 8 +sections +List information for all known sections. The output is one line per +module plus the kernel, starting with the module name. This is +followed by one or more repeats of section name, section start, +section end and section flags. This data is not designed for human +readability, it is intended to tell external debuggers where each +section has been loaded. +.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,rd,sr,ss}.man Index: 2.4.x-xfs/Documentation/kdb/kdb_bp.man =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/kdb_bp.man Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/kdb_bp.man Mon Nov 22 12:30:27 2004 @@ -0,0 +1,194 @@ +.TH BD 1 "1 June 2003" +.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. +.P +The +.B be +command will re-enable a disabled breakpoint. +.P +The +.B bc +command will clear a breakpoint from the breakpoint table. +.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.4.x-xfs/Documentation/kdb/kdb_bt.man =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/kdb_bt.man Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/kdb_bt.man Mon Nov 22 12:30:27 2004 @@ -0,0 +1,219 @@ +.TH BT 1 "20 July 2003" +.SH NAME +bt \- Stack Traceback command +.SH SYNOPSIS +bt [ ] +.LP +btp +.LP +btt +.LP +bta [ DRSTZU ] +.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). +.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. +.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 processes. +If a parameter is specified, it is a single string consisting of the +letters D, R, S, T, Z and U, in any order. +Each letter selects processes in a specific state, when multiple +letters are specified, a process will be traced if it is in any of the +specified states. +\fBbta\ RD\fR displays only tasks that are running or are in an +uninterruptible sleep. +The states are\ :- +.IP D 3 +Uninterruptible sleep. +.PD 0 +.IP R 3 +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. +.IP S 3 +Interruptible sleep. +.IP T 3 +Traced or stopped. +.IP Z 3 +Zombie. +.IP U 3 +Unrunnable. +.PD 1 +.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. +.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. +.IP * 3 +The start address of the section. +.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 +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. +.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. +.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. +.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.4.x-xfs/Documentation/kdb/kdb_env.man =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/kdb_env.man Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/kdb_env.man Mon Nov 22 12:30:27 2004 @@ -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.4.x-xfs/Documentation/kdb/kdb_ll.man =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/kdb_ll.man Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/kdb_ll.man Mon Nov 22 12:30:27 2004 @@ -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.4.x-xfs/Documentation/kdb/kdb_md.man =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/kdb_md.man Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/kdb_md.man Mon Nov 22 12:30:27 2004 @@ -0,0 +1,125 @@ +.TH MD 1 "25 September, 2001" +.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 +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 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 +If the \fBNOSECT\fP environment variable is non-zero then the +section information is suppressed. +.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.4.x-xfs/Documentation/kdb/kdb_rd.man =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/kdb_rd.man Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/kdb_rd.man Mon Nov 22 12:30:27 2004 @@ -0,0 +1,114 @@ +.TH RD 1 "1 June 2003" +.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. 'n' argumnet is only used for XScale platform to identify +the want 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 +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. + +.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.4.x-xfs/Documentation/kdb/kdb_sr.man =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/kdb_sr.man Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/kdb_sr.man Mon Nov 22 12:30:27 2004 @@ -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.4.x-xfs/Documentation/kdb/kdb_ss.man =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/kdb_ss.man Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/kdb_ss.man Mon Nov 22 12:30:27 2004 @@ -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.4.x-xfs/Documentation/kdb/slides =================================================================== --- 2.4.x-xfs.orig/Documentation/kdb/slides Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/Documentation/kdb/slides Mon Nov 22 12:30:27 2004 @@ -0,0 +1,1383 @@ +#! /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 + rmmod Remove a kernel module + 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.4.x-xfs/Makefile =================================================================== --- 2.4.x-xfs.orig/Makefile Mon Nov 22 12:29:59 2004 +++ 2.4.x-xfs/Makefile Mon Nov 22 12:30:27 2004 @@ -37,10 +37,12 @@ MAKEFILES = $(TOPDIR)/.config GENKSYMS = /sbin/genksyms DEPMOD = /sbin/depmod +KALLSYMS = /sbin/kallsyms MODFLAGS = -DMODULE CFLAGS_KERNEL = PERL = perl AWK = awk +TMPPREFIX = RPM := $(shell if [ -x "/usr/bin/rpmbuild" ]; then echo rpmbuild; \ else echo rpm; fi) @@ -130,6 +132,11 @@ LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib crypto +ifeq ($(CONFIG_KDB),y) +CORE_FILES += kdb/kdb.o +SUBDIRS += kdb +endif + DRIVERS-n := DRIVERS-y := DRIVERS-m := @@ -202,7 +209,7 @@ CLEAN_FILES = \ kernel/ksyms.lst include/linux/compile.h \ vmlinux System.map \ - .tmp* \ + $(TMPPREFIX).tmp* \ drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \ drivers/char/conmakehash \ drivers/char/drm/*-mod.c \ @@ -248,6 +255,7 @@ scripts/lxdialog/*.o scripts/lxdialog/lxdialog \ .menuconfig.log \ include/asm \ + kdb/gen-kdb_cmds.c \ .hdepend scripts/mkdep scripts/split-include scripts/docproc \ $(TOPDIR)/include/linux/modversions.h \ kernel.spec @@ -285,16 +293,42 @@ boot: vmlinux @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C arch/$(ARCH)/boot +LD_VMLINUX := $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \ + --start-group \ + $(CORE_FILES) \ + $(DRIVERS) \ + $(NETWORKS) \ + $(LIBS) \ + --end-group +ifeq ($(CONFIG_KALLSYMS),y) +LD_VMLINUX_KALLSYMS := $(TMPPREFIX).tmp_kallsyms3.o +else +LD_VMLINUX_KALLSYMS := +endif + vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o init/do_mounts.o linuxsubdirs - $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \ - --start-group \ - $(CORE_FILES) \ - $(DRIVERS) \ - $(NETWORKS) \ - $(LIBS) \ - --end-group \ - -o vmlinux + @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" kallsyms + +.PHONY: kallsyms + +kallsyms: +ifeq ($(CONFIG_KALLSYMS),y) + @echo kallsyms pass 1 + $(LD_VMLINUX) -o $(TMPPREFIX).tmp_vmlinux1 + @$(KALLSYMS) $(TMPPREFIX).tmp_vmlinux1 > $(TMPPREFIX).tmp_kallsyms1.o + @echo kallsyms pass 2 + @$(LD_VMLINUX) $(TMPPREFIX).tmp_kallsyms1.o -o $(TMPPREFIX).tmp_vmlinux2 + @$(KALLSYMS) $(TMPPREFIX).tmp_vmlinux2 > $(TMPPREFIX).tmp_kallsyms2.o + @echo kallsyms pass 3 + @$(LD_VMLINUX) $(TMPPREFIX).tmp_kallsyms2.o -o $(TMPPREFIX).tmp_vmlinux3 + @$(KALLSYMS) $(TMPPREFIX).tmp_vmlinux3 > $(TMPPREFIX).tmp_kallsyms3.o +endif + $(LD_VMLINUX) $(LD_VMLINUX_KALLSYMS) -o $(TMPPREFIX)vmlinux +ifneq ($(TMPPREFIX),) + mv $(TMPPREFIX)vmlinux vmlinux +endif $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map + @rm -f $(TMPPREFIX).tmp_vmlinux* $(TMPPREFIX).tmp_kallsyms* symlinks: rm -f include/asm Index: 2.4.x-xfs/drivers/char/keyboard.c =================================================================== --- 2.4.x-xfs.orig/drivers/char/keyboard.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/drivers/char/keyboard.c Mon Nov 22 12:30:27 2004 @@ -42,6 +42,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #define SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -263,6 +266,13 @@ } else rep = test_and_set_bit(keycode, key_down); +#ifdef CONFIG_KDB + if (!up_flag && (keycode == E1_PAUSE) && kdb_on) { + kdb(KDB_REASON_KEYBOARD, 0, kbd_pt_regs); + return; + } +#endif /* CONFIG_KDB */ + #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == SYSRQ_KEY) { sysrq_pressed = !up_flag; Index: 2.4.x-xfs/drivers/char/serial.c =================================================================== --- 2.4.x-xfs.orig/drivers/char/serial.c Mon Nov 22 12:30:00 2004 +++ 2.4.x-xfs/drivers/char/serial.c Mon Nov 22 12:30:27 2004 @@ -223,6 +223,21 @@ #include #endif +#ifdef CONFIG_KDB +#include +#ifdef CONFIG_SERIAL_CONSOLE +/* + * 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_SERIAL_CONSOLE */ +#endif /* CONFIG_KDB */ /* * All of the compatibilty code so we can compile serial.c against * older kernels is hidden in serial_compat.h @@ -588,6 +603,18 @@ } } ch = serial_inp(info, UART_RX); +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_KDB) + if ((info->line == kdb_serial_line) && kdb_on) { + 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_SERIAL_CONSOLE && CONFIG_KDB */ *tty->flip.char_buf_ptr = ch; icount->rx++; @@ -6020,6 +6047,30 @@ if (serial_in(info, UART_LSR) == 0xff) return -1; +#if defined(CONFIG_SERIAL_CONSOLE) && defined(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; + kdb_serial.io_type = info->io_type; + switch (info->io_type) { + case SERIAL_IO_MEM: +#ifdef SERIAL_IO_MEM32 + case SERIAL_IO_MEM32: +#endif + kdb_serial.iobase = (unsigned long)(info->iomem_base); + kdb_serial.ioreg_shift = info->iomem_reg_shift; + break; + default: + kdb_serial.iobase = state->port; + kdb_serial.ioreg_shift = 0; + break; + } + } +#endif /* CONFIG_SERIAL_CONSOLE && CONFIG_KDB */ + return 0; } Index: 2.4.x-xfs/drivers/char/sn_serial.c =================================================================== --- 2.4.x-xfs.orig/drivers/char/sn_serial.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/drivers/char/sn_serial.c Mon Nov 22 12:30:27 2004 @@ -52,6 +52,21 @@ #include #include +#ifdef CONFIG_KDB +#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 */ + #if defined(CONFIG_SGI_L1_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) static char sysrq_serial_str[] = "\eSYS"; static char *sysrq_serial_ptr = sysrq_serial_str; @@ -327,6 +342,23 @@ "obtaining data from the console (0x%0x)\n", ch); break; } +#ifdef CONFIG_KDB + if (kdb_on) { + if (ch == *kdb_serial_ptr) { + if (!(*++kdb_serial_ptr)) { + if (!regs) + KDB_ENTER(); /* to get some registers */ + else + kdb(KDB_REASON_KEYBOARD, 0, regs); + kdb_serial_ptr = (char *)kdb_serial_str; + break; + } + } + else + kdb_serial_ptr = (char *)kdb_serial_str; + } +#endif /* CONFIG_KDB */ + #if defined(CONFIG_SGI_L1_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) if (sysrq_requested) { unsigned long sysrq_timeout = sysrq_requested + HZ*5; @@ -1054,6 +1086,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; } @@ -1075,4 +1116,43 @@ } } + +#ifdef CONFIG_KDB +int +l1_control_in_polled(int offset) +{ + int sal_call_status = 0, input; + int ret = 0; + + if (IS_RUNNING_ON_SIMULATOR()) { + ret = readb((unsigned long)master_node_bedrock_address + (offset<< 3)); + return(ret); + } + 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 (IS_RUNNING_ON_SIMULATOR()) { + return readb((unsigned long)master_node_bedrock_address + (UART_RX<< 3)); + } + + if (!ia64_sn_console_getc(&ch)) + return ch; + else + return 0; +} +#endif /* CONFIG_KDB */ + #endif /* CONFIG_SGI_L1_SERIAL_CONSOLE */ Index: 2.4.x-xfs/drivers/sbus/char/sab82532.c =================================================================== --- 2.4.x-xfs.orig/drivers/sbus/char/sab82532.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/drivers/sbus/char/sab82532.c Mon Nov 22 12:30:27 2004 @@ -42,6 +42,18 @@ #include "sunserial.h" +#if defined(CONFIG_KDB) +#include +/* + * 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 const char *kdb_serial_ptr = kdb_serial_str; +#endif /* CONFIG_KDB */ + static DECLARE_TASK_QUEUE(tq_serial); /* This is (one of many) a special gross hack to allow SU and @@ -318,8 +330,12 @@ } static void receive_chars(struct sab82532 *info, - union sab82532_irq_status *stat) + union sab82532_irq_status *stat, + struct pt_regs *regs) { +#if defined(CONFIG_KDB) + int need_kdb = 0; +#endif struct tty_struct *tty = info->tty; unsigned char buf[32]; unsigned char status; @@ -373,6 +389,18 @@ break; } +#if defined(CONFIG_KDB) + if (info->is_console && kdb_on) { + if (buf[i] == *kdb_serial_ptr) { + if (!(*++kdb_serial_ptr)) { + need_kdb = 1; + kdb_serial_ptr = kdb_serial_str; + break; + } + } else + kdb_serial_ptr = kdb_serial_str; + } +#endif /* CONFIG_KDB */ tty->flip.count++; *tty->flip.char_buf_ptr++ = buf[i++]; status = buf[i++]; @@ -392,7 +420,10 @@ else *tty->flip.flag_buf_ptr++ = TTY_NORMAL; } - +#ifdef CONFIG_KDB + if (need_kdb) + kdb(KDB_REASON_KEYBOARD, 0, regs); +#endif queue_task(&tty->flip.tqueue, &tq_timer); } @@ -600,7 +631,7 @@ if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) - receive_chars(info, &status); + receive_chars(info, &status, regs); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC))) check_status(info, &status); @@ -625,7 +656,7 @@ if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) - receive_chars(info, &status); + receive_chars(info, &status, regs); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC))) check_status(info, &status); Index: 2.4.x-xfs/drivers/sbus/char/su.c =================================================================== --- 2.4.x-xfs.orig/drivers/sbus/char/su.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/drivers/sbus/char/su.c Mon Nov 22 12:30:27 2004 @@ -74,6 +74,20 @@ #endif #include +#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 */ + #include #include #include @@ -400,6 +414,18 @@ saw_console_brk = 1; if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; +#ifdef CONFIG_KDB + if ((info->line == kdb_serial_line) && kdb_on) { + 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 */ *tty->flip.char_buf_ptr = ch; icount->rx++; @@ -2972,6 +2998,16 @@ info->is_console = 1; +#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; } Index: 2.4.x-xfs/drivers/sbus/char/sunkbd.c =================================================================== --- 2.4.x-xfs.orig/drivers/sbus/char/sunkbd.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/drivers/sbus/char/sunkbd.c Mon Nov 22 12:30:27 2004 @@ -44,6 +44,10 @@ #include #endif +#ifdef CONFIG_KDB +#include +#endif + #include "sunkbd.h" #define SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -138,6 +142,9 @@ static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, +#ifdef CONFIG_KDB + call_kdb, +#endif SAK, decr_console, incr_console, spawn_console, bare_num; static void_fnp spec_fn_table[] = { @@ -145,7 +152,10 @@ show_state, send_intr, lastcons, caps_toggle, num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, SAK, - decr_console, incr_console, spawn_console, bare_num + decr_console, incr_console, spawn_console, bare_num, +#ifdef CONFIG_KDB + call_kdb +#endif }; /* maximum values each key_handler can handle */ @@ -813,6 +823,13 @@ { } +#ifdef CONFIG_KDB +static void call_kdb() +{ + kdb(KDB_REASON_KEYBOARD, 0, pt_regs); +} +#endif + static void do_null() { sun_compute_shiftstate(); Index: 2.4.x-xfs/drivers/sbus/char/sunkeymap.c =================================================================== --- 2.4.x-xfs.orig/drivers/sbus/char/sunkeymap.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/drivers/sbus/char/sunkeymap.c Mon Nov 22 12:30:27 2004 @@ -9,7 +9,13 @@ u_short plain_map[NR_KEYS] = { 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf100, 0xf101, 0xf109, 0xf102, 0xf10a, 0xf103, 0xf10b, 0xf104, 0xf701, 0xf105, 0xf200, - 0xf106, 0xf107, 0xf108, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf209, + 0xf106, 0xf107, 0xf108, 0xf703, 0xf603, +#ifdef CONFIG_KDB + /* Pause (keycode 0x15) triggers kdb */ 0xf214, +#else + 0xf11d, +#endif + 0xf200, 0xf209, 0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf060, 0xf07f, 0xf115, 0xf03d, 0xf30d, 0xf30c, Index: 2.4.x-xfs/drivers/usb/hid-core.c =================================================================== --- 2.4.x-xfs.orig/drivers/usb/hid-core.c Mon Nov 22 12:30:00 2004 +++ 2.4.x-xfs/drivers/usb/hid-core.c Mon Nov 22 12:30:27 2004 @@ -57,6 +57,29 @@ #define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik " #define DRIVER_DESC "USB HID support drivers" +#if defined(CONFIG_KDB_USB) +#include +extern struct kdb_usb_exchange kdb_usb_infos; +struct hid_device *hid_kbd = NULL; + +/* kdb_usb_hid_reset_timer + * This function reset the timer in the input_dev structure + * If you don't do that you'll be unable to exit KDB in the case + * you've entered by pressing the Pause key + */ +void hid_reset_timer(void) +{ + struct list_head *lh; + struct hid_input *hidinput; + + list_for_each (lh, &hid_kbd->inputs) { + hidinput = list_entry(lh, struct hid_input, list); + if(hidinput->input.timer.list.next) + list_del(&hidinput->input.timer.list); + } +} +#endif /* CONFIG_KDB_USB */ + static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; @@ -1415,7 +1438,16 @@ printk(": USB HID v%x.%02x %s [%s] on usb%d:%d.%d\n", hid->version >> 8, hid->version & 0xff, c, hid->name, dev->bus->busnum, dev->devnum, ifnum); - +#if defined(CONFIG_KDB_USB) + /* Initialisation of the KDB structure */ + if (!strcmp(c, "Keyboard")) { + hid_kbd = hid; + kdb_usb_infos.urb = &hid->urb; + kdb_usb_infos.buffer = &hid->buffer[0]; + kdb_usb_infos.reset_timer = hid_reset_timer; + kdb_usb_infos.driver = HID_ACTIVE; + } +#endif return hid; } Index: 2.4.x-xfs/drivers/usb/host/usb-uhci.c =================================================================== --- 2.4.x-xfs.orig/drivers/usb/host/usb-uhci.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/drivers/usb/host/usb-uhci.c Mon Nov 22 12:30:27 2004 @@ -40,7 +40,10 @@ #include #include #include - +#if defined(CONFIG_KDB_USB) +#include +extern struct kdb_usb_exchange kdb_usb_infos; +#endif /* This enables more detailed sanity checks in submit_iso */ //#define ISO_SANITY_CHECK @@ -2913,6 +2916,115 @@ } #endif +/* ------------------------------------------------------------------ */ +/* KDB part */ + +#if defined(CONFIG_KDB_USB) +/* +* The part of the code of UHCI controller that +* process the interrupt transfer +*/ + +void uhci_process_kdb_interrupt (uhci_t *s, struct urb *urb) +{ + int i; + urb_priv_t *urb_priv = urb->hcpriv; + struct list_head *p = urb_priv->desc_list.next; + uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list); + + int actual_length; + int status = 0; + + for (i = 0; p != &urb_priv->desc_list; p = p->next, i++) // Maybe we allow more than one TD later ;-) + { + desc = list_entry (p, uhci_desc_t, desc_list); + + if (is_td_active(desc)) { + // do not process active TDs + //dbg("TD ACT Status @%p %08x",desc,le32_to_cpu(desc->hw.td.status)); + break; + } + + if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) { + // do not process one-shot TDs, no recycling + break; + } + // extract transfer parameters from TD + + actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status)); + status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe)); + + // see if EP is stalled + if (status == -EPIPE) { + // set up stalled condition + usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); + } + + // if any error occurred: ignore this td, and continue + if (status != 0) { + //uhci_show_td (desc); + urb->error_count++; + goto recycle; + } + else + urb->actual_length = actual_length; + +recycle: + uhci_urb_dma_sync(s, urb, urb->hcpriv); + + if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) && + (urb->status != -ENOENT)) { + + urb->status = -EINPROGRESS; + + // Recycle INT-TD if interval!=0, else mark TD as one-shot + if (urb->interval) { + + desc->hw.td.info &= cpu_to_le32(~(1 << TD_TOKEN_TOGGLE)); + if (status==0) { + desc->hw.td.info |= cpu_to_le32((usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE)); + usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); + } else { + desc->hw.td.info |= cpu_to_le32((!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), + usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE)); + } + desc->hw.td.status= cpu_to_le32((urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC | + (urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27)); + mb(); + } else { + uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB); + // correct toggle after unlink + usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)); + clr_td_ioc(desc); // inactivate TD + } + } + } +} + +/* uhci_kdb_poll + * This function is a minimalist version of the + * controller interrupt handler + */ +void uhci_kdb_poll (void *__uhci, struct urb *urb) +{ + uhci_t *s = __uhci; + + if (!kdb_usb_infos.urb || !kdb_usb_infos.buffer || !kdb_usb_infos.reset_timer) + return; + + /* Reset input timer to be able to quit KDB */ + (*kdb_usb_infos.reset_timer)(); + + s->unlink_urb_done=0; + uhci_process_kdb_interrupt (s, urb); + + clean_descs(s, CLEAN_NOT_FORCED); + uhci_cleanup_unlink(s, CLEAN_NOT_FORCED); + uhci_switch_timer_int(s); +} +#endif +/*-------------------------------------------------------------------*/ _static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size) { uhci_t *s; @@ -2932,6 +3044,10 @@ return -1; memset (s, 0, sizeof (uhci_t)); +#if defined(CONFIG_KDB_USB) + kdb_usb_infos.uhci = (void *)s; + kdb_usb_infos.poll_func = uhci_kdb_poll; +#endif INIT_LIST_HEAD (&s->free_desc); INIT_LIST_HEAD (&s->urb_list); INIT_LIST_HEAD (&s->urb_unlinked); Index: 2.4.x-xfs/drivers/usb/usbkbd.c =================================================================== --- 2.4.x-xfs.orig/drivers/usb/usbkbd.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/drivers/usb/usbkbd.c Mon Nov 22 12:30:27 2004 @@ -77,6 +77,25 @@ int open; }; + +#if defined(CONFIG_KDB_USB) +#include +static struct usb_kbd *usb_kbd_ptr = NULL; +extern struct kdb_usb_exchange kdb_usb_infos; + +/* usb_kbd_reset_timer + * This function reset the timer in the input_dev structure + * If you don't do that you'll be unable to exit KDB in the case + * you've entered by pressing the Pause key + */ + +void usb_kbd_reset_timer(void) +{ + if(usb_kbd_ptr->dev.timer.list.next) + list_del(&usb_kbd_ptr->dev.timer.list); +} +#endif /* CONFIG_KDB_USB */ + static void usb_kbd_irq(struct urb *urb) { struct usb_kbd *kbd = urb->context; @@ -214,6 +233,14 @@ FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp, usb_kbd_irq, kbd, endpoint->bInterval); +#if defined(CONFIG_KDB_USB) + /* Init the KDB structure */ + usb_kbd_ptr = kbd; + kdb_usb_infos.urb = &kbd->irq; + kdb_usb_infos.buffer = &kbd->new[0]; + kdb_usb_infos.reset_timer = usb_kbd_reset_timer; + kdb_usb_infos.driver = HID_ACTIVE; +#endif /* CONFIG_KDB_USB */ kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; kbd->dr.bRequest = USB_REQ_SET_REPORT; Index: 2.4.x-xfs/include/linux/dis-asm.h =================================================================== --- 2.4.x-xfs.orig/include/linux/dis-asm.h Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/include/linux/dis-asm.h Mon Nov 22 12:30:27 2004 @@ -0,0 +1,307 @@ +/* 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; }) +#define xmalloc(size) ({ void *res = kmalloc(size, GFP_ATOMIC); if (!res) BUG(); res; }) +#define free(address) kfree(address) + +#include + +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.4.x-xfs/include/linux/kallsyms.h =================================================================== --- 2.4.x-xfs.orig/include/linux/kallsyms.h Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/include/linux/kallsyms.h Mon Nov 22 12:30:27 2004 @@ -0,0 +1,169 @@ +/* kallsyms headers + Copyright 2000 Keith Owens + + This file is part of the Linux modutils. It is exported to kernel + space so debuggers can access the kallsyms data. + + The kallsyms data contains all the non-stack symbols from a kernel + or a module. The kernel symbols are held between __start___kallsyms + and __stop___kallsyms. The symbols for a module are accessed via + the struct module chain which is based at module_list. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef MODUTILS_KALLSYMS_H +#define MODUTILS_KALLSYMS_H 1 + +/* Have to (re)define these ElfW entries here because external kallsyms + * code does not have access to modutils/include/obj.h. This code is + * included from user spaces tools (modutils) and kernel, they need + * different includes. + */ + +#ifndef ELFCLASS32 +#ifdef __KERNEL__ +#include +#else /* __KERNEL__ */ +#include +#endif /* __KERNEL__ */ +#endif /* ELFCLASS32 */ + +#ifndef ELFCLASSM +#define ELFCLASSM ELF_CLASS +#endif + +#ifndef ElfW +# if ELFCLASSM == ELFCLASS32 +# define ElfW(x) Elf32_ ## x +# define ELFW(x) ELF32_ ## x +# else +# define ElfW(x) Elf64_ ## x +# define ELFW(x) ELF64_ ## x +# endif +#endif + +/* Format of data in the kallsyms section. + * Most of the fields are small numbers but the total size and all + * offsets can be large so use the 32/64 bit types for these fields. + * + * Do not use sizeof() on these structures, modutils may be using extra + * fields. Instead use the size fields in the header to access the + * other bits of data. + */ + +struct kallsyms_header { + int size; /* Size of this header */ + ElfW(Word) total_size; /* Total size of kallsyms data */ + int sections; /* Number of section entries */ + ElfW(Off) section_off; /* Offset to first section entry */ + int section_size; /* Size of one section entry */ + int symbols; /* Number of symbol entries */ + ElfW(Off) symbol_off; /* Offset to first symbol entry */ + int symbol_size; /* Size of one symbol entry */ + ElfW(Off) string_off; /* Offset to first string */ + ElfW(Addr) start; /* Start address of first section */ + ElfW(Addr) end; /* End address of last section */ +}; + +struct kallsyms_section { + ElfW(Addr) start; /* Start address of section */ + ElfW(Word) size; /* Size of this section */ + ElfW(Off) name_off; /* Offset to section name */ + ElfW(Word) flags; /* Flags from section */ +}; + +struct kallsyms_symbol { + ElfW(Off) section_off; /* Offset to section that owns this symbol */ + ElfW(Addr) symbol_addr; /* Address of symbol */ + ElfW(Off) name_off; /* Offset to symbol name */ +}; + +#define KALLSYMS_SEC_NAME "__kallsyms" +#define KALLSYMS_IDX 2 /* obj_kallsyms creates kallsyms as section 2 */ + +#define kallsyms_next_sec(h,s) \ + ((s) = (struct kallsyms_section *)((char *)(s) + (h)->section_size)) +#define kallsyms_next_sym(h,s) \ + ((s) = (struct kallsyms_symbol *)((char *)(s) + (h)->symbol_size)) + +#ifdef CONFIG_KALLSYMS + +int kallsyms_symbol_to_address( + const char *name, /* Name to lookup */ + unsigned long *token, /* Which module to start with */ + const char **mod_name, /* Set to module name or "kernel" */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ); + +int kallsyms_address_to_symbol( + unsigned long address, /* Address to lookup */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ); + +int kallsyms_sections(void *token, + int (*callback)(void *, /* token */ + const char *, /* module name */ + const char *, /* section name */ + ElfW(Addr), /* Section start */ + ElfW(Addr), /* Section end */ + ElfW(Word) /* Section flags */ + ) + ); + +#else + +static inline int kallsyms_address_to_symbol( + unsigned long address, /* Address to lookup */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ) +{ + return -ESRCH; +} + +#endif + +int kallsyms_symbol_complete( + char *prefix_name /* Prefix of a symbol name to lookup */ + ); +int kallsyms_symbol_next( + char *prefix_name, /* Prefix of a symbol name to lookup */ + int flag /* Indicate if search from the head */ + ); + +#endif /* kallsyms.h */ Index: 2.4.x-xfs/include/linux/kdb.h =================================================================== --- 2.4.x-xfs.orig/include/linux/kdb.h Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/include/linux/kdb.h Mon Nov 22 12:30:27 2004 @@ -0,0 +1,339 @@ +#ifndef _KDB_H +#define _KDB_H + +/* + * Kernel Debugger Architecture Independent Global Headers + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * Copyright (C) 2000 Stephane Eranian + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include + +#define KDB_MAJOR_VERSION 4 +#define KDB_MINOR_VERSION 3 +#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 */ + + /* + * kdb_on + * + * Defines whether kdb is on or not. Default value + * is set by CONFIG_KDB_OFF. Boot with kdb=on/off + * or echo "[01]" > /proc/sys/kernel/kdb to change it. + */ +extern int kdb_on; + + /* Global 'enter the debugger' variable tested by scheduler, spinlocks + * etc., to handle problems when interrupts are not working or are not + * safe. + */ +extern volatile int kdb_enter_debugger; + +#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SGI_L1_SERIAL_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 */ + + /* + * 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 */ + +extern volatile int kdb_flags; /* Global flags, see kdb_state for per cpu state */ + +#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)) +#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) + + /* + * 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_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()) + + /* + * 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_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; + +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; + +#ifdef CONFIG_KDB +extern int kdb(kdb_reason_t, int, struct pt_regs *); +#else +#define kdb(reason,error_code,frame) (0) +#endif + +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; + + /* + * 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_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 void kdb_printf(const char *,...) + __attribute__ ((format (printf, 1, 2))); +extern void kdb_init(void); +extern void kdb_symbol_print(kdb_machreg_t, const kdb_symtab_t *, unsigned int); +extern char *kdb_read(char *buffer, size_t bufsize); +extern char *kdb_strdup(const char *str, int type); + +#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); + + /* + * Let other code know that kdb is in control. Routines registered + * on this list are called from the initial cpu with 1 when kdb is + * entered and 0 when kdb exits. + * + * WARNING: If a module registers itself on this list (or any notifier + * list) then there is a race condition. The module could be in the + * middle of removal on one cpu when it is called via the notifier + * chain on another cpu. It is the responsibility of the module to + * prevent this race. The safest way is for the module to define a + * 'can_unload' function which unregisters the module from all + * notifier chains before allowing the module to be unloaded. + */ + +extern struct notifier_block *kdb_notifier_list; + + /* + * 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); + +#ifdef CONFIG_KDB_USB +#include +#define KDB_USB_ACTIVE 1 /* Keyboard driver is usbkbd */ +#define HID_ACTIVE 2 /* Keyboard driver is hid */ + +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 */ + int driver; /* driver mode, see above KDB_USB_KBD */ +}; +extern struct kdb_usb_exchange kdb_usb_infos; /* KDB common structure */ +#endif /* CONFIG_KDB_USB */ + +#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__ ((unused,__section__ (".kdb_initcall.init"))) = fn; +#define kdb_module_exit(fn) \ + static exitcall_t __kdb_exitcall_##fn __attribute__ ((unused,__section__ (".kdb_exitcall.exit"))) = fn; +#endif /* MODULE */ + + +/* + * A backport of the 2.5 scheduler is used by many vendors of 2.4-based + * distributions. + * We can only guess its presence by the lack of the SCHED_YIELD flag. + * If the heuristic doesn't work, change this define by hand. + */ +#ifndef SCHED_YIELD +#define __KDB_HAVE_NEW_SCHEDULER 1 +#endif + +static inline +int kdb_process_cpu(const struct task_struct *p) +{ +#ifdef __KDB_HAVE_NEW_SCHEDULER + return p->cpu; /* p->cpu for O(1) scheduler */ +#else + return p->processor; /* p->processor for not O(1) scheduler */ +#endif +} + +extern struct task_struct *kdb_current_task; +extern struct page * kdb_follow_page(struct mm_struct *, unsigned long, int); /* from mm/memory.c */ + +extern const char kdb_serial_str[]; + +#endif /* !_KDB_H */ Index: 2.4.x-xfs/include/linux/kdbprivate.h =================================================================== --- 2.4.x-xfs.orig/include/linux/kdbprivate.h Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/include/linux/kdbprivate.h Mon Nov 22 12:30:27 2004 @@ -0,0 +1,380 @@ +#ifndef _KDBPRIVATE_H +#define _KDBPRIVATE_H + +/* + * Kernel Debugger Architecture Independent Private Headers + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include + +#include "bfd.h" + +/* + * 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) + + /* + * 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 void kdba_printbpreg(kdbhard_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. + */ + +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 *); + + /* + * Architecture specific Stack Traceback functions. + */ + +struct task_struct; + +extern int kdba_bt_address(kdb_machreg_t, int); +extern int kdba_bt_process(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_bp(int, const char **, const char **, struct pt_regs *); +extern int kdb_bc(int, const char **, const char **, struct pt_regs *); +extern int kdb_bt(int, const char **, const char **, struct pt_regs *); +extern int kdb_ss(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 int 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 void kdba_printaddress(kdb_machreg_t, disassemble_info *, int); +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(int argc, const char **argv, const char **envp); +extern unsigned long kdb_task_state(const struct task_struct *p, unsigned long mask); +extern void kdb_ps1(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); + + /* + * 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 */ + struct kdba_running_process arch; /* arch dependent save data */ +}; + +extern struct kdb_running_process kdb_running_process[/* NR_CPUS */]; +extern struct task_struct *kdb_active_task[/* NR_CPUS */]; + +extern void kdb_save_running(struct pt_regs *); +extern void kdb_unsave_running(struct pt_regs *); + +/* 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; + +/* Compatibility code until cpu_online() is in the standard kernel */ +#ifndef cpu_online +#ifdef CONFIG_SMP +#define cpu_online(cpu) test_bit(cpu, &cpu_online_map) +#else /* !SMP */ +#define cpu_online(cpu) ({ BUG_ON((cpu) != 0); 1; }) +#endif /* SMP */ +#endif /* cpu_online */ + +/* kdb needs to know if a task owns the cpu. Due to bugs in the scheduling code + * the initial tasks on each cpu do not decode correctly, uni-processor also has + * incorrect state for task_has_cpu. Use my own function to workaround the + * scheduler bugs. + */ + +#define kdb_task_has_cpu(p) (kdb_active_task[kdb_process_cpu(p)] == p) + +/* Simplify coexistence with NPTL */ +#ifdef do_each_thread +#define kdb_do_each_thread(g, p) do_each_thread(g, p) +#define kdb_while_each_thread(g, p) while_each_thread(g, p) +#else +#define kdb_do_each_thread(g, p) { (void)g; for_each_task(p) +#define kdb_while_each_thread(g, p) } +#endif + +#endif /* !_KDBPRIVATE_H */ Index: 2.4.x-xfs/include/linux/module.h =================================================================== --- 2.4.x-xfs.orig/include/linux/module.h Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/include/linux/module.h Mon Nov 22 12:30:27 2004 @@ -413,4 +413,29 @@ #define SET_MODULE_OWNER(some_struct) do { } while (0) #endif +extern void print_modules(void); + +#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS) + +extern struct module *module_list; + +/* + * print_symbols takes a format string containing one %s. + * If support for resolving symbols is compiled in, the %s will + * be replaced by the closest symbol to the address and the entire + * string is printk()ed. Otherwise, nothing is printed. + */ +extern void print_symbol(const char *fmt, unsigned long address); + +#else + +#include +static inline int +print_symbol(const char *fmt, unsigned long address) +{ + return -ESRCH; +} + +#endif + #endif /* _LINUX_MODULE_H */ Index: 2.4.x-xfs/include/linux/sysctl.h =================================================================== --- 2.4.x-xfs.orig/include/linux/sysctl.h Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/include/linux/sysctl.h Mon Nov 22 12:30:27 2004 @@ -124,6 +124,7 @@ KERN_CORE_USES_PID=52, /* int: use core or core.%pid */ KERN_TAINTED=53, /* int: various kernel tainted flags */ KERN_CADPID=54, /* int: PID of the process to notify on CAD */ + KERN_KDB=55, /* int: kdb on/off */ KERN_CORE_PATTERN=56, /* string: pattern for core-files */ KERN_PPC_L3CR=57, /* l3cr register on PPC */ KERN_EXCEPTION_TRACE=58, /* boolean: exception trace */ Index: 2.4.x-xfs/init/main.c =================================================================== --- 2.4.x-xfs.orig/init/main.c Mon Nov 22 12:30:00 2004 +++ 2.4.x-xfs/init/main.c Mon Nov 22 12:30:27 2004 @@ -74,6 +74,10 @@ #include #endif +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -261,6 +265,25 @@ } if (next != NULL) *next++ = 0; +#ifdef CONFIG_KDB + /* kdb=on, kdb=off, kdb=early */ + if (strncmp(line, "kdb=", 4) == 0) { + if (strcmp(line+4, "on") == 0) { + kdb_on = 1; + continue; + } + if (strcmp(line+4, "off") == 0) { + kdb_on = 0; + continue; + } + if (strcmp(line+4, "early") == 0) { + kdb_on = 1; + kdb_flags |= KDB_FLAG_EARLYKDB; + continue; + } + printk("Boot flag %s not recognised, assumed to be environment variable\n", line); + } +#endif /* CONFIG_KDB */ if (!strncmp(line,"init=",5)) { line += 5; execute_command = line; @@ -408,6 +431,13 @@ kmem_cache_sizes_init(); pgtable_cache_init(); +#ifdef CONFIG_KDB + kdb_init(); + if (KDB_FLAG(EARLYKDB)) { + KDB_ENTER(); + } +#endif /* CONFIG_KDB */ + /* * For architectures that have highmem, num_mappedpages represents * the amount of memory the kernel can use. For other architectures Index: 2.4.x-xfs/kdb/ChangeLog =================================================================== --- 2.4.x-xfs.orig/kdb/ChangeLog Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/ChangeLog Mon Nov 22 12:30:27 2004 @@ -0,0 +1,793 @@ +2004-03-24 Keith Owens + + * Sync with XFS 2.4.25. + * kdb v4.3-2.4.25-common-2. + +2004-02-19 Keith Owens + + * kdb v4.3-2.4.25-common-1. + +2004-02-11 Keith Owens + + * Convert longjmp buffers from static to dynamic allocation, for large + cpu counts. + * Tweak kdbm_task for SMP/UP. + * Update to 2.4.25-rc1. + * 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. + * kdb v4.3-2.4.25-rc1-common-1. + +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.4.x-xfs/kdb/Makefile =================================================================== --- 2.4.x-xfs.orig/kdb/Makefile Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/Makefile Mon Nov 22 12:30:27 2004 @@ -0,0 +1,53 @@ +# +# Copyright (c) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +O_TARGET := kdb.o +export-objs := kdbmain.o kdb_io.o +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 /vmlinux-obj.o, $(subdir-y)) + +override CFLAGS := $(CFLAGS:%-pg=% ) + +EXTRA_CFLAGS += -I $(TOPDIR)/arch/$(ARCH)/kdb + +include $(TOPDIR)/Rules.make + +gen-kdb_cmds.c: kdb_cmds Makefile + $(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};");}' \ + kdb_cmds > gen-kdb_cmds.c Index: 2.4.x-xfs/kdb/kdb_bp.c =================================================================== --- 2.4.x-xfs.orig/kdb/kdb_bp.c Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/kdb_bp.c Mon Nov 22 12:30:27 2004 @@ -0,0 +1,648 @@ +/* + * Kernel Debugger Architecture Independent Breakpoint Handler + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#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 + */ + +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] + * + * 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 + +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 " in enabled", + i, bp->bp_addr); + + kdb_printf("\n"); + break; + case KDBCMD_BD: + if (!bp->bp_enabled) { + return 0; + } + + /* + * 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. + */ + +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.4.x-xfs/kdb/kdb_bt.c =================================================================== --- 2.4.x-xfs.orig/kdb/kdb_bt.c Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/kdb_bt.c Mon Nov 22 12:30:27 2004 @@ -0,0 +1,196 @@ +/* + * Kernel Debugger Architecture Independent Stack Traceback + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#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 [DRSTZU] All 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(struct task_struct *p, unsigned long mask, int argcount, int btaprompt) +{ + int diag; + char buffer[2]; + 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, envp); + /* Run the active tasks first */ + for (cpu = 0; cpu < smp_num_cpus; ++cpu) { + p = kdb_active_task[cpu]; + if (kdb_bt1(p, mask, argcount, btaprompt)) + return 0; + } + /* Now the inactive tasks */ + kdb_do_each_thread(g, p) { + if (kdb_task_has_cpu(p) && kdb_active_task[kdb_process_cpu(p)] == 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))) + return kdb_bt1(p, ~0, 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; + return kdb_bt1((struct task_struct *)addr, ~0, argcount, 0); + } else if (strcmp(argv[0], "btc") == 0) { + unsigned long cpu = ~0; + struct kdb_running_process *krp; + 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 >= smp_num_cpus || !krp->seqno) { + 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 < smp_num_cpus; ++cpu, ++krp) { + if (!krp->seqno) + continue; + sprintf(buf, "btt 0x%p\n", krp->p); + kdb_parse(buf, regs); + touch_nmi_watchdog(); + } + 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(current, ~0, argcount, 0); + } + } + + /* NOTREACHED */ + return 0; +} Index: 2.4.x-xfs/kdb/kdb_cmds =================================================================== --- 2.4.x-xfs.orig/kdb/kdb_cmds Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/kdb_cmds Mon Nov 22 12:30:27 2004 @@ -0,0 +1,6 @@ +# 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. + Index: 2.4.x-xfs/kdb/kdb_id.c =================================================================== --- 2.4.x-xfs.orig/kdb/kdb_id.c Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/kdb_id.c Mon Nov 22 12:30:27 2004 @@ -0,0 +1,263 @@ +/* + * Kernel Debugger Architecture Independent Instruction Disassembly + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#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 + + +#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); + if (tab == 2) { + if((count=kallsyms_symbol_complete(p_tmp))>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(kallsyms_symbol_complete(p_tmp)>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 spinlock_t kdb_printf_lock = SPIN_LOCK_UNLOCKED; + + /* 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; + } + + 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 + 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, smp_processor_id()); + moreprompt = buf2; + } +#endif + + kdb_input_flush(); + c = console_drivers; +#ifdef CONFIG_SPARC64 + if (c == NULL) + prom_printf("%s", 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); + } + 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("kdb: Initialization failed - no console\n"); + while (1) {}; + } + kdb_input_flush(); +#endif + return; +} + +EXPORT_SYMBOL(kdb_read); Index: 2.4.x-xfs/kdb/kdbmain.c =================================================================== --- 2.4.x-xfs.orig/kdb/kdbmain.c Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/kdbmain.c Mon Nov 22 12:30:27 2004 @@ -0,0 +1,3665 @@ +/* + * Kernel Debugger Architecture Independent Main Code + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2000 Stephane Eranian + * Xscale (R) modifications copyright (C) 2003 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +/* + * 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 +#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE) +#include +#endif + +#include + +#if defined(CONFIG_MODULES) +extern struct module *module_list; +#endif + + /* + * Kernel debugger state flags + */ +volatile int kdb_flags; +volatile int kdb_enter_debugger; + + /* + * kdb_lock protects updates to kdb_initial_cpu. Used to + * single thread processors through the kernel debugger. + */ +spinlock_t kdb_lock = SPIN_LOCK_UNLOCKED; +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 */ +struct task_struct *kdb_active_task[NR_CPUS]; /* Task that is active on each cpu */ + +volatile int kdb_state[NR_CPUS]; /* Per cpu state */ + +struct task_struct *kdb_current_task; + +#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; +struct notifier_block *kdb_notifier_list; /* racy for modules, see comments in kdb.h */ +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", + (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[] = "\001"; + +/* + * 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 (char *)0; +} + +/* + * 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: + */ + +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: + */ + +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], 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_KERNEL); + 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_KERNEL); + 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 (argc != 3) + return KDB_ARGCOUNT; + if (defcmd_in_progress) { + kdb_printf("kdb: nested defcmd detected, assuming missing endefcmd\n"); + kdb_defcmd2("endefcmd", "endefcmd"); + } + defcmd_set = kmalloc((defcmd_set_count + 1) * sizeof(*defcmd_set), GFP_KERNEL); + 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_KERNEL); + s->usage = kdb_strdup(argv[2], GFP_KERNEL); + s->help = kdb_strdup(argv[3], GFP_KERNEL); + 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')) + 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_DUMP) || defined(CONFIG_DUMP_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. + */ + +int +kdb_reboot(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + machine_restart(0); + 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; + + kdb_go_count = 0; + if (reason != KDB_REASON_DEBUG && + reason != KDB_REASON_SILENT) { + kdb_printf("\nEntering kdb (current=0x%p, pid %d) ", (void *)current, 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) ", (void *)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. + */ + return KDB_CMD_SSB; /* Continue with SSB command */ + + break; + case KDB_DB_SS: + break; + case KDB_DB_SSBPT: + 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: + kdb_printf("due to KDB_ENTER()\n"); + break; + case KDB_REASON_KEYBOARD: + kdb_printf("due to Keyboard Entry\n"); + break; + case KDB_REASON_SWITCH: + kdb_printf("due to cpu switch\n"); + if (KDB_STATE(GO_SWITCH)) { + KDB_STATE_CLEAR(GO_SWITCH); + 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); + 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: + return KDB_CMD_GO; /* Silent entry, silent exit */ + break; + default: + kdb_printf("kdb: unexpected reason code: %d\n", reason); + return 0; /* Not for us, dismiss it */ + } + + kdba_local_arch_setup(); + + kdb_current_task = 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(); + + 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\n", + kdb_data, online); + prev_kdb_data = kdb_data; + } + touch_nmi_watchdog(); + mdelay(1000); + } + 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; + int wait_for_cpus = reason != KDB_REASON_SILENT; + /* 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' */ + + if (wait_for_cpus) { + wait_for_cpus = 0; + 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. + */ + +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 = 1; /* Default is kdb handled it */ + int ss_event; + kdb_dbtrap_t db_result=KDB_DB_NOBPT; + + 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)) + return 0; + + 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); + return 0; /* 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"); + return(0); + } + } + } else if (!KDB_IS_RUNNING()) { + kdb_printf("kdb: CPU switch without kdb running, I'm confused\n"); + return(0); + } + + /* + * 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. + */ + 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()) + ; + + spin_lock(&kdb_lock); + } + KDB_DEBUG_STATE("kdb 5", reason); + + kdb_initial_cpu = smp_processor_id(); + ++kdb_seqno; + spin_unlock(&kdb_lock); + notifier_call_chain(&kdb_notifier_list, 1, NULL); + } + + 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 (smp_num_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(reason, 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) + ; + notifier_call_chain(&kdb_notifier_list, 0, NULL); + 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(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); + 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: + */ + +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; + kdb_symtab_t symtab; + int symbolic = 0; + int valid = 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; + 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) { + int num = (symbolic?1 :(16 / bytesperword)); + char cbuf[32]; + char *c = cbuf; + int i; + + memset(cbuf, '\0', sizeof(cbuf)); + kdb_printf(kdb_machreg_fmt0 " ", addr); + + for(i = 0; i < num && repeat--; i++) { + if (kdb_getword(&word, addr, bytesperword)) + return 0; + + 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 = wc.c + 8 - bytesperword; + wc.word = cpu_to_be64(word); +#define printable_char(c) ({unsigned char __c = 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); + } + 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. + */ + +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: + */ + +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: + */ + +int +kdb_rd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + /* + */ + + if (argc == 0) { + return kdba_dumpregs(regs, NULL, NULL); + } + + if (argc > 2) { + return KDB_ARGCOUNT; + } + + return kdba_dumpregs(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). + */ + +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], 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. + */ +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, 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. + */ + +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 module *find_module(const char *); +extern void free_module(struct module *, int); + +/* + * 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: + * + */ + +int +kdb_lsmod(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct module *mod; + struct module_ref *mr; + + if (argc != 0) + return KDB_ARGCOUNT; + + kdb_printf("Module Size modstruct Used by\n"); + for (mod = module_list; mod && mod->next ;mod = mod->next) { + kdb_printf("%-20s%8lu 0x%p %4ld ", mod->name, mod->size, (void *)mod, + (long)atomic_read(&mod->uc.usecount)); + + if (mod->flags & MOD_DELETED) + kdb_printf(" (deleted)"); + else if (mod->flags & MOD_INITIALIZING) + kdb_printf(" (initializing)"); + else if (!(mod->flags & MOD_RUNNING)) + kdb_printf(" (uninitialized)"); + else { + if (mod->flags & MOD_AUTOCLEAN) + kdb_printf(" (autoclean)"); + if (!(mod->flags & MOD_USED_ONCE)) + kdb_printf(" (unused)"); + } + + if (mod->refs) { + kdb_printf(" [ "); + + mr = mod->refs; + while (mr) { + kdb_printf("%s ", mr->ref->name); + mr = mr->next_ref; + } + + kdb_printf("]"); + } + + kdb_printf("\n"); + } + + return 0; +} + +/* + * kdb_rmmod + * + * This function implements the 'rmmod' command. Removes a given + * kernel module. + * + * 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: + * Danger: free_module() calls mod->cleanup(). If the cleanup routine + * relies on interrupts then it will hang, kdb has interrupts disabled. + */ + +int +kdb_rmmod(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct module *mod; + + + if (argc != 1) + return KDB_ARGCOUNT; + + kdb_printf("Attempting to remove module: [%s]\n", argv[1]); + if ((mod = find_module(argv[1])) == NULL) { + kdb_printf("Unable to find a module by that name\n"); + return 0; + } + + if (mod->refs != NULL || __MOD_IN_USE(mod)) { + kdb_printf("Module is in use, unable to unload\n"); + return 0; + } + + free_module(mod, 0); + kdb_printf("Module successfully unloaded\n"); + + 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: + */ + +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] + * + * 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. + */ + +int +kdb_dmesg(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + char *syslog_data[4], *start, *end, c; + int diag, logging, logsize, lines = 0; + + if (argc > 1) + return KDB_ARGCOUNT; + if (argc) { + char *cp; + lines = simple_strtoul(argv[1], &cp, 0); + if (*cp || lines < 0) + lines = 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[0] + (syslog_data[2] - syslog_data[0]) % logsize; + end = syslog_data[0] + (syslog_data[3] - syslog_data[0]) % logsize; +#define KDB_WRAP(p) if (p < syslog_data[0]) p = syslog_data[1]-1; else if (p >= syslog_data[1]) p = syslog_data[0] + if (lines) { + char *p = end; + ++lines; + do { + --p; + KDB_WRAP(p); + if (*p == '\n') { + if (--lines == 0) { + ++p; + KDB_WRAP(p); + break; + } + } + } while (p != start); + start = p; + } + /* Do a line at a time (max 200 chars) to reduce protocol overhead */ + c = '\0'; + while(1) { + char *p; + int chars = 0; + if (!*start) { + while (!*start) { + ++start; + KDB_WRAP(start); + if (start == end) + break; + } + if (start == end) + break; + } + p = start; + while (*start && chars < 200) { + c = *start; + ++chars; + ++start; + KDB_WRAP(start); + if (start == end || c == '\n') + break; + } + if (chars) + kdb_printf("%.*s", chars, p); + if (start == end) + break; + } + 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. + */ + +int +kdb_cpu(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long cpunum; + int diag, first = 1, 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; +} + +/* + * kdb_ps + * + * This function implements the 'ps' command which shows + * a list of the active processes. + * + * ps [DRSTZU] 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(struct task_struct *p) +{ + kdb_printf("0x%p %8d %8d %d %4d %c 0x%p %c%s\n", + (void *)p, p->pid, p->p_pptr->pid, + kdb_task_has_cpu(p), kdb_process_cpu(p), + (p->state == 0) ? 'R' : + (p->state < 0) ? 'U' : + (p->state & TASK_UNINTERRUPTIBLE) ? 'D' : + (p->state & TASK_STOPPED || p->ptrace & PT_PTRACED) ? 'T' : + (p->state & TASK_ZOMBIE) ? 'Z' : + (p->state & TASK_INTERRUPTIBLE) ? 'S' : '?', + (void *)(&p->thread), + (p == current) ? '*': ' ', + p->comm); + if (kdb_task_has_cpu(p)) { + struct kdb_running_process *krp = kdb_running_process + kdb_process_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); + } + } +} + +int +kdb_ps(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct task_struct *g, *p; + unsigned long mask, cpu; + + 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, envp); + /* Run the active tasks first */ + for (cpu = 0; cpu < smp_num_cpus; ++cpu) { + p = kdb_active_task[cpu]; + if (!kdb_task_state(p, mask)) + continue; + kdb_ps1(p); + } + /* Now the real tasks */ + kdb_do_each_thread(g, p) { + if (!kdb_task_state(p, mask)) + continue; + 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 [] + * + * 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: + */ + + +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) { + 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; + } + + kdb_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: + */ + +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_KERNEL))) { + 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_sections_callback + * + * Invoked from kallsyms_sections for each section. + * + * Inputs: + * prevmod Previous module name + * modname Module name + * secname Section name + * secstart Start of section + * secend End of section + * secflags Section flags + * Outputs: + * None. + * Returns: + * Always zero + * Locking: + * none. + * Remarks: + */ + +static int +kdb_sections_callback(void *token, const char *modname, const char *secname, + ElfW(Addr) secstart, ElfW(Addr) secend, ElfW(Word) secflags) +{ + const char **prevmod = (const char **)token; + if (*prevmod != modname) { + *prevmod = modname; + kdb_printf("\n%s", modname); + } + kdb_printf(" %s " kdb_elfw_addr_fmt0 " " kdb_elfw_addr_fmt0 " 0x%x", + secname, secstart, secend, secflags); + return(0); +} + +/* + * kdb_sections + * + * This function implements the 'sections' command which prints the + * kernel and module sections. + * + * 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: + */ + +int +kdb_sections(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + char *prev_mod = NULL; + if (argc != 0) { + return KDB_ARGCOUNT; + } + kallsyms_sections(&prev_mod, kdb_sections_callback); + kdb_printf("\n"); /* End last module */ + 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: + */ + +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: + */ + +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; + } +#ifdef do_each_thread + p = p->group_leader; +#else /* !do_each_thread */ + /* In case the process is not a thread group leader, find the leader. */ + if (p->tgid != p->pid) { + struct task_struct *tg; + for_each_task(tg) { + if (tg->pid == p->tgid) { + p = tg; + break; + } + } + } +#endif /* do_each_thread */ + 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; +} + +/* + * 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_KERNEL); + 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("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, "[DRSTZU]", "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); + kdb_register_repeat("sections", kdb_sections, "", "List kernel and module sections", 0, KDB_REPEAT_NONE); +#if defined(CONFIG_MODULES) + kdb_register_repeat("lsmod", kdb_lsmod, "", "List loaded kernel modules", 0, KDB_REPEAT_NONE); + kdb_register_repeat("rmmod", kdb_rmmod, "", "Remove a kernel module", 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); + + /* 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) { + kdb_printf("kdb_cmd[%d]%s: %s", + i, defcmd_in_progress ? "[defcmd]" : "", 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 }; + +/* + * kdb_init + * + * Initialize the kernel debugger environment. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +void __init +kdb_init(void) +{ + /* + * 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 */ + 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(KDB_REASON_SILENT, 0, 0); /* Activate any preset breakpoints on boot cpu */ + 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 */ + +} + +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(kdb_getword); +EXPORT_SYMBOL(kdb_putword); +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(kdbgetsymval); +EXPORT_SYMBOL(kdbnearsym); +EXPORT_SYMBOL(kdb_printf); +EXPORT_SYMBOL(kdb_symbol_print); +EXPORT_SYMBOL(kdb_notifier_list); +EXPORT_SYMBOL(kdb_enter_debugger); +EXPORT_SYMBOL(kdb_current_task); +EXPORT_SYMBOL(kdba_dumpregs); Index: 2.4.x-xfs/kdb/kdbsupport.c =================================================================== --- 2.4.x-xfs.orig/kdb/kdbsupport.c Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/kdbsupport.c Mon Nov 22 12:30:27 2004 @@ -0,0 +1,863 @@ +/* + * Kernel Debugger Architecture Independent Support Functions + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * 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) +{ + memset(symtab, 0, sizeof(*symtab)); + return(kallsyms_symbol_to_address( + symname, + NULL, + &symtab->mod_name, + &symtab->mod_start, + &symtab->mod_end, + &symtab->sec_name, + &symtab->sec_start, + &symtab->sec_end, + &symtab->sym_name, + &symtab->sym_start, + &symtab->sym_end)); +} + +/* + * 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: + */ + +int +kdbnearsym(unsigned long addr, kdb_symtab_t *symtab) +{ + int ret; + memset(symtab, 0, sizeof(*symtab)); + ret = kallsyms_address_to_symbol( + addr, + &symtab->mod_name, + &symtab->mod_start, + &symtab->mod_end, + &symtab->sec_name, + &symtab->sec_start, + &symtab->sec_end, + &symtab->sym_name, + &symtab->sym_start, + &symtab->sym_end); + if (symtab->mod_name && *symtab->mod_name == '\0') + symtab->mod_name = "kernel"; + return ret; +} + +#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 */ + +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 - 4); + if (KDB_DEBUG(AR)) { + kdb_printf(" callee arg0=0x%lx args=%ld\n", + ar->arg0, ar->args); + } + } + } + } + + return(1); +} + +/* + * 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_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 DRSTZU to a mask for + * the process state field and return the value. If no argument is + * supplied, return ~0. + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * Outputs: + * none. + * Returns: + * Mask for process state. + * Locking: + * none. + */ + +#define UNRUNNABLE (1UL << (8*sizeof(unsigned long) - 1)) /* unrunnable is < 0 */ +#define RUNNING (1UL << (8*sizeof(unsigned long) - 2)) +#define TRACED (1UL << (8*sizeof(unsigned long) - 3)) + +unsigned long +kdb_task_state_string(int argc, const char **argv, const char **envp) +{ + long res = ~0; + if (argc >= 1) { + const char *s = argv[1]; + res = 0; + 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 | TRACED; break; + case 'Z': res |= TASK_ZOMBIE; break; + case 'U': res |= UNRUNNABLE; break; + default: + kdb_printf("kdb_task_state unknown flag '%c' ignored\n", *s); + break; + } + ++s; + } + } + return res; +} + +/* + * 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) +{ + return ((mask & p->state) || + (mask & RUNNING && p->state == 0) || + (mask & TRACED && p->ptrace & PT_PTRACED)); +} + +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; + 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(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. temporary restriction. */ + if ((start & PAGE_MASK) != ((start+len) & PAGE_MASK)) { + kdb_printf("%s: crosses page boundary: addr=%08lx, len=%d\n", + __FUNCTION__, start, len); + return NULL; + } + + /* we need to align start address to the current page boundary, PAGE_ALIGN + * aligns to next page boundary. + */ + 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 kdb_follow_page(mm, start, write); +} + +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; +} Index: 2.4.x-xfs/kdb/modules/Makefile =================================================================== --- 2.4.x-xfs.orig/kdb/modules/Makefile Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/modules/Makefile Mon Nov 22 12:30:27 2004 @@ -0,0 +1,42 @@ +# +# Copyright (c) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +O_TARGET := vmlinux-obj.o +obj-$(CONFIG_KDB_MODULES) += kdbm_vm.o kdbm_pg.o kdbm_task.o +ifdef CONFIG_X86 +obj-$(CONFIG_KDB_MODULES) += kdbm_x86.o +endif +CFLAGS_kdbm_vm.o += -I $(TOPDIR)/drivers/scsi + +EXTRA_CFLAGS += -I $(TOPDIR)/arch/$(ARCH)/kdb + +include $(TOPDIR)/Rules.make Index: 2.4.x-xfs/kdb/modules/kdbm_pg.c =================================================================== --- 2.4.x-xfs.orig/kdb/modules/kdbm_pg.c Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/modules/kdbm_pg.c Mon Nov 22 12:30:27 2004 @@ -0,0 +1,662 @@ +/* + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#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 */ + +static char *pg_flag_vals[] = { + "PG_locked", "PG_error", "PG_referenced", "PG_uptodate", + "PG_dirty", "PG_unused_5", "PG_lru", "PG_active", + "PG_slab", "PG_unused_9", "PG_skip", "PG_highmem", + "PG_checked", "PG_arch_1", "PG_reserved", "PG_launder", + "PG_fs_1", + NULL }; + +static char *bh_state_vals[] = { + "Uptodate", "Dirty", "Lock", "Req", + "Mapped", "New", "Async", "Wait_IO", + "Launder", "Attached", "JBD", "Sync" + "Delay", + "Private", + NULL }; + +static char *inode_flag_vals[] = { + "I_DIRTY_SYNC", "I_DIRTY_DATASYNC", "I_DIRTY_PAGES", "I_LOCK", + "I_FREEING", "I_CLEAR", + /*XFS*/ "I_NEW", + 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 char *page_flags(unsigned long flags) +{ + return(map_flags(flags, pg_flag_vals)); +} + +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(" next 0x%p bno %llu rsec %llu size %d dev 0x%x rdev 0x%x\n", + bh.b_next, (unsigned long long)bh.b_blocknr, + (unsigned long long)bh.b_rsector, bh.b_size, + bh.b_dev, bh.b_rdev); + kdb_printf(" count %d state 0x%lx [%s] b_list %d\n", + bh.b_count.counter, bh.b_state, + map_flags(bh.b_state, bh_state_vals), bh.b_list); + kdb_printf(" ftime %ld (%ld) b_next_free 0x%p b_prev_free 0x%p\n", + bh.b_flushtime, bh.b_flushtime - jiffies, + bh.b_next_free, bh.b_prev_free); + kdb_printf(" b_reqnext 0x%p b_data 0x%p\n", + bh.b_reqnext, bh.b_data); + kdb_printf(" b_inode_buffers.prev 0x%p b_inode_buffers.next 0x%p\n", + bh.b_inode_buffers.prev, bh.b_inode_buffers.next); + 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 +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; + + if (addr < PAGE_OFFSET) + addr = (unsigned long) &mem_map[addr]; + + if ((diag = kdb_getarea(page, addr))) + return(diag); + + kdb_printf("struct page at 0x%lx\n", addr); + kdb_printf(" next 0x%p prev 0x%p addr space 0x%p index %lu (offset 0x%x)\n", + page.list.next, page.list.prev, page.mapping, page.index, + (int)(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.buffers) + kdb_printf(" buffers 0x%p\n", page.buffers); + + return 0; +} + +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(" rq_dev 0x%x cmd %d errors %d sector %llu nr_sectors %lu waiting 0x%p\n", + rq.rq_dev, rq.cmd, rq.errors, + (unsigned long long)rq.sector, rq.nr_sectors, + rq.waiting); + + kdb_printf(" hsect %llu hnrsect %lu nrseg %u nrhwseg %u currnrsect %lu seq %d\n", + (unsigned long long)rq.hard_sector, rq.hard_nr_sectors, + rq.nr_segments, rq.nr_hw_segments, + rq.current_nr_sectors, rq.elevator_sequence); + kdb_printf(" "); + kdb_printf("bh 0x%p bhtail 0x%p req_q 0x%p\n\n", + rq.bh, rq.bhtail, rq.q); + + return (unsigned long) rq.queue.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 [%s]\n", addr, + rq.plugged ? "plugged" : "running"); + kdb_printf(" free %d list [0x%p, 0x%p]\n", + rq.rq.count, + rq.rq.free.prev, + rq.rq.free.next); + kdb_printf(" pending[read] %d pending[write] %d\n", + rq.rq.pending[READ], + rq.rq.pending[WRITE]); + + 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("bh 0x%lx bno %8llu [%s]\n", addr, + (unsigned long long)bh.b_blocknr, + map_flags(bh.b_state, bh_state_vals)); +} + +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; + int which=0; + + struct list_head *head, *curr; + + if (argc < 1) + return KDB_ARGCOUNT; + + 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); + } + + 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; + + again: + if (which == 0){ + which=1; + head = &inode->i_mapping->clean_pages; + kdb_printf("CLEAN page_struct index cnt flags\n"); + } else if (which == 1) { + which=2; + head = &inode->i_mapping->dirty_pages; + kdb_printf("DIRTY page_struct index cnt flags\n"); + } else if (which == 2) { + which=3; + head = &inode->i_mapping->locked_pages; + kdb_printf("LOCKED page_struct index cnt flags\n"); + } else { + goto out; + } + + curr = head->next; + while (curr != head) { + struct page page; + struct list_head curr_struct; + + addr = (unsigned long) list_entry(curr, struct page, list); + if ((diag = kdb_getarea(page, addr))) + goto out; + + if (!addr1 || page.index == addr1 || + (addr1 == -1 && (page.flags & ( 1 << PG_locked)))) + { + kdb_printf(" 0x%lx%6lu%5d 0x%lx ", + addr, page.index, page.count.counter, + page.flags); + if (page.buffers) + do_buffer((unsigned long) page.buffers); + else + kdb_printf("bh [NULL]\n"); + } + + if ((diag = kdb_getarea(curr_struct, (unsigned long) curr))) + goto out; + + curr = curr_struct.next; + } + goto again; + 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_dev = 0x%x i_size %Ld\n", + inode->i_ino, atomic_read(&inode->i_count), + inode->i_dev, 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.prv = 0x%p\n", + list_entry(inode->i_hash.next, struct inode, i_hash), + list_entry(inode->i_hash.prev, struct inode, i_hash)); + + 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_dirty_buffers.nxt = 0x%p i_dirty_buffers.prv = 0x%p\n", + list_entry(inode->i_dirty_buffers.next, + struct buffer_head, b_inode_buffers), + list_entry(inode->i_dirty_buffers.prev, + struct buffer_head, b_inode_buffers)); + + kdb_printf(" i_dirty_data_buffers.nxt = 0x%p i_dirty_data_buffers.prv = 0x%p\n", + list_entry(inode->i_dirty_data_buffers.next, + struct buffer_head, b_inode_buffers), + list_entry(inode->i_dirty_data_buffers.prev, + struct buffer_head, b_inode_buffers)); + + 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_locked_inodes.next 0x%p s_locked_inodes.prev 0x%p\n", + sb->s_locked_inodes.next, sb->s_locked_inodes.prev); +out: + if (sb) + kfree(sb); + return diag; +} + + +static int +kdbm_kiobuf(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct kiobuf *kiobuf = NULL; + struct page page; + struct page **page_array = NULL; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + int i, s; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs))) + goto out; + if (!(kiobuf = kmalloc(sizeof(*kiobuf), GFP_ATOMIC))) { + kdb_printf("kdbm_kiobuf: cannot kmalloc kiobuf\n"); + goto out; + } + if ((diag = kdb_getarea(*kiobuf, addr))) + goto out; + + kdb_printf("kiobuf at 0x%lx\n", addr); + kdb_printf(" nr_pages %d array_len %d offset 0x%x length 0x%x\n", + kiobuf->nr_pages, kiobuf->array_len, + kiobuf->offset, kiobuf->length); + kdb_printf(" errno %d\n", kiobuf->errno); + kdb_printf(" page_struct page_addr cnt flags\n"); + s = kiobuf->nr_pages*sizeof(*page_array); + if (!(page_array = kmalloc(s, GFP_ATOMIC))) { + kdb_printf("kdbm_kiobuf: cannot kmalloc page_array\n"); + goto out; + } + if ((diag = kdb_getarea_size(page_array, (unsigned long)kiobuf->maplist, s))) + goto out; + kiobuf->maplist = page_array; + for (i = 0; i < kiobuf->nr_pages; i++) { + if ((diag = kdb_getarea(page, (unsigned long) kiobuf->maplist[i]))) + goto out; + kdb_printf(" 0x%p", kiobuf->maplist[i]); + kdb_printf(" 0x%p", page_address(kiobuf->maplist[i])); + kdb_printf(" %d 0x%lx\n", page.count.counter, page.flags); + } +out: + if (kiobuf) + kfree(kiobuf); + if (page_array) + kfree(page_array); + return diag; +} + +#ifdef CONFIG_X86 +/* 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.buffers) { + 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 */ + +static int __init kdbm_pg_init(void) +{ + kdb_register("kiobuf", kdbm_kiobuf, "", "Display kiobuf", 0); + kdb_register("page", kdbm_page, "", "Display page", 0); + 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("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); +#ifdef CONFIG_X86 + kdb_register("memmap", kdbm_memmap, "", "page table summary", 0); +#endif + + return 0; +} + + +static void __exit kdbm_pg_exit(void) +{ + kdb_unregister("kiobuf"); + kdb_unregister("page"); + kdb_unregister("inode"); + kdb_unregister("sb"); + kdb_unregister("bh"); + kdb_unregister("inode_pages"); + kdb_unregister("req"); + kdb_unregister("rqueue"); +#ifdef CONFIG_X86 + kdb_unregister("memmap"); +#endif +} + +module_init(kdbm_pg_init) +module_exit(kdbm_pg_exit) Index: 2.4.x-xfs/kdb/modules/kdbm_task.c =================================================================== --- 2.4.x-xfs.orig/kdb/modules/kdbm_task.c Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/modules/kdbm_task.c Mon Nov 22 12:30:27 2004 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("SGI"); +MODULE_DESCRIPTION("Debug struct task and sigset information"); +MODULE_LICENSE("GPL"); + +#ifdef __KDB_HAVE_NEW_SCHEDULER +static char * +kdb_cpus_allowed_string(struct task_struct *tp) +{ +#ifndef CPUMASK_WORDCOUNT + static char maskbuf[BITS_PER_LONG/4+8]; + sprintf(maskbuf, "0x%0lx", tp->cpus_allowed); +#elif CONFIG_SMP + int i, j; + static char maskbuf[CPUMASK_WORDCOUNT * BITS_PER_LONG / 4 + 8]; + + strcpy(maskbuf, "0x"); + for (j=2, i=CPUMASK_WORDCOUNT-1; i >= 0; i--) { + j += sprintf(maskbuf + j, "%0lx", tp->cpus_allowed[i]); + } +#else + static char maskbuf[BITS_PER_LONG/4+8]; + sprintf(maskbuf, "0x%0lx", 0); +#endif /* CPUMASK_WORDCOUNT */ + + return maskbuf; +} +#endif /* __KDB_HAVE_NEW_SCHEDULER */ + +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; + + 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; + } + + kdb_printf( + "struct task at 0x%p, pid=%d flags=0x%lx state=%ld comm=\"%s\"\n", + tp, tp->pid, tp->flags, tp->state, tp->comm); + + kdb_printf(" cpu=%d policy=%lu ", kdb_process_cpu(tp), tp->policy); +#ifdef __KDB_HAVE_NEW_SCHEDULER + kdb_printf( + "prio=%d static_prio=%d cpus_allowed=%s", + tp->prio, tp->static_prio, kdb_cpus_allowed_string(tp)); +#else + kdb_printf( + "cpus_runnable=%lx cpus_allowed=%lx", + tp->cpus_runnable, tp->cpus_allowed); +#endif + kdb_printf(" &thread=0x%p\n", &tp->thread); + + kdb_printf(" need_resched=%ld ", tp->need_resched); +#ifdef __KDB_HAVE_NEW_SCHEDULER + kdb_printf( + "sleep_timestamp=%lu time_slice=%u", + tp->sleep_timestamp, tp->time_slice); +#else + kdb_printf( + "counter=%ld nice=%ld", + tp->counter, tp->nice); +#endif + kdb_printf(" lock_depth=%d\n", tp->lock_depth); + + kdb_printf( + " fs=0x%p files=0x%p mm=0x%p nr_local_pages=%u\n", + tp->fs, tp->files, tp->mm, tp->nr_local_pages); + + 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 locks=%d semundo=0x%p semsleeping=0x%p\n", + tp->user, tp->locks, tp->semundo, tp->semsleeping); + + kdb_printf( + " sig=0x%p &blocked=0x%p &sigpending=0x%p\n", + tp->sig, &tp->blocked, &tp->sigpending); + + kdb_printf( + " times.utime=%ld times_stime=%ld times_cutime=%ld times_cstime=%ld\n", + tp->times.tms_utime, tp->times.tms_stime, tp->times.tms_cutime, + tp->times.tms_cstime); + +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.4.x-xfs/kdb/modules/kdbm_vm.c =================================================================== --- 2.4.x-xfs.orig/kdb/modules/kdbm_vm.c Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kdb/modules/kdbm_vm.c Mon Nov 22 12:30:27 2004 @@ -0,0 +1,707 @@ +/* + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#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; +} 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_DENYWRITE, "DENYWRITE" }, + { VM_EXECUTABLE, "EXECUTABLE" }, + { VM_LOCKED, "LOCKED" }, + { VM_IO , "IO " }, + { 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("vm_next_share = 0x%p\n", (void *) vp->vm_next_share); + kdb_printf("vm_pprev_share = 0x%p\n", (void *) vp->vm_pprev_share); + 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(q, 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%lx", 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; + pid_t pid; + struct mm_struct *mm, copy_of_mm; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + if (argc < 3 || argc > 4) { + return KDB_ARGCOUNT; + } + + if (strcmp(argv[1], "-p") == 0) { + struct task_struct *tp; + if ((diag = kdbgetularg(argv[2], (unsigned long *) &pid))) { + return diag; + } + if (!(tp = find_task_by_pid(pid))) { + kdb_printf("No process with pid == %d found\n", pid); + return 0; + } + if (!tp->mm) { + kdb_printf("task structure's mm field is NULL\n"); + 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)) { + pmd = pmd_offset(pgd, addr); + if (pmd_present(*pmd)) { + pte = pte_offset(pmd, addr); + if (pte_present(*pte)) { + kdbm_print_pte(pte); + } + } + } + + kdb_printf("\n"); + addr += PAGE_SIZE; + } + + return 0; +} + +static int +kdbm_fp(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct file f; + struct inode *i = NULL; + struct dentry d; + 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)) || + (diag = kdb_getarea(d, (unsigned long)f.f_dentry))) + goto out; + if (!(i = kmalloc(sizeof(*i), GFP_ATOMIC))) { + kdb_printf("kdbm_fp: cannot kmalloc inode\n"); + goto out; + } + if ((diag = kdb_getarea(*i, (unsigned long)d.d_inode))) + goto out; + + kdb_printf("name.name 0x%p name.len %d\n", + d.d_name.name, d.d_name.len); + + kdb_printf("File Pointer at 0x%lx\n", addr); + + kdb_printf(" f_list.nxt = 0x%p f_list.prv = 0x%p\n", + f.f_list.next, f.f_list.prev); + + kdb_printf(" f_dentry = 0x%p f_op = 0x%p\n", + f.f_dentry, 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 f_reada = %ld f_ramax = %ld\n", + f.f_pos, f.f_reada, f.f_ramax); + + kdb_printf(" f_raend = %ld f_ralen = %ld f_rawin = %ld\n\n", + f.f_raend, f.f_ralen, f.f_rawin); + + + kdb_printf("\nDirectory Entry at 0x%p\n", f.f_dentry); + kdb_printf(" d_name.len = %d d_name.name = 0x%p>\n", + 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_hash.nxt = 0x%p d_hash.prv = 0x%p\n", + d.d_hash.next, d.d_hash.prev); + + 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_child.next, d.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\n\n", + d.d_op, d.d_sb); + + + kdb_printf("\nInode Entry at 0x%p\n", d.d_inode); + + 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 i_dev = 0x%x\n", + i->i_ino, atomic_read(&i->i_count), i->i_dev); + + kdb_printf(" i_hash.nxt = 0x%p i_hash.prv = 0x%p\n", + i->i_hash.next, i->i_hash.prev); + + 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); + +out: + if (i) + kfree(i); + return diag; +} + +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(" fl_notify = 0x%p fl_insert = 0x%p fl_remove = 0x%p\n", + fl.fl_notify, fl.fl_insert, fl.fl_remove); + + 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) +{ + struct dentry d; + int nextarg; + unsigned long addr; + long offset; + int diag; + char buf[256]; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + if ((diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs)) || + (diag = kdb_getarea(d, addr))) + return diag; + + + kdb_printf("Dentry at 0x%lx\n", addr); + + 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.prev); + + 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_child.next, d.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\n\n", + d.d_op, d.d_sb); + + 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("next = 0x%p host_queue = 0x%p\n", + sh.next, sh.host_queue); + kdb_printf("ehandler = 0x%p eh_wait = 0x%p en_notify = 0x%p eh_action = 0x%p\n", + sh.ehandler, sh.eh_wait, sh.eh_notify, sh.eh_action); + kdb_printf("eh_active = 0x%d host_wait = 0x%p hostt = 0x%p host_busy = %d\n", + sh.eh_active, &sh.host_wait, sh.hostt, sh.host_active.counter); + kdb_printf("host_failed = %d extra_bytes = %d host_no = %d resetting = %d\n", + sh.host_failed, sh.extra_bytes, 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->next, sd->prev, sd->host); + kdb_printf("device_busy = %d device_queue 0x%p\n", + sd->device_busy, sd->device_queue); + 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 char * +str_rq_status(int rq_status) +{ + switch (rq_status) { + case RQ_INACTIVE: + return "RQ_INACTIVE"; + case RQ_ACTIVE: + return "RQ_ACTIVE"; + case RQ_SCSI_BUSY: + return "RQ_SCSI_BUSY"; + case RQ_SCSI_DONE: + return "RQ_SCSI_DONE"; + case RQ_SCSI_DISCONNECTING: + return "RQ_SCSI_DISCONNECTING"; + default: + return "UNKNOWN"; + } +} + +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("host = 0x%p state = %d owner = %d device = 0x%p\nb", + sc->host, sc->state, sc->owner, sc->device); + kdb_printf("next = 0x%p reset_chain = 0x%p eh_state = %d done = 0x%p\n", + sc->next, sc->reset_chain, sc->eh_state, sc->done); + kdb_printf("serial_number = %ld serial_num_at_to = %ld retries = %d timeout = %d\n", + sc->serial_number, sc->serial_number_at_timeout, sc->retries, sc->timeout); + kdb_printf("id/lun/cmnd = [%d/%d/%d] cmd_len = %d old_cmd_len = %d\n", + sc->target, sc->lun, sc->channel, 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 bh_next = 0x%p request_bufflen = %d\n", + sc->request_buffer, sc->bh_next, sc->request_bufflen); + kdb_printf("use_sg = %d old_use_sg = %d sglist_len = %d abore_reason = %d\n", + sc->use_sg, sc->old_use_sg, sc->sglist_len, sc->abort_reason); + 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); + kdb_printf("request struct\n"); + kdb_printf("rq_status = %s rq_dev = [%d/%d] errors = %d cmd = %d\n", + str_rq_status(sc->request.rq_status), + MAJOR(sc->request.rq_dev), + MINOR(sc->request.rq_dev), sc->request.cmd, + sc->request.errors); + kdb_printf("sector = %llu nr_sectors = %lu current_nr_sectors = %lu\n", + (unsigned long long)sc->request.sector, + sc->request.nr_sectors, sc->request.current_nr_sectors); + kdb_printf("buffer = 0x%p bh = 0x%p bhtail = 0x%p\n", + sc->request.buffer, sc->request.bh, sc->request.bhtail); + +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("dentry", kdbm_dentry, "", "Display interesting dentry stuff", 0); + kdb_register("filp", kdbm_fp, "", "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("dentry"); + 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.4.x-xfs/kernel/Makefile =================================================================== --- 2.4.x-xfs.orig/kernel/Makefile Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/kernel/Makefile Mon Nov 22 12:30:27 2004 @@ -19,6 +19,7 @@ obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_KALLSYMS) += kallsyms.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is Index: 2.4.x-xfs/kernel/kallsyms.c =================================================================== --- 2.4.x-xfs.orig/kernel/kallsyms.c Thu Jan 1 10:00:00 1970 +++ 2.4.x-xfs/kernel/kallsyms.c Mon Nov 22 12:30:27 2004 @@ -0,0 +1,418 @@ +/* An example of using kallsyms data in a kernel debugger. + + Copyright 2000 Keith Owens April 2000 + + This file is part of the Linux modutils. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + This code uses the list of all kernel and module symbols to :- + + * Find any non-stack symbol in a kernel or module. Symbols do + not have to be exported for debugging. + + * Convert an address to the module (or kernel) that owns it, the + section it is in and the nearest symbol. This finds all non-stack + symbols, not just exported ones. + + You need modutils >= 2.3.11 and a kernel with the kallsyms patch + which was compiled with CONFIG_KALLSYMS. + */ + +#include +#include +#include +#include +#include +#include + +/* These external symbols are only set on kernels compiled with + * CONFIG_KALLSYMS. + */ + +extern const char __start___kallsyms[]; +extern const char __stop___kallsyms[]; + +static struct module **kallsyms_module_list; + +static void kallsyms_get_module_list(void) +{ + const struct kallsyms_header *ka_hdr; + const struct kallsyms_section *ka_sec; + const struct kallsyms_symbol *ka_sym; + const char *ka_str; + int i; + const char *p; + + if (__start___kallsyms >= __stop___kallsyms) + return; + ka_hdr = (struct kallsyms_header *)__start___kallsyms; + ka_sec = (struct kallsyms_section *) + ((char *)(ka_hdr) + ka_hdr->section_off); + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + + for (i = 0; i < ka_hdr->symbols; kallsyms_next_sym(ka_hdr, ka_sym), ++i) { + p = ka_str + ka_sym->name_off; + if (strcmp(p, "module_list") == 0) { + if (ka_sym->symbol_addr) + kallsyms_module_list = (struct module **)(ka_sym->symbol_addr); + break; + } + } +} + +static inline void kallsyms_do_first_time(void) +{ + static int first_time = 1; + if (first_time) + kallsyms_get_module_list(); + first_time = 0; +} + +/* A symbol can appear in more than one module. A token is used to + * restart the scan at the next module, set the token to 0 for the + * first scan of each symbol. + */ + +int kallsyms_symbol_to_address( + const char *name, /* Name to lookup */ + unsigned long *token, /* Which module to start at */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_section *ka_sec; + const struct kallsyms_symbol *ka_sym = NULL; + const char *ka_str = NULL; + const struct module *m; + int i = 0, l; + const char *p, *pt_R; + char *p2; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + /* Restart? */ + m = *kallsyms_module_list; + if (token && *token) { + for (; m; m = m->next) + if ((unsigned long)m == *token) + break; + if (m) + m = m->next; + } + + for (; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) { + p = ka_str + ka_sym->name_off; + if (strcmp(p, name) == 0) + break; + /* Unversioned requests match versioned names */ + if (!(pt_R = strstr(p, "_R"))) + continue; + l = strlen(pt_R); + if (l < 10) + continue; /* Not _R.*xxxxxxxx */ + (void)simple_strtoul(pt_R+l-8, &p2, 16); + if (*p2) + continue; /* Not _R.*xxxxxxxx */ + if (strncmp(p, name, pt_R-p) == 0) + break; /* Match with version */ + } + if (i < ka_hdr->symbols) + break; + } + + if (token) + *token = (unsigned long)m; + if (!m) + return(0); /* not found */ + + ka_sec = (const struct kallsyms_section *) + ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off); + *mod_name = *(m->name) ? m->name : "kernel"; + *mod_start = ka_hdr->start; + *mod_end = ka_hdr->end; + *sec_name = ka_sec->name_off + ka_str; + *sec_start = ka_sec->start; + *sec_end = ka_sec->start + ka_sec->size; + *sym_name = ka_sym->name_off + ka_str; + *sym_start = ka_sym->symbol_addr; + if (i < ka_hdr->symbols-1) { + const struct kallsyms_symbol *ka_symn = ka_sym; + kallsyms_next_sym(ka_hdr, ka_symn); + *sym_end = ka_symn->symbol_addr; + } + else + *sym_end = *sec_end; + return(1); +} + +int kallsyms_address_to_symbol( + unsigned long address, /* Address to lookup */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_section *ka_sec = NULL; + const struct kallsyms_symbol *ka_sym; + const char *ka_str; + const struct module *m; + int i; + unsigned long end; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + for (m = *kallsyms_module_list; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sec = (const struct kallsyms_section *) + ((char *)ka_hdr + ka_hdr->section_off); + /* Is the address in any section in this module? */ + for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) { + if (ka_sec->start <= address && + (ka_sec->start + ka_sec->size) > address) + break; + } + if (i < ka_hdr->sections) + break; /* Found a matching section */ + } + + if (!m) + return(0); /* not found */ + + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + *mod_name = *(m->name) ? m->name : "kernel"; + *mod_start = ka_hdr->start; + *mod_end = ka_hdr->end; + *sec_name = ka_sec->name_off + ka_str; + *sec_start = ka_sec->start; + *sec_end = ka_sec->start + ka_sec->size; + *sym_name = *sec_name; /* In case we find no matching symbol */ + *sym_start = *sec_start; + *sym_end = *sec_end; + + for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) { + if (ka_sym->symbol_addr > address) + continue; + if (i < ka_hdr->symbols-1) { + const struct kallsyms_symbol *ka_symn = ka_sym; + kallsyms_next_sym(ka_hdr, ka_symn); + end = ka_symn->symbol_addr; + } + else + end = *sec_end; + if (end <= address) + continue; + if ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off + != (char *)ka_sec) + continue; /* wrong section */ + *sym_name = ka_str + ka_sym->name_off; + *sym_start = ka_sym->symbol_addr; + *sym_end = end; + break; + } + return(1); +} + +/* List all sections in all modules. The callback routine is invoked with + * token, module name, section name, section start, section end, section flags. + */ +int kallsyms_sections(void *token, + int (*callback)(void *, const char *, const char *, ElfW(Addr), ElfW(Addr), ElfW(Word))) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_section *ka_sec = NULL; + const char *ka_str; + const struct module *m; + int i; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + for (m = *kallsyms_module_list; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sec = (const struct kallsyms_section *) ((char *)ka_hdr + ka_hdr->section_off); + ka_str = ((char *)(ka_hdr) + ka_hdr->string_off); + for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) { + if (callback( + token, + *(m->name) ? m->name : "kernel", + ka_sec->name_off + ka_str, + ka_sec->start, + ka_sec->start + ka_sec->size, + ka_sec->flags)) + return(0); + } + } + return(1); +} + + +/* paramter prefix_name is a buffer provided by the caller, it must ends with '\0'. */ +/* return the extra string together with the given prefix of a symbol name. */ +/* return 0 means no prefix string is found. */ +/* return >0 means prefix string is found. */ +int kallsyms_symbol_complete( + char *prefix_name /* Prefix of a symbol name to lookup */ + ) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_symbol *ka_sym = NULL; + const char *ka_str = NULL; + const struct module *m; + int i = 0; + int prefix_len=strlen(prefix_name); + int cur_pos=0, last_pos=0; + int find=0; + int number=0; + const char *p; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + for (m = *kallsyms_module_list; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) { + p = ka_str + ka_sym->name_off; + if (strncmp(p, prefix_name,prefix_len) == 0) { + ++number; + if (find == 0) { + last_pos = strlen(p); + strncpy(prefix_name, p, last_pos+1); + find = 1; + } + else { + for (cur_pos = prefix_len ; cur_pos < last_pos; cur_pos++) { + if (*(p + cur_pos) == '\0' + || *(p + cur_pos) != prefix_name[cur_pos]) { + last_pos = cur_pos; + prefix_name[cur_pos] = '\0'; + break; + } + } + } + } + } + } + + return number; +} + +/* paramter prefix_name is a buffer provided by the caller, it must ends with '\0'. */ +/* parameter flag = 0 means search from the head, flag = 1 means continue search. */ +/* return a symbol string which matches the given prefix. */ +/* return 0 means no prefix string is found. */ +/* return >0 means prefix string is found. */ +int kallsyms_symbol_next( + char *prefix_name, /* Prefix of a symbol name to lookup */ + int flag /* Indicate if search from the head */ + ) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const char *ka_str = NULL; + static const struct kallsyms_symbol *ka_sym; + static const struct module *m; + static int i; + int prefix_len=strlen(prefix_name); + const char *p; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + if(!flag) { + m = *kallsyms_module_list; + } + + for (; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + if(!flag) { + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + i = 0; + } + ka_str = ((char *)(ka_hdr) + ka_hdr->string_off); + + for (; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) { + p = ka_str + ka_sym->name_off; + if (strncmp(p, prefix_name,prefix_len) == 0) { + strncpy(prefix_name, p, strlen(p)+1); + ++i; + kallsyms_next_sym(ka_hdr, ka_sym); + return 1; + } + } + } + + return 0; +} Index: 2.4.x-xfs/kernel/ksyms.c =================================================================== --- 2.4.x-xfs.orig/kernel/ksyms.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/kernel/ksyms.c Mon Nov 22 12:30:27 2004 @@ -58,6 +58,9 @@ #ifdef CONFIG_KMOD #include #endif +#ifdef CONFIG_KALLSYMS +#include +#endif extern void set_device_ro(kdev_t dev,int flag); @@ -84,6 +87,15 @@ EXPORT_SYMBOL(inter_module_put); EXPORT_SYMBOL(try_inc_mod_count); +#ifdef CONFIG_KALLSYMS +extern const char __start___kallsyms[]; +extern const char __stop___kallsyms[]; +EXPORT_SYMBOL(__start___kallsyms); +EXPORT_SYMBOL(__stop___kallsyms); +EXPORT_SYMBOL(kallsyms_symbol_to_address); +EXPORT_SYMBOL(kallsyms_address_to_symbol); +#endif + /* process memory management */ EXPORT_SYMBOL(do_mmap_pgoff); EXPORT_SYMBOL(do_munmap); @@ -622,3 +634,8 @@ /* To match ksyms with System.map */ extern const char _end[]; EXPORT_SYMBOL(_end); + +#if defined(CONFIG_KDB_USB) +#include +EXPORT_SYMBOL(kdb_usb_infos); +#endif Index: 2.4.x-xfs/kernel/module.c =================================================================== --- 2.4.x-xfs.orig/kernel/module.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/kernel/module.c Mon Nov 22 12:30:27 2004 @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -1248,6 +1249,30 @@ show: s_show }; +#define MODLIST_SIZE 4096 + +/* + * this function isn't smp safe but that's not really a problem; it's + * called from oops context only and any locking could actually prevent + * the oops from going out; the line that is generated is informational + * only and should NEVER prevent the real oops from going out. + */ +void print_modules(void) +{ + static char modlist[MODLIST_SIZE]; + struct module *this_mod; + int pos = 0; + + this_mod = module_list; + while (this_mod) { + if (this_mod->name) + pos += snprintf(modlist+pos, MODLIST_SIZE-pos-1, + "%s ", this_mod->name); + this_mod = this_mod->next; + } + printk("%s\n",modlist); +} + #else /* CONFIG_MODULES */ /* Dummy syscalls for people who don't want modules */ @@ -1293,4 +1318,81 @@ return 1; } +void print_modules(void) +{ +} + #endif /* CONFIG_MODULES */ + + +#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS) + +#define MAX_SYMBOL_SIZE 512 + +static void +address_to_exported_symbol(unsigned long address, const char **mod_name, + const char **sym_name, unsigned long *sym_start, + unsigned long *sym_end) +{ + struct module *this_mod; + int i; + + for (this_mod = module_list; this_mod; this_mod = this_mod->next) { + /* walk the symbol list of this module. Only symbols + who's address is smaller than the searched for address + are relevant; and only if it's better than the best so far */ + for (i = 0; i < this_mod->nsyms; i++) + if ((this_mod->syms[i].value <= address) && + (*sym_start < this_mod->syms[i].value)) { + *sym_start = this_mod->syms[i].value; + *sym_name = this_mod->syms[i].name; + *mod_name = this_mod->name; + if (i + 1 < this_mod->nsyms) + *sym_end = this_mod->syms[i+1].value; + else + *sym_end = (unsigned long) this_mod + this_mod->size; + } + } +} + +void +print_symbol(const char *fmt, unsigned long address) +{ + /* static to not take up stackspace; if we race here too bad */ + static char buffer[MAX_SYMBOL_SIZE]; + + const char *mod_name = NULL, *sec_name = NULL, *sym_name = NULL; + unsigned long mod_start, mod_end, sec_start, sec_end, + sym_start, sym_end; + char *tag = ""; + + memset(buffer, 0, MAX_SYMBOL_SIZE); + + sym_start = 0; + if (!kallsyms_address_to_symbol(address, &mod_name, &mod_start, &mod_end, &sec_name, &sec_start, &sec_end, &sym_name, &sym_start, &sym_end)) { + tag = "E "; + address_to_exported_symbol(address, &mod_name, &sym_name, &sym_start, &sym_end); + } + + if (sym_start) { + if (*mod_name) + snprintf(buffer, MAX_SYMBOL_SIZE - 1, "%s%s+%#x/%#x [%s]", + tag, sym_name, + (unsigned int)(address - sym_start), + (unsigned int)(sym_end - sym_start), + mod_name); + else + snprintf(buffer, MAX_SYMBOL_SIZE - 1, "%s%s+%#x/%#x", + tag, sym_name, + (unsigned int)(address - sym_start), + (unsigned int)(sym_end - sym_start)); + printk(fmt, buffer); + } +#if 0 + else { + printk(fmt, "[unresolved]"); + } +#endif +} + +#endif Index: 2.4.x-xfs/kernel/printk.c =================================================================== --- 2.4.x-xfs.orig/kernel/printk.c Mon Nov 22 12:30:00 2004 +++ 2.4.x-xfs/kernel/printk.c Mon Nov 22 12:30:27 2004 @@ -297,6 +297,20 @@ return error; } +#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 + asmlinkage long sys_syslog(int type, char * buf, int len) { if ((type != 3) && !capable(CAP_SYS_ADMIN)) Index: 2.4.x-xfs/kernel/sched.c =================================================================== --- 2.4.x-xfs.orig/kernel/sched.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/kernel/sched.c Mon Nov 22 12:30:27 2004 @@ -658,6 +658,12 @@ #endif /* CONFIG_SMP */ +#ifdef CONFIG_KDB + { + extern struct task_struct *kdb_active_task[]; + kdb_active_task[smp_processor_id()] = next; + } +#endif kstat.context_swtch++; /* * there are 3 processes which are affected by a context switch: Index: 2.4.x-xfs/kernel/signal.c =================================================================== --- 2.4.x-xfs.orig/kernel/signal.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/kernel/signal.c Mon Nov 22 12:30:27 2004 @@ -1323,3 +1323,60 @@ return ret ? ret : (unsigned long)old_sa.sa.sa_handler; } #endif /* !alpha && !__ia64__ && !defined(__mips__) */ + +#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->sigmask_lock)) { + 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->sigmask_lock); +#ifndef __KDB_HAVE_NEW_SCHEDULER + if (!spin_trylock(&runqueue_lock)) { + kdb_printf("Can't do kill command now.\n" + "The runqueue lock is held somewhere else in kernel, try again later\n"); + return; + } + spin_unlock(&runqueue_lock); +#endif /* __KDB_HAVE_NEW_SCHEDULER */ + 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.4.x-xfs/kernel/sysctl.c =================================================================== --- 2.4.x-xfs.orig/kernel/sysctl.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/kernel/sysctl.c Mon Nov 22 12:30:27 2004 @@ -28,6 +28,9 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif /* CONFIG_KDB */ #include #include #include @@ -278,6 +281,10 @@ {KERN_EXCEPTION_TRACE,"exception-trace", &exception_trace,sizeof(int),0644,NULL,&proc_dointvec}, #endif +#ifdef CONFIG_KDB + {KERN_KDB, "kdb", &kdb_on, sizeof(int), + 0644, NULL, &proc_dointvec}, +#endif /* CONFIG_KDB */ {0} }; Index: 2.4.x-xfs/mm/memory.c =================================================================== --- 2.4.x-xfs.orig/mm/memory.c Mon Nov 22 12:29:09 2004 +++ 2.4.x-xfs/mm/memory.c Mon Nov 22 12:30:27 2004 @@ -1497,3 +1497,15 @@ } return page; } + +#ifdef CONFIG_KDB +struct page * kdb_follow_page(struct mm_struct *mm, unsigned long address, int write) +{ + struct page *page = follow_page(mm, address, write); + + if (!page) + return get_page_map(page); + + return page; +} +#endif