1. 程式人生 > >獲取Linux核心未匯出符號的幾種方式

獲取Linux核心未匯出符號的幾種方式

從Linux核心的2.6某個版本開始,核心引入了匯出符號的機制。只有在核心中使用EXPORT_SYMBOL或EXPORT_SYMBOL_GPL匯出的符號才能在核心模組中直接使用。然而,核心並沒有匯出所有的符號。例如,在3.8.0的核心中,do_page_fault就沒有被匯出。

    而我的核心模組中需要使用do_page_fault,那麼有那些方法呢?這些方法分別有什麼優劣呢?

    下面以do_page_fault為例,一一進行分析:

  1. 修改核心,新增EXPORT_SYMBOL(do_page_fault)或EXPORT_SYMBOL_GPL(do_page_fault)。
    這種方法適用於可以修改核心的情形。在可以修改核心的情況下,這是最簡單的方式。

  2. 使用kallsyms_lookup_name讀取
    kallsyms_lookup_name本身也是一個核心符號,如果這個符號被匯出了,那麼就可以在核心模組中呼叫kallsyms_lookup_name(“do_page_fault”)來獲得do_page_fault的符號地址。
    這種方法的侷限性在於kallsyms_lookup_name本身不一定被匯出。

  3. 讀取/boot/System.map-<kernel-version>,再使用核心模組引數傳入核心模組
    System.map-<kernel-version>是編譯核心時產生的,它裡面記錄了編譯時核心符號的地址。如果能夠保證當前使用的核心與System.map-<kernel-version>是一一對應的,那麼從System.map-<kernel-version>中讀出的符號地址就是正確的。其中,kernel-version可以通過’uname -r’獲得。
    但是這種方法也有侷限性,在模組執行的時候,System.map-<kernel-version>檔案不一定存在,即使存在也不能保證與當前核心是正確對應的。

  4. 讀取/proc/kallsyms,再使用核心模組引數傳入核心模組
    /proc/kallsyms是一個特殊的檔案,它並不是儲存在磁碟上的檔案。這個檔案只有被讀取的時候,才會由核心產生內容。因為這些內容是核心動態生成的,所以可以保證其中讀到的地址是正確的,不會有System.map-<kernel-version>的問題。
    需要注意的是,從核心2.6.37開始,普通使用者是沒有辦法從/proc/kallsyms中讀到正確的值。在某些版本中,該檔案為空。在較新的版本中,該檔案中所有符號的地址均為0(除非/porc/sys/kernel/kptr_restrict 的值被設為0)。但是root使用者是可以從/proc/kallsyms中讀到正確的值的。好在載入模組也需要root許可權,可以在載入模組時用指令碼獲取符號的地址。命令:
    #cat /proc/kallsyms | grep "\<do_page_fault\>" | awk '{print $1}'

    不過,根據我的實際使用經驗,/proc/kallsyms中符號的數量比Systemp.map-<kernel-version>要少一些。