gdb调试段错误及使用
在编程调试中,经常出现段错误,此时可用gdb调试。具体方法为注册段错误信号处理函数,在处理函数中启动gdb。
具体代码如下:
void segv_handler(int no)
{
char buf[];
char cmd[];
FILE *file; snprintf(buf, sizeof(buf), "/proc/%d/cmdline", getpid());
if(!(file = fopen(buf, "r")))
{
exit(EXIT_FAILURE);
}
if(!fgets(buf, sizeof(buf), file))
{
eixt(EXIT_FAILURE);
}
if(buf[strlen(buf) - ] == '\n')
{
buf[strlen(buf) -] = '\0';
}
snprintf(cmd, sizeof(cmd), "gdb %s %d", buf, getpid());
system(cmd);
}
注册函数:
signal(SIGSEGV, segv_handler);
下面转自一些总结:
作为一名程序猿,日常开发中解决各种bug是不可避免的。对于简单的bug通过日志分析,或者增加打印信息就能很快定位到原因并解决。但是对于某些比较复杂的情况,想要定位到bug往往十分困难。查阅了很多资料,经过不断尝试,我发现gdb调试能够起到很大的帮助。下面我将对使用gdb的一些常用技巧和实例做下总结。
下面总结下比较关键的几个用法:
一、启动GDB调试
使用gdb调试首先在编译程序时加上-g参数:$ gcc –g –o foo foo.c
启动gdb调试有多种方法,可以根据不同的场景选择合适的方式,这也是gdb比较好用的地方。
1. 程序没有运行时,gdb +<program> 直接用gdb运行程序;
2. 程序运行中的gdb调试有两种方式:
a.ps查看程序的PID,gdb + <program> + PID ,自动挂接到已运行的程序;
b.ps产看程序的PID,gdb + <program>运行gdb后,用attach + PID指令挂接到程序, 并用detach来取消挂接的进程。
3. 程序已经死掉后,gdb +<program> + core文件进行调试,core文件是程序非法执行后产生的“核心转储”文件。有些情况下core不能生成,需要用ulimit -c unlimited指令先设置系统环境。
二、针对第二种gdb启动方式,可以有如下实现方式。
程序发生段错误,但是该异常发生有一定的随机性,为了捕获异常并进行gdb调试,在程序中捕获SIGSEGV信号并进行如下处理,这样当程序运行出现段错误时直接进入gdb调试环境。
三、gdb调试常用指令
关于gdb调试的常用指令及介绍可以参考这里,http://blog.csdn.net/liwf616/article/details/46833107
Gdb环境下直接按下回车表示执行上一条命令
1. break 设置断点,
break10 设置断点,在源程序第10行
breakfunc 设置断点,在func函数入口处
infobreak 查看断点信息
2. run 运行程序,可简写为r
3. next 单步跟踪,函数调用当作一条简单语句执行,可简写为n
step 单步跟踪,函数调进入被调用函数体内,可简写为s
stepi 或si单步跟踪一条机器指令
nexti 或ni单步跟踪一条机器指令
4. continue 继续运行程序,可简写为c
5. print 打印变量、字符串、表达式等的值,可简写为p
p count 打印count的值
p cou1+cou2+cou3 打印表达式值
6. bt 查看函数堆栈
7. finish 退出函数
8. quit 退出GDB
9. shell 不退出GDB就使用shell命令
10. make <make-args>不退出GDB就重新编译程序
11. set args指定运行时参数。(如:set args10 20 30 40 50)
showargs查看设置好的运行参数。
12. path <dir>设定程序的运行路径。
showpaths 查看程序的运行路径。
13. set environment varname [=value] 设置环境变量。如:setenv USER=hchen
showenvironment [varname] 查看环境变量。
14. 其他
cd<dir> 相当于shell的cd命令。
pwd 显示当前的所在目录。
infoterminal 显示程序用到的终端模式。
tty指写输入输出的终端设备。如:tty /dev/ttyb
until在一个循环体内单步跟踪时,该命令运行程序到退出循环体。简写u
四、多线程调试
用gdb调试的好处是可以查看程序运行时的堆栈等信息,可以很直观的发现问题。
info threads //显示当前可调试的所有线程,每个线程前面有一个gdb为其分配的ID;
thread ID //切换到该ID对应的线程;
bt //显示该线程的堆栈信息
thread apply all bt //显示所有线程堆栈信息
break fun.c:123 thread ID //设置指定线程的断点
set scheduler-locking off|on|step //off表示不锁定任何线程,所有线程都执行;on只有当前线程执行;step在单步时除了next过一个函数外,只有当前线程执行
五、示例
当本目录文件wang大小超过2*1024时可能出现段错误(超过很大时,小时短时间不会出现),会进入segv_handler(),但不会触发gdb。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <signal.h>
#include <string.h>
#include <execinfo.h> #define SYSLOG_LINE_BUFFER_SIZE 2*1024
#define BUFFER_SIZE 4*1024
#define FILEN "wang" char bbuf[BUFFER_SIZE]={}; void m_syslog_dbg(char *format, ...)
{
va_list ptr;
char buf[SYSLOG_LINE_BUFFER_SIZE] = {}; openlog("log", , LOG_DAEMON);
// put log
va_start(ptr, format);
vsprintf(buf, format, ptr);
va_end(ptr);
syslog(LOG_DEBUG, "%s", buf);
closelog(); return;
} void segv_handler(int no)
{
printf("seg....\n");
#if 1
void * array[]; /* 25 层,太够了 : ),你也可以自己设定个其他值 */
char **strings; int nSize = backtrace(array, sizeof(array)/sizeof(array[]));
for (int i=nSize-; i>=; i--){ /* 头尾几个地址不必输出,看官要是好奇,输出来看看就知道了 */ /* 修正array使其指向正在执行的代码 */
// printf("SIGSEGV catched when running code at %x\n", (char*)array[i] - 1);
printf("SIGSEGV catched when running code at %x\n", array[i]); }
#if 1
strings = backtrace_symbols(array, nSize);
printf("backtrace...%d\n", nSize);
if(strings == NULL){
printf("strings NULL\n");
exit(EXIT_FAILURE);
} for(int i=nSize-; i>=; i--){
printf("%s\n", strings[i]);
} free(strings);
#endif #endif
#if 0
char buf[];
char cmd[];
FILE *file;
pid_t pid = getpid(); snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
if((file = fopen(buf, "r")) == NULL){
exit(EXIT_FAILURE);
}
if(fgets(buf, sizeof(buf), file) == NULL ){
exit(EXIT_FAILURE);
} if(buf[strlen(buf)-] == '\n'){
buf[strlen(buf)-] = '\0';
} snprintf(cmd, sizeof(cmd), "/usr/bin/gdb %s %d", buf, pid);
printf("receive signo %d-->%s\n", no, cmd);
// system(cmd);
// while(1);
#endif
}
int main(void )
{ signal(SIGSEGV, segv_handler); struct stat st;
int ret = ;
ret = stat(FILEN, &st);
if(ret != ){
perror("stat");
return -;
} int fd = open(FILEN, O_RDONLY);
if(fd < ){
printf("open error\n");
return -;
} //read(fd, bbuf, st.st_size);
ret = read(fd, bbuf, sizeof(bbuf));
printf("file size = %d, %d\n", ret, getpid());
m_syslog_dbg("recevice [%s]\n", bbuf); printf("the end\n");
while(){
sleep();
printf("running...\n");
} close(fd);
return ;
}
参考:
1. backtrace、backtrace_symbols、backtrace_symbols_fd-support for application self-debugging
3. C/C++捕获段错误,打印出错的具体位置(精确到哪一行)_转
4. gdb调试段错误及使用
gdb调试段错误及使用的更多相关文章
- 【转】gdb 调试段错误
[转]gdb 调试段错误 转自:blog.csdn.net/yangzhu1982/article/details/6318600 开发嵌入式Linux的时候经常会遇到segmentation fau ...
- 使用gdb调试段错误
[https://blog.csdn.net/xj9120/article/details/91380074] 1.bt 2.frame number 3.一般是内存问题 4.kill
- Linux下调试段错误 (gdb,core,ulimit)
Linux环境下经常遇到某个进程挂掉而找不到原因,我们可以通过生成core file文件加上gdb来定位. (1)首先 在makefile中要增加编译调试选项 -g,才可以利用下面的gdb来调试 gc ...
- linux ulimit的使用,如何产生core文件,调试段错误
---恢复内容开始--- 下面先简单介绍下ulimit命令: 1. limit -a 可以查看系统各种资源的限制,如: core文件大小,数据段的大小等. $ ulimit -a core file ...
- 使用单进程、strace、gdb调试PHP错误
使用单进程.strace.gdb调试PHP错误 PHP一般是在FPM的呵护下运行的,但是某些情况下进程异常崩溃会导致502.下面是解决思想: 1. 单进程运行: php -d display_erro ...
- 在Linux中调试段错误(core dumped)
在Linux中调试段错误(core dumped) 在作比赛的时候经常遇到段错误, 但是一般都采用的是printf打印信息这种笨方法,而且定位bug比较慢,今天尝试利用gdb工具调试段错误. 段错误( ...
- linux驱动调试--段错误之oops信息分析
linux驱动调试--段错误之oops信息分析 http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29401328&id= ...
- GDB core命令的使用调试段错误
#include <stdio.h> void func(){ int *p = NULL; printf("*p:%d\n", *p);//断错误 } int mai ...
- 利用linux信号机制调试段错误(Segment fault)
在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过 ...
随机推荐
- BZOJ3098 Hash Killer II 【概率】
挺有意思的一题 就是卡一个\(hash\) 我们先取L大概几十保证结果会超出\(10^9 + 7\) 然后就随机输出\(10^5\)个字符 由题目的提示我们可以想到,如果我们有\(n\)个数,选\(k ...
- java面试题之HashMap和TreeMap的区别
HashMap和TreeMap的区别 相同点: 都是以key和value的形式存储: key不可以重复: 都是线程不安全的: 不同点: HashMap的key可以为空 TreeMap的key值是有序的 ...
- hdu 6119 小小粉丝度度熊
小小粉丝度度熊 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- 转 使用putty从linux主机上面往windows主机下面拷贝文件
更新一下,把putty的包解压以后,想要在dos窗口中直接使用,必须把putty解压的文件的路径添加到环境变量中,这样使用起来就会非常简单了. 郁闷了好久,终于搞定了putty的上传下载文件命令psc ...
- 利用jenkins和hockey组织iOS持续交付过程
1. jenkins可以单独作为web应用部署和启动,但建议将其部署在tomcat上,可以方便的管理其他一些web应用,下面讲解如何在Mac设备上安装tomcat 到tomcat官网下载适用于Mac设 ...
- LeetCode OJ--Binary Tree Postorder Traversal
http://oj.leetcode.com/problems/binary-tree-postorder-traversal/ 树的后序遍历,可以使用递归,也可以使用栈,下面是栈的实现代码 #inc ...
- 转载——Step by Step 创建一个 Web Service
原创地址:http://www.cnblogs.com/jfzhu/p/4022139.html 转载请注明出处 (一)创建Web Service 创建第一个项目,类型选择ASP.NET Empty ...
- 洛谷—— P2251 质量检测
https://www.luogu.org/problemnew/show/P2251 题目背景 无 题目描述 为了检测生产流水线上总共N件产品的质量,我们首先给每一件产品打一个分数A表示其品质,然后 ...
- 洛谷——P2912 [USACO08OCT]牧场散步Pasture Walking(lca)
题目描述 The N cows (2 <= N <= 1,000) conveniently numbered 1..N are grazing among the N pastures ...
- c实现的trim函数
功能:去掉字符串首尾的空格,换行符等空白. 代码: #include <string.h> #include <stdio.h> #include <ctype.h> ...