Linux-debug

1.        内存检查

实际开发中经常出现的问题是内存泄漏,用开源的代码加入检测一下是个很实用的方法

比如用memwatch,它简单适用,只需要memwatch.hmemwatch.c两个文件加入源代码编译;另外记得需要检测的*.c加入memwatch.h这个头文件;最后编译选项加入MEMWATCH。重新编译代码,在memwatch.c目录下产生memwatch.log文件:

============= MEMWATCH 2.71 Copyright (C) 1992-1999 Johan Lindh =============

 

Started at Wed Jan 28 21:50:56 2008

 

Modes: __STDC__ 32-bit mwDWORD==(unsigned long)

mwROUNDALLOC==4 sizeof(mwData)==32 mwDataSize==32

 

 

Stopped at Wed Jan 28 21:51:59 2008

 

unfreed: <1> main.c(371), 8192 bytes at 0x805f7fc      {00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................}

 

Memory usage statistics (global):

 N)umber of allocations made: 1

 L)argest memory usage      : 8192

 T)otal of all alloc() calls: 8192

 U)nfreed bytes totals      : 8192

上面log文件指出,在main.c被执行到第371行时所分配的内存仍未被释放,该段内存的大小为8192byte,查看第371行代码

char *commandBuf=(char *)malloc(MAX_INPUT_LEN);

这里没有释放,需要添加代码free

2.        Crash

另外一个问题就是系统crash问题,这个可以利用gdb连接到调试目标板上,当crash的时候用bt看栈信息;但是推荐在代码中直接利用加sigsegv.csigsegv.h,另外在main函数中加调用setup_sigsegv();即可,下面是写的一个测试crash函数,因为die函数中NULL指针赋值了,运行main的时候会直接挂掉的

......

/*

* Function:    die

* Purpose:    test for backtrace

* Arguments:

* Returns:

*/

int die()

{

    char *err = NULL;

    strcpy(err, "die");

    return 0;

}

 

/*

* Function:    main

* Purpose:

* Arguments:

* Returns:

*/

int main(int argc, char* argv[])

{

    int rc;

    pthread_t pid;

    pthread_t pid_server;

    setup_sigsegv();

 

    rc = pthread_create(&pid, NULL, (void *) &dbg_entry, NULL);

    if (rc < 0)

        printf("error:%s/n", strerror(rc));  

 

    rc = pthread_create(&pid_server, NULL, (void *) &dbg_server1,

            (void *) "/var/dbg.ipc");   

    if (rc < 0)

        printf("error:%s/n", strerror(rc));  

    die();

    while (1);

    return 0;

}

这里是挂掉后打印出来的信息,在地址0x8049f49的地方挂掉的,此函数运行结束后PC的地址是0x8049fd9

### BEGIN LOG - DATE: 081025, TIME: 145642 ###

 

./debug

Segmentation Fault!

info.si_signo = 11

info.si_errno = 0

info.si_code  = 1 (SEGV_MAPERR)

info.si_addr  = (nil)

reg[00]       = 0x00000033

reg[01]       = 0x00000000

reg[02]       = 0x0000007b

reg[03]       = 0x0000007b

reg[04]       = 0xbffdd670

reg[05]       = 0xbffdd6e4

reg[06]       = 0xbffdd638

reg[07]       = 0xbffdd638

reg[08]       = 0x00d25ff4

reg[09]       = 0x00000000

reg[10]       = 0xb75df4c4

reg[11]       = 0x00000000

reg[12]       = 0x0000000e

reg[13]       = 0x00000006

reg[14]       = 0x08049f49

reg[15]       = 0x00000073

reg[16]       = 0x00010246

reg[17]       = 0xbffdd638

reg[18]       = 0x0000007b

Stack trace:

 1: 0x8049f49 <(null)+134520649> (./debug)

 2: 0x8049fd9 <(null)+134520793> (./debug)

 3: 0xc15e23 <__libc_start_main+211> (/lib/tls/libc.so.6)

End of stack trace

[huangyonggang@localhost bin.x86]$

 

### END LOG - DATE: 081025, TIME: 145652 ###

于是        

反汇编[huangyonggang@localhost bin.x86]$ objdump -D debug &>log

或者[huangyonggang@localhost bin.x86]$ strace debug &>log1

可以得到后面的,根据上面的栈信息,可以找到8049f49地址就是挂掉的位置,这里就是die函数中的串拷贝,接着找8049fd9地址,就是die函数结束后PC的地址

......

