1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Linux內(nèi)核調(diào)試?yán)鳎黭probe 原理與實(shí)現(xiàn)

        共 17748字,需瀏覽 36分鐘

         ·

        2022-06-17 15:35

        在《Linux 內(nèi)核調(diào)試?yán)?| kprobe 的使用》一文中,我們介紹過(guò)怎么使用 kprobe 來(lái)追蹤內(nèi)核函數(shù),而本文將會(huì)介紹 kprobe 的原理和實(shí)現(xiàn)

        kprobe 原理

        kprobe 可以用來(lái)跟蹤內(nèi)核函數(shù)中某一條指令在運(yùn)行前和運(yùn)行后的情況。

        我們只需在 kprobe 模塊中定義好指令執(zhí)行前的回調(diào)函數(shù) pre_handler() 和執(zhí)行后的回調(diào)函數(shù) post_handler(),那么內(nèi)核將會(huì)在被跟蹤的指令執(zhí)行前調(diào)用 pre_handler() 函數(shù),并且在指令執(zhí)行后調(diào)用 post_handler() 函數(shù)。如下圖所示:

        (圖1)

        那么,內(nèi)核是怎樣做到在被跟蹤指令執(zhí)行前調(diào)用 pre_handler() 函數(shù)和指令執(zhí)行后調(diào)用 post_handler() 函數(shù)的呢?

        如果你讀過(guò)我們之前寫的一篇文章《斷點(diǎn)的原理》,那么就比較容易理解 kprobe 的原理了,因?yàn)?kprobe 使用了類似于斷點(diǎn)的機(jī)制來(lái)實(shí)現(xiàn)的。

        如果不了解斷點(diǎn)的原理,那么請(qǐng)先看看這篇文章《斷點(diǎn)的原理》。

        當(dāng)使用 kprobe 來(lái)跟蹤內(nèi)核函數(shù)的某條指令時(shí),kprobe 首先會(huì)把要追蹤的指令保存起來(lái),然后把要追蹤的指令替換成 int3 指令。如下圖所示:


        (圖2)

        被追蹤的指令替換成 int3 指令后,當(dāng)內(nèi)核執(zhí)行到這條指令時(shí),將會(huì)觸發(fā) do_int3() 異常處理例程。

        do_int3() 異常處理例程的執(zhí)行過(guò)程如下:

        1. 首先調(diào)用 kprobe 模塊的 pre_handler() 回調(diào)函數(shù)。
        2. 然后將 CPU 設(shè)置為單步調(diào)試模式。
        3. 接著從異常處理例程中返回,并且執(zhí)行原來(lái)的指令。

        我們通過(guò)下圖來(lái)展示 do_int3() 函數(shù)的執(zhí)行過(guò)程:

        (圖3)

        由于設(shè)置了單步調(diào)試模式,當(dāng)執(zhí)行完原來(lái)的指令后,將會(huì)觸發(fā) debug異常(這是 Intel x86 CPU 的一個(gè)特性)。

        當(dāng) CPU 觸發(fā) debug異常 后,內(nèi)核將會(huì)執(zhí)行 debug 異常處理例程 do_debug(),而 do_debug() 異常處理例程將會(huì)調(diào)用 kprobe 模塊的 post_handler() 回調(diào)函數(shù)。

        下圖展示了 kprobe 的執(zhí)行流程:

        (圖4)

        kprobe 實(shí)現(xiàn)

        了解了 kprobe 的原理后,現(xiàn)在我們開始分析 kprobe 的代碼實(shí)現(xiàn)。

        由于 kprobe 的細(xì)節(jié)很多,本文只會(huì)對(duì) kprobe 整個(gè)大體實(shí)現(xiàn)方式進(jìn)行分析,有些細(xì)節(jié)需要讀者自行閱讀源碼了解。

        1. kprobe 初始化

        一個(gè)功能的實(shí)現(xiàn),一般都需要先初始化其所使用的資源和環(huán)境,kprobe 功能也不例外。

        下面我們來(lái)看看 kprobe 的初始化過(guò)程,kprobe 的初始化由 init_kprobes() 函數(shù)實(shí)現(xiàn):

        static int __init init_kprobes(void)
        {
            int i, err = 0;
            unsigned long offset = 0, size = 0;
            char *modname, namebuf[128];
            const char *symbol_name;
            void *addr;
            struct kprobe_blackpoint *kb;

            // 1) 初始化用于存儲(chǔ) kprobe 模塊的哈希表
            for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
                INIT_HLIST_HEAD(&kprobe_table[i]);
                ...
            }

            // 2) 初始化 kprobe 的黑名單函數(shù)列表(不能被 kprobe 跟蹤的函數(shù)列表)
            for (kb = kprobe_blacklist; kb->name != NULL; kb++) {
                kprobe_lookup_name(kb->name, addr);
                if (!addr)
                    continue;

                kb->start_addr = (unsigned long)addr;
                symbol_name = kallsyms_lookup(kb->start_addr, &size, &offset, &modname,
                                              namebuf);
                if (!symbol_name)
                    kb->range = 0;
                else
                    kb->range = size;
            }
            ...

            kprobes_all_disarmed = false;

            // 3) 初始化CPU架構(gòu)相關(guān)的環(huán)境(x86架構(gòu)的實(shí)現(xiàn)為空)
            err = arch_init_kprobes();

            // 4) 注冊(cè)die通知鏈(這個(gè)比較重要)
            if (!err)
                err = register_die_notifier(&kprobe_exceptions_nb);

            // 5) 注冊(cè)模塊通知鏈
            if (!err)
                err = register_module_notifier(&kprobe_module_nb);
            ...
            return err;
        }

        上面代碼精簡(jiǎn)了一些與 kprobe 功能無(wú)關(guān)的代碼(如 kretprobe 的功能代碼)。

        init_kprobes() 函數(shù)主要完成 5 件事情:

        1. 初始化用于存儲(chǔ) kprobe 模塊的哈希表。
        2. 初始化 kprobe 的黑名單函數(shù)列表(不能被 kprobe 跟蹤的函數(shù)列表)。
        3. 初始化CPU架構(gòu)相關(guān)的環(huán)境(x86 CPU架構(gòu)的實(shí)現(xiàn)為空)。
        4. 注冊(cè)die通知鏈(重要)。
        5. 注冊(cè)模塊通知鏈。

        kprobe模塊哈希表

        我們?cè)凇?a style="box-sizing: border-box;color: rgb(239, 112, 96);text-decoration: none;background-color: initial;outline: none;cursor: pointer;transition: color 0.3s ease 0s;touch-action: manipulation;overflow-wrap: break-word;font-weight: bold;border-bottom: 1px solid rgb(239, 112, 96);" data-linktype="2">Linux 內(nèi)核調(diào)試?yán)?| kprobe 的使用》一文中介紹過(guò),一個(gè) kprobe 模塊是由一個(gè) struct kprobe 結(jié)構(gòu)來(lái)描述的。我們?cè)賮?lái)重溫一下這個(gè)結(jié)構(gòu):

        struct kprobe {
            // 用于保存到 kprobe 模塊哈希表
            struct hlist_node hlist;
            ...
            kprobe_opcode_t *addr;
            const char *symbol_name;
            unsigned int offset;
            // 回調(diào)函數(shù)
            kprobe_pre_handler_t pre_handler;
            kprobe_post_handler_t post_handler;
            ...

            kprobe_opcode_t opcode;
            struct arch_specific_insn ainsn;
            u32 flags;
        };

        struct kprobe 結(jié)構(gòu)的 hlist 字段用于把當(dāng)前結(jié)構(gòu)存放到 kprobe 模塊 哈希表中,如下圖所示:

        (圖5)

        內(nèi)核把跟蹤的指令地址作為鍵,然后將 kprobe 結(jié)構(gòu)保存到哈希表中,這樣就能通過(guò)指令的地址快速查找到對(duì)應(yīng)的 kprobe 結(jié)構(gòu)。

        注冊(cè) die 通知鏈

        通知鏈 機(jī)制是內(nèi)核用于做一些事件回調(diào)操作的功能,比如說(shuō):當(dāng)關(guān)機(jī)時(shí),需要把內(nèi)存中的數(shù)據(jù)寫入到磁盤,就可以通過(guò) 通知鏈 來(lái)實(shí)現(xiàn)。

        kprobe 在初始化階段,會(huì)把 kprobe_exceptions_notify() 回調(diào)函數(shù)注冊(cè)到 die 通知鏈中。代碼如下:

        static struct notifier_block kprobe_exceptions_nb = {
            .notifier_call = kprobe_exceptions_notify,
            ...
        };

        static int __init init_kprobes(void)
        {
            ...
            if (!err)
                err = register_die_notifier(&kprobe_exceptions_nb);
            ...
        }

        init_kprobes() 通過(guò)調(diào)用 register_die_notifier() 函數(shù)將 kprobe_exceptions_notify() 回調(diào)函數(shù)注冊(cè)到 die 通知鏈中。

        當(dāng) CPU 觸發(fā)斷點(diǎn)異常時(shí)(執(zhí)行 int3 指令),內(nèi)核將會(huì)執(zhí)行 do_int3() 異常處理例程,而 do_int3() 例程將會(huì)調(diào)用 die 通知鏈中的回調(diào)函數(shù)。此時(shí),kprobe_exceptions_notify() 回調(diào)函數(shù)將會(huì)被執(zhí)行。

        關(guān)于 kprobe_exceptions_notify() 回調(diào)函數(shù)的執(zhí)行流程下面將會(huì)介紹。

        2. 注冊(cè) kprobe 實(shí)例

        在《Linux 內(nèi)核調(diào)試?yán)?| kprobe 的使用》一文中介紹過(guò),編寫好的 kprobe 模塊需要通過(guò)調(diào)用 register_kprobe() 函數(shù)來(lái)注冊(cè)到內(nèi)核。

        我們來(lái)看看 register_kprobe() 函數(shù)的實(shí)現(xiàn):

        int __kprobes register_kprobe(struct kprobe *p)
        {
            ...
            // 1) 獲取要跟蹤的指令的內(nèi)存地址
            addr = kprobe_addr(p);       
            ...
            p->addr = addr;
            ...
            // 2) 檢測(cè)跟蹤點(diǎn)是否合法
            ret = check_kprobe_address_safe(p, &probed_mod); 
            ...
            // 3) 保存被跟蹤指令的值
            ret = prepare_kprobe(p);
            ...
            // 4) 將 kprobe 結(jié)構(gòu)添加到 kprobe 模塊哈希表中
            hlist_add_head_rcu(&p->hlist,
                               &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);

            // 5) 將要跟蹤的指令替換成 int3 指令
            if (!kprobes_all_disarmed && !kprobe_disabled(p))
                arm_kprobe(p);
            ...
            return ret;
        }

        經(jīng)過(guò)精簡(jiǎn)后,上面代碼只留下了主要流程。

        從上面代碼可以看出,register_kprobe() 函數(shù)主要完成 5 件事情:

        1. 獲取要跟蹤的內(nèi)核函數(shù)中的指令內(nèi)存地址(跟蹤點(diǎn))。
        2. 檢測(cè)跟蹤點(diǎn)地址是否合法。
        3. 保存被跟蹤指令的值。
        4. 將當(dāng)前注冊(cè)的 kprobe 結(jié)構(gòu)添加到 kprobe 模塊哈希表中。
        5. 將要跟蹤的指令替換成 int3 指令。

        下面說(shuō)說(shuō)這 5 件事情分別要完成什么功能:

        獲取跟蹤指令的內(nèi)存地址

        一般來(lái)說(shuō),我們要跟蹤一個(gè)內(nèi)核函數(shù)的某條指令,都是通過(guò)內(nèi)核函數(shù)名去指定的(當(dāng)然也可以直接指定指令的內(nèi)存地址,但這個(gè)方法比較麻煩)。

        所以,內(nèi)核首先需要通過(guò)函數(shù)名,來(lái)獲取其第一條指令對(duì)應(yīng)的內(nèi)存地址。而內(nèi)核是通過(guò)調(diào)用 kprobe_addr() 函數(shù)來(lái)獲取跟蹤函數(shù)的內(nèi)存地址。

        而 kprobe_addr() 最終會(huì)調(diào)用 kallsyms_lookup_name() 來(lái)獲取跟蹤函數(shù)的內(nèi)存地址。kallsyms_lookup_name() 函數(shù)的實(shí)現(xiàn),本文不再展開細(xì)說(shuō),有興趣可以自行閱讀代碼或者查閱其他文獻(xiàn)。

        檢測(cè)跟蹤點(diǎn)地址是否合法

        這個(gè)過(guò)程主要對(duì)跟蹤指令的內(nèi)存地址進(jìn)行合法檢測(cè),主要檢查幾個(gè)點(diǎn):

        1. 跟蹤點(diǎn)是否已經(jīng)被 ftrace 跟蹤,如果是就返回錯(cuò)誤(kprobe 與 ftrace 不能同時(shí)跟蹤同一個(gè)地址)。
        2. 跟蹤點(diǎn)是否在內(nèi)核代碼段,因?yàn)?kprobe 只能跟蹤內(nèi)核函數(shù),所以跟蹤點(diǎn)必須在內(nèi)核代碼段中。
        3. 跟蹤點(diǎn)是否在 kprobe 的黑名單中,如果是就返回錯(cuò)誤。
        4. 跟蹤點(diǎn)是否在內(nèi)核模塊代碼段中,kprobe 也可以跟蹤內(nèi)核模塊的函數(shù)。

        保存被跟蹤指令的值

        內(nèi)核通過(guò)調(diào)用 prepare_kprobe() 函數(shù)來(lái)保存被跟蹤的指令,而 prepare_kprobe() 最終會(huì)調(diào)用 CPU 架構(gòu)相關(guān)的 arch_prepare_kprobe() 函數(shù)來(lái)完成任務(wù)。

        我們來(lái)看看 arch_prepare_kprobe() 函數(shù)的實(shí)現(xiàn):

        int __kprobes arch_prepare_kprobe(struct kprobe *p)
        {
            ...
            // 1) 申請(qǐng)內(nèi)存空間,用于存放原指令的數(shù)據(jù)
            p->ainsn.insn = get_insn_slot();
            ...
            // 2) 保存原來(lái)指令的值
            return arch_copy_kprobe(p);
        }

        最終結(jié)果如 圖2 所示。

        將當(dāng) kprobe 結(jié)構(gòu)添加到哈希表中

        將當(dāng)前 kprobe 結(jié)構(gòu)添加到 kprobe 模塊哈希表中,主要為了能夠通過(guò)跟蹤點(diǎn)的內(nèi)存地址快速查找到對(duì)應(yīng)的 kprobe 結(jié)構(gòu),如 圖5 所示。

        將跟蹤點(diǎn)替換成 int3 指令

        將跟蹤點(diǎn)替換成 int3 指令的目的是,當(dāng) CPU 執(zhí)行到跟蹤點(diǎn)時(shí),將會(huì)觸發(fā)產(chǎn)生斷點(diǎn)中斷,這時(shí)內(nèi)核將會(huì)調(diào)用 do_int3() 處理異常,如 圖2 所示。

        將跟蹤點(diǎn)替換成 int3 指令是由 arm_kprobe() 函數(shù)完成,其調(diào)用鏈如下:

        arm_kprobe()
        └→ __arm_kprobe()
           └→ arch_arm_kprobe()

        從上面的調(diào)用可以看到,arm_kprobe() 最終會(huì)調(diào)用 arch_arm_kprobe() 函數(shù)來(lái)完成替換工作,我們來(lái)看看 arch_arm_kprobe() 函數(shù)的實(shí)現(xiàn):

        #define BREAKPOINT_INSTRUCTION  0xcc

        void __kprobes arch_arm_kprobe(struct kprobe *p)
        {
            text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
        }

        從上面可以看出,arch_arm_kprobe() 函數(shù)把跟蹤點(diǎn)地址處的數(shù)據(jù)替換成 0xcc(也就是 int3 指令)。

        3. kprobe 回調(diào)

        前面說(shuō)過(guò),當(dāng) CPU 執(zhí)行到 int3 指令時(shí),將會(huì)觸發(fā)斷點(diǎn)異常。此時(shí),內(nèi)核將會(huì)調(diào)用 do_int3() 函數(shù)來(lái)處理異常。

        do_int3() 函數(shù)對(duì) kprobe 處理的調(diào)用鏈如下:

        do_int3()
        └→ notify_die()
           └→ atomic_notifier_call_chain()
              └→ __atomic_notifier_call_chain()
                 └→ notifier_call_chain()
                    └→ kprobe_exceptions_notify()

        從上面的調(diào)用鏈可以看出,do_int3() 最終會(huì)調(diào)用 kprobe_exceptions_notify() 函數(shù)來(lái)處理 kprobe 的流程。

        我們來(lái)看看 kprobe_exceptions_notify() 函數(shù)的實(shí)現(xiàn):

        int __kprobes 
        kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data)
        {
            struct die_args *args = data;
            int ret = NOTIFY_DONE;

            // 1) 如果是用戶態(tài)觸發(fā),直接返回,因?yàn)橛脩魬B(tài)不能使用 kprobe
            if (args->regs && user_mode_vm(args->regs))
                return ret;

            switch (val) {
            // 2) 如果異常是由 int3 指令觸發(fā)的,則調(diào)用 kprobe_handler() 處理異常
            case DIE_INT3:
                if (kprobe_handler(args->regs)) 
                    ret = NOTIFY_STOP;
                break;
            ...
            default:
                break;
            }

            return ret;
        }

        從上面代碼可以看出,當(dāng)異常是由 int3 指令觸發(fā)的,將會(huì)調(diào)用 kprobe_handler() 函數(shù)處理異常。

        我們來(lái)分析下 kprobe_handler() 函數(shù)的實(shí)現(xiàn):

        static int __kprobes 
        kprobe_handler(struct pt_regs *regs)
        {
            ...
            // 1) 獲取觸發(fā)異常的指令內(nèi)存地址
            addr = (kprobe_opcode_t *)(regs->ip - sizeof(kprobe_opcode_t));
            ...
            // 2) 通過(guò)內(nèi)存地址獲取 kprobe 結(jié)構(gòu)(在注冊(cè)階段將其添加到哈希表中)
            p = get_kprobe(addr);
            if (p) {
                    ...
                    // 3) 如果 kprobe 模塊定義了 pre_handler() 回調(diào),那么調(diào)用 pre_handler() 回調(diào)函數(shù)
                    if (!p->pre_handler || !p->pre_handler(p, regs))
                        // 4) 設(shè)置單步調(diào)試模式
                        setup_singlestep(p, regs, kcb, 0);
                    return 1;
                    ...
            }
            ...
            return 0;
        }

        kprobe_handler() 函數(shù)會(huì)處理幾種情況,本文我們主要按照最常見(jiàn)的情況分析,就是上面代碼的流程。

        從上面代碼可以看到,kprobe_handler() 函數(shù)主要完成 4 件事情:

        1. 獲取觸發(fā)異常的指令內(nèi)存地址(也就是 int3 指令的內(nèi)存地址)。
        2. 通過(guò)內(nèi)存地址獲取 kprobe 結(jié)構(gòu)(在注冊(cè)階段將其添加到哈希表中)。
        3. 如果 kprobe 模塊定義了 pre_handler() 回調(diào),那么調(diào)用 pre_handler() 回調(diào)函數(shù)。
        4. 設(shè)置單步調(diào)試模式。

        從上面的分析可以知道,在 do_int3() 異常處理例程中調(diào)用了 kprobe 模塊的 pre_handler() 回調(diào)函數(shù),但 post_handler() 回調(diào)函數(shù)在什么地方調(diào)用呢?

        我們知道,kprobe 模塊的 post_handler() 回調(diào)函數(shù)是在被跟蹤指令執(zhí)行完后被調(diào)用的。所以,在 do_int3() 異常處理例程中調(diào)用是不合適的。

        為了解決這個(gè)問(wèn)題,Linux 內(nèi)核使用單步調(diào)試模式來(lái)處理這種情況。設(shè)置單步調(diào)試模式由 setup_singlestep() 函數(shù)完成,我們來(lái)分析其實(shí)現(xiàn):

        static void __kprobes 
        setup_singlestep(struct kprobe *p, struct pt_regs *regs,
                         struct kprobe_ctlblk *kcb, int reenter)

        {
            ...
            // 1) 將 flags 寄存器的 TF 標(biāo)志位設(shè)置為1,進(jìn)入單步調(diào)試模式
            regs->flags |= X86_EFLAGS_TF;
            regs->flags &= ~X86_EFLAGS_IF;

            // 2) 設(shè)置異常返回后執(zhí)行的下一條指令的地址
            if (p->opcode == BREAKPOINT_INSTRUCTION)
                regs->ip = (unsigned long)p->addr;
            else
                regs->ip = (unsigned long)p->ainsn.insn;
        }

        setup_singlestep() 函數(shù)主要完成兩件事情:

        1. 將 flags 寄存器的 TF 標(biāo)志位設(shè)置為1,進(jìn)入單步調(diào)試模式(可以參考 Intel 的手冊(cè))。
        2. 設(shè)置異常處理例程(do_int3() 函數(shù))返回后,執(zhí)行下一條指令的地址(執(zhí)行原來(lái)的指令)。

        設(shè)置完單步調(diào)試模式后,內(nèi)核就從 do_int3() 異常處理例程中返回,接著執(zhí)行原來(lái)的指令。

        4. 單步調(diào)試

        由于設(shè)置了單步調(diào)試模式后,CPU 每執(zhí)行一條指令,都會(huì)觸發(fā)一次 debug 異常。這時(shí),內(nèi)核將會(huì)調(diào)用 do_debug() 異常處理例程來(lái)處理 debug 異常。

        然而,在 do_debug() 異常處理例程中,會(huì)通過(guò)調(diào)用 kprobe_exceptions_notify() 函數(shù)來(lái)執(zhí)行 kprobe 模塊的 post_handler() 回調(diào)函數(shù)。我們來(lái)看看其調(diào)用鏈:

        do_debug()
        └→ notify_die()
           └→ atomic_notifier_call_chain()
              └→ __atomic_notifier_call_chain()
                 └→ notifier_call_chain()
                    └→ kprobe_exceptions_notify()
                       └→ post_kprobe_handler()
                          └→ post_handler()

        從上面的調(diào)用鏈可以看出,do_deubg() 也是通過(guò)調(diào)用 kprobe_exceptions_notify() 函數(shù)來(lái)處理 kprobe 機(jī)制的流程。

        下面我們來(lái)分析 kprobe_exceptions_notify() 函數(shù)對(duì) debug 異常的處理過(guò)程,代碼如下:

        int __kprobes 
        kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, 
                                 void *data)

        {
            struct die_args *args = data;
            int ret = NOTIFY_DONE;

            // 1) 如果是用戶態(tài)觸發(fā)的異常,那么直接返回
            if (args->regs && user_mode_vm(args->regs))
                return ret;

            switch (val) {
            ...
            // 2) 如果是 debug 異常觸發(fā)的,那么就調(diào)用 post_kprobe_handler() 進(jìn)行處理
            case DIE_DEBUG:
                if (post_kprobe_handler(args->regs)) {
                    ...
                }
                break;
            ...
            default:
                break;
            }
            return ret;
        }

        從上面代碼可知,如果當(dāng)前發(fā)生的異常是 debug 異常,那么將會(huì)調(diào)用 post_kprobe_handler() 函數(shù)進(jìn)行處理。

        我們來(lái)看看 post_kprobe_handler() 函數(shù)的實(shí)現(xiàn):

        static int __kprobes post_kprobe_handler(struct pt_regs *regs)
        {
            ...
            // 如果 kprobe 模塊實(shí)現(xiàn)了 post_handler() 回調(diào)函數(shù),那么就執(zhí)行 post_handler() 回調(diào)函數(shù)
            if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
                ...
                cur->post_handler(cur, regs, 0);
            }
            ...
            return 1;
        }

        如果 kprobe 模塊實(shí)現(xiàn)了 post_handler() 回調(diào)函數(shù),那么 post_kprobe_handler() 將會(huì)執(zhí)行它。

        總結(jié)

        本文主要介紹了 kprobe 的原理與實(shí)現(xiàn),正如本文開始時(shí)所說(shuō),kprobe 機(jī)制的細(xì)節(jié)很多,所以本文不可能對(duì)所有細(xì)節(jié)進(jìn)行分析。

        如果大家對(duì) kprobe 的所有實(shí)現(xiàn)細(xì)節(jié)有興趣,可以自行閱讀源碼。

        瀏覽 190
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            黄色高清视频在线观看 | 1024人妻一区二区三区 | www.日本黄色视频 | 狠狠色噜噜色狠狠狠综合久久成人 | 国产丝袜一区 | 在线黄 | 与狮子啪的h文 | 成人无码区免费A片在线 | 做爱小视频 免费 | 久草热久|