gdb调试coredump(原理篇)

上一篇博客里我们通过3个例子介绍了gdb调试coredump的时候,比较常用到的一些命令和定位方法。这篇内容里,我们将尝试去探讨gdb调试coredump的原理,以及它们背后的一些东西。

Coredump 的原理

  1、coredump简介

上一篇博客,我们也提到coredump叫做核心转储,实际上也就是进程运行过程中的一个内存快照,当进程crash的时候,操作系统接收异常指令之后,在进程crash之前,会把进程做一个内存快照,将这些信息保存在一个文件中,这个文件就是coredump文件。

这个文件里包含进程的内存里的地址信息,寄存器信息,堆栈调用信息等。

能造成进程coredump的信号有:

名字

说明

ANSI C  POSIX.1

SVR4  4.3+BSD

缺省动作

SIGABRT

异常终止(abort)

  .       .

  .      .

终止w/core

SIGBUS

硬件故障

          .

  .      .

终止w/core

SIGEMT

硬件故障

  .      .

终止w/core

SIGFPE

算术异常

  .       .

  .      .

终止w/core

SIGILL

非法硬件指令

  .       .

  .      .

终止w/core

SIGIOT

硬件故障

  .      .

终止w/core

SIGQUIT

终端退出符

          .

  .      .

终止w/core

SIGSEGV

无效存储访问

  .       .

  .      .

终止w/core

SIGSYS

无效系统调用

  .      .

终止w/core

SIGTRAP

硬件故障

  .      .

终止w/core

SIGXCPU

超过CPU限制(setrlimit)

  .      .

终止w/core

SIGXFSZ

超过文件长度限制(setrlimit)

  .      .

终止w/core

如我们最常见的segmentfault 就是对应上面的SIGSEGV,也就是对应kill命令的信号11.

上面的所有信号都是和kill命令对应的。

  2、coredump文件格式

1)使用file命令查看

root@ubuntu:/var/core_log# file core_DumpNewTest_1483768078_6527

core_DumpNewTest_1483768078_6527: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from './DumpNewTest'

如上,通过file命令,可以看到这个文件是core file,同时由哪个进程产生

  2)试用readelf查看

  Readelf -h core* 即可看到core文件的类型里标识为

 

如下,为ELF.h头文件的定义

如图,有一个字节标识ELF文件类型。

 

如上,ELF格式的文件主要有4种类型。Core文件对应的e_type的值为4。

3) 查看core文件内容

readelf -a core*

 

使用objdump -t 查看,

objdump -t core*

 

如上,通过readelf和objdump我们可以看到,core文件和其他ELF格式文件相比,少了很多头节点信息,同时也没有符号表信息和调试信息等内容。

但它记录了程序之前的装载地址和地址偏移,以及堆栈、寄存器等信息。

gdb的原理

 GDB由三个部分组成:
 (1)用户接口user interface,除支持传统的CLI接口还支持mi接口(ddd等工具使用)
 (2)符号处理层symbol handling,当gdb ./debugme后GDB会读取文件的符号信息,之后的原代码,变量/函数/类型的显示都由该部分进行(everything you can do without live process)。
 (3)目标系统处理层target system handling。包括执行控制,断点设置,单步执行,堆栈分析等操作都有该部分来进行。

 

BFD provides support for gdb in several ways:

identifying executable and core files

BFD will identify a variety of file types, including a.out, coff, and several variants

thereof, as well as several kinds of core files.

access to sections of files

BFD parses the file headers to determine the names, virtual addresses, sizes,

and file locations of all the various named sections in files (such as the text

section or the data section). gdb simply calls BFD to read or write section x

at byte offset y for length z.

specialized core file support

BFD provides routines to determine the failing command name stored in a core

file, the signal with which the program failed, and whether a core file matches

(i.e. could be a core dump of) a particular executable file.

locating the symbol information

gdb uses an internal interface of BFD to determine where to find the symbol

information in an executable file or symbol-file. gdb itself handles the reading of symbols, since BFD does not “understand” debug symbols, but gdb uses

BFD’s cached information to find the symbols, string table, etc.

如上,在gdb的官方用户手册上,有说明,gdb通过BFD来识别core文件,同时通过BFD提供的一套现有机制来确定core文件中的程序crash的命令以及导致crash相关的信号,并能够确定一个core文件和可执行程序是否匹配。BFD还提供了一套接口给gdb用于读取可执行文件中的符号信息等。

 

如上截图,regset_from_core_section 接口中提供了读取和解析正确的寄存器信息的能力。

 

如上,gdb通过使用BFD,以及自身封装和实现了一些接口,结合起来能够识别并读取core文件信息,并和可执行文件匹配起来,从core文件中读取调用堆栈、crash的信号、命令,寄存器信息等内容,再从可执行文件中找到匹配的符号信息,能够使得gdb调试core文件时让我们能看到地址和地址偏移对应的符号,而不是十六进制的数字。

Gdb对BFD的依赖

根据上面的GDB官方用户手册上可以看到,gdb是通过BFD来读取core文件的堆栈、寄存器等信息,因此从这点上看gdb是依赖于bfd的。

从头文件:

从头文件引用看,gdb是引用了BFD的头文件的。因此我认为是可以理解为GDB需要依赖于BFD的库的。

但是通过ldd看,却看不到依赖关系

 

如上截图,objudmp是依赖了bfd的,但是gdb却看不到bfd的依赖关系。这是什么情况呢?

刚开始,我认为可能是gdb属于间接依赖了bfd,我把gdb所有依赖的库都ldd了一下,但是都没有依赖bfd的,而且就算是间接依赖应该通过ldd也能看到。这个问题困扰了为很久。最后又去看了一下gdb的源码目录结构,发现,gdb源码里实际是有BFD的,也就是说gdb把bfd给直接包含进来了。

 

如上图,gdb源码里有一个单独的BFD目录,里面包含了BFD的完整实现。因此gdb对于系统中额bfd库不存在依赖,而是它直接包含了bfd的完整实现。

下图是gdb的整体结构图:

猜你喜欢

转载自blog.csdn.net/sunlin972913894/article/details/113001810