Linux核心panic到ramdump基本流程
阿新 • • 發佈:2019-02-10
Linux核心空指標訪問異常大致流程
插一下arm系統模式切換說明/* arm處理有很多模式,暫存器也有各個模式下專用和通用的暫存器 當從使用者態等切入異常模式的時候,cpsr會發生切換,pc指標強制指向對應異常向量地址。 彙編程式碼vector_\name處理時會從異常模式切到svc模式,不然一些暫存器不是通用的,回不去。 vector_\name: .if \correction sub lr, lr, #\correction .endif @ @ Save r0, lr_<exception> (parent PC) and spsr_<exception> @ (parent CPSR) @ stmia sp, {r0, lr} @ save r0, lr mrs lr, spsr str lr, [sp, #8] @ save spsr @ @ Prepare for SVC32 mode. IRQs remain disabled. @ mrs r0, cpsr eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE) msr spsr_cxsf, r0 之後進入對應異常處理,同時保持異常之前模式下的暫存器,sp等資訊,r0和lr在上面的程式碼已經儲存到堆疊了。 .macro usr_entry UNWIND(.fnstart ) UNWIND(.cantunwind ) @ don't unwind the user space sub sp, sp, #S_FRAME_SIZE ARM( stmib sp, {r1 - r12} ) 之後處理完成時,恢復這些暫存器資訊,跳轉pc,回到異常之前。 */
先看下異常向量表的定義,感覺很繞
early_trap_init
#define CONFIG_VECTORS_BASE 0xffff0000 early_trap_init((void *)CONFIG_VECTORS_BASE); memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
先看一個巨集定義vector_stub 引數是name mode第三個應該是為b指令手動設定返回地址的
這塊的解釋借用別人的用下https://www.cnblogs.com/yangjiguang/p/7629928.html
參考https://blog.csdn.net/forever_2015/article/details/53235716?locationNum=6&fps=1
.macro vector_stub, name, mode, correction=0 .align 5 vector_\name: .if \correction sub lr, lr, #\correction .endif @ @ Save r0, lr_<exception> (parent PC) and spsr_<exception> @ (parent CPSR) @ stmia sp, {r0, lr} @ save r0, lr mrs lr, spsr str lr, [sp, #8] @ save spsr @ @ Prepare for SVC32 mode. IRQs remain disabled. @ mrs r0, cpsr eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE) msr spsr_cxsf, r0 @ @ the branch table must immediately follow this code @ and lr, lr, #0x0f THUMB( adr r0, 1f ) THUMB( ldr lr, [r0, lr, lsl #2] ) mov r0, sp ARM( ldr lr, [pc, lr, lsl #2] ) movs pc, lr @ branch to handler in SVC mode ENDPROC(vector_\name)
.equ stubs_offset, __vectors_start + 0x200 - __stubs_start
__vectors_start:
ARM( swi SYS_ERROR0 )
THUMB( svc #0 )
THUMB( nop )
W(b) vector_und + stubs_offset
W(ldr) pc, .LCvswi + stubs_offset
W(b) vector_pabt + stubs_offset
W(b) vector_dabt + stubs_offset
W(b) vector_addrexcptn + stubs_offset
W(b) vector_irq + stubs_offset
W(b) vector_fiq + stubs_offset
.globl __vectors_end
__vectors_end:
__stubs_start:
......
/*
* Data abort dispatcher
* Enter in ABT mode, spsr = USR CPSR, lr = USR PC
*/
vector_stub dabt, ABT_MODE, 8
.long __dabt_usr @ 0 (USR_26 / USR_32)
.long __dabt_invalid @ 1 (FIQ_26 / FIQ_32)
.long __dabt_invalid @ 2 (IRQ_26 / IRQ_32)
.long __dabt_svc @ 3 (SVC_26 / SVC_32)
.long __dabt_invalid @ 4
.long __dabt_invalid @ 5
.long __dabt_invalid @ 6
.long __dabt_invalid @ 7
.long __dabt_invalid @ 8
.long __dabt_invalid @ 9
.long __dabt_invalid @ a
.long __dabt_invalid @ b
.long __dabt_invalid @ c
.long __dabt_invalid @ d
.long __dabt_invalid @ e
.long __dabt_invalid @ f
......
.globl __stubs_end
__stubs_end:
最後會跳轉到__dabt_svc-->dabt_helper
bl CPU_DABORT_HANDLER
ENTRY(v7_early_abort)
mrc p15, 0, r1, c5, c0, 0 @ get FSR
mrc p15, 0, r0, c6, c0, 0 @ get FAR
/*
* V6 code adjusts the returned DFSR.
* New designs should not need to patch up faults.
*/
#if defined(CONFIG_VERIFY_PERMISSION_FAULT)
/*
* Detect erroneous permission failures and fix
*/
ldr r3, =0x40d @ On permission fault
and r3, r1, r3
cmp r3, #0x0d
bne do_DataAbort
mcr p15, 0, r0, c7, c8, 0 @ Retranslate FAR
isb
mrc p15, 0, ip, c7, c4, 0 @ Read the PAR
and r3, ip, #0x7b @ On translation fault
cmp r3, #0x0b
bne do_DataAbort
bic r1, r1, #0xf @ Fix up FSR FS[5:0]
and ip, ip, #0x7e
orr r1, r1, ip, LSR #1
#endif
b do_DataAbort
ENDPROC(v7_early_abort)
do_DataAbort
static struct fsr_info fsr_info[] = {
/*
* The following are the standard ARMv3 and ARMv4 aborts. ARMv5
* defines these to be "precise" aborts.
*/
{ do_bad, SIGSEGV, 0, "vector exception" },
{ do_bad, SIGBUS, BUS_ADRALN, "alignment exception" },
{ do_bad, SIGKILL, 0, "terminal exception" },
{ do_bad, SIGBUS, BUS_ADRALN, "alignment exception" },
{ do_bad, SIGBUS, 0, "external abort on linefetch" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" },
{ do_bad, SIGBUS, 0, "external abort on linefetch" },
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
{ do_bad, SIGBUS, 0, "external abort on non-linefetch" },
{ do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" },
{ do_bad, SIGBUS, 0, "external abort on non-linefetch" },
{ do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault" },
{ do_bad, SIGBUS, 0, "external abort on translation" },
{ do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" },
{ do_bad, SIGBUS, 0, "external abort on translation" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" },
/*
* The following are "imprecise" aborts, which are signalled by bit
* 10 of the FSR, and may not be recoverable. These are only
* supported if the CPU abort handler supports bit 10.
*/
{ do_bad, SIGBUS, 0, "unknown 16" },
{ do_bad, SIGBUS, 0, "unknown 17" },
{ do_bad, SIGBUS, 0, "unknown 18" },
{ do_bad, SIGBUS, 0, "unknown 19" },
{ do_bad, SIGBUS, 0, "lock abort" }, /* xscale */
{ do_bad, SIGBUS, 0, "unknown 21" },
{ do_bad, SIGBUS, BUS_OBJERR, "imprecise external abort" }, /* xscale */
{ do_bad, SIGBUS, 0, "unknown 23" },
{ do_bad, SIGBUS, 0, "dcache parity error" }, /* xscale */
{ do_bad, SIGBUS, 0, "unknown 25" },
{ do_bad, SIGBUS, 0, "unknown 26" },
{ do_bad, SIGBUS, 0, "unknown 27" },
{ do_bad, SIGBUS, 0, "unknown 28" },
{ do_bad, SIGBUS, 0, "unknown 29" },
{ do_bad, SIGBUS, 0, "unknown 30" },
{ do_bad, SIGBUS, 0, "unknown 31" },
};
//硬體斷點異常捕獲
hook_fault_code(FAULT_CODE_DEBUG, hw_breakpoint_pending, SIGTRAP,TRAP_HWBKPT, "watchpoint debug exception");
if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs)) 這裡根據異常的標誌,找到對應的hook函式執行。
do_translation_fault
do_page_fault
__do_page_fault
__do_kernel_fault
die("Oops", regs, fsr);
if (in_interrupt())
panic("Fatal exception in interrupt");
if (panic_on_oops)
panic("Fatal exception");
if (ret != NOTIFY_STOP)
do_exit(SIGSEGV);
void panic(const char *fmt, ...)
__die dump執行緒stack和暫存器
local_irq_disable(); 鎖中斷
dump_stack(); 列印堆疊,防止二次panic
if (panic_timeout != 0) { 選擇是否重啟裝置
/*
* This will not be a clean reboot, with everything
* shutting down. But if there is a chance of
* rebooting the system it will be rebooted.
*/
emergency_restart();
}
不重啟進入ramdump流程
ramdump_entry()
dump出ap的ddr空間,需要的裝置暫存器資訊,通過usb的內部dma控制器寫出去
應用coredump參考https://blog.csdn.net/omnispace/article/details/77600721
處理器提供專門斷點暫存器儲存一個地址,處理器在執行程式過程,會不斷去匹配,可以設定成不同的模式來觸發程式中斷,如執行到這個地址,讀這個地址或寫這個地址, 並且可以設定長度,按8位,16位,或32位來觸發。和軟體斷點比,好處是可以支援讀寫斷點,程式斷點不需要改寫記憶體,可以設在ROM中,在虛擬地址對映前也可設定等等。
軟硬體斷點參考https://blog.csdn.net/sxw1002/article/details/77169610