crash> help bt
bt: 功能是Display a kernel stack backtrace
需要使用pid 或者 taskp,指定process,如果不指定,就是当前进程。
NAME
bt - backtrace
SYNOPSIS
bt [-a|-g|-r|-t|-T|-l|-e|-E|-f|-F|-o|-O] [-R ref] [-s [-x|d]] [-I ip] [-S sp]
[pid | task]
DESCRIPTION
Display a kernel stack backtrace. If no arguments are given, the stack
trace of the current context will be displayed.
/*-a : active task on each CPU*/
-a displays the stack traces of the active task on each CPU.
(only applicable to crash dumps)
/*-g: all threads in the thread group of the target task*/
-g displays the stack traces of all threads in the thread group of
the target task; the thread group leader will be displayed first.
/*-r: dump the 2 pages,正好是进程的栈*/
-r display raw stack data, consisting of a memory dump of the two
pages of memory containing the task_union structure.
/*-t/T: 用于当back trace 解析失败的情形*/
-t display all text symbols found from the last known stack location
to the top of the stack. (helpful if the back trace fails)
-T display all text symbols found from just above the task_struct or
thread_info to the top of the stack. (helpful if the back trace
fails or the -t option starts too high in the process stack).
/*-l: 显示文件和行号*/
-l show file and line number of each stack trace text location.
/*-e/E: what is exception frames?中断?*/
-e search the stack for possible kernel and user mode exception frames.
-E search the IRQ stacks (x86, x86_64 and ppc64), and the exception
stacks (x86_64) for possible exception frames; all other arguments
will be ignored since this is not a context-sensitive operation.
/*-f/F:display all stack data contained in a frame*/
-f display all stack data contained in a frame; this option can be
used to determine the arguments passed to each function; on ia64,
the argument register contents are dumped.
-F similar to -f, except that the stack data is displayed symbolically
when appropriate; if the stack data references a slab cache object,
the name of the slab cache will be displayed in brackets; on ia64,
the substitution is done to the argument register contents.
/*-R:?????*/
-R ref display stack trace only if there is a reference to this symbol
or text address.
/*-s/x/d:symbol name plus its offset*/
-s display the symbol name plus its offset.
-x when displaying a symbol offset with the -s option, override the
default output format with hexadecimal format.
-d when displaying a symbol offset with the -s option, override the
default output format with decimal format.
/*-I: ???*/
-I ip use ip as the starting text location.
/*-S sp use sp as the starting stack frame address.*/
-S sp use sp as the starting stack frame address.
/*指定某个process*/
pid displays the stack trace(s) of this pid.
taskp displays the stack trace the the task referenced by this hexadecimal
task_struct pointer.
Multiple pid and taskp arguments may be specified.
crash> bt -e
PID: 286 TASK: c0b3a000 CPU: 0 COMMAND: "in.rlogind"
KERNEL-MODE EXCEPTION FRAME AT c0b3bf44:
EAX: 00000000 EBX: c0e68280 ECX: 00000000 EDX: 00000004 EBP: c0b3bfbc
DS: 0018 ESI: 00000004 ES: 0018 EDI: c0e68284
CS: 0010 EIP: c012f803 ERR: ffffff09 EFLAGS: 00000246
USER-MODE EXCEPTION FRAME AT c0b3bfc4:
EAX: 0000008e EBX: 00000004 ECX: bfffc9a0 EDX: 00000000
DS: 002b ESI: bfffc8a0 ES: 002b EDI: 00000000
SS: 002b ESP: bfffc82c EBP: bfffd224
CS: 0023 EIP: 400d032e ERR: 0000008e EFLAGS: 00000246
crash> bt
PID: 1320 TASK: e6915be0 CPU: 0 COMMAND: "sh"
#0 [<c01e1a1c>] (sysrq_handle_crash) from [<c01e215c>]
#1 [<c01e20b4>] (__handle_sysrq) from [<c01e2238>]
#2 [<c01e220c>] (write_sysrq_trigger) from [<c00f2a50>]
#3 [<c00f29b8>] (proc_reg_write) from [<c00ad9c4>]
#4 [<c00ad910>] (vfs_write) from [<c00adb14>]
#5 [<c00adad4>] (sys_write) from [<c000df00>]
pc : [<400f9d94>] lr : [<400ad257>] psr: 20000010
sp : beca68e0 ip : 400c2f38 fp : 400c7404
r10: 40a37e94 r9 : 00000000 r8 : 40a36c04
r7 : 00000004 r6 : 00000001 r5 : 00000002 r4 : 00000003
r3 : ffffffff r2 : 00000002 r1 : 40a36c04 r0 : 00000001
Flags: nzCv IRQs on FIQs on Mode USER_32 ISA ARM
crash> bt -r
stack 的低地址是thread_info,栈的大小为8K 从高地址开始存放。
PID: 1320 TASK: e6915be0 CPU: 0 COMMAND: "sh"
e6364000: 00000000 00000000 bf000000 e6915be0
e6364010: default_exec_domain 00000000 00000015 c0e4f360
e6364020: e6915be0 e6364000 00000000 e6333be0
e6364030: 00000000 init_task e6365cac e6365c80
e6364040: __schedule+1008 00000000 00000000 00000000
----
crash> bt -S e6365ec8
crash> log | grep -10 "PC is"
pll0 clock rate set to 400000000.
CPU1: platform_cpu_die
CPU1: shutdown
SysRq : Trigger a crash
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = e6398000
[00000000] *pgd=00000000
Internal error: Oops: 805 [#1] SMP ARM
Modules linked in:
CPU: 0 Not tainted (3.4.0-g40efdaf-dirty #5)
PC is at sysrq_handle_crash+0x38/0x48
LR is at l2x0_cache_sync+0x34/0x3c
pc : [<c01e1a50>] lr : [<c0019c74>] psr: 60000093
sp : e6365ec8 ip : e6365eb0 fp : e6365ed4
r10: e6bb4bec r9 : e6364000 r8 : 00000000
r7 : 60000013 r6 : 00000063 r5 : 00000004 r4 : c0701718
r3 : 00000000 r2 : 00000001 r1 : a0000093 r0 : c07220c0
Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c53c7d Table: a639804a DAC: 00000015
PC: 0xc01e19d0:
crash> bt -S e6365ec8
PID: 1320 TASK: e6915be0 CPU: 0 COMMAND: "sh"
#0 [<c01e1a1c>] (sysrq_handle_crash) from [<c01e215c>]
#1 [<c01e20b4>] (__handle_sysrq) from [<c01e2238>]
#2 [<c01e220c>] (write_sysrq_trigger) from [<c00f2a50>]
#3 [<c00f29b8>] (proc_reg_write) from [<c00ad9c4>]
#4 [<c00ad910>] (vfs_write) from [<c00adb14>]
#5 [<c00adad4>] (sys_write) from [<c000df00>]
pc : [<400f9d94>] lr : [<400ad257>] psr: 20000010
sp : beca68e0 ip : 400c2f38 fp : 400c7404
r10: 40a37e94 r9 : 00000000 r8 : 40a36c04
r7 : 00000004 r6 : 00000001 r5 : 00000002 r4 : 00000003
r3 : ffffffff r2 : 00000002 r1 : 40a36c04 r0 : 00000001
Flags: nzCv IRQs on FIQs on Mode USER_32 ISA ARM
有关bt -f/F的细节
r15PC The Program Counter.
r14LR The Link Register.
r12IP The Intra-Procedure-call scratch register. (可简单的认为暂存SP)
实际上,还有一个r11是optional的,被称为FP,即framepointer。
structstackframe {
unsignedlong fp;
unsignedlong sp;
unsignedlong lr;
unsignedlong pc;
};
一般函数的开头都是:
crash> dis vfp_restore_user_hwstate
0xc0008df0 <vfp_restore_user_hwstate>: mov r12, sp
0xc0008df4 <vfp_restore_user_hwstate+0x4>: push {r3, r4, r5, r6, r11, r12, lr, pc}
以该帧为例说明帧头的意思:
#0 [<c0560fa4>] (__raw_spin_lock_irqsave) from [<c056105c>]
[PC: c0560fa4 LR: c056105c SP: c97e1c78 FP: c97e1c9c SIZE: 24]
c97e1c78: 00000004 0000000c c97e1c9c c97e1c90
c97e1c88: c056105c c0560fac
SP:意思是该函数栈结束的地址【从高地址到低地址存放】,如
[PC: c0560fa4 LR: c056105c SP: c97e1c78
c97e1c78: 00000004 ----
PC:函数的入口地址+4, 如
[PC: c0560fa4 LR: c056105c SP: c97e1c78
crash> dis __raw_spin_lock_irqsave
0xc0560fa0 <__raw_spin_lock_irqsave>: mov r12, sp
0xc0560fa4 <__raw_spin_lock_irqsave+0x4>: push {r4, r5, r11, r12
LR:函数被调用后,返回到哪里,或者说哪里调用了该函数
[PC: c0560fa4 LR: c056105c SP: c97e1c78
crash> dis c056105c -r
0xc0561044 <_raw_spin_lock_irqsave>: mov r12, sp
0xc0561048 <_raw_spin_lock_irqsave+0x4>: push {r11, r12, lr, pc}
0xc056104c <_raw_spin_lock_irqsave+0x8>: sub r11, r12, #4
0xc0561050 <_raw_spin_lock_irqsave+0xc>: stmfd sp!, {lr}
0xc0561054 <_raw_spin_lock_irqsave+0x10>: ldmfd sp!, {lr}
0xc0561058 <_raw_spin_lock_irqsave+0x14>: bl 0xc0560fa0 <__raw_spin_lock_irqsave>
0xc056105c <_raw_spin_lock_irqsave+0x18>: ldm sp, {r11, sp, pc}
FP:
[PC: c0560fa4 LR: c056105c SP: c97e1c78 FP: c97e1c9c SIZE: 24]
crash> rd c97e1c9c【fp的内容是前一帧的PC值(保存在栈里的)】
c97e1c9c: c0561050
保存在栈里的内容:
从高地址开始依次是 PC/LR/SP/FP 4个寄存器
这里PC的内容是当前+8,也就是函数开始+12,LR是函数的返回地址,或者说哪里调用的这个函数
其他的就看什么入栈了。