獲取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>要少一些。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM