diff options
| author | Vivek Goyal <vgoyal@in.ibm.com> | 2005-06-25 17:58:15 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-25 19:24:52 -0400 |
| commit | b089f4a68eccd9782c89262c0d7cae146d5a8a40 (patch) | |
| tree | a84874a801e54dd89e5093392aedf49cece4cb11 /Documentation/kdump | |
| parent | a3ea8ac8468f5c7fc65684331dfba3260d5b2d93 (diff) | |
[PATCH] kdump: Documentation for Kdump
This patch contains the documentation for the kexec based crash dump tool.
Quick kdump-howto
================================================================
1) Download and build kexec-tools.
2) Download and build the latest kexec/kdump (-mm) kernel patchset.
Two kernels need to be built in order to get this feature working.
A) First kernel:
a) Enable "kexec system call" feature:
CONFIG_KEXEC=y
b) Physical load address (use default):
CONFIG_PHYSICAL_START=0x100000
c) Enable "sysfs file system support":
CONFIG_SYSFS=y
d) Boot into first kernel with the command line parameter "crashkernel=Y@X":
For example: "crashkernel=64M@16M".
B) Second kernel:
a) Enable "kernel crash dumps" feature:
CONFIG_CRASH_DUMP=y
b) Physical load addreess, use same load address as X in "crashkernel"
kernel parameter in d) above, e.g., 16 MB or 0x1000000.
CONFIG_PHYSICAL_START=0x1000000
c) Enable "/proc/vmcore support" (Optional, in Pseudo filesystems).
CONFIG_PROC_VMCORE=y
3) Boot into the first kernel.
4) Load the second kernel to be booted using:
kexec -p <second-kernel> --crash-dump --args-linux --append="root=<root-dev>
maxcpus=1 init 1"
5) System reboots into the second kernel when a panic occurs. A module can be
written to force the panic, for testing purposes.
6) See Documentation/kdump.txt for how to read the first kernel's
memory image and how to analyze it.
Signed-off-by: Hariprasad Nellitheertha <hari@in.ibm.com>
Signed-off-by: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com>
Signed-off-by: randy_dunlap <rdunlap@xenotime.net>
Signed-off-by: Maneesh Soni <maneesh@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'Documentation/kdump')
| -rw-r--r-- | Documentation/kdump/gdbmacros.txt | 179 | ||||
| -rw-r--r-- | Documentation/kdump/kdump.txt | 135 |
2 files changed, 314 insertions, 0 deletions
diff --git a/Documentation/kdump/gdbmacros.txt b/Documentation/kdump/gdbmacros.txt new file mode 100644 index 000000000000..bc1b9eb92ae1 --- /dev/null +++ b/Documentation/kdump/gdbmacros.txt | |||
| @@ -0,0 +1,179 @@ | |||
| 1 | # | ||
| 2 | # This file contains a few gdb macros (user defined commands) to extract | ||
| 3 | # useful information from kernel crashdump (kdump) like stack traces of | ||
| 4 | # all the processes or a particular process and trapinfo. | ||
| 5 | # | ||
| 6 | # These macros can be used by copying this file in .gdbinit (put in home | ||
| 7 | # directory or current directory) or by invoking gdb command with | ||
| 8 | # --command=<command-file-name> option | ||
| 9 | # | ||
| 10 | # Credits: | ||
| 11 | # Alexander Nyberg <alexn@telia.com> | ||
| 12 | # V Srivatsa <vatsa@in.ibm.com> | ||
| 13 | # Maneesh Soni <maneesh@in.ibm.com> | ||
| 14 | # | ||
| 15 | |||
| 16 | define bttnobp | ||
| 17 | set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) | ||
| 18 | set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next) | ||
| 19 | set $init_t=&init_task | ||
| 20 | set $next_t=(((char *)($init_t->tasks).next) - $tasks_off) | ||
| 21 | while ($next_t != $init_t) | ||
| 22 | set $next_t=(struct task_struct *)$next_t | ||
| 23 | printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm | ||
| 24 | printf "===================\n" | ||
| 25 | set var $stackp = $next_t.thread.esp | ||
| 26 | set var $stack_top = ($stackp & ~4095) + 4096 | ||
| 27 | |||
| 28 | while ($stackp < $stack_top) | ||
| 29 | if (*($stackp) > _stext && *($stackp) < _sinittext) | ||
| 30 | info symbol *($stackp) | ||
| 31 | end | ||
| 32 | set $stackp += 4 | ||
| 33 | end | ||
| 34 | set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off) | ||
| 35 | while ($next_th != $next_t) | ||
| 36 | set $next_th=(struct task_struct *)$next_th | ||
| 37 | printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm | ||
| 38 | printf "===================\n" | ||
| 39 | set var $stackp = $next_t.thread.esp | ||
| 40 | set var $stack_top = ($stackp & ~4095) + 4096 | ||
| 41 | |||
| 42 | while ($stackp < $stack_top) | ||
| 43 | if (*($stackp) > _stext && *($stackp) < _sinittext) | ||
| 44 | info symbol *($stackp) | ||
| 45 | end | ||
| 46 | set $stackp += 4 | ||
| 47 | end | ||
| 48 | set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off) | ||
| 49 | end | ||
| 50 | set $next_t=(char *)($next_t->tasks.next) - $tasks_off | ||
| 51 | end | ||
| 52 | end | ||
| 53 | document bttnobp | ||
| 54 | dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER | ||
| 55 | end | ||
| 56 | |||
| 57 | define btt | ||
| 58 | set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) | ||
| 59 | set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next) | ||
| 60 | set $init_t=&init_task | ||
| 61 | set $next_t=(((char *)($init_t->tasks).next) - $tasks_off) | ||
| 62 | while ($next_t != $init_t) | ||
| 63 | set $next_t=(struct task_struct *)$next_t | ||
| 64 | printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm | ||
| 65 | printf "===================\n" | ||
| 66 | set var $stackp = $next_t.thread.esp | ||
| 67 | set var $stack_top = ($stackp & ~4095) + 4096 | ||
| 68 | set var $stack_bot = ($stackp & ~4095) | ||
| 69 | |||
| 70 | set $stackp = *($stackp) | ||
| 71 | while (($stackp < $stack_top) && ($stackp > $stack_bot)) | ||
| 72 | set var $addr = *($stackp + 4) | ||
| 73 | info symbol $addr | ||
| 74 | set $stackp = *($stackp) | ||
| 75 | end | ||
| 76 | |||
| 77 | set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off) | ||
| 78 | while ($next_th != $next_t) | ||
| 79 | set $next_th=(struct task_struct *)$next_th | ||
| 80 | printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm | ||
| 81 | printf "===================\n" | ||
| 82 | set var $stackp = $next_t.thread.esp | ||
| 83 | set var $stack_top = ($stackp & ~4095) + 4096 | ||
| 84 | set var $stack_bot = ($stackp & ~4095) | ||
| 85 | |||
| 86 | set $stackp = *($stackp) | ||
| 87 | while (($stackp < $stack_top) && ($stackp > $stack_bot)) | ||
| 88 | set var $addr = *($stackp + 4) | ||
| 89 | info symbol $addr | ||
| 90 | set $stackp = *($stackp) | ||
| 91 | end | ||
| 92 | set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off) | ||
| 93 | end | ||
| 94 | set $next_t=(char *)($next_t->tasks.next) - $tasks_off | ||
| 95 | end | ||
| 96 | end | ||
| 97 | document btt | ||
| 98 | dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER | ||
| 99 | end | ||
| 100 | |||
| 101 | define btpid | ||
| 102 | set var $pid = $arg0 | ||
| 103 | set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) | ||
| 104 | set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next) | ||
| 105 | set $init_t=&init_task | ||
| 106 | set $next_t=(((char *)($init_t->tasks).next) - $tasks_off) | ||
| 107 | set var $pid_task = 0 | ||
| 108 | |||
| 109 | while ($next_t != $init_t) | ||
| 110 | set $next_t=(struct task_struct *)$next_t | ||
| 111 | |||
| 112 | if ($next_t.pid == $pid) | ||
| 113 | set $pid_task = $next_t | ||
| 114 | end | ||
| 115 | |||
| 116 | set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off) | ||
| 117 | while ($next_th != $next_t) | ||
| 118 | set $next_th=(struct task_struct *)$next_th | ||
| 119 | if ($next_th.pid == $pid) | ||
| 120 | set $pid_task = $next_th | ||
| 121 | end | ||
| 122 | set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off) | ||
| 123 | end | ||
| 124 | set $next_t=(char *)($next_t->tasks.next) - $tasks_off | ||
| 125 | end | ||
| 126 | |||
| 127 | printf "\npid %d; comm %s:\n", $pid_task.pid, $pid_task.comm | ||
| 128 | printf "===================\n" | ||
| 129 | set var $stackp = $pid_task.thread.esp | ||
| 130 | set var $stack_top = ($stackp & ~4095) + 4096 | ||
| 131 | set var $stack_bot = ($stackp & ~4095) | ||
| 132 | |||
| 133 | set $stackp = *($stackp) | ||
| 134 | while (($stackp < $stack_top) && ($stackp > $stack_bot)) | ||
| 135 | set var $addr = *($stackp + 4) | ||
| 136 | info symbol $addr | ||
| 137 | set $stackp = *($stackp) | ||
| 138 | end | ||
| 139 | end | ||
| 140 | document btpid | ||
| 141 | backtrace of pid | ||
| 142 | end | ||
| 143 | |||
| 144 | |||
| 145 | define trapinfo | ||
| 146 | set var $pid = $arg0 | ||
| 147 | set $tasks_off=((size_t)&((struct task_struct *)0)->tasks) | ||
| 148 | set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next) | ||
| 149 | set $init_t=&init_task | ||
| 150 | set $next_t=(((char *)($init_t->tasks).next) - $tasks_off) | ||
| 151 | set var $pid_task = 0 | ||
| 152 | |||
| 153 | while ($next_t != $init_t) | ||
| 154 | set $next_t=(struct task_struct *)$next_t | ||
| 155 | |||
| 156 | if ($next_t.pid == $pid) | ||
| 157 | set $pid_task = $next_t | ||
| 158 | end | ||
| 159 | |||
| 160 | set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off) | ||
| 161 | while ($next_th != $next_t) | ||
| 162 | set $next_th=(struct task_struct *)$next_th | ||
| 163 | if ($next_th.pid == $pid) | ||
| 164 | set $pid_task = $next_th | ||
| 165 | end | ||
| 166 | set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off) | ||
| 167 | end | ||
| 168 | set $next_t=(char *)($next_t->tasks.next) - $tasks_off | ||
| 169 | end | ||
| 170 | |||
| 171 | printf "Trapno %ld, cr2 0x%lx, error_code %ld\n", $pid_task.thread.trap_no, \ | ||
| 172 | $pid_task.thread.cr2, $pid_task.thread.error_code | ||
| 173 | |||
| 174 | end | ||
| 175 | document trapinfo | ||
| 176 | Run info threads and lookup pid of thread #1 | ||
| 177 | 'trapinfo <pid>' will tell you by which trap & possibly | ||
| 178 | addresthe kernel paniced. | ||
| 179 | end | ||
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt new file mode 100644 index 000000000000..b0f412e42791 --- /dev/null +++ b/Documentation/kdump/kdump.txt | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | Documentation for kdump - the kexec-based crash dumping solution | ||
| 2 | ================================================================ | ||
| 3 | |||
| 4 | DESIGN | ||
| 5 | ====== | ||
| 6 | |||
| 7 | Kdump uses kexec to reboot to a second kernel whenever a dump needs to be taken. | ||
| 8 | This second kernel is booted with very little memory. The first kernel reserves | ||
| 9 | the section of memory that the second kernel uses. This ensures that on-going | ||
| 10 | DMA from the first kernel does not corrupt the second kernel. | ||
| 11 | |||
| 12 | All the necessary information about Core image is encoded in ELF format and | ||
| 13 | stored in reserved area of memory before crash. Physical address of start of | ||
| 14 | ELF header is passed to new kernel through command line parameter elfcorehdr=. | ||
| 15 | |||
| 16 | On i386, the first 640 KB of physical memory is needed to boot, irrespective | ||
| 17 | of where the kernel loads. Hence, this region is backed up by kexec just before | ||
| 18 | rebooting into the new kernel. | ||
| 19 | |||
| 20 | In the second kernel, "old memory" can be accessed in two ways. | ||
| 21 | |||
| 22 | - The first one is through a /dev/oldmem device interface. A capture utility | ||
| 23 | can read the device file and write out the memory in raw format. This is raw | ||
| 24 | dump of memory and analysis/capture tool should be intelligent enough to | ||
| 25 | determine where to look for the right information. ELF headers (elfcorehdr=) | ||
| 26 | can become handy here. | ||
| 27 | |||
| 28 | - The second interface is through /proc/vmcore. This exports the dump as an ELF | ||
| 29 | format file which can be written out using any file copy command | ||
| 30 | (cp, scp, etc). Further, gdb can be used to perform limited debugging on | ||
| 31 | the dump file. This method ensures methods ensure that there is correct | ||
| 32 | ordering of the dump pages (corresponding to the first 640 KB that has been | ||
| 33 | relocated). | ||
| 34 | |||
| 35 | SETUP | ||
| 36 | ===== | ||
| 37 | |||
| 38 | 1) Download http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz | ||
| 39 | and apply http://lse.sourceforge.net/kdump/patches/kexec-tools-1.101-kdump.patch | ||
| 40 | and after that build the source. | ||
| 41 | |||
| 42 | 2) Download and build the appropriate (latest) kexec/kdump (-mm) kernel | ||
| 43 | patchset and apply it to the vanilla kernel tree. | ||
| 44 | |||
| 45 | Two kernels need to be built in order to get this feature working. | ||
| 46 | |||
| 47 | A) First kernel: | ||
| 48 | a) Enable "kexec system call" feature (in Processor type and features). | ||
| 49 | CONFIG_KEXEC=y | ||
| 50 | b) This kernel's physical load address should be the default value of | ||
| 51 | 0x100000 (0x100000, 1 MB) (in Processor type and features). | ||
| 52 | CONFIG_PHYSICAL_START=0x100000 | ||
| 53 | c) Enable "sysfs file system support" (in Pseudo filesystems). | ||
| 54 | CONFIG_SYSFS=y | ||
| 55 | d) Boot into first kernel with the command line parameter "crashkernel=Y@X". | ||
| 56 | Use appropriate values for X and Y. Y denotes how much memory to reserve | ||
| 57 | for the second kernel, and X denotes at what physical address the reserved | ||
| 58 | memory section starts. For example: "crashkernel=64M@16M". | ||
| 59 | |||
| 60 | B) Second kernel: | ||
| 61 | a) Enable "kernel crash dumps" feature (in Processor type and features). | ||
| 62 | CONFIG_CRASH_DUMP=y | ||
| 63 | b) Specify a suitable value for "Physical address where the kernel is | ||
| 64 | loaded" (in Processor type and features). Typically this value | ||
| 65 | should be same as X (See option d) above, e.g., 16 MB or 0x1000000. | ||
| 66 | CONFIG_PHYSICAL_START=0x1000000 | ||
| 67 | c) Enable "/proc/vmcore support" (Optional, in Pseudo filesystems). | ||
| 68 | CONFIG_PROC_VMCORE=y | ||
| 69 | |||
| 70 | Note: Options a) and b) depend upon "Configure standard kernel features | ||
| 71 | (for small systems)" (under General setup). | ||
| 72 | Option a) also depends on CONFIG_HIGHMEM (under Processor | ||
| 73 | type and features). | ||
| 74 | Both option a) and b) are under "Processor type and features". | ||
| 75 | |||
| 76 | 3) Boot into the first kernel. You are now ready to try out kexec-based crash | ||
| 77 | dumps. | ||
| 78 | |||
| 79 | 4) Load the second kernel to be booted using: | ||
| 80 | |||
| 81 | kexec -p <second-kernel> --crash-dump --args-linux --append="root=<root-dev> | ||
| 82 | maxcpus=1 init 1" | ||
| 83 | |||
| 84 | Note: i) <second-kernel> has to be a vmlinux image. bzImage will not work, | ||
| 85 | as of now. | ||
| 86 | ii) By default ELF headers are stored in ELF32 format (for i386). This | ||
| 87 | is sufficient to represent the physical memory up to 4GB. To store | ||
| 88 | headers in ELF64 format, specifiy "--elf64-core-headers" on the | ||
| 89 | kexec command line additionally. | ||
| 90 | iii) For now (or until it is fixed), it's best to build the | ||
| 91 | second-kernel without multi-processor support, i.e., make it | ||
| 92 | a uniprocessor kernel. | ||
| 93 | |||
| 94 | 5) System reboots into the second kernel when a panic occurs. A module can be | ||
| 95 | written to force the panic, for testing purposes. | ||
| 96 | |||
| 97 | 6) Write out the dump file using | ||
| 98 | |||
| 99 | cp /proc/vmcore <dump-file> | ||
| 100 | |||
| 101 | Dump memory can also be accessed as a /dev/oldmem device for a linear/raw | ||
| 102 | view. To create the device, type: | ||
| 103 | |||
| 104 | mknod /dev/oldmem c 1 12 | ||
| 105 | |||
| 106 | Use "dd" with suitable options for count, bs and skip to access specific | ||
| 107 | portions of the dump. | ||
| 108 | |||
| 109 | Entire memory: dd if=/dev/oldmem of=oldmem.001 | ||
| 110 | |||
| 111 | ANALYSIS | ||
| 112 | ======== | ||
| 113 | |||
| 114 | Limited analysis can be done using gdb on the dump file copied out of | ||
| 115 | /proc/vmcore. Use vmlinux built with -g and run | ||
| 116 | |||
| 117 | gdb vmlinux <dump-file> | ||
| 118 | |||
| 119 | Stack trace for the task on processor 0, register display, memory display | ||
| 120 | work fine. | ||
| 121 | |||
| 122 | Note: gdb cannot analyse core files generated in ELF64 format for i386. | ||
| 123 | |||
| 124 | TODO | ||
| 125 | ==== | ||
| 126 | |||
| 127 | 1) Provide a kernel pages filtering mechanism so that core file size is not | ||
| 128 | insane on systems having huge memory banks. | ||
| 129 | 2) Modify "crash" tool to make it recognize this dump. | ||
| 130 | |||
| 131 | CONTACT | ||
| 132 | ======= | ||
| 133 | |||
| 134 | Hariprasad Nellitheertha - hari at in dot ibm dot com | ||
| 135 | Vivek Goyal (vgoyal@in.ibm.com) | ||
