Linux coredump调试

一、概念

Coredump:

         Coredump叫做核心转储,它是进程运行时在突然奔溃的那一刻的一个内存快照。操作系统在程序发生异常而异常在进程内部又没有在内部灭有被捕获的情况下,会把进程此刻内存、寄存器状态、运行堆栈等信息转储保存在一个文件里。

       该文件也是二进制文件,可以使用gdb、elfdump、objdump或者windows下的windebug、solaris下的mdb进行打开分析里面的具体内容。

二、产生原因

  • 内存访问越界

1)由于使用错误的下标,导致数组访问越界;

2)搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符;

3)使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。

  • 多线程程序使用了线程不安全的函数;
  • 多线程读写的数据未加锁保护,对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成core dump;
  • 非法指针

1)使用空指针

2)随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某总结构或类型,或者这种结构或者类型的数据,否则不要将它转换为这种结构或类型的指针,而应该讲这段内存拷贝到一个这种结构或者类型中,再访问这个结构或类型。这是因为

如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它时就很容易因为bus error而core dump。

  • 堆栈溢出

      不要使用大量的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误;

三、设置

1、查看core文件存储位置

$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %P

  2、修改core位置

可以通过修改kernel的参数来指定内核生成的coredump文件的文件名。常见设置如下:

//在终端键入下列命令

echo "/data/coredump/core.%e.%p" > /proc/sys/kernel/core_pattern

      在这条命令中,/data/coredump是你自己指定的存放coredump文件的路径,所有产生的coredump文件将会存放在这里,%e表示程序的文件名,%p表示进程的ID(当然还有一些其他的参数可以设置,例:%t显示创建的时间),但是前提要把目录/data/coredump创建好,不然无法生成文件

%E:程序文件的完整路径(路径中的/会被!替代)

%p:进程 ID

%t:进程奔溃的时间戳

%s:哪个信号让进程奔溃

3、修改core文件大小

linux系统默认生成core文件时空,可以用命令查看

ulimit -c
//详细信息
ulimit -a

如果结果是0,我们需要修改其大小

//当前有效的修改
ulimit -c [size]  //这里size一般修改为unlimited,或者是其他数字:2048

以上修改只对当前的shell有效,一旦关闭,则恢复原来的值

四、实践

readelf -h 读取coredump文件头,判断是不是core文件

root@localhost:/home/localhost/dumpcore# readelf -h core.test2.4824

ELF 头:

  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00

  类别:                              ELF64

  数据:                              2 补码,小端序 (little endian)

  版本:                              1 (current)

  OS/ABI:                            UNIX - System V

  ABI 版本:                          0

  类型:                              CORE (Core 文件)

  系统架构:                          Advanced Micro Devices X86-64

  版本:                              0x1

  入口点地址:               0x0

  程序头起点:          64 (bytes into file)

  Start of section headers:          0 (bytes into file)

  标志:             0x0

  本头的大小:       64 (字节)

  程序头大小:       56 (字节)

  Number of program headers:         32

  节头大小:         0 (字节)

  节头数量:         0

  字符串表索引节头: 0

例子:

程序

#include <iostream>

#include <stdio.h>

#include <stdlib.h>

void DumpCrash(){

char *pStr ="test_conntent";

free(pStr);

}

int main(){

DumpCrash();

return 0;

}

编译:

 

我们发现在相应的目录下出现了core文件,我们用这个core文件来调试一下:

localhost@localhost:~/C++/testcore$ gdb test core

GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1

Copyright (C) 2016 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law.  Type "show copying"

and "show warranty" for details.

This GDB was configured as "x86_64-linux-gnu".

Type "show configuration" for configuration details.

For bug reporting instructions, please see:

<http://www.gnu.org/software/gdb/bugs/>.

Find the GDB manual and other documentation resources online at:

<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".

Type "apropos word" to search for commands related to "word"...

Reading symbols from test...done.

[New LWP 4107]

Core was generated by `./test'.

Program terminated with signal SIGABRT, Aborted.

#0  0x00007f42b5332428 in __GI_raise (sig=sig@entry=6)

---Type <return> to continue, or q <return> to quit---

    at ../sysdeps/unix/sysv/linux/raise.c:54

54../sysdeps/unix/sysv/linux/raise.c: 没有那个文件或目录.

(gdb) where

#0  0x00007f42b5332428 in __GI_raise (sig=sig@entry=6)

    at ../sysdeps/unix/sysv/linux/raise.c:54

#1  0x00007f42b533402a in __GI_abort () at abort.c:89

#2  0x00007f42b53747ea in __libc_message (do_abort=do_abort@entry=2,

    fmt=fmt@entry=0x7f42b548ded8 "*** Error in `%s': %s: 0x%s ***\n")

    at ../sysdeps/posix/libc_fatal.c:175

#3  0x00007f42b5381698 in malloc_printerr (ar_ptr=0x0, ptr=<optimized out>,

    str=0x7f42b548df00 "munmap_chunk(): invalid pointer", action=<optimized out>)

    at malloc.c:5006

#4  munmap_chunk (p=<optimized out>) at malloc.c:2842

#5  __GI___libc_free (mem=<optimized out>) at malloc.c:2963

#6  0x0000000000400722 in DumpCrash () at test.cpp:8

#7  0x000000000040072e in main () at test.cpp:13

 

我们使用where或者bt查看一下堆栈信息:

(gdb) bt

#0  0x00007f42b5332428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54

#1  0x00007f42b533402a in __GI_abort () at abort.c:89

#2  0x00007f42b53747ea in __libc_message (do_abort=do_abort@entry=2,

    fmt=fmt@entry=0x7f42b548ded8 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175

#3  0x00007f42b5381698 in malloc_printerr (ar_ptr=0x0, ptr=<optimized out>,

    str=0x7f42b548df00 "munmap_chunk(): invalid pointer", action=<optimized out>) at malloc.c:5006

#4  munmap_chunk (p=<optimized out>) at malloc.c:2842

#5  __GI___libc_free (mem=<optimized out>) at malloc.c:2963

#6  0x0000000000400722 in DumpCrash () at test:8

#7  0x000000000040072e in main () at test:13

(gdb) where

#0  0x00007f42b5332428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54

#1  0x00007f42b533402a in __GI_abort () at abort.c:89

#2  0x00007f42b53747ea in __libc_message (do_abort=do_abort@entry=2,

    fmt=fmt@entry=0x7f42b548ded8 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175

#3  0x00007f42b5381698 in malloc_printerr (ar_ptr=0x0, ptr=<optimized out>,

    str=0x7f42b548df00 "munmap_chunk(): invalid pointer", action=<optimized out>) at malloc.c:5006

#4  munmap_chunk (p=<optimized out>) at malloc.c:2842

#5  __GI___libc_free (mem=<optimized out>) at malloc.c:2963

#6  0x0000000000400722 in DumpCrash () at test:8

#7  0x000000000040072e in main () at test:13

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值