08049f46 <die>:

 8049f46:    55                       push   %ebp

 8049f47:    89 e5                    mov    %esp,%ebp

 8049f49:    c7 05 00 00 00 00 64     movl   $0x656964,0x0

 8049f50:    69 65 00

 8049f53:    b8 00 00 00 00           mov    $0x0,%eax

 8049f58:    c9                       leave 

 8049f59:    c3                       ret   

 

08049f5a <main>:

 8049f5a:    55                       push   %ebp

 8049f5b:    89 e5                    mov    %esp,%ebp

 8049f5d:    83 ec 08                 sub    $0x8,%esp

 8049f60:    83 e4 f0                 and    $0xfffffff0,%esp

 8049f63:    83 ec 10                 sub    $0x10,%esp

 8049f66:    e8 82 08 00 00           call   804a7ed <setup_sigsegv>

 8049f6b:    6a 00                    push   $0x0

 8049f6d:    68 4b 97 04 08           push   $0x804974b

 8049f72:    6a 00                    push   $0x0

 8049f74:    8d 45 fc                 lea    0xfffffffc(%ebp),%eax

 8049f77:    50                       push   %eax

 8049f78:    e8 43 ef ff ff           call   8048ec0 <pthread_create@plt>

 8049f7d:    83 c4 10                 add    $0x10,%esp

 8049f80:    85 c0                    test   %eax,%eax

 8049f82:    79 1a                    jns    8049f9e <main+0x44>

 8049f84:    83 ec 0c                 sub    $0xc,%esp

 8049f87:    50                       push   %eax

 8049f88:    e8 63 ef ff ff           call   8048ef0 <strerror@plt>

 8049f8d:    83 c4 08                 add    $0x8,%esp

 8049f90:    50                       push   %eax

 8049f91:    68 bf e3 04 08           push   $0x804e3bf

 8049f96:    e8 63 f7 ff ff           call   80496fe <printf>

 8049f9b:    83 c4 10                 add    $0x10,%esp

 8049f9e:    68 c9 e3 04 08           push   $0x804e3c9

 8049fa3:    68 79 9b 04 08           push   $0x8049b79

 8049fa8:    6a 00                    push   $0x0

 8049faa:    8d 45 f8                 lea    0xfffffff8(%ebp),%eax

 8049fad:    50                       push   %eax

 8049fae:    e8 0d ef ff ff           call   8048ec0 <pthread_create@plt>

 8049fb3:    83 c4 10                 add    $0x10,%esp

 8049fb6:    85 c0                    test   %eax,%eax

 8049fb8:    79 1a                    jns    8049fd4 <main+0x7a>

 8049fba:    83 ec 0c                 sub    $0xc,%esp

 8049fbd:    50                       push   %eax

 8049fbe:    e8 2d ef ff ff           call   8048ef0 <strerror@plt>

 8049fc3:    83 c4 08                 add    $0x8,%esp

 8049fc6:    50                       push   %eax

 8049fc7:    68 bf e3 04 08           push   $0x804e3bf

 8049fcc:    e8 2d f7 ff ff           call   80496fe <printf>

 8049fd1:    83 c4 10                 add    $0x10,%esp

 8049fd4:    e8 6d ff ff ff           call   8049f46 <die>

 8049fd9:    eb fe                    jmp    8049fd9 <main+0x7f>

 8049fdb:    90                       nop   

......

更进一步的设计是把这些打印信息打到syslog放到储存中去,这样的话,系统crash过后,可以拿出来分析

3.        sigsegv的实现

分析sigsegv的实现,SIGSEGV信号意味着指针所对应的地址是无效地址,没有物理内存对应该地址,绑定信号处理函数signal_segv,当段错误出现的时候会处理;实际应用中可能crash是因为其它比如信号SIGBUS,这个信号是因为试图访问一块无文件内容对应的内存区域,比如超过文件尾的内存区域;所以多绑定几个经常引起死机的信号是必需的

int setup_sigsegv() {

    struct sigaction action;

    memset(&action, 0, sizeof(action));

    action.sa_sigaction = signal_segv;

    action.sa_flags = SA_SIGINFO;

    if(sigaction(SIGSEGV, &action, NULL) < 0) {

        perror("sigaction");

        return 0;

    }

 

    return 1;

}

4.        小结

嵌入式的ARMPPCsigsegv不好用,只可以到两层,不像x86可以到很多层,经常找不到crash问题   

 

你可能感兴趣的:(Linux-debug)