在內(nèi)核調(diào)試中,經(jīng)常需要知道某個(gè)函數(shù)的地址,或者根據(jù)函數(shù)地址找到對(duì)應(yīng)的函數(shù),從而進(jìn)行更深一步的debug。
下面介紹四種獲取內(nèi)核函數(shù)地址的方法:
1、System.map
在編譯Linux內(nèi)核時(shí),會(huì)產(chǎn)生一個(gè)內(nèi)核映像文件System.map
,也叫 內(nèi)核符號(hào)表 。
內(nèi)核符號(hào)表是一個(gè)映射,它將內(nèi)核代碼段中的地址映射到對(duì)應(yīng)的函數(shù)名或全局變量名。
在System.map
文件中,每一行都包含一個(gè)內(nèi)核符號(hào),每個(gè)符號(hào)包含三部分:
- 地址 :符號(hào)在內(nèi)核內(nèi)存中的地址。
- 類型 :符號(hào)的類型。例如,"T"表示該符號(hào)是一個(gè)在代碼段中的函數(shù)。
- 名稱 :符號(hào)的名字,可以是函數(shù)名或者變量名。
例如,我們要查找名為“do_fork
”的函數(shù)的地址,可以使用以下命令:
grep ' do_fork' System.map
然后會(huì)得到類似于這樣的輸出:
c0105020 T do_fork
這代表,c0105020
就是函數(shù)do_fork
的地址,T
代表該符號(hào)是個(gè)函數(shù)。
或者,直接打開(kāi)System.map
搜索對(duì)應(yīng)函數(shù)名或者地址。System.map
內(nèi)容類似如下:
c0004000 A swapper_pg_dir
c0008000 T __init_begin
c0008000 T _sinittext
c0008000 T _stext
c0008000 T stext
c0008034 t __enable_mmu
c0008060 t __turn_mmu_on
......
A、T、t等都代表不同的類型,具體類型的定義可參考:
類型 | 說(shuō)明 |
---|---|
A | 該符號(hào)的值是不能改變的,等于const |
B | 該符號(hào)來(lái)自于未初始化代碼段bss段 |
C | 該符號(hào)是通用的,通用的符號(hào)指未初始化的數(shù)據(jù)。當(dāng)鏈接時(shí),多個(gè)通用符號(hào)可能對(duì)應(yīng)一個(gè)名稱,如果該符號(hào)在某一個(gè)位置定義,這個(gè)通用符號(hào)被當(dāng)做未定義的引用。不明白,內(nèi)核中也沒(méi)有該類型的符號(hào) |
D | 該符號(hào)位于初始化的數(shù)據(jù)段 |
G | 位于初始化數(shù)據(jù)段,專門對(duì)應(yīng)小的數(shù)據(jù)對(duì)象,比如global int x,對(duì)應(yīng)的大數(shù)據(jù)對(duì)象為 數(shù)組類型等 |
I | 到其他符號(hào)的間接引用,是對(duì)于a.out文件的GNU擴(kuò)展,使用非常少 |
N | 調(diào)試符號(hào) |
R | 只讀代碼段的符號(hào) |
S | BSS段(未初始化數(shù)據(jù)段)的小對(duì)象符號(hào) |
T | 代碼段符號(hào),全局函數(shù),t為局部函數(shù) |
U | 未定義的符號(hào) |
V | 該符號(hào)是一個(gè)weak object,當(dāng)其連接到為定義的對(duì)象上上,該符號(hào)的值變?yōu)? |
W | 類似于V |
- | 該符號(hào)是a.out文件中的一個(gè)stabs symbol,獲取調(diào)試信息 |
? | 未知類型的符號(hào) |
2、vmlinux
vmlinux
也是Linux
編譯出來(lái)的內(nèi)核映像文件,可以通過(guò)nm
、objdump
和readelf
等工具來(lái)查看它的符號(hào)表,從而獲取函數(shù)地址。
2.1 nm讀取vmlinux
nm
命令是用于查看二進(jìn)制文件(如可執(zhí)行文件、目標(biāo)文件、庫(kù))的符號(hào)表的工具,所以可以用nm
命令來(lái)讀取vmlinux
里的符號(hào)表。
nm
查找vmlinux
中函數(shù)名為do_fork
的地址:
nm vmlinux | grep "do_fork"
nm
查找vmlinux
中地址為c0105020
的符號(hào):
nm vmlinux | grep c0105020
nm
命令的輸出,與System.map
類似,會(huì)的得到類似于以下的輸出:
c0105020 T do_fork
2.2 objdump反匯編vmlinux
objdump
工具用于反匯編,可以將vmlinux
反匯編出來(lái),得到的反匯編文件就會(huì)包含函數(shù)名和對(duì)應(yīng)的 地址 ,可以直接查看文本內(nèi)容。
- 使用objdump查看vmlinux函數(shù)地址 :
objdump -d vmlinux | grep "函數(shù)名"
這會(huì)返回與指定函數(shù)名匹配的符號(hào)的地址、類型和名稱。objdump
的-d
選項(xiàng)表示反匯編代碼。
也可以將vmlinux的內(nèi)容全部反匯編出來(lái),重定向到一個(gè)文件,然后直接查看文本內(nèi)容:
objdump -D vmlinux > vmlinux_dump.txt
上述命令會(huì)將vmlinux
所有內(nèi)容反匯編,并將結(jié)果輸出到vmlinux_dump.txt
文件中,-D
表示反匯編所有代碼段。
2.3 readelf讀取vmlinux
使用readelf也可以讀取vmlinux的符號(hào)表,命令如下:
readelf -s vmlinux
由于vmlinux比較大,如果要查找某個(gè)函數(shù)的地址,需要使用grep進(jìn)行過(guò)濾。
例如,找到do_fork
函數(shù)的地址,你可以使用以下命令:
readelf -s vmlinux | grep "do_fork"
然后,你就會(huì)看到類似這樣的輸出:
56481: c10601e0 96 FUNC GLOBAL DEFAULT 1 do_fork
輸出內(nèi)容表示,do_fork
函數(shù)的地址是c10601e0
。
3、/proc/kallsyms
vmlinux
是編譯時(shí)生成的,假設(shè)你沒(méi)有vmlinux
這個(gè)文件,只有正在運(yùn)行的Linux
系統(tǒng),此時(shí)也可以通過(guò)/proc/kallsyms
獲取函數(shù)地址。
/proc/kallsyms
是一個(gè)由運(yùn)行中的 內(nèi)核動(dòng)態(tài)生成的虛擬文件 ,它反映了 當(dāng)前運(yùn)行的內(nèi)核的狀態(tài) 。
通常這個(gè)節(jié)點(diǎn)是不會(huì)打開(kāi)的,因?yàn)闀?huì)增加內(nèi)核大小,要使用這個(gè)節(jié)點(diǎn),需要打開(kāi)內(nèi)核選項(xiàng):
CONFIG_KALLSYMS=y
如果想獲取do_fork
函數(shù)的地址,可以使用以下命令:
cat /proc/kallsyms | grep " do_fork"
然后會(huì)返回一個(gè)包含do_fork
函數(shù)地址的行,如:
ffffffff810b57b0 T do_fork
輸出內(nèi)容表示do_fork
函數(shù)的地址是ffffffff810b57b0
。
4、內(nèi)核接口
也可以在代碼中獲取內(nèi)核符號(hào)表,同樣需要打開(kāi)內(nèi)核選項(xiàng)CONFIG_KALLSYMS=y
。
kallsyms_lookup_name
- 已知函數(shù)名,獲取地址:
kallsyms_lookup_name("函數(shù)名" )
該函數(shù)會(huì)返回對(duì)應(yīng)函數(shù)名的地址。
sprint_symbol
- 已知地址,返回對(duì)應(yīng)符號(hào):
#include < linux/kallsyms.h >
int sprint_symbol(char *buffer, unsigned long address)
- buffer:符號(hào)名緩存區(qū),保存結(jié)果。
- address:符號(hào)地址。
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1392瀏覽量
40610 -
Linux
+關(guān)注
關(guān)注
87文章
11378瀏覽量
211342 -
調(diào)試
+關(guān)注
關(guān)注
7文章
593瀏覽量
34213 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4355瀏覽量
63318
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
四種模擬輸入信號(hào)的保護(hù)電路實(shí)現(xiàn)方法
FPGA 設(shè)計(jì)的四種常用思想與技巧
請(qǐng)問(wèn)MATHLIB的庫(kù)函數(shù)為什么每個(gè)都有四種?有什么區(qū)別?
Word技巧:快速實(shí)現(xiàn)雙面打印的四種方法
教你四種神奇的電腦開(kāi)機(jī)方法
如何延長(zhǎng)iPhone的壽命 告訴你四種方法
四種特殊的線路板電鍍方法
四種常用的諧波治理方法
改善您的模數(shù)轉(zhuǎn)換器系統(tǒng)電源抑制狀況的四種方法

評(píng)論