0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

kernel panic流程分析

CHANBAEK ? 來源:人人極客社區(qū) ? 作者:Hilbert ? 2023-01-19 16:14 ? 次閱讀

我們在項目開發(fā)過程中,很多時候會出現(xiàn)由于某種原因經(jīng)常會導(dǎo)致手機(jī)系統(tǒng)死機(jī)重啟的情況(重啟分Android重啟跟kernel重啟,而我們這里只討論kernel重啟也就是 kernel panic 的情況),死機(jī)重啟基本算是影響最嚴(yán)重的系統(tǒng)問題了,有穩(wěn)定復(fù)現(xiàn)的,也有概率出現(xiàn)的,解題難度也千差萬別,出現(xiàn)問題后,通常我們會拿到類似這樣的kernel log信息(下面log僅以調(diào)用BUG()為例,其它異常所致的死機(jī)log信息會有一些不同之處):

[    2.052157] <2>-(2)[1:swapper/0]------------[ cut here ]------------
[    2.052163] <2>-(2)[1:swapper/0]Kernel BUG at c04289dc [verbose debug info unavailable]
[    2.052169] <2>-(2)[1:swapper/0]Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM
[    2.052178] <2>-(2)[1:swapper/0]disable aee kernel api[    3.052192] <2>-(2)[1:swapper/0]Non-crashing CPUs did not react to IPI
[    3.052204] <2>-(2)[1:swapper/0]CPU: 2 PID: 1 Comm: swapper/0 Tainted: G        W      3.18.35+ #3
[    3.052211] <2>-(2)[1:swapper/0]task: df060000 ti: df04a000 task.ti: df04a000
[    3.052227] <2>-(2)[1:swapper/0]PC is at ltr553_i2c_probe+0x94/0x9c
[    3.052233] <2>-(2)[1:swapper/0]LR is at 0x0
[    3.052242] <2>-(2)[1:swapper/0]pc : []    lr : [<00000000>]    psr: a0000113
[    3.052242] <2>sp : df04bd30  ip : 00000000  fp : df04bd4c
[    3.052249] <2>-(2)[1:swapper/0]r10: 00000003  r9 : de348fc0  r8 : c0428948
[    3.052255] <2>-(2)[1:swapper/0]r7 : dea1bc00  r6 : dea1bc04  r5 : dea1bc20  r4 : c0b53358
[    3.052262] <2>-(2)[1:swapper/0]r3 : c115ef4c  r2 : 00000000  r1 : 00000000  r0 : de366a00
[    4.354655] <2>-(2)[1:swapper/0] oops_end, 1, 11
[    4.354740] <2>-(2)[1:swapper/0]Kernel panic - not syncing: Fatal exception

這是linux 內(nèi)核在死機(jī)之前輸出的相關(guān)重要信息,包括PC指針、調(diào)用棧等在內(nèi)的非常重要的便于Debug的線索,比如我們可以借助GUN tools(add2Line)工具結(jié)合內(nèi)核符號映射表vmlinux來定位當(dāng)前PC指針?biāo)诘拇a具體行數(shù)(定位到出錯代碼行并不意味著就找到了問題的根本原因跟修復(fù)異常,這個需要根據(jù)異常的復(fù)雜程度而論)。深入理解這些關(guān)鍵打印log信息的含義和機(jī)制非常有助于我們對于此類死機(jī)問題的定位和分析(對于內(nèi)存被踩、硬件不穩(wěn)定導(dǎo)致的一類問題分析有局限性),這也是我們需要深入學(xué)習(xí)內(nèi)核異常流程的初衷。

這里我們必須弄清楚幾個問題:

  • 這些死機(jī)前留下的關(guān)鍵register信息是怎么來的,有什么用,具體含義是什么?
  • 如何利用這些遺留的線索找到出問題代碼具體在哪支文件,在哪一行?
  • 內(nèi)核發(fā)生致命異常到死機(jī)的總流程是怎樣的,類似死機(jī)問題應(yīng)該如何著手分析?

為此,本文就從最常見的主動觸發(fā)BUG()為例解析上面的疑問及分析整個kernel panic流程。

什么是BUG() ?

