天天看點

gdb調試解決找不到源代碼的問題前言找到源代碼的必要性涉及到的指令gdb怎樣找源代碼具體示例總結

文章目錄

  • 前言
  • 找到源代碼的必要性
  • 涉及到的指令
  • gdb怎樣找源代碼
    • 源代碼目錄集合
    • 源代碼檔案
    • 目錄集合的預設值
    • 檢視各種目錄
      • 檢視源代碼檔案名和編譯目錄
      • 檢視源代碼搜尋目錄
      • 檢視目前目錄
  • 具體示例
    • 使用 dir 指令解決
    • 使用 cd 指令解決
    • 使用 set substitute-path 指令解決
  • 總結

前言

通過

gdb

啟動程式,打好斷點運作,開始調試輸入

list

指令,結果發現找不到源代碼,是不是很糟心,讓我們來看看怎麼解決這種情況。

先來說明我們要處理的情況,調試程式找不到源代碼首先你得有源代碼,如果編譯完程式你把源代碼删了,或者單獨把執行程式拷貝到一個沒有源代碼的機器上,那麼拜拜吧您嘞,這種情況不是本文能解決的。

如果你确實有源代碼,正常編譯源代碼并且加入了

-g

選項,編譯完之後沒有改變源代碼位置,那麼調試的時候基本都會找到源代碼,是以這種情況也不在我們的讨論範圍之内。

分析到現在就剩下一種情況,程式編譯完成之後我移動了代碼的位置。實際工作中可能不會這麼無聊,故意改變目錄位置讓調試程式找不到,但是工作中常常會出現釋出機編譯完代碼要在開發機調試的情況,兩台機器上的代碼時一樣的,但是源代碼的位置可能放置的不同,那麼在個人開發機上調試這樣的程式就會找不到源代碼,這也就是我們要解決的問題。

找到源代碼的必要性

其實在我看來找不到源代碼的問題沒有那麼嚴重,編譯程式裡記錄了檔案名,行号等資訊,可以在調試的時候對照着本地的源代碼進行“盲調”,這種“盲調”的操作之前可沒少幹,因為線上環境中沒有源代碼,我隻能一邊對照着

gdb

調試輸出的行号,一邊對照本地的源代碼進行程式分析,通過這種方法也解決了不少問題。

雖然看着源代碼調試沒有那麼必要,但是如果可以看見那肯定是更好了,是以本文還是列舉出最常見的處理方法,解決一下本來有代碼,但因為目錄不比對無法正常調試的問題。

涉及到的指令

下面幾個指令是

gdb

指令,注意要放到和

gdb

互動指令行輸入才可以,别管會不會,先混個臉熟,以後要經常用的:

  • show dir

  • dir 目錄

  • set dir 目錄1:目錄2:目錄3

  • dir

  • pwd

  • cd 目錄

  • set substitute-path from-path to-path

gdb怎樣找源代碼

有時候很奇怪,代碼明明就在那裡,

gdb

你睜開眼睛行不行,為什麼你就是找不到呢?其實

gdb

也很苦的好不好,一直幫你查問題還要忍受着你每天的埋怨,到底是什麼原因導緻

gdb

對眼前的代碼視而不見呢?

其實

gdb

查找代碼也要遵循一定的規則,不能每次都全盤掃描吧,那不是得給它累死。舉個例子吧,我們在安裝一些軟體,特别是一些指令行工具的時候,總是有一步要求你把工具或軟體所在目錄添加到環境變量中,這個變量的名字叫做

Path

這個

Path

其實就是電腦上衆多軟體所在目錄的集合,當你直接使用軟體的程式時,會優先從

Path

這個集合中的目錄下去找,成功找到就會直接調用,否則提醒你軟體不存在。

源代碼目錄集合

而在

gdb

的調試過程中也有這樣一個目錄集合,我暫且稱它為

SourcePathSet

,後面就用這個名字了,因為還要涉及到多種查找目錄,請注意區分。

gdb

在查找源碼的時候首先在

SourcePathSet

中所包含的目錄下找,如果找不到就會提示查找失敗了,也就是這篇文章所提到的問題。

源代碼檔案

程式在編譯的過程中會記錄源檔案的名字和路徑,這個路徑可能是絕對路徑,比如

/mnt/d/main.cpp

,也可能是相對路徑

../main.cpp

,究竟是哪一種取決于編譯時使用的參數。

我們以絕對路徑為例,比如檔案名為

/mnt/d/main.cpp

,我們可以把它拆分成包含路徑和不包含路徑兩種形式:

/mnt/d/main.cpp

main.cpp

,當

SourcePathSet

中包含一個路徑叫

/mnt/e

時,

gdb

搜尋的路徑包括以下幾種:

  • /mnt/d/main.cpp

  • /mnt/e/mnt/d/main.cpp

  • /mnt/e/main.cpp

當源檔案是相對路徑

../main.cpp

的時候,那麼搜尋的路徑就變成了下面兩個:

  • /mnt/e/../main.cpp

  • /mnt/e/main.cpp

說到這裡你可能就明白了,當

gdb

找不到源檔案的時候,修改

SourcePathSet

就可以了,把想讓它搜尋的路徑添加到

SourcePathSet

,如果符合它的搜尋規則,那麼就可以找到了。

目錄集合的預設值

SourcePathSet

gdb

啟動後開始生效,預設值并不是空,而是

$cdir:$cwd

,這又是什麼鬼?其中的

$cdir

叫做編譯目錄,是代碼在編譯時記錄到程式中的,

$cwd

表示目前的調試目錄,可以通過

cd

指令來修改,要注意這個

cd

修改的是

gdb

會話中的目前目錄,不會影響啟動

gdb

前檔案系統中的目錄位置。

假設

$cdir

的值是

/usr

cwd

的值是

/home/albert

,我們又添加了

/mnt/e

SourcePathSet

中,那麼此時

SourcePathSet

的值為

/mnt/e:$cdir:$cwd

,如果源檔案的是

/mnt/d/main.cpp

,查找的目錄就會出現以下幾種:

  • /mnt/d/main.cpp

  • /mnt/e/mnt/d/main.cpp

  • /usr/mnt/d/main.cpp

  • /home/albert/mnt/d/main.cpp

  • /mnt/e/main.cpp

  • /usr/main.cpp

  • /home/albert/main.cpp

檢視各種目錄

先做一下準備工作,編寫一段簡單代碼,另存檔案名為

main.cpp

,儲存在目錄

/mnt/d/cpp

下:

#include <iostream>
using namespace std;

int main()
{
    int a = 1;
    int b = 2;
    int c = a + b;

    cout << "c = " << c << endl;

    return 0;
}
           

切換到目錄

/mnt/d

下, 檢視

cpp

目錄下檔案并使用

g++

編譯,編譯完成後将檔案

mian.cpp

移動到

/mnt

目錄下:

[email protected]:/mnt/d$ ls cpp/
main.cpp
[email protected]:/mnt/d$ g++ /mnt/d/cpp/main.cpp -g -o main
[email protected]:/mnt/d$ ls main
main
[email protected]:/mnt/d$ sudo mv cpp/main.cpp ../
[sudo] password for albert:
[email protected]:/mnt/d$ ls ../
c  d  e  f  main.cpp
           

啟動

gdb

調試程式并打好斷點,輸入

run

運作發現,斷點被觸發,但是顯示出

No such file or directory.

,說明沒有找到源代碼檔案。

[email protected]:/mnt/d$ gdb -q main
Reading symbols from main...done.
(gdb) b 8
Breakpoint 1 at 0x4008ac: file /mnt/d/cpp/main.cpp, line 8.
(gdb) run
Starting program: /mnt/d/main

Breakpoint 1, main () at /mnt/d/cpp/main.cpp:8
8   /mnt/d/cpp/main.cpp: No such file or directory.
           

檢視源代碼檔案名和編譯目錄

直接在

gdb

指令行中輸入

info source

回車就可以了

(gdb) info source
Current source file is /mnt/d/cpp/main.cpp
Compilation directory is /mnt/d
Source language is c++.
Producer is GNU C++ 5.4.0 20160609 -mtune=generic -march=x86-64 -g -fstack-protector-strong.
Compiled with DWARF 2 debugging format.
Does not include preprocessor macro info.
(gdb)
           

通過這個指令發現,源代碼檔案是

/mnt/d/cpp/main.cpp

,編譯目錄是

/mnt/d

檢視源代碼搜尋目錄

gdb

環境下輸入

show dir

指令就可以顯示

SourcePathSet

這個集合中都有哪些目錄,由于還沒有設定過現在還是預設值

