代碼編譯後移動目錄引發gdb找不到代碼文件

咱們從一個最簡單的C語言程序開始。源文件main.c 用戶目錄gdb文件夾下。ui

florian@florian-pc:~/gdb$ cat main.cspa

int main().net

{debug

    return 0;調試

};orm

而後將源文件編譯爲main(須要調試選項-g),並將main.c移動到src/main.c下,而後對main進行調試。blog

florian@florian-pc:~/gdb$ gcc main.c -o main -g字符串

florian@florian-pc:~/gdb$ mv main.c src/main.cget

florian@florian-pc:~/gdb$ gdb main源碼

(gdb) b main

Breakpoint 1 at 0x8048397: file main.c, line 3.

(gdb) list

1   main.c: 沒有那個文件或目錄.

    in main.c

gdb中,使用list命令查看源代碼時,沒法找到源文件main.c

探究

因爲對DWARF調試格式並不清晰,我本覺得使用調試選項編譯的可執行程序內部包含了源文件的內容,這樣不管源碼是否存在,可執行程序均可以被正常調試。可是,從上邊的例子中能夠看出,事實並不是如此。

咱們能夠做一個簡單的推測:因爲移動源文件的位置後,gdb沒法找到源文件的位置,估計可執行文件的調試段內保存的不是源文件的內容,而是路徑信息。

main.c移動回來,從新編譯,生成目標文件main.o,並查看其段信息。

florian@florian-pc:~/gdb$ mv src/main.c main.c

florian@florian-pc:~/gdb$ gcc -c main.c -o main.o -g

florian@florian-pc:~/gdb$ objdump -s main.o

 

main.o:     file format elf32-i386

 

Contents of section .text:

 0000 5589e5b8 00000000 5dc3               U.......].     

……

Contents of section .debug_str:

 0000 6d61696e 2e63002f 686f6d65 2f666c6f      main.c./home/flo

 0010 7269616e 2f676462 00474e55 20432034      rian/gdb.GNU C 4

 0020 2e342e35 006d6169 6e00                      .4.5.main.     

……

咱們發如今.debug_str段內,有兩個很明顯的字符串信息。

1/home/florian/gdb:看起來很像源文件所在的絕對路徑。

2main.c:顯而易見,是源文件的名稱。

驗證

咱們再把main.c移動到src目錄下,再次編譯,看看字符串的信息有何變化。

florian@florian-pc:~/gdb$ mv main.c src/main.c

florian@florian-pc:~/gdb$ gcc -c src/main.c -o main.o -g

florian@florian-pc:~/gdb$ objdump -s main.o

 

main.o:     file format elf32-i386

 

Contents of section .text:

 0000 5589e5b8 00000000 5dc3               U.......].     

……

Contents of section .debug_str:

 0000 2f686f6d 652f666c 6f726961 6e2f6764      /home/florian/gd

 0010 6200474e 55204320 342e342e 35007372      b.GNU C 4.4.5.sr

 0020 632f6d61 696e2e63 006d6169 6e00           c/main.c.main. 

.debug_str段內的兩個字符串信息發生了變化。

1/home/florian/gdb:可見該字符串爲執行gcc命令時的當前目錄的絕對路徑。

2src/main.c:該字符串爲源文件相對於當前目錄的相對路徑。

將兩個目錄合併,即可以獲得源文件的絕對路徑:

/home/florian/gdb /src/main.c

結論

因而可知,使用調試選項編譯生成的可執行文件內並不是保存了源文件的內容,而是源文件的絕對路徑信息。DWARF調試格式(詳見這裏)定義的其餘debug段內保存了二進制代碼與源文件行號的對應關係,這樣gdblist命令工做時,實際是讀取可執行文件內的行號信息,並將源文件的代碼內容顯示出來。這也是爲何將源文件移動後,list命令信息沒法找到源文件的緣由。

從這裏,咱們也能夠清楚一個事實:當源碼目錄的源文件路徑發生變化後,若是須要對可執行文件進行調試,則必須從新編譯。

相似的問題不單單在gdblist命令中存在,objdump –S命令用於交叉顯示反彙編代碼與源代碼,一樣會受移動源文件的影響。

相關文章
相關標籤/搜索