精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

一文吃透Kprobes:從源碼探秘到調試實戰

系統 Linux
在使用 Kprobes 的過程中,可能會遇到一些常見問題,這些問題就像是前進道路上的絆腳石,但只要我們掌握了解決方法,就能輕松跨越。

曾經,有一位開發者在維護一個基于 Linux 內核的服務器系統時,遇到了一個棘手的問題:系統時不時會出現短暫的卡頓,排查日志卻找不到明顯線索。經過一番分析,他懷疑是某個內核函數在特定條件下執行異常。但傳統的調試方法,如添加打印語句,需要重新編譯內核,不僅繁瑣,還可能影響生產環境。

這時,Kprobes 技術進入了他的視野。通過 Kprobes,他在懷疑的內核函數入口處設置了探測點,收集函數的輸入參數和執行時間等信息。經過一段時間的監測和分析,終于發現是一個資源競爭問題導致了卡頓。通過修改代碼,成功解決了這個困擾已久的難題。這個故事充分展現了 Kprobes 在調試內核問題時的強大作用。

那么,Kprobes 究竟是什么呢?簡單來說,Kprobes 是 Linux 內核提供的一種動態調試機制,它允許開發者在不修改內核源碼、不重啟系統的情況下,對內核函數進行探測。無論是內核開發者排查性能瓶頸,還是驅動開發者調試設備驅動,Kprobes 都能提供極大的便利,讓你深入內核執行的 “幕后”,一探究竟。

一、Kprobes 概述

Kprobes 是 Linux 內核中一種強大的動態探測機制,猶如一把 “萬能鑰匙”,能打開內核函數的 “神秘大門” 。它允許開發者在不重新編譯內核、不重啟系統的情況下,對內核函數進行實時監測和分析,極大地提高了調試和性能優化的效率。這對于內核開發者來說,無疑是一項 “神器”,讓他們能夠在不中斷系統運行的情況下,深入了解內核的運行狀態,快速定位和解決問題。

Kprobes 的出現,解決了傳統內核調試方法的諸多痛點。在 Kprobes 之前,開發者若要調試內核函數,往往需要在函數中添加打印語句,然后重新編譯內核并重啟系統。這個過程不僅繁瑣耗時,還可能影響生產環境的穩定性。而 Kprobes 打破了這些限制,它就像一個 “隱形的觀察者”,可以隨時在運行中的內核函數中插入探測點,收集函數的執行信息,如函數參數、返回值、執行時間等,卻不會對內核的正常運行造成干擾。

二、Kprobes 如何運作

2.1關鍵數據結構

在 Kprobes 的源碼世界里,struct kprobe是一個核心結構體,它就像是一個 “探測點管理器”,承載著 Kprobes 運作的關鍵信息。下面是struct kprobe的簡化定義:

struct kprobe {
    kprobe_opcode_t *addr;            // 被探測點的地址
    const char *symbol_name;          // 被探測函數的名稱
    unsigned int offset;              // 被探測點在函數內部的偏移,若為0則表示函數入口
    kprobe_pre_handler_t pre_handler; // 該回調函數用于在執行被探測指令前執行
    kprobe_post_handler_t post_handler; // 該回調函數用于在執行完被探測指令后執行
    kprobe_fault_handler_t fault_handler; // 此函數用于在出現內存訪問錯誤時進行處理
    kprobe_opcode_t opcode;           // 保存被替換的原始指令
    struct arch_specific_insn ainsn;  // 架構相關的指令信息
    u32 flags;                        // 各種狀態標志
};

其中,addr成員指明了探測點的具體位置,它是 Kprobes 定位內核函數中特定指令的 “導航儀” 。symbol_name則以函數名的形式,為開發者提供了一種更直觀的方式來指定探測目標,就像是給探測點貼上了一個清晰的 “標簽” 。offset用于精確到函數內部的具體指令,讓探測更加細致入微,如同在精密儀器中調整刻度,實現精準探測。

pre_handler、post_handler和fault_handler這三個回調函數,是 Kprobes 與內核交互的 “橋梁” 。pre_handler在被探測指令執行前被調用,就像是比賽前的熱身,讓開發者有機會提前獲取信息、設置環境;post_handler在指令執行后登場,如同賽后的復盤,用于收集指令執行后的結果和狀態;fault_handler則在內存訪問出錯時發揮作用,是處理異常情況的 “救火隊員” 。

opcode保存了被斷點指令替換的原始指令,確保在探測完成后,內核能夠恢復到原本的執行狀態,就像在書本中夾了一張書簽,方便后續繼續閱讀。ainsn和flags則分別負責存儲架構相關的指令信息和各種狀態標志,為 Kprobes 在不同硬件架構上的穩定運行提供支持,以及記錄探測點的各種狀態,如是否啟用、是否出錯等。

2.2注冊與卸載流程

當我們想要使用 Kprobes 對某個內核函數進行探測時,就需要將探測點注冊到內核中。這個過程就像是在圖書館的書架上添加一本新書,需要遵循一定的流程。下面是注冊 Kprobes 探測點的關鍵代碼示例:

#include <linux/module.h>
#include <linux/kprobes.h>

// 定義pre_handler回調函數
static int handler_pre(struct kprobe *p, struct pt_regs *regs) {
    pr_info("< %s > pre_handler: p->addr = 0x%p, ip = %lx, flags = 0x%lx\n",
            p->symbol_name, p->addr, regs->ip, regs->flags);
    return 0;
}

