⑴ 分析linux内核崩溃信息
分析kernel比较关键的就是看三点:
1) 内核会给出一个崩溃原因的猜测,这内里容是,CPU 0 Unable to handle kernel paging request at virtual address 00000000
2) 看pc指针的值,这里是epc == 00000000
3) 看调用栈Call Trace:[ //可惜后面没给出来
通常是根据指针加上偏移值跟反汇编代码对照,找到出问题的指令。
这个panic的原因比较明显,应该是引用了空指针,试图执行0x00000000出的代码。
⑵ linux程序崩溃自动重启
可能是因为它出现了故障吧,所以它才会重启。
⑶ linux c 段错误如何定位
1. 段错误是什么
一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址、访问了系统保护的内存地址、访问了只读的内存地址等等情况。这里贴一个对于“段错误”的准确定义(参考Answers.com):
A segmentation fault (often shortened to segfault) is a particular error condition that can occur ring the operation of computer software. In short, a segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (e.g., attempts to write to a read-only location, or to overwrite part of the operating system). Systems based on processors like the Motorola 68000 tend to refer to these events as Address or Bus errors.
Segmentation is one approach to memory management and protection in the operating system. It has been superseded by paging for most purposes, but much of the terminology of segmentation is still used, "segmentation fault" being an example. Some operating systems still have segmentation at some logical level although paging is used as the main memory management policy.
On Unix-like operating systems, a process that accesses invalid memory receives the SIGSEGV signal. On Microsoft Windows, a process that accesses invalid memory receives the STATUS_ACCESS_VIOLATION exception.
2. 段错误产生的原因
2.1 访问不存在的内存地址
#include<stdio.h>
#include<stdlib.h>
void main()
{
int *ptr = NULL;
*ptr = 0;
}
2.2 访问系统保护的内存地址
#include<stdio.h>
#include<stdlib.h>
void main()
{
int *ptr = (int *)0;
*ptr = 100;
}
2.3 访问只读的内存地址
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main()
{
char *ptr = "test";
strcpy(ptr, "TEST");
}
2.4 栈溢出
#include<stdio.h>
#include<stdlib.h>
void main()
{
main();
}
等等其他原因。
3. 段错误信息的获取
程序发生段错误时,提示信息很少,下面有几种查看段错误的发生信息的途径。
3.1 dmesg
dmesg可以在应用程序crash掉时,显示内核中保存的相关信息。如下所示,通过dmesg命令可以查看发生段错误的程序名称、引起段错误发生的内存地址、指令指针地址、堆栈指针地址、错误代码、错误原因等。以程序2.3为例:
panfeng@ubuntu:~/segfault$ dmesg
[ 2329.479037] segfault3[2700]: segfault at 80484e0 ip 00d2906a sp bfbbec3c error 7 in libc-2.10.1.so[cb4000+13e000]
3.2 -g
使用gcc编译程序的源码时,加上-g参数,这样可以使得生成的二进制文件中加入可以用于gdb调试的有用信息。以程序2.3为例:
panfeng@ubuntu:~/segfault$ gcc -g -o segfault3 segfault3.c
3.3 nm
使用nm命令列出二进制文件中的符号表,包括符号地址、符号类型、符号名等,这样可以帮助定位在哪里发生了段错误。以程序2.3为例:
panfeng@ubuntu:~/segfault$ nm segfault3
08049f20 d _DYNAMIC
08049ff4 d _GLOBAL_OFFSET_TABLE_
080484dc R _IO_stdin_used
w _Jv_RegisterClasses
08049f10 d __CTOR_END__
08049f0c d __CTOR_LIST__
08049f18 D __DTOR_END__
08049f14 d __DTOR_LIST__
080484ec r __FRAME_END__
08049f1c d __JCR_END__
08049f1c d __JCR_LIST__
0804a014 A __bss_start
0804a00c D __data_start
08048490 t __do_global_ctors_aux
08048360 t __do_global_dtors_aux
0804a010 D __dso_handle
w __gmon_start__
0804848a T __i686.get_pc_thunk.bx
08049f0c d __init_array_end
08049f0c d __init_array_start
08048420 T __libc_csu_fini
08048430 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
0804a014 A _edata
0804a01c A _end
080484bc T _fini
080484d8 R _fp_hw
080482bc T _init
08048330 T _start
0804a014 b completed.6990
0804a00c W data_start
0804a018 b dtor_idx.6992
080483c0 t frame_mmy
080483e4 T main
U memcpy@@GLIBC_2.0
3.4 ldd
使用ldd命令查看二进制程序的共享链接库依赖,包括库的名称、起始地址,这样可以确定段错误到底是发生在了自己的程序中还是依赖的共享库中。以程序2.3为例:
panfeng@ubuntu:~/segfault$ ldd ./segfault3
linux-gate.so.1 => (0x00e08000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00675000)
/lib/ld-linux.so.2 (0x00482000)
⑷ linux进程挂死应该如何定位
kill -11 发一个段错误信号给它,生成一个coremp文件,然后用gdb分析调用栈
对了,希望你没有屏蔽signal 11,同时要启用coremp。
⑸ 如何查找Linux死机原因
因为 Linux 广泛用于生产环境,所以每一次宕机都会引起相当大的损失。它 Uptime 达到上百天也许你习以为常,但是只要 Down 十几秒,就会立即急的满头大汗。真的很难以想象证交所宕机会怎么样,也许全国股民会闹翻天。所以我们需要一些小技巧来查找死机的原因,从而避免死机或者内核崩溃。(话说 windows 天天蓝屏也没感觉呀 :-o 难道已经麻木了 :oops: ) 请注意:以下方法可能不适用于 Server,因为桌面环境和 Server 还是有很大区别的。 X Crash 事实上 Linux 内核很少出错,平常我们所遇到的“死机”都是 X 无响应造成的错觉。那 X 没响应了应该怎么处理呢? 通常套路是 Ctrl + Alt +F7 (F8) 切换到某个 tty,然后用 root 登陆,执行 top 查看吃资源最多的程序,然后使用 pkill/kill/killall 等命令杀死该程序。或使用组合键 Ctrl + Alt + Backspace重启 X (黑日白月注:这个快捷键组合在最新的 Ubuntu 和 Fedora 中关闭)。 如果偶遇切换 tty 失败或者没响应,锋孝可以试着使用 SSH 登陆此电脑,然后再杀死程序。也许只是 X 不响应,而内核和 SSH daemon 仍然工作,故此可以实施此法。 arch 配置 SSH daemon 万一X 不给力,各种方法试了无效,又没有办法通过 SSH 登陆到此 pc,那怎么办呢?别着急,我们还有万能的 “reisub” 大法。不过在启用前先要激活内核 sysrq 功能 (via) 。系统启动时执行:echo “1” > /proc/sys/Kernel/sysrq 或者修改 /etc/sysctl.conf 文件,设置 Kernel.sysrq = 1。系统异常时依次按下 Alt+sysrq+{reisub} ,然后系统会自动重启。(有关 sysrq 请看:Linux 死机了怎么办?) 不建议长按 Power 按键强制关机,有可能损坏硬件或者丢失数据,甚至导致磁盘坏道! X 崩溃而内核完好 常见的症状有:程序无响应,花屏,鼠标移动指针无动作,键盘输入没有识别等。但后台的音乐可以正常播放,或者键盘 Caps Lock/Num Lock/Scroll Lock 按键按后对应 LED 可以正常亮灭。遇到此种情况可以使用上述方法重启 X 或者电脑即可悄基橘恢复正常。 Application Crash 这个比较常见,但是也是相当难解决的。因为 Linux 上的应用软件大部分都是开源的,所以可能没有超高的稳定性。也许由于库的缺少或者版本错误,或启团者代码的 Bug,都有可能导致程序出现异常。 一般遇到这种问题,建议检查配置文件是否正确,对配置文件的错误修改可能导致程序的运行失败。如果您确信配置文件没有错误但是程序仍然异常,可以尝试把配置文件删除(注意备份!),然后再次打开软件尝试。
⑹ 如何分析linux crash
如前文所述,当 linux 系统内核发生崩溃的时候,可以通过 kmp 等方式收集内核崩溃之前的内存,生成一个转储文件 vmcore。内核开发者通过分析该 vmcore 文件就可以诊断出内核崩溃的原因,从而进行操作系统的代码改进。那么 crash 就是一个被广泛使用的内核崩溃转储文件分析工具,掌握 crash 的使用技巧,对于定位问题有着十分重要的作用。
使用 crash 的先决条件
由于 crash 用于调试内核崩溃的转储文件,因此使用 crash 需要依赖如下条件:
1. kernel 映像文件 vmlinux 在编译的时候必须指定了 -g 参数,即带有调试信息。
2. 需要有一个内存崩溃转储文件(例如 vmcore),或者可以通过 /dev/mem 或 /dev/crash 访问的实时系统内存。如果 crash 命令行没有指定转储文件,则 crash 默认使用实时系统内存,这时需要 root 权限。
3. crash 支持的平台处理器包括:x86, x86_64, ia64, ppc64, arm, s390, s390x ( 也有部分 crash 版本支持 Alpha 和 32-bit PowerPC,但是对于这两种平台的支持不保证长期维护 )。
4. crash 支持 2.2.5-15(含)以后的 Linux 内核版本。随着 Linux 内核的更新,crash 也在不断升级以适应新的内核。
crash 安装指南
要想使用 crash 调试内核转储文件,需要安装 crash 工具和内核调试信息包。不同的发行版安装包名称略有差异,这里仅列出 RHEL 和 SLES 发行版对应的安装包名称如下:
表 1. crash 工具和内核调试包系统版本crash 工具名称
内核调试信息包RHEL6.2
crashkernel-debuginfo-common
kernel-debuginfoSLES11SP2crashkernel-default-debuginfo
kernel-ppc64-debuginfo
以 RHEL 为例,安装 crash 及内核调试信息包的步骤如下:
rpm -ivh crash-5.1.8-1.el6.ppc64.rpm
rpm -ivh kernel-debuginfo-common-ppc64-2.6.32-220.el6.ppc64.rpm
rpm -ivh kernel-debuginfo-2.6.32-220.el6.ppc64.rpm启动 crash启动参数说明
使用 crash 调试转储文件,需要在命令行输入两个参数:debug kernel 和 mp file,其中 mp file 是内核转储文件的名称,debug kernel 是由内核调试信息包安装的,不同的发行版名称略有不同,以 RHEL 和 SLES 为例:
RHEL6.2:/usr/lib/debug/lib/moles/2.6.32-220.el6.ppc64/vmlinux
SLES11SP2:/usr/lib/debug/boot/vmlinux-3.0.13-0.27-ppc64.debug
使用 crash -h 或 man crash 可以查看 crash 支持的一系列选项,这里仅以常用的选项为例说明如下:
-h:打印帮助信息
-d:设置调试级别
-S:使用 /boot/System.map 作为默认的映射文件
-s:不显示版本、初始调试信息等,直接进入命令行
-i file:启动之后自动运行 file 中的命令,再接受用户输入
⑺ Linux操作系统死机处理方法有哪些
Linux 中,有如下几种方法来获取各种崩溃时产生的信息。
1.Core mp
Core mp 通常用来调试应用程序错误,当某些应用程序运行出现异常崩溃时,可以开启系统的 core mp 功能,来得到一个程序崩溃时的内存信息,用来分析崩溃原因:
在/etc/profile里加上(或者修改)一条:
ulimit -c 0
运行命令:sysctl -w "kernel.core_name_format=/coremp/%n.core"
该命令意思是指core文件放在/coremp目录下,文件名是进程名+.core
2.Diskmp
diskmp工具提供了在单机上创建和采集vmcore(kernel mp)的能力,而无须使用网络。当内核本身出现崩溃的时候,当前的内存和CPU状态以及相关的信息都会被保存到一个支持diskmp的磁盘上的保留分区上。在下一次重新启动的时候,当系统重新启动,diskmp的初始化脚本会从保留分区中读取保存的信息并创建一个vcore文件,然后这个文件被再次存放到/var/crash/目录下,文件名为127.0.0.1-
如下是一个配置 HP SCSI 设备上启用 diskmp 的过程,如果不是 HP SCSI 设备(即设备名为 /dev/sdX的形式),则无须执行第三、四两个步骤。但需要在第一步前先执行命令: modprobe
diskmp
第一步:编辑 /etc/sysconfig/diskmp文件,将一个空白分区的设备名填入后保存退出,例如:
DEVICE=/dev/cciss/c0d0p2
第二步:初使化 mp 设备
#service diskmp initialformat
警告:该分区的所以数据会丢失。
第三步:使用 cciss_mp 模块替换当前的 cciss 模块:
在 /etc/modprobe.conf 找到如下行:
alias scsi_hostadapter cciss
修改为:
alias scsi_hostadapter cciss_mp
再增加一行:
options cciss_mp mp_drive=1
注:假设diskmp文件中配置的为 /dev/cciss/c0d[#a]p[#b], 请设置为: options cciss_mp mp_drive=[#a]
第四步:重建 initrd 文件:
#mv /boot/initrd-`uname -r`.img /boot/initrd-`uname -r`.img.old
#mkinitrd /boot/initrd-`uname -r`.img `uname -r`
第五步:设置 diskmp 服务能够开机自启动:
# chkconfig diskmp on
3.Netmp
如果使用红旗DC4.0 或 3.0 版本系统,是不能支持 diskmp 的,可以利用netmp 来达到输出vmcore 的目的。但是Netmp要求至少有一个服务器以及任意数目的客户端。服务器用来接收客户端死机时的信息,客户端是经常死机的机器。
(一)服务器配置:
(1).检验netmp服务器是否安装完毕:
rpm -q netmp-server
如果未安装,请在光盘 RedFlag/RPMS/ 目录中找到 netmp-server 打头的软件包,执行命令:
rpm -ivh netmp-server-x.x.x.rpm (x为版本号)
进行安装。
(2).服务器包安装后,用命令:
passwd netmp
更改用户的密码.
(3).打开服务:
chkconfig netmp-server on
(4).运行服务器:
service netmp-server start
(二)客户端配置:
(1).校验客户端是否已安装
rpm -q netmp
如果未安装,在光盘 RedFlag/RPMS/ 目录中找到 netm 打头的软件包,执行命令:
rpm -ivh netmp-x.x.x.rpm (x为版本号)
安装.
(2).编辑文件/etc/sysconfig/netmp,添加如下行:
DEV=eth0
NETDUMPADDR=172.16.81.182
NETDUMPMACADDR=00:0C:29:79:F4:E0
172.16.81.182指 netmp 服务器地址。
(3).运行下面的命令,出现提示符时输入密码:
service netmp propagate
(4).打开客户端:
chkconfig netmp on
(5).运行客户端:
service netmp start
(6).测试
为了测试netmp的配置是否正确,在netmp客户机上做下面操作:
cp /usr/share/doc/netmp-xxxxxx/crash.c .
gcc -DKERNEL -DMODULE -I/lib/moles/$(uname -r)/build/include -c crash.c
insmod ./crash.o
这会造成系统崩溃,会在netmp服务器的/var/crash/<客户端IP>/目录下,看到一个核心转储。当客户机正在转储数据到服务器的时候,你会看到一个名叫“vmcore-incomplete"的文件。当转储结束后,该文件会改名成 "vmcore"。"vmcore"文件的大小会变化,可能达到几个GB.在一个内存是512M的系统上,上面的测试会产生大约510M的vmcore文件。
⑻ 程序有几万行代码,编译通过了,运行的时候崩溃了,怎么定位错误面试题。。求解
呵呵,这个我最复在行啦,制说实话,调试的过程中,不怕崩掉,就怕什么错误信息都没有。
首先,既然down掉了,那么肯定会有错误信息,这个通常是出在调试环境的console或log文件中,根据错误信息的内容初步判断错误类型,如果是编译后的初次调试,大部分情况下是空指针(空内存)访问错误,即实际为null的内存被使用,当然也可能是其他错误。无论怎样,在这个位置加入断点,即在这行代码不出错,一旦执行该行,程序即崩溃(无法调试的环境下则加入充分的debug信息),再次运行程序,在这一点上监视各个变量,找到导致崩溃的变量值,向上追溯,找到给该变量赋值的逻辑,如果是通过其他变量传递过来的,则逐层向上逆向追踪,通过断点来找到函数的呼出元,当找到赋值操作的根源时,错误的原因也就找到了,接下来就是分析原因,讨论对策,查找影响范围了。。。。
down掉的程序不可怕,可怕的是没有任何错误信息得bug(加上这句可以提高印象分哦O(∩_∩)O~)
⑼ 如何快速定位Linux Panic出错的代码行
内核Panic时,一般会打印回调,并打印出当前出错的地址:
kernel/panic.c:panic():
#ifdef CONFIG_DEBUG_BUGVERBOSE
/*
* Avoid nested stack-mping if a panic occurs ring oops processing
*/
if (!test_taint(TAINT_DIE) && oops_in_progress <= 1)
mp_stack();
#endif
而mp_stack()调用关系如下:
mp_stack() --> __mp_stack() --> show_stack() --> mp_backtrace()
mp_backtrace()会打印整个回调,例如:
[<001360ac>] (unwind_backtrace+0x0/0xf8) from [<00147b7c>] (warn_slowpath_common+0x50/0x60)
[<00147b7c>] (warn_slowpath_common+0x50/0x60) from [<00147c40>] (warn_slowpath_null+0x1c/0x24)
[<00147c40>] (warn_slowpath_null+0x1c/0x24) from [<0014de44>] (local_bh_enable_ip+0xa0/0xac)
[<0014de44>] (local_bh_enable_ip+0xa0/0xac) from [<0019594c>] (bdi_register+0xec/0x150)
通常,上面的回调会打印出出错的地址。
解决方案
通过分析,要快速定位出错的代码行,其实就是快速查找到出错的地址对应的代码?
相应的工具有addr2line, gdb, objmp等,这几个工具在How to read a Linux kernel panic?都有介绍,我们将针对上面的实例做更具体的分析。
需要提到的是,代码的实际运行是不需要符号的,只需要地址就行。所以如果要调试代码,必须确保调试符号已经编译到内核中,不然,回调里头打印的是一堆地址,根本看不到符号,那么对于上面提到的情况二而言,将无法准确定位问题。
情况一
在代码编译连接时,每个函数都有起始地址和长度,这个地址是程序运行时的地址,而函数内部,每条指令相对于函数开始地址会有偏移。那么有了地址以后,就可以定位到该地址落在哪个函数的区间内,然后找到该函数,进而通过计算偏移,定位到代码行。
情况二
但是,如果拿到的日志文件所在的系统版本跟当前的代码版本不一致,那么编译后的地址就会有差异。那么简单地直接通过地址就可能找不到原来的位置,这个就可能需要回调里头的函数名信息。先通过函数名定位到所在函数,然后通过偏移定位到代码行。