有過驅(qū)動調(diào)試經(jīng)驗的人肯定都知道這個東西,這里的BUG跟我們一般認(rèn)為的“軟件缺陷”可不是一回事,這里說的BUG()其實是linux kernel中用于攔截內(nèi)核程序超出預(yù)期的行為,屬于軟件主動匯報異常的一種機(jī)制。這里有個疑問,就是什么時候會用到呢?一般來說有兩種用到的情況,一是軟件開發(fā)過程中,若發(fā)現(xiàn)代碼邏輯出現(xiàn)致命fault后就可以調(diào)用BUG()讓kernel死掉(類似于assert),這樣方便于定位問題,從而修正代碼執(zhí)行邏輯;另外一種情況就是,由于某種特殊原因(通常是為了debug而需抓ramdump),我們需要系統(tǒng)進(jìn)入kernel panic的情況下使用。

BUG()跟BUG_ON(1)其實本質(zhì)是一回事,后者只是在前者的基礎(chǔ)上做了簡單的封裝而已,BUG()的實現(xiàn) 本質(zhì)是埋入一條未定義指令:0xe7f001f2,觸發(fā)ARM發(fā)起Undefined Instruction異常(PS:ARM有分10種異常類型,詳細(xì)可以復(fù)習(xí)ARM異常模型章節(jié))。

-3.18/arch/arm/include/asm/bug.h>
#define BUG_INSTR_VALUE 0xe7f001f2
#define BUG_INSTR(__value) __inst_arm(__value)
#define BUG() _BUG(__FILE__, __LINE__, BUG_INSTR_VALUE)
#define _BUG(file, line, value) __BUG(file, line, value)
#define __BUG(__file, __line, __value)    \\
do {        \\
 asm volatile(BUG_INSTR(__value) "\\n");   \\
 unreachable();      \\
} while (0)

BUG() 流程分析

BUG()到系統(tǒng)重啟的總流程圖:

圖片

調(diào)用BUG()會向CPU下發(fā)一條未定義指令而觸發(fā)ARM發(fā)起未定義指令異常,隨后進(jìn)入kernel異常處理流程歷經(jīng) Oops,die(),__die()等流程輸出用于調(diào)試分析的關(guān)鍵線索,最后進(jìn)入panic()結(jié)束自己再獲得重生的過程,這個就是整個過程的基本流程,下面先來看die()具體做了什么呢?

die() 流程

源碼:

void die(const char *str, struct pt_regs *regs, int err)
{
 enum bug_trap_type bug_type = BUG_TRAP_TYPE_NONE;
 unsigned long flags = oops_begin();
 int sig = SIGSEGV;
 
 if (!user_mode(regs))
  bug_type = report_bug(regs->ARM_pc, regs);
 if (bug_type != BUG_TRAP_TYPE_NONE)
  str = "Oops - BUG";
 if (__die(str, err, regs))
  sig = 0;
 oops_end(flags, regs, sig);
}

總流程大致如下:

圖片

通常來說,代碼分析過程結(jié)合kernel log一起看會理解來得更加深刻,如果是BUG()/BUG_ON(1)導(dǎo)致的異常,那么走到report_bug 就可以看到下面標(biāo)志性 log:

enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) 
{
...
 if (!is_valid_bugaddr(bugaddr))
  return BUG_TRAP_TYPE_NONE;
...
 printk(KERN_DEFAULT "------------[ cut here ]------------\\n");
 if (file)
  pr_crit("kernel BUG at %s:%u!\\n", file, line);
 else
  pr_crit("Kernel BUG at %p [verbose debug info unavailable]\\n",
   (void *)bugaddr);
 
===>
[    2.052157] <2>-(2)[1:swapper/0]------------[ cut here ]------------
[    2.052163] <2>-(2)[1:swapper/0]Kernel BUG at c04289dc [verbose debug info unavailable]
[    2.052169] <2>-(2)[1:swapper/0]Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM

所以如果在log中看到了這個 “[ cut here ]” 的信息就推斷是軟件發(fā)生致命fault而主動call了BUG()所致的系統(tǒng)重啟了,就可以根據(jù)相關(guān)信息嘗試定位分析修復(fù)異常了.這里要注意的是還有另外一種__WARN()的情況也會打印出 “[ cut here ]” 的標(biāo)志性log但是內(nèi)核并不會掛掉,容易造成誤導(dǎo):

#define __WARN()    warn_slowpath_null(__FILE__, __LINE__)
#define __WARN_printf(arg...) warn_slowpath_fmt(__FILE__, __LINE__, arg)
void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
{
...
 warn_slowpath_common(file, line, __builtin_return_address(0),
        TAINT_WARN, &args);
static void warn_slowpath_common(const char *file, int line, void *caller,
     unsigned taint, struct slowpath_args *args)
{
...
 pr_warn("------------[ cut here ]------------\\n");
 pr_warn("WARNING: CPU: %d PID: %d at %s:%d %pS()\\n",
  raw_smp_processor_id(), current->pid, file, line, caller);
 
===>
[    1.106219] <2>-(2)[1:swapper/0]------------[ cut here ]------------
[    1.107018] <2>-(2)[1:swapper/0]WARNING: CPU: 2 PID: 1 at /home/android/work/prj/n-6580/kernel-3.18/kernel/irq/manage.c:454 __enable_irq+0x50/0x8c()

所以其實從顯現(xiàn)上很好區(qū)分兩種情況,如果是BUG()/BUG_ON(1)那么內(nèi)核一定會掛掉重啟,而__WARN()只會dump_stack()而不會死機(jī), 從源碼跟log信息也可以容易區(qū)分兩種情況,如果是BUG()/BUG_ON(1)的話一定有類似下面的log輸出,只要搜索關(guān)鍵字:“Internal error: Oops” 即可。

[    2.052163] <2>-(2)[1:swapper/0]Kernel BUG at c04289dc [verbose debug info unavailable]
[    2.052169] <2>-(2)[1:swapper/0]Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM

__die() 流程分析

從上面輸出的log信息還不足以定位具體出問題的代碼位置,包括定位異常所需要的最關(guān)鍵的 PC指針、調(diào)用棧等這些對于調(diào)試來說至關(guān)重要的線索信息都是在__die()中輸出。

流程圖:

圖片

打印出標(biāo)志性log信息:

static int __die(const char *str, int err, struct pt_regs *regs)
{
...
 printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP
        S_ISA "\\n", str, err, ++die_counter);
===>
[    2.052169] <2>-(2)[1:swapper/0]Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM

log 顯示異常str是Oops - BUG,error-code 為0,die計數(shù)器次數(shù):1

Oops 的本意為 “哎呀” 的一個俚語,這里意形象的意指kernel出現(xiàn)了一件意外而不知道該如何處理的事件。

notify_die() 會通知對Oops感興趣的模塊執(zhí)行相關(guān)回調(diào),比如mtk的aee異常引擎模塊就是通過注冊到die_chain通知鏈上的。

int notrace notify_die(enum die_val val, const char *str,
        struct pt_regs *regs, long err, int trap, int sig)
{
 struct die_args args = {
  .regs = regs,
  .str = str,
  .err = err,
  .trapnr = trap,
  .signr = sig,
 };
 return atomic_notifier_call_chain(&die_chain, val, &args);
}

mtk的aee異常引擎在kernel初始化的時候會去注冊到die_chain通知鏈,而且我們可以看到其實還注冊了panic通知鏈。

int __init aee_ipanic_init(void)
{
 spin_lock_init(&ipanic_lock);
 mrdump_init();
 atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
 register_die_notifier(&die_blk);
 register_ipanic_ops(&ipanic_oops_ops);
 ipanic_log_temp_init();
 ipanic_msdc_init();
 LOGI("ipanic: startup, partition assgined %s\\n", AEE_IPANIC_PLABEL);
 return 0;
}

而對我們調(diào)試追蹤有用的關(guān)鍵信息是在 __show_regs() 里面打印的:

void __show_regs(struct pt_regs *regs)
{
 unsigned long flags;
 char buf[64];
 
 show_regs_print_info(KERN_DEFAULT);
 print_symbol("PC is at %s\\n", instruction_pointer(regs));
 print_symbol("LR is at %s\\n", regs->ARM_lr);
 printk("pc : [<%08lx>]    lr : [<%08lx>]    psr: %08lx\\n"
        "sp : %08lx  ip : %08lx  fp : %08lx\\n",
  regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr,
  regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
 printk("r10: %08lx  r9 : %08lx  r8 : %08lx\\n",
  regs->ARM_r10, regs->ARM_r9,
  regs->ARM_r8);
 printk("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\\n",
  regs->ARM_r7, regs->ARM_r6,
  regs->ARM_r5, regs->ARM_r4);
 printk("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\\n",
  regs->ARM_r3, regs->ARM_r2,
  regs->ARM_r1, regs->ARM_r0);
 flags = regs->ARM_cpsr;
 buf[0] = flags & PSR_N_BIT ? 'N' : 'n';
 buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';
 buf[2] = flags & PSR_C_BIT ? 'C' : 'c';
 buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
 buf[4] = '\\0';
 printk("Flags: %s  IRQs o%s  FIQs o%s  Mode %s  ISA %s  Segment %s\\n",
  buf, interrupts_enabled(regs) ? "n" : "ff",
  fast_interrupts_enabled(regs) ? "n" : "ff",
  processor_modes[processor_mode(regs)],
  isa_modes[isa_mode(regs)],
  get_fs() == get_ds() ? "kernel" : "user");
 show_extra_register_data(regs, 128);
}
void dump_stack_print_info(const char *log_lvl)
{
 printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\\n",
        log_lvl, raw_smp_processor_id(), current->pid, current->comm,
        print_tainted(), init_utsname()->release,
        (int)strcspn(init_utsname()->version, " "),
        init_utsname()->version);
...

這里打印出了重要的pc停下的位置、相關(guān)寄存器信息,發(fā)生的是user還是kernel的異常、發(fā)生異常的cpu、進(jìn)程pid等信息。

圖片

接下來 dump_mem() 用于dump出當(dāng)前線程的內(nèi)存信息:

dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp,
 THREAD_SIZE + (unsigned long)task_stack_page(tsk));

使用 dump_backtrace(regs, tsk) 打印出調(diào)試最直觀的調(diào)用棧信息:

[    3.056363] <2>-(2)[1:swapper/0]Backtrace: -(2)[1:swapper/0]
[ 3.056386] <2>-(2)[1:swapper/0][] (dump_backtrace) from [] (show_stack+0x18/0x1c) [ 3.056393] <2>-(2)[1:swapper/0] r6:c103d790-(2)[1:swapper/0] r5:ffffffff-(2)[1:swapper/0] r4:00000000-(2)[1:swapper/0] r3:00000000-(2)[1:swapper/0] [ 3.056426] <2>-(2)[1:swapper/0][] (show_stack) from [] (dump_stack+0x90/0xa4) [ 3.056439] <2>-(2)[1:swapper/0][] (dump_stack) from [] (ipan6503] <2>-(2)[1:swapper/0][] (notifier_call_chain) from [] (atomic_notifier_call_chain+0x3c/0x50) [ 3.056509] <2>-(2)[1:swapper/0] r10:c10efec4-(2)[1:swapper/0] r9:df060000-(2)[1:swapper/0] r8:df04a020-(2)[1:swapper/0] r7:c0caaaf0-(2)[1:swapper/0] r6:c10f0c88-(2)[1:swapper/0] r5:00000001 [ 3.056539] <2>-(2)[1:swapper/0] r4:df04bb74-(2)[1:swapper/0] [ 3.056554] <2>-(2)[1:swapper/0][] (atomic_notifier_call_chain) from [] (notify_die+0x44/0x4c) [ 3.056560] <2>-(2)[1:swapper/0] r6:df04bce8-(2)[1:swapper/0] r5:00000000-(2)[1:swapper/0] r4:00000001-(2)[1:swapper/0] [ 3.056585] <2>-(2)[1:swapper/0][] (notify_die) from [] (die+0x114/0x41c) [ 3.056590] <2>-(2)[1:swapper/0] r4:c102826c-(2)[1:swapper/0] [ 3.056607] <2>-(2)[1:swapper/0][] (die) from [] (arm_notify_die+0x24/0x5c) [ 3.056612] <2>-(2)[1:swapper/0] r10:df04a000-(2)[1:swapper/0] r9:00000000-(2)[1:swapper/0] r8:df04bce8-(2)[1:swapper/0] r7:e7f001f2-(2)[1:swapper/0] r6:df04a000-(2)[1:swapper/0] r5:c04289dc [ 3.056642] <2>-(2)[1:swapper/0] r4:00000004-(2)[1:swapper/0] [ 3.056658] <2>-(2)[1:swapper/0][] (arm_notify_die) from [] (do_undefinstr+0x1a4/0x1ec) [ 3.056670] <2>-(2)[1:swapper/0][] (do_undefinstr) from [] (__und_svc_finish+0x0/0x34) [ 3.056676] <2>-(2)[1:swapper/0]Exception stack(0xdf04bce8 to 0xdf04bd30) [ 3.056687] <2>-(2)[1:swapper/0]bce0: de366a00 00000000 00000000 c115ef4c c0b53358 dea1bc20 [ 3.056698] <2>-(2)[1:swapper/0]bd00: dea1bc04 dea1bc00 c0428948 de348fc0 00000003 df04bd4c 00000000 df04bd30 [ 3.056706] <2>-(2)[1:swapper/0]bd20: 00000000 c04289dc a0000113 ffffffff [ 3.056711] <2>-(2)[1:swapper/0] r9:c010c98c-(2)[1:swapper/0] r8:e7100000-(2)[1:swapper/0] r7:00000000-(2)[1:swapper/0] r6:c010cd98-(2)[1:swapper/0] r5:00000000-(2)[1:swapper/0] r4:c04289e0 [ 3.056750] <2>-(2)[1:swapper/0][] (ltr553_i2c_probe) from [] (i2c_device_probe+0xd0/0x12c) [ 3.056756] <2>-(2)[1:swapper/0] r5:dea1bc20-(2)[1:swapper/0] r4:c0b53358-(2)[1:swapper/0] [ 3.056778] <2>-(2)[1:swapper/0][] (i2c_device_probe) from [] (driver_probe_device+0x160/0x43c)

通過上面的調(diào)用棧信息結(jié)合GUN Tools(add2Line)基本就可以定位發(fā)生異常的具體代碼位置了。

最后會通過dump_instr(KERN_EMERG, regs) 打印出pc指針和前4條指令:

static void dump_instr(const char *lvl, struct pt_regs *regs)
{
...
 for (i = -4; i < 1 + !!thumb; i++) {
  unsigned int val, bad;
  if (thumb)
   bad = __get_user(val, &((u16 *)addr)[i]);
  else
   bad = __get_user(val, &((u32 *)addr)[i]);
  if (!bad)
   p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ", width, val);
  else {
   p += sprintf(p, "bad PC value");
   break;
  }
 }
 printk("%sCode: %s\\n", lvl, str);
..
===>
[    3.226706] <2>-(2)[1:swapper/0][] (/0]Code: e89da830 e30e3f4c e34c3115 e5830000 (e7f001f2)

看到這個 e7f001f2 了吧,是不是很眼熟?這個就是BUG()中埋入的未定義指令!

到這一步,大部分關(guān)鍵信息都已經(jīng)輸出了,可以通過add2Line工具定位出具體死在的代碼行號,大致看看發(fā)生了什么,如果是BUG()導(dǎo)致的異常,那么就可以考慮分析和修復(fù)異常了,因為BUG()屬于主動匯報異常,一般來說debug難度會相對其它的被動上報方式容易得多.

例如:

從上面log知PC死在的地址,通過add2Line工具結(jié)合內(nèi)核符號映射表 vmlinux 就可以定位出具體代碼所在文件行號:

arm-linux-androideabi-addr2line -e out/target/product/$project/obj/KERNEL_OBJ/vmlinux -f -C c04289dc
ltr553_i2c_probe
/aosp/kernel-3.18/drivers/misc/mediatek/alsps/ltr553/ltr553.c:3278

定位到了具體代碼行號就可以進(jìn)一步分析代碼log找出問題原因修復(fù)異常了(一般來說BUG()導(dǎo)致的異常比較好解,其它的情況難度就是天差地別了..)。 那么接下來kernel要干什么呢?重要信息都輸出完了接下來就直接走 kernel panic 流程了.

panic 流程

panic 本意是“恐慌”的意思,這里意旨kernel發(fā)生了致命錯誤導(dǎo)致無法繼續(xù)運行下去的情況。

流程圖:

圖片

最后附上總時序圖:

圖片

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Android
    +關(guān)注

    關(guān)注

    12

    文章

    3949

    瀏覽量

    128494
  • BUG
    BUG
    +關(guān)注

    關(guān)注

    0

    文章

    156

    瀏覽量

    15786
  • Kernel
    +關(guān)注

    關(guān)注

    0

    文章

    48

    瀏覽量

    11347
收藏 人收藏

    評論

    相關(guān)推薦

    掛載文件系統(tǒng)出現(xiàn)"kernel panic..." 史上最全解決方案

    defaults...Kernel panic - not syncing: No init found.Try passing init=optionto kernel. bootargs為
    發(fā)表于 08-01 16:31

    qualcomm平臺的Little Kernel啟動流程

    1、前言這篇文章介紹了msm8916平臺的Little Kernel(LK)的啟動流程。Little Kernel的作用是在啟動的時候初始化硬件,從存儲器中載入Linux內(nèi)核和ramdisk到RAM
    發(fā)表于 09-25 15:42

    kernel移植報錯

    最近移植4.14的內(nèi)核,燒到開發(fā)板中出現(xiàn)如下錯誤:---[ end trace 1c64f040d891693a ]---Kernel panic - not syncing: Attempted
    發(fā)表于 02-25 15:51

    Kernel panic - not syncing: No init found

    我按韋老師的教學(xué)視頻制作UBOOT\KERNEL,走了整個流程,最后甚至把老師的補(bǔ)丁拿來直接使用,只有文件系統(tǒng)是自己做的,但是,始終過不了“Kernel panic - not syn
    發(fā)表于 05-14 07:45

    配置nfs啟動出現(xiàn)kernel panic

    an initial console.Failed to execute /linuxrc.Attempting defaults...Kernel panic - not syncing
    發(fā)表于 05-17 07:45

    OpenHarmony 2.0 Canary Linux Kernel 的編譯流程

    selinux=0 rootdelay=5 blkdevparts=mmcblk0: **1M(boot),9M(kernel),50M(rootfs),50M(userfs),-(userdata
    發(fā)表于 12-23 11:31

    nuc980不管如何都是開不起來kernel panic是怎么回事?

    ?) 010f16384 ram15(driver?) Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0
    發(fā)表于 06-13 08:19

    Linux Kernel Panic的產(chǎn)生的原因?

    同學(xué)還沒搞清楚自己到底要什么信息來定位,有的問題復(fù)現(xiàn)時的環(huán)境只能保持幾分鐘甚至幾十秒鐘,這勢必會浪費了測試同學(xué)的勞動成果。 6.2 分析kernel panic 搜集了足夠的panic
    發(fā)表于 06-15 06:24

    解決那些千奇百怪的 Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block 錯誤

    傳言道:80%的 Kernel panic 是都是同一個報錯: 剩下 5% 是 init 設(shè)置錯了,其余的是剩余各式各樣的 ---[ end Kernel panic - not
    發(fā)表于 07-31 10:40

    μClinux-kernel-2.6芯片級移植分析與實現(xiàn)

    本文介紹并分析了將基于最新一代Linux 內(nèi)核kernel-2.6 的μClinux-kernel-2.6,移植到尚未被具體支持的處理器芯片Philips-LPC2294 的全過程。給出了2.6 版本內(nèi)核向具體處理器的芯片級移
    發(fā)表于 06-16 09:22 ?13次下載

    使用Trace View對對Kernel進(jìn)行性能仿真分析

    Kernel進(jìn)行性能分析需要對其進(jìn)行仿真,同時還要用到Vitis Analyzer。為便于說明,我們以一個簡單的Vitis工程為例。這個工程中有兩個kernel,相應(yīng)的代碼如下圖所示
    的頭像 發(fā)表于 03-15 15:30 ?2069次閱讀

    深入分析內(nèi)核panic的內(nèi)核錯誤處理方案

    die函數(shù)主要執(zhí)行oops相關(guān)流程,且若異常為中斷流程中觸發(fā)或設(shè)置了panic_on_oops選項,則進(jìn)一步通過panic將系統(tǒng)掛起。
    發(fā)表于 04-14 15:18 ?4033次閱讀

    解析start_kernel函數(shù)

    上次我們寫過了 Linux 啟動詳細(xì)流程,這次單獨解析 start_kernel 函數(shù)。
    的頭像 發(fā)表于 04-17 18:05 ?1393次閱讀

    kernel日志寫入logd介紹

    kernel日志寫入logd介紹 通過logcat命令獲取kernel日志比較特殊,故作為一個例子進(jìn)行梳理。 2.3.1 整體流程 2.3.2 命令打印kernel日志 通過logca
    的頭像 發(fā)表于 11-23 17:11 ?857次閱讀
    <b class='flag-5'>kernel</b>日志寫入logd介紹

    kernel的啟動分為哪兩個階段

    設(shè)計。在運行過程中運行地址和加載地址一致(如果不明白的話建議先參考一下《[kernel 啟動流程] 前篇——vmlinux.lds分析》)。 (上一篇
    的頭像 發(fā)表于 12-04 16:45 ?785次閱讀