// 定義post_handler回調函數
static void handler_post(struct kprobe *p, struct pt_regs *regs, unsigned long flags) {
    pr_info("< %s > post_handler: p->addr = 0x%p, flags = 0x%lx\n",
            p->symbol_name, p->addr, flags);
}

// 定義fault_handler回調函數
int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr) {
    pr_info("fault_handler: p->addr = 0x%p, trap #%d\n", p->addr, trapnr);
    return 0;
}

// 定義kprobe結構
static struct kprobe kp = {
   .symbol_name = "do_fork",       // 要追蹤的內核函數為do_fork
   .pre_handler = handler_pre,    // pre_handler回調函數
   .post_handler = handler_post,  // post_handler回調函數
   .fault_handler = handler_fault // fault_handler回調函數
};

// 模塊初始化函數,用于注冊kprobe
static int __init kprobe_init(void) {
    int ret;
    ret = register_kprobe(&kp);
    if (ret < 0) {
        pr_err("register_kprobe failed, returned %d\n", ret);
        return ret;
    }
    pr_info("Planted kprobe at %p\n", kp.addr);
    return 0;
}

// 模塊退出函數,用于卸載kprobe
static void __exit kprobe_exit(void) {
    unregister_kprobe(&kp);
    pr_info("kprobe at %p unregistered\n", kp.addr);
}

module_init(kprobe_init);
module_exit(kprobe_exit);
MODULE_LICENSE("GPL");

在上述代碼中,首先定義了三個回調函數handler_pre、handler_post和handler_fault,分別用于在被探測指令執行前、執行后和出現內存訪問錯誤時執行。然后,創建了一個struct kprobe結構體實例kp,并指定要探測的內核函數為do_fork,同時將三個回調函數與kp關聯起來。

在kprobe_init函數中,通過調用register_kprobe函數將kp注冊到內核中。如果注冊成功,會打印出探測點的地址;如果失敗,則打印錯誤信息并返回錯誤碼。

2.3回調函數機制

Kprobes 的回調函數機制是其實現動態探測的核心,它就像是一個精心編排的 “演出”,每個回調函數在不同的時刻登場,為開發者提供內核運行時的關鍵信息。

pre_handler回調函數在被探測指令執行前被觸發,此時,內核的執行流程就像行駛到一個岔路口,暫時停下,先進入pre_handler函數。在這個函數中,開發者可以獲取當前的寄存器狀態、被探測函數的參數等信息。例如,在前面的代碼中,handler_pre函數通過pr_info函數打印出了被探測函數的名稱、探測點地址、指令指針ip和標志寄存器flags的值,這些信息就像是內核運行時的 “快照”,為開發者分析問題提供了重要線索。

post_handler回調函數則在被探測指令執行完畢后閃亮登場。它就像是在一場比賽結束后,對比賽結果進行總結和分析。在這個函數中,開發者可以獲取指令執行后的返回值、內核狀態的變化等信息。同樣以之前的代碼為例,handler_post函數打印出了被探測函數的名稱、探測點地址和標志寄存器的值,幫助開發者了解指令執行后的情況。

fault_handler回調函數是在執行pre_handler、post_handler或單步執行被探測指令時出現內存訪問異常時被調用的。它就像是一個緊急救援小組,在出現問題時迅速響應。當內核在執行探測相關操作時發生內存錯誤,fault_handler函數會被觸發,開發者可以在這個函數中進行錯誤處理,如打印錯誤信息、記錄故障現場等,以便后續排查問題。

通過這三個回調函數的協同工作,Kprobes 為開發者打造了一個全方位、多層次的內核探測體系,讓開發者能夠深入了解內核的運行細節,快速定位和解決問題。

三、Kprobe實現原理

當安裝一個kprobes探測點時。kprobe首先備份被探測的指令,然后使用斷點指令(即在i386和x86_64的int3指令)來代替被探測指令的頭一個或幾個字節。當CPU運行到探測點時,將因運行斷點指令而運行trap操作,那將導致保存CPU的寄存器,調用對應的trap處理函數。而trap處理函數將調用對應的notifier_call_chain(內核中一種異步工作機制)中注冊的全部notifier函數。kprobe正是通過向trap對應的notifier_call_chain注冊關聯到探測點的處理函數來實現探測處理的。

當kprobe注冊的notifier被運行時,它首先運行關聯到探測點的pre_handler函數,并把對應的kprobe struct和保存的寄存器作為該函數的參數,接著,kprobe單步運行被探測指令的備份。最后,kprobe運行post_handler。等全部這些運行完成后。緊跟在被探測指令后的指令流將被正常運行。

kretprobe也使用了kprobes來實現,當用戶調用register_kretprobe()時,kprobe在被探測函數的入口建立了一個探測點。當運行到探測點時,kprobe保存了被探測函數的返回地址并代替返回地址為一個trampoline的地址,kprobe在初始化時定義了該trampoline而且為該trampoline注冊了一個kprobe,當被探測函數運行它的返回指令時。控制傳遞到該trampoline,因此kprobe已經注冊的相應于trampoline的處理函數將被運行。而該處理函數會調用用戶關聯到該kretprobe上的處理函數。處理完成后,設置指令寄存器指向已經備份的函數返回地址。因而原來的函數返回被正常運行。

被探測函數的返回地址保存在類型為kretprobe_instance的變量中。結構kretprobe的maxactive字段指定了被探測函數能夠被同一時候探測的實例數,函數register_kretprobe()將預分配指定數量的kretprobe_instance。假設被探測函數是非遞歸的而且調用時已經保持了自旋鎖(spinlock),那么maxactive為1就足夠了;假設被探測函數是非遞歸的且執行時是搶占失效的,那么maxactive為NR_CPUS就能夠了;假設maxactive被設置為小于等于0, 它被設置到缺省值(假設搶占使能, 即配置了 CONFIG_PREEMPT,缺省值為10和2*NR_CPUS中的最大值,否則缺省值為NR_CPUS)。

假設maxactive被設置的太小了,一些探測點的運行可能被丟失,可是不影響系統的正常運行,在結構kretprobe中nmissed字段將記錄被丟失的探測點運行數,它在返回探測點被注冊時設置為0,每次當運行探測函數而沒有kretprobe_instance可用時,它就加1。

四 、Kprobe限制

kprobe同意在同一地址注冊多個kprobes,可是不能同一時候在該地址上有多個jprobes。通常,用戶能夠在內核的不論什么位置注冊探測點,特別是能夠對中斷處理函數注冊探測點,可是也有一些例外。假設用戶嘗試在實現kprobe的代碼(包含kernel/kprobes.c和arch/*/kernel/kprobes.c以及do_page_fault和notifier_call_chain)中注冊探測點。register_*probe將返回-EINVAL。

假設為一個內聯(inline)函數注冊探測點,kprobe無法保證對該函數的全部實例都注冊探測點,由于gcc可能隱式地內聯一個函數。因此,要記住,用戶可能看不到預期的探測點的運行。一個探測點處理函數可以改動被探測函數的上下文,如改動內核數據結構,寄存器等。因此,kprobe可以用來安裝bug解決代碼或注入一些錯誤或測試代碼。

假設一個探測處理函數調用了還有一個探測點,該探測點的處理函數不將執行,可是它的nmissed數將加1。多個探測點處理函數或同一處理函數的多個實例可以在不同的CPU上同一時候執行。除了注冊和卸載,kprobe不會使用mutexe或分配內存。探測點處理函數在執行時是失效搶占的。依賴于特定的架構,探測點處理函數執行時也可能是中斷失效的。因此,對于不論什么探測點處理函數,不要使用導致睡眠或進程調度的不論什么內核函數(如嘗試獲得semaphore)。

kretprobe是通過代替返回地址為提前定義的trampoline的地址來實現的。因此棧回溯和gcc內嵌函數__builtin_return_address()調用將返回trampoline的地址而不是真正的被探測函數的返回地址。

假設一個函數的調用次數與它的返回次數不同樣,那么在該函數上注冊的kretprobe探測點可能產生無法預料的結果(do_exit()就是一個典型的樣例,但do_execve() 和 do_fork()沒有問題)。

五、怎樣在內核中引入Kprobe

probe已經被包括在2.6內核中。可是僅僅有最新的內核才提供了上面描寫敘述的所有功能,因此假設讀者想實驗本文附帶的內核模塊,須要最新的內核,作者在2.6.18內核上測試的這些代碼。內核缺省時并沒有使能kprobe,因此用戶需使能它。

為了使能kprobe。用戶必須在編譯內核時設置CONFIG_KPROBES,即選擇在“Instrumentation Support“中的“Kprobes”項。假設用戶希望動態載入和卸載使用kprobe的模塊,還必須確保“Loadable module support” (CONFIG_MODULES)和“Module unloading” (CONFIG_MODULE_UNLOAD)設置為y。假設用戶還想使用kallsyms_lookup_name()來得到被探測函數的地址,也要確保CONFIG_KALLSYMS設置為y,當然設置CONFIG_KALLSYMS_ALL為y將更好。

內核中引入Kprobe需要進行以下步驟:

  1. 首先需要確認內核版本是否支持Kprobe,可以通過查詢文檔或者源代碼來確定。
  2. 在內核配置文件中開啟CONFIG_KPROBES選項。
  3. 編譯內核,并安裝新的內核。
  4. 寫一個 Kprobe 監聽函數,在該函數中可以添加相應的邏輯,例如日志輸出、性能統計等等。Kprobe 監聽函數需要使用 Kprobe API 來注冊到系統中。
  5. 使用 insmod 命令加載編寫好的模塊,即可開始監聽指定的內核函數并執行相應操作。

六、Kprobe使用實例

6.1編寫簡單的 Kprobes 探測模塊

接下來,讓我們通過一個具體的例子,來深入了解如何編寫一個簡單的 Kprobes 探測模塊。假設我們要探測do_sys_open函數,這個函數負責處理系統的文件打開操作,在實際的系統調試中,了解文件打開的具體情況,如文件名、打開標志等信息,對于排查文件相關的問題非常有幫助。以下是詳細的代碼實現:

#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/sched.h>

// 定義一個計數器,用于統計函數被調用的次數
static int count = 0;

// pre_handler回調函數,在被探測指令執行前被調用
static int handler_pre(struct kprobe *p, struct pt_regs *regs) {
    // 從寄存器中獲取文件名和標志信息
    char *filename = (char *)regs->di;
    int flags = (int)regs->si;
    // 打印函數調用信息,包括文件名和標志
    printk(KERN_INFO "do_sys_open called with filename=%s, flags=%x\n", filename, flags);
    // 計數器加一
    count++;
    return 0;
}

// 定義kprobe結構,指定要探測的函數為do_sys_open,并關聯pre_handler回調函數
static struct kprobe kp = {
   .symbol_name = "do_sys_open",
   .pre_handler = handler_pre,
};

// 模塊初始化函數,用于注冊kprobe
static int __init mymodule_init(void) {
    int ret;
    // 調用register_kprobe函數注冊kprobe
    ret = register_kprobe(&kp);
    if (ret < 0) {
        // 如果注冊失敗,打印錯誤信息
        printk(KERN_INFO "register_kprobe failed\n");
        return ret;
    }
    // 如果注冊成功,打印成功信息
    printk(KERN_INFO "kprobe registered\n");
    return 0;
}

// 模塊退出函數,用于卸載kprobe
static void __exit mymodule_exit(void) {
    // 調用unregister_kprobe函數卸載kprobe
    unregister_kprobe(&kp);
    // 打印卸載信息,包括函數被調用的次數
    printk(KERN_INFO "kprobe unregistered\n");
    printk(KERN_INFO "do_sys_open called %d times\n", count);
}

// 聲明模塊初始化和退出函數
module_init(mymodule_init);
module_exit(mymodule_exit);
// 指定模塊許可證為GPL
MODULE_LICENSE("GPL");

在上述代碼中,首先定義了一個count變量,用于統計do_sys_open函數被調用的次數。handler_pre函數是pre_handler回調函數,它從寄存器中獲取do_sys_open函數的參數filename和flags,并通過printk函數打印出來,同時將count加一。

然后,創建了一個struct kprobe結構體實例kp,指定要探測的函數為do_sys_open,并將handler_pre函數關聯到kp的pre_handler成員。

在mymodule_init函數中,通過register_kprobe函數將kp注冊到內核中,如果注冊失敗,打印錯誤信息并返回錯誤碼;如果注冊成功,打印成功信息。

在mymodule_exit函數中,通過unregister_kprobe函數將kp從內核中卸載,并打印卸載信息和do_sys_open函數被調用的次數。

6.2基于ftrace使用kprobe

kprobe和內核的ftrac結合使用,需要對內核進行配置,然后添加探測點、進行探測、查看結果。

(1)kprobe配置

打開"General setup"->"Kprobes",以及"Kernel hacking"->"Tracers"->"Enable kprobes-based dynamic events"。

CONFIG_KPROBES=y
CONFIG_OPTPROBES=y
CONFIG_KPROBES_ON_FTRACE=y
CONFIG_UPROBES=y
CONFIG_KRETPROBES=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_OPTPROBES=y
CONFIG_HAVE_KPROBES_ON_FTRACE=y
CONFIG_KPROBE_EVENT=y

(2)kprobe trace events使用

kprobe事件相關的節點有如下:

/sys/kernel/debug/tracing/kprobe_events-----------------------配置kprobe事件屬性,增加事件之后會在kprobes下面生成對應目錄。
/sys/kernel/debug/tracing/kprobe_profile----------------------kprobe事件統計屬性文件。
/sys/kernel/debug/tracing/kprobes/<GRP>/<EVENT>/enabled-------使能kprobe事件
/sys/kernel/debug/tracing/kprobes/<GRP>/<EVENT>/filter--------過濾kprobe事件
/sys/kernel/debug/tracing/kprobes/<GRP>/<EVENT>/format--------查詢kprobe事件顯示格式

下面就結合實例,看一下如何使用kprobe事件。

(3)kprobe事件配置

新增一個kprobe事件,通過寫kprobe_events來設置。

p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS]-------------------設置一個probe探測點
r[:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS]------------------------------設置一個return probe探測點
-:[GRP/]EVENT----------------------------------------------------------刪除一個探測點

細節解釋如下:

GRP        : Group name. If omitted, use "kprobes" for it.------------設置后會在events/kprobes下創建<GRP>目錄。
 EVENT        : Event name. If omitted, the event name is generated based on SYM+offs or MEMADDR.---指定后在events/kprobes/<GRP>生成<EVENT>目錄。MOD        : Module name which has given SYM.--------------------------模塊名,一般不設
 SYM[+offs]    : Symbol+offset where the probe is inserted.-------------被探測函數名和偏移
 MEMADDR    : Address where the probe is inserted.----------------------指定被探測的內存絕對地址
 FETCHARGS    : Arguments. Each probe can have up to 128 args.----------指定要獲取的參數信息。%REG        : Fetch register REG---------------------------------------獲取指定寄存器值
 @ADDR        : Fetch memory at ADDR (ADDR should be in kernel)--------獲取指定內存地址的值
 @SYM[+|-offs]    : Fetch memory at SYM +|- offs (SYM should be a data symbol)---獲取全局變量的值 $stackN    : Fetch Nth entry of stack (N >= 0)----------------------------------獲取指定棧空間值,即sp寄存器+N后的位置值
 $stack    : Fetch stack address.-----------------------------------------------獲取sp寄存器值
 $retval    : Fetch return value.(*)--------------------------------------------獲取返回值,用戶return kprobe
 $comm        : Fetch current task comm.----------------------------------------獲取對應進程名稱。
 +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**)------------- NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
 FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
          (x8/x16/x32/x64), "string" and bitfield are supported.----------------設置參數的類型,可以支持字符串和比特類型
  (*) only for return probe.
  (**) this is useful for fetching a field of data structures.

執行如下兩條命令就會生成目錄/sys/kernel/debug/tracing/events/kprobes/myprobe;第三條命令則可以刪除指定kprobe事件,如果要全部刪除則echo > /sys/kernel/debug/tracing/kprobe_events。

echo 'p:myprobe do_sys_open dfd=%ax filename=%dx flags=%cx mode=+4($stack)' > /sys/kernel/debug/tracing/kprobe_events
echo 'r:myretprobe do_sys_open ret=$retval' >> /sys/kernel/debug/tracing/kprobe_events-----------------------------------------------------這里面一定要用">>",不然就會覆蓋前面的設置。

echo '-:myprobe' >> /sys/kernel/debug/tracing/kprobe_events
echo '-:myretprobe' >> /sys/kernel/debug/tracing/kprobe_events

參數后面的寄存器是跟架構相關的,%ax、%dx、%cx表示第1/2/3個參數,超出部分使用$stack來存儲參數。

函數返回值保存在$retval中。

(4)kprobe使能

對kprobe事件的是能通過往對應事件的enable寫1開啟探測;寫0暫停探測。

echo > /sys/kernel/debug/tracing/trace
echo 'p:myprobe do_sys_open dfd=%ax filename=%dx flags=%cx mode=+4($stack)' > /sys/kernel/debug/tracing/kprobe_events
echo 'r:myretprobe do_sys_open ret=$retval' >> /sys/kernel/debug/tracing/kprobe_events

echo 1 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enable
echo 1 > /sys/kernel/debug/tracing/events/kprobes/myretprobe/enable
ls
echo 0 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enable
echo 0 > /sys/kernel/debug/tracing/events/kprobes/myretprobe/enable

cat /sys/kernel/debug/tracing/trace

然后在/sys/kernel/debug/tracing/trace中可以看到結果。

sourceinsight4.-3356  [000] .... 3542865.754536: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd6764a0 filename=0x8000 flags=0x1b6 mode=0xe3afff48ffffffff
            bash-26041 [001] .... 3542865.757014: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x8241 flags=0x1b6 mode=0xe0c0ff48ffffffff
              ls-18078 [005] .... 3542865.757950: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x1 mode=0xc1b7bf48ffffffff
              ls-18078 [005] d... 3542865.757953: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3
              ls-18078 [005] .... 3542865.757966: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x6168 mode=0xc1b7bf48ffffffff
              ls-18078 [005] d... 3542865.757969: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3
              ls-18078 [005] .... 3542865.758001: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x6168 mode=0xc1b7bf48ffffffff
              ls-18078 [005] d... 3542865.758004: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3
              ls-18078 [005] .... 3542865.758030: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x1000 mode=0xc1b7bf48ffffffff
              ls-18078 [005] d... 3542865.758033: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3
              ls-18078 [005] .... 3542865.758055: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x1000 mode=0xc1b7bf48ffffffff
              ls-18078 [005] d... 3542865.758057: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3
              ls-18078 [005] .... 3542865.758080: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x19d0 mode=0xc1b7bf48ffffffff
              ls-18078 [005] d... 3542865.758082: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3
              ls-18078 [005] .... 3542865.758289: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x8000 flags=0x1b6 mode=0xc1b7bf48ffffffff
              ls-18078 [005] d... 3542865.758297: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3
              ls-18078 [005] .... 3542865.758339: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x88000 flags=0x0 mode=0xc1b7bf48ffffffff
              ls-18078 [005] d... 3542865.758343: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3
              ls-18078 [005] .... 3542865.758444: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x98800 flags=0x2 mode=0xc1b7bf48ffffffff
              ls-18078 [005] d... 3542865.758446: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3
            bash-26041 [001] .... 3542865.760416: myprobe: (do_sys_open+0x0/0x290) dfd=0xffffffffbd676460 filename=0x8241 flags=0x1b6 mode=0xe0c0ff48ffffffff
            bash-26041 [001] d... 3542865.760426: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3
            bash-26041 [001] d... 3542865.793477: myretprobe: (SyS_open+0x1e/0x20 <- do_sys_open) ret=0x3

(5)kprobe事件過濾

跟蹤函數需要通過filter進行過濾,可以有效過濾掉冗余信息。filter文件用于設置過濾條件,可以減少trace中輸出的信息,它支持的格式和c語言的表達式類似,支持 ==,!=,>,<,>=,<=判斷,并且支持與&&,或||,還有()。

echo 'filename==0x8241' > /sys/kernel/debug/tracing/events/kprobes/myprobe/filter

(6)kprobe和棧配合使用

如果要在顯示函數的同時顯示其棧信息,可以通過配置trace_options來達到。

echo stacktrace > /sys/kernel/debug/tracing/trace_options

(7)kprobe_profile統計信息

獲取一段kprobe時間之后,可以再kprobe_profile中查看統計信息。

后面兩列分別表示命中和未命中的次數。

cat /sys/kernel/debug/tracing/kprobe_profile    myprobe

6.3調試工具搭配使用

在使用 Kprobes 進行調試時,搭配其他工具可以更高效地分析和解決問題,就像一場精彩的交響樂,不同的樂器相互配合,才能演奏出美妙的旋律。

查看內核日志是一個非常重要的輔助手段。在前面的代碼中,我們使用了printk函數來輸出調試信息,這些信息會被記錄到內核日志中。通過查看內核日志,我們可以了解 Kprobes 探測模塊的運行情況,如探測點是否成功注冊、回調函數是否被正確調用、函數的參數和執行結果等。在 Linux 系統中,可以使用dmesg命令來查看內核日志,例如:dmesg | grep "do_sys_open",這個命令會過濾出內核日志中與do_sys_open相關的信息,方便我們快速定位問題。

gdb調試器也能與 Kprobes 配合使用,為調試工作提供更多便利。雖然 Kprobes 主要用于動態調試運行中的內核,但在某些情況下,結合gdb可以更深入地分析問題。比如,當 Kprobes 探測到某個函數出現異常,但通過printk輸出的信息不足以定位問題時,可以使用gdb來調試內核模塊。首先,需要在內核編譯時開啟調試信息,然后使用gdb加載內核和內核模塊,通過設置斷點、單步執行等操作,詳細分析函數的執行過程,找出問題的根源。

6.4常見問題與解決方法

在使用 Kprobes 的過程中,可能會遇到一些常見問題,這些問題就像是前進道路上的絆腳石,但只要我們掌握了解決方法,就能輕松跨越。

探測點無法注冊是一個常見的問題。這可能是由于目標函數不存在、符號未導出或內核保護等原因導致的。當遇到這種情況時,首先要確認目標函數是否存在,可以通過查看內核源碼或使用nm命令查看內核符號表來確認。如果函數存在,再檢查符號是否導出,可以查看/proc/kallsyms文件,看目標函數的符號是否在其中。如果是內核保護導致的問題,例如內核處于寫保護狀態,可能需要臨時關閉相關保護機制,但這需要謹慎操作,因為關閉保護機制可能會影響系統的穩定性和安全性。

回調函數未按預期執行也是一個需要關注的問題。這可能是由于回調函數中存在錯誤,如內存訪問越界、空指針引用等,導致回調函數執行異常。在編寫回調函數時,要確保代碼的正確性和健壯性,避免出現這些常見的錯誤。同時,要注意回調函數的執行環境,因為回調函數運行在中斷上下文中,所以不能執行可能會導致阻塞的操作,如睡眠、等待信號量等。如果需要進行一些復雜的操作,可以將這些操作放到工作隊列或內核線程中執行,以避免影響回調函數的正常執行。

責任編輯:武曉燕 來源: 深度Linux
相關推薦

2020-02-07 11:07:53

數組鏈表單鏈表

2017-11-28 15:20:27

Python語言編程

2021-04-27 11:28:21

React.t事件元素

2024-09-18 13:57:15

2025-09-26 08:52:57

2024-08-09 08:41:14

2025-02-03 07:00:00

Java接口工具

2023-08-27 21:29:43

JVMFullGC調優

2025-06-18 04:00:00

2022-03-18 13:58:00

RocketMQ消息隊列

2024-08-26 08:58:50

2017-10-18 17:16:59

ZeroHeroPython

2019-06-23 15:21:42

Google谷歌平板

2020-02-21 14:35:57

JavaScript繼承前端

2021-09-10 16:10:21

panda透視表語言

2019-07-04 15:16:42

數據架構Flink數據倉庫

2021-01-26 05:19:56

語言Go Context

2025-04-09 05:22:00

2024-10-11 09:27:52

2021-08-30 19:04:29

jsIO
點贊
收藏

51CTO技術棧公眾號

aaaaaa毛片| 伊人影院综合在线| 亚洲 欧美 自拍偷拍| 国产深夜精品| 深夜福利一区二区| 久久无码专区国产精品s| 永久免费毛片在线播放| 国产精品家庭影院| 国产成人成网站在线播放青青| 自拍偷拍欧美亚洲| 三上亚洲一区二区| 亚洲а∨天堂久久精品喷水| 狠狠热免费视频| 国产精品探花在线| 欧美国产日韩精品免费观看| 亚洲自拍欧美色图| aaa在线视频| 欧美三级不卡| 中文字幕亚洲欧美在线| 国产性猛交96| 亚洲日本中文| 色婷婷久久99综合精品jk白丝| 亚洲黄色网址在线观看| 极品白浆推特女神在线观看 | 国产日本欧美一区| 在线观看 中文字幕| 亚洲91视频| 在线观看国产成人av片| 人妻av一区二区三区| 日本成人福利| 色综合婷婷久久| 亚洲欧美日韩国产中文| 亚洲精品人成| 日本美女一级片| 九九国产精品视频| 欧洲亚洲女同hd| 免费在线黄色片| 日韩一区电影| 亚洲深夜福利在线| 成人性生活免费看| 91大神精品| 欧美一二三四在线| 伊人国产精品视频| 欧美亚洲福利| 欧美系列日韩一区| 欧美激情精品久久久久久小说| 美女网站视频在线| 一区二区三区美女视频| 国产欧美自拍视频| 国产原创精品视频| 中文字幕在线不卡视频| 先锋影音日韩| 69xxxx欧美| 国产精品五月天| 欧美91看片特黄aaaa| 免费日韩视频| 97**国产露脸精品国产| 不卡的免费av| 一区在线播放| 高清欧美电影在线| 日韩精品视频免费看| 亚洲午夜一区| 午夜精品国产精品大乳美女| 日韩精品一区三区| 国产农村妇女毛片精品久久莱园子| 91成人性视频| 五月天激情四射| 日本aⅴ亚洲精品中文乱码| 国产精品久久久久久久久久新婚| 最近中文字幕免费观看| 青草国产精品久久久久久| 国产精品久久久久久久久久小说| 一本色道久久综合精品婷婷| 国产专区综合网| 成人在线免费网站| 午夜影院免费体验区| 久久久久久麻豆| 亚洲综合五月天| 1区2区3区在线视频| 亚洲一区二区三区小说| 九九九九免费视频| 国产精品久久久久77777丨| 91精品婷婷国产综合久久性色| 国产5g成人5g天天爽| 91亚洲精品视频在线观看| 日韩美女av在线| 一级二级黄色片| 国产精品av久久久久久麻豆网| 91精品国产色综合久久不卡98| 国产99免费视频| 国产一区美女在线| 成人欧美大片| 日韩高清欧美激情| 国产欧美一区二区三区在线看| 国产尤物在线观看| 国产99久久久精品| 欧美二区在线看| 麻豆系列在线观看| 午夜私人影院久久久久| 韩国中文字幕av| 亚洲精品国产九九九| 国产丝袜精品第一页| 日韩精品123区| 国产偷自视频区视频一区二区| 国产精品免费久久久久影院| 丰满熟妇人妻中文字幕| 国产欧美一区二区精品仙草咪| 五月天在线免费视频| 午夜欧美激情| 日韩一级片在线观看| 国产精品国产三级国产专业不| 欧美三级黄美女| 国产欧美在线播放| 欧美色18zzzzxxxxx| 亚洲一区二区三区四区五区中文| 亚洲一二三区av| 天天久久夜夜| 欧美日韩国产成人高清视频| 天天射天天干天天| youjizz久久| 日本在线视频www色| 精品美女一区| 亚洲天堂成人在线| 亚洲另类欧美日韩| 国产成人av电影在线播放| 亚洲高清视频在线观看| 亚洲日本天堂| 日韩av在线资源| 久久久久免费看| 韩国精品一区二区| 自拍另类欧美| 福利视频一区| 伊人久久久久久久久久久久久| 黄网在线观看视频| 99久久久免费精品国产一区二区 | 中文字幕中文字幕精品| 欧美日韩福利视频| 午夜老司机福利| 亚洲卡通欧美制服中文| 三级一区二区三区| 四季av一区二区凹凸精品| 国产成人激情小视频| 色鬼7777久久| 欧美日韩国产在线播放| 国产麻豆剧传媒精品国产av| 国内精品福利| 俄罗斯精品一区二区| 18加网站在线| 精品久久人人做人人爱| 国产精品第九页| aaa亚洲精品| 免费黄色日本网站| 一呦二呦三呦国产精品| 国产精品欧美一区二区三区不卡 | 亚洲专区**| 久久久精品亚洲| 国产老妇伦国产熟女老妇视频| 亚洲国产成人私人影院tom| 亚洲精品怡红院| 欧美久久精品一级c片| 国产精品亚洲欧美导航| 秋霞a级毛片在线看| 91精品国模一区二区三区| 日韩欧美综合视频| 岛国精品在线观看| 国产午夜伦鲁鲁| 蜜桃成人av| 国产欧美一区二区| 亚洲91av| 亚洲精品美女在线| 怡红院av久久久久久久| 国产精品―色哟哟| 超碰人人cao| 日韩午夜免费视频| 日韩欧美亚洲区| 国产一区二区三区免费观看在线 | 亚洲欧洲一二区| 欧美激情精品久久久久久变态| 少妇喷水在线观看| 欧美在线一区二区三区| 三上悠亚在线观看视频| 国产成a人亚洲精品| 一区二区国产精品视频| 国模无码视频一区| 亚洲一区日本| 伊人色综合影院| 国产精品久久久久久亚洲av| 久久精品亚洲欧美日韩精品中文字幕| 91久久精品久久国产性色也91| 亚洲大胆人体大胆做受1| 亚洲国产黄色片| 中文天堂在线资源| 亚洲国产成人高清精品| 免费在线观看a视频| 国产精品综合二区| 国产二区视频在线播放| 91影院成人| 蜜桃91精品入口| 99久久久成人国产精品| 欧美在线一级va免费观看| 午夜视频在线| 日韩国产欧美区| av无码精品一区二区三区宅噜噜| 天天综合日日夜夜精品| 午夜精品福利在线视频| 国产亚洲欧美中文| 五月天丁香社区| 九色|91porny| 女人另类性混交zo| 尤物精品在线| 国产又粗又爽又黄的视频| 九九综合在线| 国产欧美日韩一区| 看亚洲a级一级毛片| 国产大片精品免费永久看nba| 欧美日韩在线视频免费观看| 中文字幕日韩精品有码视频| 香蕉久久一区二区三区| 日韩欧美黄色影院| 国产原创中文av| 在线看国产一区二区| 日本系列第一页| 一区二区三区久久| 欧美日韩黄色网| 国产精品久久久久一区二区三区| 日韩 中文字幕| 成人aaaa免费全部观看| 久久久久无码精品| 国内一区二区视频| 亚洲高清免费在线观看| 日日夜夜一区二区| 免费男同深夜夜行网站 | 精品亚洲一区二区三区在线播放 | 亚洲免费一级电影| 日韩一级在线播放| 精品88久久久久88久久久| 国内精品国产成人国产三级| 欧美日韩国产精品成人| 羞羞色院91蜜桃| 欧美无砖砖区免费| 中文字字幕在线观看| 欧美日韩综合在线| 中文字幕在线观看你懂的| 在线观看一区二区视频| 亚洲欧美一二三区| 在线观看免费视频综合| 福利网址在线观看| 欧美影院午夜播放| 亚洲天堂777| 欧美妇女性影城| 一本色道久久综合亚洲| 在线电影一区二区三区| hs视频在线观看| 精品日韩一区二区三区免费视频| 国产999久久久| 精品国产一区二区在线观看| 欧美自拍第一页| 精品无人国产偷自产在线| 免费在线超碰| 尤物yw午夜国产精品视频明星| 成人免费黄色网页| 日韩中文字幕视频在线观看| 黄色片免费在线观看| 成人444kkkk在线观看| 日本高清成人vr专区| 久久久久久成人| 欧美在线极品| 国产精品视频一区国模私拍| 亚洲欧美久久精品| dy888夜精品国产专区| 久久综合社区| 亚欧洲精品在线视频免费观看| 色婷婷一区二区三区| 欧美交换配乱吟粗大25p| 在线日韩电影| 中文字幕欧美人妻精品一区| 激情综合一区二区三区| 国产免费一区二区三区最新6| 91偷拍与自偷拍精品| 国产白丝一区二区三区 | 免费拍拍拍网站| 性8sex亚洲区入口| 五月婷婷六月丁香激情| 国产suv精品一区二区883| asian性开放少妇pics| 国产精品久久毛片av大全日韩| 久久久久久久久久91| 日韩欧美在线中文字幕| 91丨porny丨在线中文 | 国产二区视频在线观看| 久久香蕉频线观| 少妇淫片在线影院| 成人伊人精品色xxxx视频| 日本午夜精品| 欧美少妇一级片| 精品在线观看入口| 精品毛片久久久久久| 国产乱码精品一区二区亚洲| 日韩精品一区二区三区电影| 裸体素人女欧美日韩| 久久黄色一级视频| 国产欧美一二三区| 久久久美女视频| 在线观看日韩毛片| 欧美熟妇交换久久久久久分类 | 中文字幕在线不卡| 欧美黄色一级网站| 日本精品视频一区二区| 亚洲欧美激情网| 国产一区欧美日韩| 人人人妻人人澡人人爽欧美一区| 亚洲激情图片一区| 中文字幕一级片| 日韩精品中文字幕有码专区| 182tv在线播放| 国产一区视频在线播放| 天天躁日日躁狠狠躁欧美巨大小说| 一区中文字幕在线观看| 久久婷婷av| 星空大象在线观看免费播放| 亚洲欧美日韩一区| 亚洲天堂手机版| 一道本无吗dⅴd在线播放一区| 国产99在线观看| 国产精品亚洲综合| 欧美日本在线| 欧美特黄aaa| 国产精品色婷婷久久58| 久久青青草原亚洲av无码麻豆| 亚洲第一页在线| 国产在线拍揄自揄拍视频| 亚洲a区在线视频| 国产精品麻豆久久| 潘金莲激情呻吟欲求不满视频| 91麻豆免费观看| 久久草视频在线| 亚洲精品一线二线三线无人区| 在线看三级电影| 91九色在线免费视频| 亚洲有吗中文字幕| 4438x全国最大成人| 亚洲欧美另类图片小说| 国产精品久久久久久久久久久久久久久久 | 欧美性69xxxx肥| 亚洲色大成网站www| 97精品视频在线观看| 免费看久久久| 日本福利视频在线| 91视频精品在这里| aaaaaa毛片| 这里只有精品在线播放| 成人性片免费| 青春草在线视频免费观看| 国产精品91久久| 五月天婷婷激情网| 欧美激情视频在线免费观看 欧美视频免费一 | 国产精品任我爽爆在线播放| 欧美大黑帍在线播放| 成人天堂资源www在线| 国产污污视频在线观看| 亚洲色图av在线| 久久天天久久| 中文字幕精品在线播放| 高清shemale亚洲人妖| 日韩污视频在线观看| 亚洲欧美在线播放| 看片一区二区| 青青草视频国产| 91蝌蚪porny成人天涯| 波多野结衣不卡| 久久精品国产综合| 国内视频在线精品| 午夜肉伦伦影院| 国产精品不卡一区| 黑人精品一区二区| 日韩免费在线看| 亚洲综合中文| 在线免费观看a级片| 欧美性受xxxx| 日韩激情av| 青青草成人网| 国产麻豆视频一区二区| 日韩欧美一区二区一幕| 视频在线观看99| 久久97精品| 色呦色呦色精品| 亚洲成人精品一区| 午夜在线小视频| 精品九九九九| 国产一区二区在线免费观看| 精品91久久久| 久久精品99久久久香蕉| 欧美天堂影院| 在线观看视频在线观看| 日韩欧美在线一区| 污片视频在线免费观看| 日韩激情视频| 国产美女永久免费无遮挡| 亚洲高清毛片| 四虎成人免费影院|