$cdir:$cwd

(gdb) show dir
Source directories searched: $cdir:$cwd
(gdb)
           

檢視目前目錄

檢視目前目錄就比較簡單了,直接

pwd

就搞定了

(gdb) pwd
Working directory /mnt/d.
(gdb)
           

我們“如願以償”的讓

gdb

找不到代碼了,從現在的環境來看,

$cdir

$cwd

相同都是

/mnt/d

,是以此時搜尋的目錄隻有:

  • /mnt/d/cpp/main.cpp

  • /mnt/d/mnt/d/cpp/main.cpp

  • /mnt/d/main.cpp

而代碼被我們移動到了

/mnt/main.cpp

gdb

自然就找不到了,後面來看看具體怎麼處理這種情況。

具體示例

說了這麼多原理的東西,如果弄明白了這些很容易找到解決問題的辦法,下面寫一個完整點的例子,來感受一些具體怎麼修複這個問題,建立三個檔案

mainpro.cpp

mymath.h

mymath.cpp

,目錄結構和内容如下:

[email protected]:/mnt/d$ tree /mnt/d/mainpro/
/mnt/d/mainpro/
|-- core
|   `-- mainpro.cpp
`-- kit
    |-- mymath.cpp
    `-- mymath.h
           
//mainpro.cpp
#include "../kit/mymath.h"
#include <iostream>
using namespace std;

int main()
{
    int a = 1, b = 2;
    mymath* m = new mymath();

    int c = m->add(a, b);
    cout << "c = " << c << endl;

    return 0;
}
           
//mymath.h
class mymath
{
public:
    int add(int a, int b);
};
           
//mymath.cpp
#include "mymath.h"

int mymath::add(int a, int b)
{
    int c = a + b;
    return c;
}
           

/mnt/d/mainpro

目錄下編譯代碼,然後将代碼檔案所在目錄

core

kit

拷貝到

/mnt/e/newpro

目錄下,将可執行檔案拷貝到

/home/albert

目錄下。

[email protected]:/mnt/d/mainpro$ g++ /mnt/d/mainpro/core/mainpro.cpp /mnt/d/mainpro/kit/mymath.cpp -g -o mainpro
[email protected]:/mnt/d/mainpro$ tree
.
|-- core
|   `-- mainpro.cpp
|-- kit
|   |-- mymath.cpp
|   `-- mymath.h
`-- mainpro

2 directories, 4 files
[email protected]:/mnt/d/mainpro$ mkdir /mnt/e/newpro
[email protected]:/mnt/d/mainpro$ sudo mv core/ /mnt/e/newpro/
[email protected]:/mnt/d/mainpro$ sudo mv kit/ /mnt/e/newpro/
[email protected]:/mnt/d/mainpro$ mv mainpro /home/albert/
           

/home/albert

目錄下啟動

gdb

開始調試,先在

main

函數打斷點,查詢源檔案路徑和編譯目錄等資訊;

[email protected]:~$ gdb -q mainpro
Reading symbols from mainpro...done.
(gdb) b main
Breakpoint 1 at 0x4008de: file /mnt/d/mainpro/core/mainpro.cpp, line 7.
(gdb) run
Starting program: /home/albert/mainpro

Breakpoint 1, main () at /mnt/d/mainpro/core/mainpro.cpp:7
7   /mnt/d/mainpro/core/mainpro.cpp: No such file or directory.
(gdb) info source
Current source file is /mnt/d/mainpro/core/mainpro.cpp
Compilation directory is /mnt/d/mainpro
Source language is c++.
Producer is GNU C++ 5.4.0 20160609 -mtune=generic -march=x86-64 -g -fstack-protector-strong.
Compiled with DWARF 2 debugging format.
Does not include preprocessor macro info.
(gdb) list
2   in /mnt/d/mainpro/core/mainpro.cpp
(gdb) pwd
Working directory /home/albert.
(gdb) show dir
Source directories searched: $cdir:$cwd
(gdb)
           

果然找不到源代碼了,從上面的調試資訊來看,可以得到以下資訊:

  • 源代碼檔案為

    /mnt/d/mainpro/core/mainpro.cpp

  • 程式編譯目錄為

    /mnt/d/mainpro

  • 目前目錄為

    /home/albert

而源代碼查找清單中隻有

$cdir:$cwd

,說明隻包含

/mnt/d/mainpro

/home/albert

