对于一个运行出错的程序,我们可以有多种方法调试它,以便发生错误的原因:
d)使用gdb结合Core Dump文件来迅速定位到这个错误。这个方法,如果程序运行崩溃,那么可以迅速找到导致程序崩溃的原因。
f)补丁调试,冷热补丁
方法a) b) c)中,主要b)插旗子可以分为两类,一类是代码中通过print打印提示信息,一类是通过assert断言,二者的区别在于断言应该检测那些在程序正常运行的时候永远都不可能出现的状态。断言是用来揭示错误的,而不是用来纠正运行时刻错误的。而print打印的信息则可能“并不是那么不可饶恕的”。
方法d) f)则适用于大型工程的调试定位。补丁的应用场景:大型工程重新编译大包的时间很长,通过修改关键部分代码制作patch,运行工程时候,load patch,即可达到重新编译大包一样的效果。这里冷、热补丁的区别在于冷不丁不能运行时加载,热补丁可以运行时加载。
下面重点介绍coredump:
当用户程序运行,可能会由于某些原因发生崩溃(crash),这个时候可以产生一个Core Dump文件,记录程序发生崩溃时候内存的运行状况。这个Core Dump文件,一般名称为core或者core.pid(pid就是应用程序运行时候的pid号),它可以帮助我们找出程序崩溃的原因。
coredump产生原因:
1、内存访问越界
2、多线程程序使用了线程不安全的函数
3、多线程读写的数据未加锁保护
4、非法指针
5、堆栈溢出
coredump调试定位环境设置:
1)使用命令:ulimit -c 查看默认为0,(表示允许存储coredump的大小)命令:ulimit –c [size] 可以修改该选项,size=unlimited时候表示大小不受限制。这里size的单位是block,具体block多少字节,是具体环境而定。
2)/proc/sys/kernel/core_pattern文件最后添加设置coredump生成路径,默认生成路径与进程运行路径相同
可通过命令:echo “/data/coredump/core.%e.%p” >/proc/sys/kernel/core_pattern更改,/data/coredump/为期望生成路径,core.%e.%p为core文件命名格式,详细格式参数如下:
%p - insert pid into filename 添加pid
%u - insert current uid into filename 添加当前uid
%g - insert current gid into filename 添加当前gid
%s - insert signal that caused the coredump into the filename 添加导致产生core的信号
%t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
%h - insert hostname where the coredump happened into filename 添加主机名
%e - insert coredumping executable name into filename 添加命令名
另外,修改/proc/sys/kernel/core_pattern文件需要获取root权限,步骤如下:1)sudo passwd root 2)设置密码 3)su root
3)运行可执行文件,dump,生成core文件。
通过readelf -h core 查看core文件格式:
coredump调试:
gdb ./a.out core (这里a.out 是可执行文件, core是生成的记录)启动后可以看到进程终止前收到的系统信号
这里手打的是SIGSEGV,详细信号及其代表意义参见:
SIGABRT:调用abort函数时产生此信号。进程异常终止。
SIGBUS:指示一个实现定义的硬件故障。
SIGEMT:指示一个实现定义的硬件故障。EMT这一名字来自PDP-11的emulator trap 指令。
SIGFPE:此信号表示一个算术运算异常,例如除以0,浮点溢出等。
SIGILL:此信号指示进程已执行一条非法硬件指令。4.3BSD由abort函数产生此信号。SIGABRT现在被用于此。
SIGIOT:这指示一个实现定义的硬件故障。IOT这个名字来自于PDP-11对于输入/输出TRAP(input/outputTRAP)指令的缩写。系统V的早期版本,由abort函数产生此信号。SIGABRT现在被用于此。
SIGQUIT:当用户在终端上按退出键(一般采用Ctrl-/)时,产生此信号,并送至前台进
程组中的所有进程。此信号不仅终止前台进程组(如SIGINT所做的那样),同时产生一个core文件。
SIGSEGV:指示进程进行了一次无效的存储访问。名字SEGV表示“段违例(segmentationviolation)”。
SIGSYS:指示一个无效的系统调用。由于某种未知原因,进程执行了一条系统调用指令,但其指示系统调用类型的参数却是无效的。
SIGTRAP:指示一个实现定义的硬件故障。此信号名来自于PDP-11的TRAP指令。
SIGXCPUSVR4和4.3+BSD支持资源限制的概念。如果进程超过了其软C P U时间限制,则产生此信号。
SIGXFSZ:如果进程超过了其软文件长度限制,则SVR4和4.3+BSD产生此信号。
启动gdb后where可以看到工程down的具体行,函数。
gdb的调试命令如下:
l(list) ,显示源代码,并且可以看到对应的行号;
b(break)x, x是行号,表示在对应的行号位置设置断点;
p(print)x, x是变量名,表示打印变量x的值
r(run), 表示继续执行到断点的位置
n(next),表示执行下一步
c(continue),表示继续执行
q(quit),表示退出gdb
参考:详解coredump