内存泄露定位:
#include <mcheck.h>
启动函数开头定义:
setenv("MALLOC_TRACE", "mtrace.out", 1);
mtrace();
crach定位:
参考:
https://blog.csdn.net/gongmin856/article/details/79192259
/*
* dump.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h> /* for signal */
#include <execinfo.h> /* for backtrace() */
#define BACKTRACE_SIZE 16
void dump(void)
{
int j, nptrs;
void *buffer[BACKTRACE_SIZE];
char **strings;
nptrs = backtrace(buffer, BACKTRACE_SIZE);
printf("backtrace() returned %d addresses\n", nptrs);
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
perror("backtrace_symbols");
exit(EXIT_FAILURE);
}
for (j = 0; j < nptrs; j++)
printf(" [%02d] %s\n", j, strings[j]);
free(strings);
}
void signal_handler(int signo)
{
#if 0
char buff[64] = {0x00};
sprintf(buff,"cat /proc/%d/maps", getpid());
system((const char*) buff);
#endif
printf("\n=========>>>catch signal %d <<<=========\n", signo);
printf("Dump stack start...\n");
dump();
printf("Dump stack end...\n");
signal(signo, SIG_DFL); /* 恢复信号默认处理 */
raise(signo); /* 重新发送信号 */
}
int main(int argc, char *argv[])
{
int sum = 0x00;
signal(SIGSEGV, signal_handler); /* 为SIGSEGV信号安装新的处理函数 */
sum = add(sum);
printf(" sum = %d \n", sum);
return 0x00;
}
....................................................
7f0962fb3000-7f0962fb4000 r-xp 00000000 08:01 2895572 /home/share/work/backtrace/libadd.so
7f0962fb4000-7f09631b3000 ---p 00001000 08:01 2895572 /home/share/work/backtrace/libadd.so
7f09631b3000-7f09631b4000 r--p 00000000 08:01 2895572 /home/share/work/backtrace/libadd.so
7f09631b4000-7f09631b5000 rw-p 00001000 08:01 2895572 /home/share/work/backtrace/libadd.so
.....................................................
=========>>>catch signal 11 <<<=========
Dump stack start...
backtrace() returned 8 addresses
[00] ./backtrace(dump+0x1f) [0x400b7f]
[01] ./backtrace(signal_handler+0x83) [0x400c99]
[02] /lib/x86_64-linux-gnu/libc.so.6(+0x36150) [0x7f0962c2b150]
[03] ./libadd.so(add1+0x1a) [0x7f0962fb35c6]
[04] ./libadd.so(add+0x1c) [0x7f0962fb35f9]
[05] ./backtrace(main+0x2f) [0x400b53]
[06] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f0962c1676d]
[07] ./backtrace() [0x400a69]
Dump stack end...
段错误 (核心已转储)
所有我们正确的地址应为0x7f0962fb35c6 - 7f0962fb3000 = 0x5c6,将这个地址利用addr2line命令得到如下结果:
addr2line -e libadd.so 0x5c6
##############废弃##################
本文出自http://www.linuxidc.com/Linux/2012-11/73470p2.htm
其实很多错误不能捕获,这只是一种方法!
通常情况系,程序发生段错误时系统会发送SIGSEGV信号给程序,缺省处理是退出函数。我们可以使用 signal(SIGSEGV, &your_function);函数来接管SIGSEGV信号的处理,程序在发生段错误后,自动调用我们准备好的函数,从而在那个函数里来获取当前函数调用栈。 但是实际运用中,有些错误还是无法定位!
信号定义:参考:https://blog.csdn.net/LEON1741/article/details/78143460/
01)SIGHUP:本信号在用户终端连接(正常或非正常)结束时发出,通常是在终端的控制进程结束时,通知同一session内的各个作业,这时它们与控制终端不再关联;
02)SIGINT:程序终止(interrupt)信号,在用户键入INTR字符(通常是Ctrl-C)时发出;
03)SIGQUIT:和SIGINT类似,但由QUIT字符(通常是Ctrl-)来控制。进程在因收到SIGQUIT退出时会产生core文件,在这个意义上类似于一个程序错误信号;
04)SIGILL:执行了非法指令。通常是因为可执行文件本身出现错误,或者试图执行数据段。堆栈溢出时也有可能产生这个信号;
05)SIGTRAP:由断点指令或其它trap指令产生,由debugger使用;
06)SIGABRT:程序自己发现错误并调用abort时产生;
06)SIGIOT:在PDP-11上由iot指令产生,在其它机器上和SIGABRT一样;
07)SIGBUS:非法地址,:包括内存地址对齐(alignment)出错。eg:访问一个四个字长的整数,但其地址不是4的倍数;
08)SIGFPE:在发生致命的算术运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术的错误;
09)SIGKILL:用来立即结束程序的运行。本信号不能被阻塞,处理和忽略;
10)SIGUSR1:留给用户使用;
11)SIGSEGV:试图访问未分配给自己的内存,或试图往没有写权限的内存地址写数据;
12)SIGUSR2:留给用户使用;
13)SIGPIPE:Broken:pipe;
14)SIGALRM:时钟定时信号,计算的是实际的时间或时钟时间。alarm函数使用该信号;
15)SIGTERM:程序结束(terminate)信号,与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出。shell命令kill缺省产生这个信号;
17)SIGCHLD:子进程结束时,父进程会收到这个信号;
18)SIGCONT:让一个停止(stopped)的进程继续执行。本信号不能被阻塞。可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作。例如,重新显示提示符;
19)SIGSTOP:停止(stopped)进程的执行。注意它和terminate以及interrupt的区别:该进程还未结束,只是暂停执行。本信号不能被阻塞,处理或忽略;
20)SIGTSTP:停止进程的运行,但该信号可以被处理和忽略。用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号;
21)SIGTTIN:当后台作业要从用户终端读数据时,该作业中的所有进程会收到SIGTTIN信号。缺省时这些进程会停止执行;
22)SIGTTOU:类似于SIGTTIN,但在写终端(或修改终端模式)时收到;
23)SIGURG:有”紧急”数据或out-of-band数据到达socket时产生;
24)SIGXCPU:超过CPU时间资源限制。这个限制可以由getrlimit/setrlimit来读取/改变;
25)SIGXFSZ:超过文件大小资源限制;
26)SIGVTALRM:虚拟时钟信号。类似于SIGALRM,但是计算的是该进程占用的CPU时间;
27)SIGPROF:类似于SIGALRM/SIGVTALRM,但包括该进程用的CPU时间以及系统调用的时间;
28)SIGWINCH:窗口大小改变时发出;
29)SIGIO:文件描述符准备就绪,可以开始进行输入/输出操作;
30)SIGPWR:Power:failure;
举例如下:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <execinfo.h>
#include <signal.h>
void dump(int signo)
{
void *buffer[30] = {0};
size_t size;
char **strings = NULL;
size_t i = 0;
size = backtrace(buffer, 30);//以下2函数用于获得本进程当前栈信息。定位段错误地址
fprintf(stdout, "Obtained %zd stack frames.nm\n", size);
strings = backtrace_symbols(buffer, size);
if (strings == NULL)
{
perror("backtrace_symbols.");
exit(EXIT_FAILURE);
}
for (i = 0; i < size; i++)
{
fprintf(stdout, "%s\n", strings[i]);
}
free(strings);
strings = NULL;
exit(0);
}
void func_c()
{
*((volatile char *)0x0) = 0x9999;
}
void func_b()
{
func_c();
}
void func_a()
{
func_b();
}
int main(int argc, const char *argv[])
{
signal(SIGABRT, dump);
signal(SIGBUS, dump);
if (signal(SIGSEGV, dump) == SIG_ERR)
perror("can't catch SIGSEGV");
func_a();
return 0;
}
编译程序:-rdynamic 才能打印调用函数 -g(调试模式)才能使用addr2line定位地址
gcc -g -rdynamic test.c -o test; ./test
输出如下:
Obtained6stackframes.nm
./backstrace_debug(dump+0x45)[0x80487c9]
[0x468400]
./backstrace_debug(func_b+0x8)[0x804888c]
./backstrace_debug(func_a+0x8)[0x8048896]
./backstrace_debug(main+0x33)[0x80488cb]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x129113]
接着:
objdump -d test > test.s
在test.s中搜索804888c如下:
8048884 <func_b>:
8048884: 55 push %ebp
8048885: 89 e5 mov %esp, %ebp
8048887: e8 eb ff ff ff call 8048877 <func_c>
804888c: 5d pop %ebp
804888d: c3 ret
其中80488c时调用(call 8048877)C函数后的地址,虽然并没有直接定位到C函数,通过汇编代码, 基本可以推出是C函数出问题了(pop指令不会导致段错误的)。
我们也可以通过addr2line来查看
addr2line 0x804888c -e backstrace_debug -f
输出:
func_b
/home/astrol/c/backstrace_debug.c:57