,那麼查找的目錄有:

  • /mnt/d/mainpro/core/mainpro.cpp

  • /mnt/d/mainpro/mnt/d/mainpro/core/mainpro.cpp

  • /home/albert/mnt/d/mainpro/core/mainpro.cpp

  • /mnt/d/mainpro/mainpro.cpp

  • /home/albert/mainpro.cpp

這些目錄顯然找不到源代碼檔案了,因為檔案已經被我移動到

/mnt/e/newpro/

目錄下了,也就是

/mnt/e/newpro/core/mainpro.cpp

,下面來嘗試一些解決方法。

使用 dir 指令解決

剛才說了源代碼查找集合

SourcePathSet

中隻有

$cdir:$cwd

,我們可以自己加一個嘛,比如像下面這樣:

(gdb) dir /mnt/e/newpro/core/
Source directories searched: /mnt/e/newpro/core:$cdir:$cwd
(gdb) list
2   #include <iostream>
3   using namespace std;
4
5   int main()
6   {
7       int a = 1, b = 2;
8       mymath* m = new mymath();
9
10      int c = m->add(a, b);
11      cout << "c = " << c << endl;
(gdb)
           

這樣就可以找到了,我們接着在

add

函數上下個斷點,繼續執行

(gdb) b mymath::add
Breakpoint 2 at 0x4009a6: file /mnt/d/mainpro/kit/mymath.cpp, line 6.
(gdb) c
Continuing.

Breakpoint 2, mymath::add (this=0x613c20, a=1, b=2) at /mnt/d/mainpro/kit/mymath.cpp:6
6   /mnt/d/mainpro/kit/mymath.cpp: No such file or directory.
(gdb) list
1   in /mnt/d/mainpro/kit/mymath.cpp
(gdb) info source
Current source file is /mnt/d/mainpro/kit/mymath.cpp
Source language is c++.
Producer is GNU C++ 5.4.0 20160609 -mtune=generic -march=x86-64 -g -fstack-protector-strong.
Compiled with DWARF 2 debugging format.
Does not include preprocessor macro info.
(gdb)
           

結果發現又找不到檔案

/mnt/d/mainpro/kit/mymath.cpp

了,因為和之前不是一個檔案,這個檔案在其他的目錄下,是以還要使用

dir

指令,把新的目錄加到源代碼查找集合

SourcePathSet

中:

(gdb) dir /mnt/e/newpro/kit/
Source directories searched: /mnt/e/newpro/kit:/mnt/e/newpro/core:$cdir:$cwd
(gdb) list
1   #include "../kit/mymath.h"
2   #include <iostream>
3   using namespace std;
4
5   int main()
6   {
7       int a = 1, b = 2;
8       mymath* m = new mymath();
9
10      int c = m->add(a, b);
(gdb)
           

這次又能成功找到了,可是如果有好多個檔案要調試,難道要把所有的目錄都加進去嗎?其實可以有簡便方法的,在啟動

gdb

的時候可以指定搜尋的源代碼路徑,這些路徑都會被加到到源代碼查找集合

SourcePathSet

中,具體操作如下,先退出

gdb

,然後重新加參數啟動如下:

[email protected]:~$ gdb -q mainpro `find /mnt/e/newpro/ -type d -printf '-d %p '`
Reading symbols from mainpro...done.
(gdb) show dir
Source directories searched: /mnt/e/newpro/kit:/mnt/e/newpro/core:/mnt/e/newpro:$cdir:$cwd
(gdb)
           

其實這條指令的本來面目是

gdb -q mainpro -d xxxxx

,隻不過這組合了

find

指令以後使用起來更加友善了,可以把指定目錄下的子目錄全都添加到參數中

使用 cd 指令解決

如果是臨時調試倒是用不到上面設定啟動參數那麼麻煩,因為變量

$cwd

也在搜尋集合中,既然在編譯時記錄的源檔案被改變了位置,那麼我們調整我們的目前位置,讓代碼出現搜尋路徑中,還是上面的這個例子:

[email protected]:~$ pwd
/home/albert
[email protected]:~$ gdb -q mainpro
Reading symbols from mainpro...done.
(gdb) b main
Breakpoint 1 at 0x4008de: file /mnt/d/mainpro/core/mainpro.cpp, line 7.
(gdb) r
Starting program: /home/albert/mainpro

Breakpoint 1, main () at /mnt/d/mainpro/core/mainpro.cpp:7
7   /mnt/d/mainpro/core/mainpro.cpp: No such file or directory.
(gdb) list
2   in /mnt/d/mainpro/core/mainpro.cpp
(gdb) cd /mnt/e/newpro/core/
Working directory /mnt/e/newpro/core.
(gdb) list
2   #include <iostream>
3   using namespace std;
4
5   int main()
6   {
7       int a = 1, b = 2;
8       mymath* m = new mymath();
9
10      int c = m->add(a, b);
11      cout << "c = " << c << endl;
(gdb)
           

上面的操作通過

cd /mnt/e/newpro/core/

指令直接進入了源代碼目錄,當然就找到了,但是這還是會有點問題,當碰到需要調試好幾個檔案的時候就需要使用

cd

指令跳來跳去,要想一勞永逸,請看下面這個方法。

使用 set substitute-path 指令解決

我們移動源代碼的時候往往會整個目錄移動,或者說開發機和釋出機上面的代碼檔案組織結構是一樣,隻是所在的磁盤位置是不一樣的,是以如果可以設定用一個路徑替換原代碼檔案的路徑就好了,

set substitute-path from-path to-path

這個指令就可以達到想要的目的,這個指令還可以簡寫成

set substitute from-path to-path

,比如還是前面的例子,源代碼從

/mnt/d/mainrpo

目錄整體移動到了

/mnt/e/newpro

目錄,調試時找不到源代碼可以使用

set substitute /mnt/d/mainrpo /mnt/e/newpro

指令來指定替換目錄,這樣就可以找到源代碼啦,下面來測試一下:

[email protected]:~$ gdb -q mainpro
Reading symbols from mainpro...done.
(gdb) set substitute-path /mnt/d/mainrpo /mnt/e/newpro
(gdb) b main
Breakpoint 1 at 0x4008de: file /mnt/d/mainpro/core/mainpro.cpp, line 7.
(gdb) run
Starting program: /home/albert/mainpro

Breakpoint 1, main () at /mnt/d/mainpro/core/mainpro.cpp:7
7   /mnt/d/mainpro/core/mainpro.cpp: No such file or directory.
(gdb) cd /mnt/e/newpro/
Working directory /mnt/e/newpro.
(gdb) list
2   /mnt/d/mainpro/core/mainpro.cpp: No such file or directory.
(gdb) set substitute-path /mnt/d/mainpro /mnt/e/newpro
(gdb) list 0
1   #include "../kit/mymath.h"
2   #include <iostream>
3   using namespace std;
4
5   int main()
6   {
7       int a = 1, b = 2;
8       mymath* m = new mymath();
9
10      int c = m->add(a, b);
(gdb) info source
Current source file is /mnt/d/mainpro/core/mainpro.cpp
Compilation directory is /mnt/d/mainpro
Located in /mnt/e/newpro/core/mainpro.cpp
Contains 14 lines.
Source language is c++.
Producer is GNU C++ 5.4.0 20160609 -mtune=generic -march=x86-64 -g -fstack-protector-strong.
Compiled with DWARF 2 debugging format.
Does not include preprocessor macro info.
(gdb) pwd
Working directory /home/albert.
(gdb)
           

通過調試資訊

Located in /mnt/e/newpro/core/mainpro.cpp

可以看到,果然在新的位置找到了源代碼。

總結

  • 調試的時候找不到源碼有多種解決方法,需要根據實際情況選擇最合适的解決方案。
  • 編譯時使用絕對路徑時,推薦使用

    set substitute-path from-path to-path

    的方式。
  • 編譯時使用相對路徑時,使用

    set substitute from-path to-path

    或者

    dir new-path

    都可以。
  • 對于臨時查找一個問題,單獨調試某一個檔案時使用

    cd

    指令就可以搞定了。
  • 直接在

    gdb

    環境輸入

    dir

    指令回車确認,可以重置

    dir 目錄

    或者

    set dir 目錄

    指令修改過的源代碼搜尋目錄集合。

==>> 反爬連結,請勿點選,原地爆炸,概不負責!<<==

當人的才華不足以撐起個人的欲望時就會感到焦慮,當面對不利的情況和事件卻又無力改變時就會感到憤怒,而弱肉強食一直都是生活的本質,惟有強大才是解決這一切負面情緒的良藥~

繼續閱讀