linux内核 cpu_die,Linux内核Crash分析

结合上面的知识,看下当内核打印堆栈信息时,都打印了上面信息。下面的打印信息是工作中遇到的一种情况,打印了内核的堆栈信息,PC指针在dev_get_by_flags中,不能访问的内核虚地址为45685516,内核中一般可访问的地址都是以0xCXXXXXXX开头的地址。

Unableto handle kernel paging request atvirtualaddress45685516

pgd=c65a4000

[45685516]*pgd=00000000

Internalerror:Oops:1[#1]

lastsysfs file:/sys/devices/form/tpm/cfg_l3/l3_rule_add

Moduleslinkedin:splic mmp(P)

CPU:0Tainted:P(2.6.32.11#42)

PCisat dev_get_by_flags+0xfc/0x140

LRisat dev_get_by_flags+0xe8/0x140

pc:[]lr:[]psr:20000013

sp:c07e9c28 ip:00000000fp:c07e9c64

r10:c6bcc560 r9:c646a220 r8:c66a0000

r7:c6a00000 r6:c0204e56 r5:30687461r4:45685516

r3:00000000r2:00000010r1:c0204e56 r0:ffffffff

Flags:nzCvIRQsonFIQsonModeSVC_32 ISA ARMSegmentkernel

Control:0005397fTable:065a4000DAC:00000017

Processswapper(pid:0,stack limit=0xc07e8270)

Stack:(0xc07e9c28to0xc07ea000)

9c20:c0204e56 c6a0000045685516c69ffff0 c69ffff0 c69ffff0

9c40:c6a0000030687461c66a0000 c6a0000000000007c64b210c c07e9d24 c07e9c68

9c60:c071f764 c06bed38 c66a0000 c66a0000 c6a00000 c6a00000 c66a0000 c6a00000

9c80:c07e9cfc c07e9c90 c03350d4 c0334b2c000000340000000600000100c64b2104

9ca0:0000c4fbc0243ece c66a0000 c0beed04 c033436c c646a220 c07e9cf400000000

9cc0:c66a000000000003c0bee8e8 c0beed04 c07e9d24 c07e9ce0 c06e4f5c00004c68

9ce0:00000000faa9fea9 faa9fea90000000000000000c6bcc560 c0335138 c646a220

9d00:c66a0000 c64b2104 c085ffbc c66a0000 c0bee8e800000000c07e9d54 c07e9d28

9d20:c071f9a0 c071ebc000000000c071ebb08000000000000007c67fb460 c646a220

9d40:c0bee8c800000608c07e9d94 c07e9d58 c002a100 c071f84c c0029bb880000000

9d60:c07e9d84 c0beee0c c0335138 c66a0000 c646a22000000000c4959800 c4959800

9d80:c67fb46000000000c07e9dc4 c07e9d98 c078f0f4 c0029bc800000000c0029bb8

9da0:80000000c07e9dbc c6b8d340 c66a052000000000c646a220 c07e9dec c07e9dc8

9dc0:c078f450 c078effc00000000c67fb460 c6b8d34000000000c67fb460 c64b20f2

9de0:c07e9e24 c07e9df0 c078fb60 c078f13000000000c078f12080000000c0029a94

9e00:00000806c6b8d340 c0bee8180000000100000000c4959800 c07e9e64 c07e9e28

9e20:c002a030 c078f804 c64b207000000000c64b2078 ffc45000 c64b20c2 c085c2dc

9e40:00000000c085c2c000000000c081739800086c2ec085c2c4 c07e9e9c c07e9e68

9e60:c06c2684 c0029bc8000000010000004000000000c085c2dc c085c2c000000001

9e80:0000012c00000040c085c2d0 c0bee818 c07e9ed4 c07e9ea0 c00284e0 c06c2608

9ea0:bf00da5c00086c300000000000000001c097e7d4 c07e800000000100c08162d8

9ec0:00000002c097e7a0 c07e9f14 c07e9ed8 c00283d0 c00284785625131100023c88

9ee0:c07e9f0c00000003c08187ac000000180000000001000000c07ebc7000023cbc

9f00:5625131100023c88c07e9f24 c07e9f18 c03391e8 c0028348 c07e9f3c c07e9f28

9f20:c0028070 c03391b0 ffffffff0000001fc07e9f94 c07e9f40 c002d4d0 c0028010

9f40:0000000000000001c07e9f8860000013c07e8000 c07ebc78 c0868784 c07ebc70

9f60:00023cbc5625131100023c88c07e9f94 c07e9f98 c07e9f88 c025c3e4 c025c3f4

9f80:60000013ffffffff c07e9fb4 c07e9f98 c025c578 c025c3cc00000000c0981204

9fa0:c0025ca0 c0d01140 c07e9fc4 c07e9fb8 c0032094 c025c528 c07e9ff4 c07e9fc8

9fc0:c0008918 c0032048 c00083880000000000000000c0025ca00000000000053975

9fe0:c0868834 c00260a400000000c07e9ff800008034c00087080000000000000000

Backtrace:

[](dev_get_by_flags+0x0/0x140)from[](arp_process+0xbb4/0xc74)

r7:c64b210c r6:00000007r5:c6a00000 r4:c66a0000

(1)首先,看看这段堆栈信息是在内核中那个文件中打印出来的,在fault.c文件中,__do_kernel_fault函数,在上面的打印中Unable to handle kernel paging request at virtual address 45685516,该地址是内核空间不可访问的地址。

staticvoid__do_kernel_fault(structmm_struct*mm,unsignedlongaddr,unsignedintfsr,structpt_regs*regs)

{

/*

* Are we prepared to handle this kernel fault?

*/

if(fixup_exception(regs))

return;

/*

* No handler, we'll have to terminate things with extreme prejudice.

*/

bust_spinlocks(1);

printk(KERN_ALERT

"Unable to handle kernel %s at virtual address %08lx\n",

(addr

show_pte(mm,addr);

die("Oops",regs,fsr);

bust_spinlocks(0);

do_exit(SIGKILL);

}

(2) 对于下面的两个信息,在函数show_pte中进行了打印,下面的打印涉及到了页全局目录,页表的知识,暂时先不分析,后续补上。

pgd=c65a4000

[45685516]*pgd=00000000

voidshow_pte(structmm_struct*mm,unsignedlongaddr)

{

pgd_t*pgd;

if(!mm)

mm=&init_mm;

printk(KERN_ALERT"pgd = %p\n",mm->pgd);

pgd=pgd_offset(mm,addr);

printk(KERN_ALERT"[%08lx] *pgd=%08lx",addr,pgd_val(*pgd));

……………………

}

(3) die函数中调用在die函数中取得thread_info结构体的地址。

structthread_info*thread=current_thread_info();

staticinlinestructthread_info*current_thread_info(void){

registerunsignedlongspasm("sp");

return(structthread_info*)(sp&~(THREAD_SIZE-1));

}

Sp: 0xc07e9c28 通过current_thread_info得到 thread_info的地址

(0xc07e9c28 & 0xffffe000) = 0xC07E8000(thread_info的地址,也就是栈底的地址)

(4)下面的打印信息在__die函数中打印

Internalerror:Oops:1[#1]

lastsysfs file:/sys/devices/form/tpm/cfg_l2/l2_rule_add

Moduleslinkedin:splic mmp(P)

CPU:0Tainted:P(2.6.32.11#42)

PCisat dev_get_by_flags+0xfc/0x140

LRisat dev_get_by_flags+0xe8/0x140

pc:[]lr:[]psr:20000013

sp:c07e9c28 ip:00000000fp:c07e9c64

r10:c6bcc560 r9:c646a220 r8:c66a0000

r7:c6a00000 r6:c0204e56 r5:30687461r4:30687461

r3:00000000r2:00000010r1:c0204e56 r0:ffffffff

Flags:nzCvIRQsonFIQsonModeSVC_32 ISA ARMSegmentkernel

Control:0005397fTable:065a4000DAC:00000017

Processswapper(pid:0,stack limit=0xc07e8270)

Stack:(0xc07e9c28to0xc07ea000)

函数的调用关系:die("Oops", regs, fsr);---à __die(str, err, thread, regs);

下面是__die函数的定义:

staticvoid__die(constchar*str,interr,structthread_info*thread,structpt_regs*regs){

structtask_struct*tsk=thread->task;

staticintdie_counter;

/*Internal error: Oops: 1 [#1]*/

printk(KERN_EMERG"Internal error: %s: %x [#%d]"S_PREEMPT S_SMP"\n",

str,err,++die_counter);

/*last sysfs file: /sys/devices/form/tpm/cfg_l2/l2_rule_add*/

sysfs_printk_last_file();

/*内核中加载的模块信息Modules linked in: splic mmp(P) */

print_modules();

/*打印寄存器信息*/

__show_regs(regs);

/*Process swapper (pid: 0, stack limit = 0xc07e8270) tsk->comm task_struct结构体中的comm表示的是除去路径后的可执行文件名称,这里的swapper为idle进程,进程号为0,创建内核进程init;其中stack limit = 0xc07e8270 指向thread_info的结束地址。*/

printk(KERN_EMERG"Process %.*s (pid: %d, stack limit = 0x%p)\n",

TASK_COMM_LEN,tsk->comm,task_pid_nr(tsk),thread+1);

/* dump_mem 函数打印从栈顶到当前sp之间的内容*/

if(!user_mode(regs)||in_interrupt()){

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

dump_backtrace(regs,tsk);

dump_instr(KERN_EMERG,regs);

}

}

在上面的函数中,主要使用了thread_info,task_struct,sp之间的指向关系。task_struct结构体的成员stack是栈底,也是对应thread_info结构体的地址。堆栈数据是从栈底+8K的地方开始向下存的。SP指向的是当前的栈顶。(unsigned long)task_stack_page(tsk),

#define task_stack_page(task) ((task)->stack) ,该宏根据task_struct得到栈底,也就是thread_info地址。

#define task_thread_info(task) ((struct thread_info *)(task)->stack),该宏根据task_struct得到thread_info指针。

(5)dump_backtrace函数

该函数用于打印函数的调用关系。Fp为帧指针,用于追溯程序的方式,方向跟踪调用函数。该函数主要是fp进行检查,看看能否进行backtrace,如果可以就调用汇编的c_backtrace,在arch/arm/lib/backtrace.S函数中。

staticvoiddump_backtrace(structpt_regs*regs,structtask_struct*tsk)

{

unsignedintfp,mode;

intok=1;

printk("Backtrace: ");

if(!tsk)

tsk=current;

if(regs){

fp=regs->ARM_fp;

mode=processor_mode(regs);

}elseif(tsk!=current){

fp=thread_saved_fp(tsk);

mode=0x10;

}else{

asm("mov %0, fp":"=r"(fp)::"cc");

mode=0x10;

}

if(!fp){

printk("no frame pointer");

ok=0;

}elseif(verify_stack(fp)){

printk("invalid frame pointer 0x%08x",fp);

ok=0;

}elseif(fp

printk("frame pointer underflow");

printk("\n");

if(ok)

c_backtrace(fp,mode);

}

(6)dump_instr

根据PC指针和指令mode, 打印出当前执行的指令码

Code: 0a000008 e5944000 e2545000 0a000005 (e4153010)

9f4a8b033023d2e8b066cd807ed0a978.png

内核中函数的调用关系

Linux Kernel 的详细介绍:请点这里

Linux Kernel 的下载地址:请点这里

0b1331709591d260c1c78e86d0c51c18.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/408870.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[GAN学习系列] 初识GAN

本文大约 3800 字,阅读大约需要 8 分钟 要说最近几年在深度学习领域最火的莫过于生成对抗网络,即 Generative Adversarial Networks(GANs)了。它是 Ian Goodfellow 在 2014 年发表的,也是这四年来出现的各种 GAN 的变种的开山鼻祖了&#xff…

[GAN学习系列] 初始GAN

本文大约 3800 字,阅读大约需要 8 分钟要说最近几年在深度学习领域最火的莫过于生成对抗网络,即 Generative Adversarial Networks(GANs)了。它是 Ian Goodfellow 在 2014 年发表的,也是这四年来出现的各种 GAN 的变种的开山鼻祖了&#xff0…

[资源分享] 吴恩达最新《机器学习训练秘籍》中文版可以免费下载了

本文大约 600 字, 阅读大约需要 2 分钟 吴恩达老师在上个月底宣布终于完成了他最新的书籍《Machine Learning Yearning》的最后几个章节: 而最近这本书也有了免费的完整中文版下载了,中文版的名称是《机器学习训练秘籍》,封面如下…

Android学习笔记44:JSON数据解析

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,为Web应用开发提供了一种理想的数据交换格式。 本文将主要介绍在Android开发中,如何在服务器端创建JSON数据,以…

[GAN学习系列2] GAN的起源

本文大约 5000 字,阅读大约需要 10 分钟 这是 GAN 学习系列的第二篇文章,这篇文章将开始介绍 GAN 的起源之作,鼻祖,也就是 Ian Goodfellow 在 2014 年发表在 ICLR 的论文–Generative Adversarial Networks”,当然由于…

[资源分享] Github上八千Star的深度学习500问教程

本文大约 600 字,阅读大约需要 2 分钟这周要分享的一个资源是来自 Github 上的已经有八千多 Star 的一个深度学习知识总结,如下图所示:其 Github 地址为:https://github.com/scutan90/DeepLearning-500-questions它目前是有 16 个…

谷歌开源的 GAN 库--TFGAN

本文大约 8000 字,阅读大约需要 12 分钟 第一次翻译,限于英语水平,可能不少地方翻译不准确,请见谅! 最近谷歌开源了一个基于 TensorFlow 的库–TFGAN,方便开发者快速上手 GAN 的训练,其 Github …

linux快速php,Linux 下的这些高效指令,是你快速学习的神器

linux是一套免费使用和自由传播的类unix操作系统,是一个基于posix和unix的多用户、多任务、支持多线程和多cpu的操作系统。它能运行主要的unix工具软件、应用程序和网络协议。它支持32位和64位硬件。linux继承了unix以网络为核心的设计思想,是一个性能稳…

TensorFlow 加载多个模型的方法

采用 TensorFlow 的时候,有时候我们需要加载的不止是一个模型,那么如何加载多个模型呢? 原文:https://bretahajek.com/2017/04/importing-multiple-tensorflow-models-graphs/ 关于 TensorFlow 可以有很多东西可以说。但这次我只…

[资源分享] TensorFlow 官方中文版教程来了

最近,TensorFlow 提供了中文版的教程(Tutorials)和指南(Guide)。其中,教程是介绍了一些基本的机器学习模型,包括分类、回归等,也包括一些深度学习方面的模型,包括常用的卷…

深度学习4线性回归,逻辑回归

y是连续的则是一个回归问题,y是离散的则是一个分类问题,这边就开始考虑y是离散的情况。 对于这样的问题很多,比如判断一个人是否生病,或者判断一个邮件是否是垃圾邮件。 回归时连续型的,一般不用在上述的分类问题中&am…