1. 程式人生 > >gdb除錯coredump(原理篇)

gdb除錯coredump(原理篇)

上一篇部落格裡我們通過3個例子介紹了gdb除錯coredump的時候,比較常用到的一些命令和定位方法。這篇內容裡,我們將嘗試去探討gdb除錯coredump的原理,以及它們背後的一些東西。

Coredump 的原理

  1coredump簡介

上一篇部落格,我們也提到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命令對應的。


  2coredump檔案格式

1)使用file命令檢視

[email protected]:/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*

 

如上,通過readelfobjdump我們可以看到,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的整體結構圖: