偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

圖文詳解 Gcc -g 調(diào)試信息

系統(tǒng) Linux
DWARF(全稱:Debugging With Attributed Record Formats)是一種廣泛使用的調(diào)試數(shù)據(jù)格式標(biāo)準(zhǔn),旨在為編譯器、調(diào)試器和其他工具提供一種標(biāo)準(zhǔn)化的機(jī)制,用于描述程序的源代碼結(jié)構(gòu)、變量、類型、函數(shù)調(diào)用棧等信息。

大家好,這里是物聯(lián)網(wǎng)心球。

作為一個Linux開發(fā)者,我們經(jīng)常會通過gcc -g命令來編譯可執(zhí)行程序,-g選項(xiàng)能夠生成調(diào)試信息,開發(fā)者根據(jù)調(diào)試信息能夠快速定位并排查程序問題。

那么,調(diào)試信息到底是什么呢?本文我們一探究竟。

1.調(diào)試信息的重要性

gdb調(diào)試是一種非常重要的調(diào)試手段,如果gdb調(diào)試的程序沒有調(diào)試信息,那么我們將無法從gdb調(diào)試器中獲取到有價值的信息,調(diào)試過程也會異常困難。下面我們通過幾個場景來驗(yàn)證一下。

場景1:查看變量

通過print命令打印變量的值時,帶調(diào)試信息輸出示例如下:

(gdb) print a
$1 = 100

未帶調(diào)試信息輸出示例如下:

(gdb) print a
'a' has unknown type; cast it to its declared type

gdb調(diào)試未帶調(diào)試信息的可執(zhí)行程序時無法識別變量。

場景2:打印數(shù)據(jù)類型

通過ptype命令打印數(shù)據(jù)類型,帶調(diào)試信息輸出示例如下:

(gdb) ptype it
type = struct item {
    char num;
    int data;
}

未帶調(diào)試信息輸出示例如下:

(gdb) ptype it
No symbol table is loaded. Use the "file" command.

gdb調(diào)試未帶調(diào)試信息的可執(zhí)行程序時無法識別數(shù)據(jù)類型。

場景3:指定源文件行號設(shè)置斷點(diǎn)

通過break命令在源文件指定行號設(shè)置斷點(diǎn),帶調(diào)試信息輸出示例如下:

(gdb) break main.c:12
Breakpoint 2 at 0x55555555515c: file main.c, line 14.

未帶調(diào)試信息輸出示例如下:

(gdb) break main.c:12
No symbol table is loaded. Use the "file" command.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (main.c:12) pending.

gdb調(diào)試未帶調(diào)試信息的可執(zhí)行程序時,無法在指定源文件行號設(shè)置斷點(diǎn)。

場景4:打印堆棧

通過bt命令打印堆棧信息,帶調(diào)試信息輸出示例如下:

(gdb) bt
#0 main (argc=1, argv=0x7fffffffe468) at main.c:14

未帶調(diào)試信息輸出示例如下:

(gdb) bt
#0 0x0000555555555151 in main ()

gdb調(diào)試未帶調(diào)試信息的可執(zhí)行程序時,打印堆棧信息無行號和其他調(diào)試信息。

通過以上幾個場景的對比,我們能夠直觀的感受到,帶調(diào)試信息的可執(zhí)行文件能夠提供更加豐富和關(guān)鍵的調(diào)試信息,協(xié)助開發(fā)者高效地解決問題。

2.認(rèn)識調(diào)試信息   

調(diào)試信息其實(shí)并不神秘,它是嵌入在ELF文件中的節(jié),這些節(jié)的形式為.debug_*(*代表不同的節(jié))。

我們通過圖1來深入學(xué)習(xí)調(diào)試信息。

圖1    兩種文件對比圖1 兩種文件對比

圖1左邊為無調(diào)試信息可執(zhí)行文件,右邊為帶調(diào)試信息可執(zhí)行文件。無調(diào)試信息可執(zhí)行文件中的內(nèi)容比較少,文件占用內(nèi)存空間也比較小。通過對比,我們發(fā)現(xiàn)帶調(diào)試信息可執(zhí)行文件多了一些節(jié):.debug_aranges節(jié)、.debug_info節(jié)、.debug_abbrev節(jié)、.debug_line節(jié)、.debug_str節(jié)、.debug_line_str節(jié)。這些多出來的節(jié)就是我們今天的主角:調(diào)試信息。這些節(jié)并不是隨意生成的,需要遵循一定的規(guī)則,這個規(guī)則就是DWARF。

3.DWARF介紹

DWARF(全稱:Debugging With Attributed Record Formats)是一種廣泛使用的調(diào)試數(shù)據(jù)格式標(biāo)準(zhǔn),旨在為編譯器、調(diào)試器和其他工具提供一種標(biāo)準(zhǔn)化的機(jī)制,用于描述程序的源代碼結(jié)構(gòu)、變量、類型、函數(shù)調(diào)用棧等信息。

DWARF共經(jīng)歷了5個版本的迭代: 

  • DWARF1:1992年發(fā)布,為Unix System V的sdb調(diào)試器設(shè)計,支持C 語言,現(xiàn)已很少使用。
  • DWARF2:1993年發(fā)布,修正v1問題,增加C++支持,引入數(shù)據(jù)壓縮。
  • DWARF3:2005年發(fā)布,增加對多種語言支持,優(yōu)化數(shù)據(jù)壓縮。
  • DWARF4:2010年發(fā)布,進(jìn)一步改善數(shù)據(jù)壓縮,支持編譯器優(yōu)化后代碼描述。
  • DWARF5:2017年發(fā)布,支持調(diào)試信息分離,改進(jìn)宏和源文件描述。

DWARF的規(guī)則很復(fù)雜,筆者不建議大家直接研究DWARF標(biāo)準(zhǔn)。我們可以把DWARF標(biāo)準(zhǔn)當(dāng)做一個手冊,當(dāng)我們學(xué)習(xí)的過程中遇到問題再去查閱它。相較于直接學(xué)習(xí)DWARF標(biāo)準(zhǔn),更為有效的學(xué)習(xí)方法是選搞懂各種調(diào)試節(jié)(.debug_*)的原理和作用。

以DWARF5為例,常見的調(diào)試節(jié)見表1。

表1    DWARF5常見調(diào)試節(jié)表1 DWARF5常見調(diào)試節(jié)

通過命令:readelf -w 可執(zhí)行文件,可顯示所有的調(diào)試節(jié)。由于該命令展示的內(nèi)容比較多,限于篇幅,這里不展示輸出示例。

3.1 .debug_aranges節(jié)

.debug_aranges節(jié)用于提供內(nèi)存地址與編譯單元之間的映射關(guān)系,編譯單元后續(xù)會詳細(xì)介紹。通過.debug_aranges節(jié),調(diào)試器可以快速將程序計數(shù)器(PC)的值映射到.debug_info節(jié)中的編譯單元,從而獲取相關(guān)的調(diào)試信息。

通過命令:readelf -wr 可執(zhí)行文件,可查看.debug_aranges信息,輸出示例如下:

圖片圖片

.debug_aranges節(jié)分為兩個部分:頭部信息和地址范圍表。

頭部信息相關(guān)字段如下:

  • Length:表示該節(jié)的總長度(不包括這個長度字段本身)。
  • Version:表示 DWARF 格式的版本號,通常為2或4。
  • Offset into .debug_info:表示.debug_info節(jié)中的偏移量,用于定位編譯單元的起始位置。
  • Pointer Size:表示目標(biāo)系統(tǒng)中指針的大小,以字節(jié)為單位。
  • Segment Size:表示目標(biāo)系統(tǒng)中段選擇符的大小,以字節(jié)為單位,通常為 0。
    地址范圍表由一系列的地址范圍對組成,每個地址范圍對包含兩個字段:
  • Address:表示地址范圍的起始地址。
  • Length:表示地址范圍的長度。

gcc編譯可執(zhí)行程序時,會將源文件(如.c/.cpp文件)編譯成編譯單元并將編譯單元覆蓋的地址范圍記錄在.debug_aranges節(jié)。

gdb需要確定某個指令地址(如:0x7fff1234)對應(yīng)的源代碼位置時:    首先,通過0x7fff1234地址查詢.debug_aranges節(jié)地址范圍表,找到對應(yīng)的編譯單元在.debug_info中的偏移;然后,通過偏移定位到.debug_info中的編譯單元;最后,從編譯單元開始解析DIE樹,獲取到源碼相關(guān)的信息。

3.2 .debug_info節(jié)

.debug_info節(jié)由調(diào)試信息條目(Debugging Information Entry,DIE)構(gòu)成。DIE是.debug_info節(jié)中的一個基本單元,它通過標(biāo)簽(Tag)和屬性(Attributes)來描述程序中的一個語義實(shí)體(如:函數(shù)名、參數(shù)、局部變量、代碼行號范圍)。每個DIE可以有多個子條目,形成一個樹狀結(jié)構(gòu),用于描述更復(fù)雜的語義關(guān)系。

通過命令:readelf -wi 可執(zhí)行文件,可查看.debug_info信息,輸出示例如下:

圖片圖片

每個 DIE 包含以下幾個部分:

(1)Tag(標(biāo)簽)

Tag 是一個單字節(jié)的值,用于標(biāo)識調(diào)試信息條目(DIE)的類型。常見的Tag如下:

  • DW_TAG_compile_unit:表示一個編譯單元,通常是源文件。
  • DW_TAG_subprogram:表示一個函數(shù)或方法。
  • DW_TAG_variable:表示一個變量,可以是全局變量或局部變量。
  • DW_TAG_formal_parameter:表示函數(shù)的參數(shù)。
  • DW_TAG_typedef:表示一個類型定義。
  • DW_TAG_structure_type:表示一個結(jié)構(gòu)體類型。  
  • DW_TAG_union_type:表示一個聯(lián)合體類型。   
  • DW_TAG_enumeration_type:表示一個枚舉類型。  
  • DW_TAG_array_type:表示一個數(shù)組類型。
  • DW_TAG_base_type:表示一個基本類型,如int 、float等。
(2)Attributes(屬性)

Attributes 是一個屬性列表,每個屬性由一個屬性名稱和一個屬性值組成。常見的Attributes如下:

  • DW_AT_name:表示實(shí)體的名稱,如變量名、函數(shù)名、文件名等。  
  • DW_AT_type:表示實(shí)體的類型,通常是一個偏移量,指向.debug_info節(jié)中的另一個 DIE。
  • DW_AT_location:表示變量的存儲位置,可以是寄存器或內(nèi)存地址。
  • DW_AT_low_pc和DW_AT_high_pc:表示函數(shù)的代碼范圍,分別表示函數(shù)的起始地址和結(jié)束地址。
  • DW_AT_decl_file、DW_AT_decl_line 和DW_AT_decl_column:表示實(shí)體在源文件中的聲明位置。
(3)Children(子條目)

Children 是一個 DIE 的子條目列表,每個子條目也是一個 DIE。

3.3 .debug_abbrev節(jié)

.debug_abbrev節(jié)用于定義.debug_info節(jié)中調(diào)試信息條目(DIE)的結(jié)構(gòu)和屬性的縮寫表。通過使用縮寫表,.debug_info節(jié)可以更高效地存儲和解析調(diào)試信息,減少重復(fù)數(shù)據(jù)的存儲。

通過命令:readelf -wa 可執(zhí)行文件,可查看.debug_abbrev節(jié)信息,輸出示例如下:

圖片圖片

.debug_abbrev節(jié)中的DIE和.debug_info節(jié)中的DIE互為抽象和實(shí)現(xiàn)的關(guān)系。一個比較形象的比喻,.debug_abbrev節(jié)中的DIE如同C++中的類,.debug_info節(jié)中的DIE如同C++中的對象。類是數(shù)據(jù)類型,對象為類的具體實(shí)現(xiàn)。

3.4 .debug_line節(jié)

.debug_line節(jié)建立了機(jī)器指令地址與源代碼行號之間的映射關(guān)系,是實(shí)現(xiàn)源碼級調(diào)試的核心基礎(chǔ)。

.debug_line節(jié)的核心功能是:

  • 提供源代碼行號與機(jī)器指令地址的精確映射。
  • 使調(diào)試器能夠?qū)⒊绦蛴嫈?shù)器(PC)值轉(zhuǎn)換為源代碼位置。
  • 支持設(shè)置斷點(diǎn)、單步執(zhí)行和堆棧跟蹤等基本調(diào)試功能。

通過命令:readelf -wl 可執(zhí)行文件,可查看.debug_line節(jié)信息,輸出示例如下:

圖片圖片

注意,.debug_line節(jié)的規(guī)則比較復(fù)雜,我們可以跳過規(guī)則學(xué)習(xí),先了解.debug_line的作用。.debug_line節(jié)最終將會呈現(xiàn)一個指令地址和源文件行號的映射表,見表2。

表2    .debug_line指令地址和行號映射表表2 .debug_line指令地址和行號映射表

3.5 .debug_str節(jié)

.debug_str節(jié)是一個字符串池,它存儲了調(diào)試過程中所需的所有字符串?dāng)?shù)據(jù),包括:函數(shù)名、變量名、類型名、編譯器信息、其他文本描述。

通過命令:readelf -ws 可執(zhí)行文件,可查看.debug_str節(jié)信息,輸出示例如下:

圖片圖片

從輸出示例可以看到.debug_str包含一些我們比較常見的字符串,如果我們想使用這些字符串,只需要從調(diào)試文件指定的位置讀取這些字符串即可。

3.6 .debug_line_str節(jié)

.debug_line_str節(jié)同樣是一個字符串池。這些字符串通常包括文件名、目錄路徑等,它們被.debug_line節(jié)中的行號程序引用。

輸出示例如下:

圖片圖片

.debug_line_str和.debug_str的使用方法類似。

4.調(diào)試信息分離

調(diào)試信息分離是指將調(diào)試信息從可執(zhí)行文件中分離出來,存儲在單獨(dú)的文件中。將調(diào)試信息存儲在單獨(dú)的文件有幾個優(yōu)點(diǎn):

  • 減小可執(zhí)行文件大?。和ㄟ^將調(diào)試信息分離到單獨(dú)的文件中,可執(zhí)行文件的大小可以顯著減小。
  • 提高安全性:分離的調(diào)試信息文件可以存儲在安全的環(huán)境中,從而防止調(diào)試信息泄露。
  • 提高性能:較小的可執(zhí)行文件可以更快地加載和運(yùn)行,從而提高應(yīng)用程序的性能。

4.1 實(shí)現(xiàn)原理

為了讓大家更好的理解調(diào)試信息分離的過程,我們通過一張圖描述該過程,如圖2所示。

圖2    調(diào)試信息分離

調(diào)試信息分離具體步驟如下:

  • 步驟1:編譯帶調(diào)試信息的可執(zhí)行程序。

gcc -g編譯帶調(diào)試信息的可執(zhí)行文件,以test程序?yàn)槔?,命令如下?/span>

gcc -g -o test test.c
  • 步驟2:生成單獨(dú)的調(diào)試信息文件。

使用objcopy命令的--only-keep-debug選項(xiàng),將調(diào)試信息提取到一個單獨(dú)的文件中,命令如下:

objcopy --only-keep-debug test test.debug

test.debug文件為單獨(dú)調(diào)試文件。

  • 步驟3:去除可執(zhí)行文件中的調(diào)試信息。

使用objcopy命令的--strip-debug選項(xiàng),移除可執(zhí)行文件調(diào)試信息,

objcopy --strip-debug test

執(zhí)行完該命令,可執(zhí)行文件中的.debug_*節(jié)將全部被刪除。    

  • 步驟4:添加調(diào)試信息文件鏈接。

使用objcopy命令的--add-gnu-debuglink選項(xiàng),將調(diào)試信息文件的路徑添加到可執(zhí)行文件中。gdb調(diào)試可執(zhí)行文件時,就能夠自動查找到調(diào)試信息文件。

objcopy --add-gnu-debuglink=test.debug test

執(zhí)行完該命令,可執(zhí)行文件中將添加一個.gnu_debuglink節(jié),其中包含調(diào)試信息文件的路徑。通過以下命令可以查看.gnu_debuglink節(jié)中的內(nèi)容:

readelf -p .gnu_debuglink test

輸出示例如下:

圖片圖片

4.2 gdb調(diào)試單獨(dú)調(diào)試文件

當(dāng)我們按照上述步驟生成了單獨(dú)的調(diào)試文件后,我們既能夠獲得一個輕量級的可執(zhí)行程序,又能夠有一個完整的調(diào)試文件。當(dāng)程序在實(shí)際環(huán)境運(yùn)行出現(xiàn)問題時,我們能夠通過單獨(dú)的調(diào)試文件排查問題。

gdb調(diào)試單獨(dú)調(diào)試文件分為:手動添加調(diào)試文件和自動添加調(diào)試文件。

手動添加通過gdb add-symbol-file命令完成,輸出示例如下:

(gdb) add-symbol-file test.debug
add symbol table from file "test.debug"
(y or n) y
Reading symbols from test.debug...

自動添加的方式需要在可執(zhí)行程序中添加調(diào)試信息文件鏈接(參考調(diào)試信息分離步驟4)。注意,可執(zhí)行文件和調(diào)試文件需要在同一個目錄。輸出示例如下:

圖片圖片


責(zé)任編輯:武曉燕 來源: 物聯(lián)網(wǎng)心球
相關(guān)推薦

2011-07-18 13:11:53

2010-06-04 17:48:20

Linux編程工具

2010-06-23 10:03:01

2024-11-28 12:38:39

gcc開源編譯器

2011-07-19 16:34:01

Xcode 證書

2009-12-10 19:02:30

2015-10-26 15:48:51

安裝Ubuntu 15.1Linux

2011-11-21 15:12:54

Java斷點(diǎn)Eclipse

2018-02-07 09:25:50

Linux命令touch

2025-08-27 06:25:00

MSTP網(wǎng)絡(luò)端口

2021-04-25 06:12:19

Java內(nèi)存布局JVM

2024-09-04 09:43:36

2024-07-26 10:35:00

2009-12-11 14:05:32

Linux安裝GCC

2009-12-23 18:54:53

Fedora Core

2011-07-28 14:31:55

Xcode 調(diào)試 異常

2009-12-23 17:20:55

Fedora GCC

2017-07-13 13:13:49

AndroidAPK反編譯

2018-04-02 22:57:08

4G短視頻5G

2013-11-21 10:06:35

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號