linux C 错误排查

来源:互联网 发布:nginx跟zookeeper 编辑:程序博客网 时间:2024/05/16 13:07

linux C 错误排查


============================================================================================================
1  -g和-rdynamic参数


http://blog.chinaunix.net/uid-20717979-id-3192421.html


objdump -d ./zd >tmp.txt

 

==================================================================================================================================

addr2line 方法的使用

addr2line -e zd 0x80636C4

/mnt/hgfs/syf/UISVN/socketclient.c:2306


==================================================================================================================================
Linux下Segmentation Fault错误解决小结

  近日在做程序的Debug,主要问题是在程序退出时,会发生segmentation fault,导致程序崩溃。在历经一周磨难后终于解决,现总结如下。

对于Segmentation Fault的定义在Wikipedia上的解释为:Segmentation Fault一般指对于CPU无法寻址的内存的访问,这个错误提示产生于硬件通知操作系统一个非法内存访问。之后OS Kernel 发送一个信号(signal)给进程,引发exception。通常情况下,进程会生成核心转储(core dump),并且终止。

所以可以得出,一般产生这种问题的情况多半与指针相关:指针未初始化就访问了,重复删除了指针,访问了地址非法(0x0地址与系统地址)的指针等等。

解决Segmentation Fault:
此处主要是对gdb分析core文件和valgrind内存调用分析两种方法进行小结。
-----------------------------------------------------------------------------------------------------------------------

1. 既然是在Linux环境中,使用gdb分析core文件是最简单方便的方法。

 1.编译一下 gcc -ggdb test.c
 2.输入命令 ulimit -c unlimited
 3.运行文件 ./a.out发生segmentation falut,同时会生成一个文件core.xxxx(xxxx means pid)
 4.gdb a.out core.xxxx
 5.gdb > bt马上就会输出错误代码所在的文件和行数,同时还打印出这句错误的语句。
       
        gdb>print 变量名
------------------------------------------------------------------------------------------------------------------------

2. 对于结构复杂的程序,如涉及模板类及复杂的调用,gdb得出了出错位置,似乎这还不够,这时候要使用更为专业的工具——valgrind。

valgrind是一款专门用作内存调试,内存泄露检测的开源工具软件,valgrind这个名字取自北欧神话英灵殿的入口,不过,不能不承认,它确实是Linux下做内存调用分析的神器。一般Linux系统上应该没有自带valgrind,需要自行进行下载安装。

下载地址:http://valgrind.org/downloads/current.html

进入下载文件夹,分别执行(需要root权限,且必须按默认路径安装,否则有加载错误):

./configure

make

make install

安装成功后,使用类似如下命令启动程序:

valgrind --tool=memcheck --leak-check=full --track-origins=yes --leak-resolution=high --show-reachable=yes --log-file=memchecklog  ./controller_test

其中,–log-file=memchecklog指记录日志文件,名字为memchecklog;–tool=memcheck和–leak-check=full用于内存检测。

可以得到类似的记录:

==23735==
==23735== Thread 1:
==23735== Invalid read of size 4
==23735== at 0x804F327: ResourceHandler<HBMessage>::~ResourceHandler() (ResourceHandler.cpp:48)
==23735== by 0x804FDBE: ConnectionManager<HBMessage>::~ConnectionManager() (ConnectionManager.cpp:74)
==23735== by 0×8057288: MainThread::~MainThread() (MainThread.cpp:73)
==23735== by 0x8077B2F: main (Main.cpp:177)
==23735== Address 0×0 is not stack’d, malloc’d or (recently) free’d
==23735==

可以看到说明为无法访问Address 0x0,明显为一处错误。

这样valgrind直接给出了出错原因以及程序中所有的内存调用、释放记录,非常智能,在得知错误原因的情况下,找出错误就效率高多了。

再说一句,valgrind同时给出了程序的Memory Leak情况的报告,给出了new-delete对应情况,所有泄漏点位置给出,这一点在其他工具很难做到,十分好用。

==================================================================================================================================


=================================================================================================================================

二  gdb 调试

1 gdb zd


> list  列出源文件  l 15
> next  单步执行  n
> layout src
> print p (p为变量名)
> step  不进入的单步执行 s
> bt
> q 退出

 

启动GDB的方式

直接输入gdb
gdb 程序名
gdb 程序名 core文件
GDB启动示例

gdb
gdb ./test
gdb ./test core
GDB命令

b [linenum/func]      -以行号/函数名为标识下断点
b [filename] : [linenum]     – 在某文件某行下断点
l      -显示源代码
l [filename] : [linenum/func]      -列出某文件某行的附近代码/函数
bt      -打印堆栈
c        -类似使用VS调试时的F5键
n        -单步调试
info break  -显示断点信息
delete [num]  -删除断点,num为info break断点信息中的断点编号
disable [num] -暂时屏蔽断点,num同上
enable [num]  -恢复断点,num同上
display [variant]  -当触发断点时,显示变量variant的值
whatis [variant]   -显示变量的类型,可用ptype命令代替
finish           -跳出函数执行体,相当于VS的SHIFT+F11
u                  -跳出循环体
step             -相当于VS的F11键
p [variant]    -打印变量的值
info locals    -显示当前所有局部变量的值
layout src   -显示源代码窗口,调试时会有更新问题,可用CTRL+l更新
b [linenum/func] if [condition]  -可以在某条件成立的时候,在某处下断点
watch [variant]  -类似VS的监视变量,当触发断点时,会打印variant的值
file [程序名]       -当以gdb命令直接进入调试的时候,可以使用该命令加载所要调试的程序


调试COREDUMP文件

当程序由于某种原因崩溃后会生成core dump文件,里面包含程序崩溃时的堆栈信息和其他信息
ulimit –c unlimited
    要程序崩溃后自动生成core dump文件,需要执行ulimit -c命令设置core dump文件的大小,一般会在用户配置文件添加此命令,最后一个参数为设置core dump文件大小,这里设为不限制大小

为了能掌握更多调试信息,我们要添加编译选项-g, 并把优化选项等级设为最低(-O0, 默认为-O2)
调试core dump示例

gdb ./test core
where  -显示引起程序崩溃的位置
ba  -打印堆栈信息

gdb 的常用命令
命令 解释
   break NUM 在指定的行上设置断点。
  bt 显示所有的调用栈帧。该命令可用来显示函数的调用顺序。
  clear 删除设置在特定源文件、特定行上的断点。其用法为clear FILENAME:NUM
  continue 继续执行正在调试的程序。该命令用在程序由于处理信号或断点而 导致停止运行时。
  display EXPR 每次程序停止后显示表达式的值。表达式由程序定义的变量组成。
  file FILE 装载指定的可执行文件进行调试。
  help NAME 显示指定命令的帮助信息。
  info break 显示当前断点清单,包括到达断点处的次数等。
  info files 显示被调试文件的详细信息。
  info func 显示所有的函数名称。
  info local 显示当函数中的局部变量信息。
  info prog 显示被调试程序的执行状态。
  info var 显示所有的全局和静态变量名称。
  kill 终止正被调试的程序。
  list 显示源代码段。
  make 在不退出 gdb 的情况下运行 make 工具。
  next 在不单步执行进入其他函数的情况下,向前执行一行源代码。
  print EXPR 显示表达式 EXPR 的值。


 backtrace 显示程序中的当前位置和表示如何到达当前位置的栈跟踪(同义词:where)
breakpoint 在程序中设置一个断点
cd 改变当前工作目录
clear 删除刚才停止处的断点
commands 命中断点时,列出将要执行的命令
continue 从断点开始继续执行
delete 删除一个断点或监测点;也可与其他命令一起使用
display 程序停止时显示变量和表达时
down 下移栈帧,使得另一个函数成为当前函数
frame 选择下一条continue命令的帧
info 显示与该程序有关的各种信息
jump 在源程序中的另一点开始运行
kill 异常终止在gdb 控制下运行的程序
list 列出相应于正在执行的程序的原文件内容
next 执行下一个源程序行,从而执行其整体中的一个函数
print 显示变量或表达式的值
pwd 显示当前工作目录
pype 显示一个数据结构(如一个结构或C++类)的内容
quit 退出gdb
reverse-search 在源文件中反向搜索正规表达式
run 执行该程序
search 在源文件中搜索正规表达式
set variable 给变量赋值
signal 将一个信号发送到正在运行的进程
step 执行下一个源程序行,必要时进入下一个函数
undisplay display命令的反命令,不要显示表达式
until 结束当前循环
up 上移栈帧,使另一函数成为当前函数
watch 在程序中设置一个监测点(即数据断点)
whatis 显示变量或函数类型
****************************************************

 

 

 

 

 

 

 

 

 

 

 


四:断点(breakpoint)
break命令(可以简写为b)可以用来在调试的程序中设置断点,该命令有如下四种形式:
l break line-number 使程序恰好在执行给定行之前停止。
l break function-name 使程序恰好在进入指定的函数之前停止。
l break line-or-function if condition 如果condition(条件)是真,程序到达指定行或函数时停止。
l break routine-name 在指定例程的入口处设置断点

如果该程序是由很多原文件构成的,你可以在各个原文件中设置断点,而不是在当前的原文件中设置断点,其方法如下:
(gdb) break filename:line-number
(gdb) break filename:function-name

要想设置一个条件断点,可以利用break if命令,如下所示:
(gdb) break line-or-function if expr
例:
(gdb) break 46 if testsize==100

从断点继续运行:countinue 命令

 

 

 

 

gdb [options] --args executable-file [inferior-arguments ...]
p array[0]@100 打印数组前100个元素
p /x var 以16进制打印
break ... if COND
call printf(“abcd”)
display /x addr
undisplay 1
set var varname = value
whatis varname //显示变量varname的类型,如double,int,...
set print pretty
set {int}0x83040 = 4 //向地址0x83040写入4
until 结束当前循环
ptype 显示一个数据结构(如一个结构或C++类)的内容
checkpoint
x /40xw 0x20000
x /10i 0x312000
disassemble 0xbff00800 0x10 :address:len

finish - Execute until selected stack frame returns
display /i $pc - 单步跟踪会在打出程序代码的同时打出机器指令(也就是汇编代码)
layout src:显示源代码窗口
layout asm:显示反汇编窗口
layout regs:显示源代码/反汇编和CPU寄存器窗口
layout split:显示源代码和反汇编窗口
Ctrl + L:刷新窗口
layout prev|next
focus src|asm|regs|cmd|prev|next

add-symbol-file