Linux-ftrace-雙nop機制的實現

Linux 內核調試工具ftrace 之(NOP動態插樁的實現原理)

ftrace 是 Linux 內核中的一種跟蹤工具,主要用于性能分析、調試和內核代碼的執行跟蹤。它通過在內核代碼的關鍵點插入探針(probe)來記錄函數調用和執行信息。這對于開發者排查問題、優化性能或者理解內核行為非常有用。

linux中主要支持兩種ftrace的實現方式:

  1. _mcount機制,(主要在內核為5.10前版本),可見文章《ftrace之_mcount的實現原理》
  2. NOP指令動態插樁機制(主要在內核為5.10及以后版本)

下面將深入介紹雙NOP指令動態插樁機制的實現原理:

NOP指令動態插樁機制的實現

 * Due to -fpatchable-function-entry=2, the compiler has placed two NOPs before* the regular function prologue. For an enabled callsite, ftrace_init_nop() and* ftrace_make_call() have patched those NOPs to:** 	MOV	X9, LR* 	BL	<entry>** ... where <entry> is either ftrace_caller or ftrace_regs_caller.
  • gcc編譯內核時加上 -fpatchable-function-entry=2 選項將會在每個支持被插樁的函數最前面插入兩條NOP指令。
  • nop本身就是動態插樁機制,當需要追蹤該函數時,才會將該函數前面的nop指令替換為MOV X9, LRBL <entry><entry>ftrace_callerftrace_regs_caller)。

NOP入口的分析

1. 下面是實際的編譯的驅動函數匯編代碼:
0000000000000000 <gps_pcie_tty_close>:0:   d503201f        nop4:   d503201f        nop8:   d503233f        paciaspc:   a9bf7bfd        stp     x29, x30, [sp, #-16]!10:   aa0103e2        mov     x2, x114:   910003fd        mov     x29, sp18:   aa0003e1        mov     x1, x01c:   f941d000        ldr     x0, [x0, #928]20:   94000000        bl      0 <tty_port_close>24:   a8c17bfd        ldp     x29, x30, [sp], #1628:   d50323bf        autiasp2c:   d65f03c0        ret
2. 當該函數需要被追蹤,則將nop換成MOV X9, LRBL ftrace_caller(這里以ftrace_caller為例)。
 * Each instrumented function follows the AAPCS, so here x0-x8 and x18-x30 are
live (x18 holds the Shadow Call Stack pointer), and x9-x17 are safe to clobber.
  • 每個支持被追蹤的函數應該遵守AAPCS規定。根據 AAPCS 的規定,寄存器可分為調用者保存和被調用者保存兩類。調用者保存的寄存器需要在調用函數前由調用者保存其值,而被調用者保存的寄存器則由被調用的函數負責保存和恢復。寄存器 x0x8 以及 x18x30 被視為活躍寄存器(其中 x18 保存影子調用棧指針),而寄存器 x9x17 則可安全地被覆蓋。
  • 因此x9寄存器是可以直接用的,所以可以用來存調用者的返回地址即將LR_A存入到x9(可以發現這里和_mcount的處理方式不同,不用再先保存寄存器了)。
  • 接下來就進入ftrace_callerftrace_regs_caller
    此時棧分配如下圖:
    在這里插入圖片描述
3. ftrace_callerftrace_regs_caller中的任務
YM_CODE_START(ftrace_regs_caller)
#ifdef BTI_CBTI_C
#endifftrace_regs_entry	1b	ftrace_common
SYM_CODE_END(ftrace_regs_caller)SYM_CODE_START(ftrace_caller)
#ifdef BTI_CBTI_C
#endifftrace_regs_entry	0b	ftrace_common
SYM_CODE_END(ftrace_caller)

ftrace_callerftrace_regs_caller都會跳轉至ftrace_regs_entry,然后全部跳轉至b ftrace_common(b跳轉指令不會將返回地址存到lr寄存器中)。接下來分析一下ftrace_regs_entryftrace_common

4. ftrace_regs_entry
    .macro  ftrace_regs_entry, allregs=0/* Make room for pt_regs, plus a callee frame */sub	sp, sp, #(S_FRAME_SIZE + 16)/* Save function arguments (and x9 for simplicity) */stp	x0, x1, [sp, #S_X0]stp	x2, x3, [sp, #S_X2]stp	x4, x5, [sp, #S_X4]stp	x6, x7, [sp, #S_X6]stp	x8, x9, [sp, #S_X8]/* Optionally save the callee-saved registers, always save the FP */.if \allregs == 1//這里是allregs == 1時額外要保存的現場stp	x10, x11, [sp, #S_X10]stp	x12, x13, [sp, #S_X12]stp	x14, x15, [sp, #S_X14]stp	x16, x17, [sp, #S_X16]stp	x18, x19, [sp, #S_X18]stp	x20, x21, [sp, #S_X20]stp	x22, x23, [sp, #S_X22]stp	x24, x25, [sp, #S_X24]stp	x26, x27, [sp, #S_X26]stp	x28, x29, [sp, #S_X28].else//這里是allregs == 0時額外要保存的現場str	x29, [sp, #S_FP].endif/* Save the callsite's SP and LR */add	x10, sp, #(S_FRAME_SIZE + 16)stp	x9, x10, [sp, #S_LR]/* Save the PC after the ftrace callsite */str	x30, [sp, #S_PC]/* Create a frame record for the callsite above pt_regs */stp	x29, x9, [sp, #S_FRAME_SIZE]add	x29, sp, #S_FRAME_SIZE/* Create our frame record within pt_regs. */stp	x29, x30, [sp, #S_STACKFRAME]add	x29, sp, #S_STACKFRAME.endm
  • 在上面的現場保存后函數棧的分布如下圖:

在這里插入圖片描述

5. 跳轉到ftrace_common
SYM_CODE_START(ftrace_common)sub	x0, x30, #AARCH64_INSN_SIZE	// ip (callsite's BL insn)mov	x1, x9				// parent_ip (callsite's LR)ldr_l	x2, function_trace_op		// opmov	x3, sp				// regsSYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)bl	ftrace_stub#ifdef CONFIG_FUNCTION_GRAPH_TRACER
SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller();nop				// If enabled, this will be replaced// "b ftrace_graph_caller"
#endif/** At the callsite x0-x8 and x19-x30 were live. Any C code will have preserved* x19-x29 per the AAPCS, and we created frame records upon entry, so we need* to restore x0-x8, x29, and x30.*/
ftrace_common_return:/* Restore function arguments */ldp	x0, x1, [sp]ldp	x2, x3, [sp, #S_X2]ldp	x4, x5, [sp, #S_X4]ldp	x6, x7, [sp, #S_X6]ldr	x8, [sp, #S_X8]/* Restore the callsite's FP, LR, PC */ldr	x29, [sp, #S_FP]ldr	x30, [sp, #S_LR]ldr	x9, [sp, #S_PC]/* Restore the callsite's SP */add	sp, sp, #S_FRAME_SIZE + 16ret	x9
SYM_CODE_END(ftrace_common)
  • ftrace_common分為兩段:跳轉到對應的trace回調函數前、從跳轉的trace回調函數返回后。
  1. 跳轉到對應的trace回調函數前:
sub	x0, x30, #AARCH64_INSN_SIZE	// ip (callsite's BL insn)
mov	x1, x9				// parent_ip (callsite's LR)
ldr_l	x2, function_trace_op		// op
mov	x3, sp				// regs

主要是準備好給trace回調函數的參數。
參數類型大致為下面

(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *regs)
  1. 后面就是進入trace的回調函數中:
    • 將傳入的信息保存到trace的緩沖區中(棧幀結構體中struct pt_regs)。
    • 恢復追蹤函數B的現場,x0~x8,x19~x30。(B的環境這樣就沒有被破壞)
    • BL 到 函數B繼續執行(此時x30lr寄存器值為trace回調函數地址)。
    • 保存x0到對應的棧幀結構體中struct pt_regs的x0成員變量(函數返回值)。
    • 返回到ftrace_commonftrace_common_return繼續執行。

3.ftrace_common_return
* 這里的任務是恢復現場(通過保存的棧幀結構體struct pt_regs)。
* 通過ret指令直接跳轉到函數A。

  1. 說明:
    • 為什么要組織FP_N、FP_B的幀記錄(即存放上一個函數的FP、LR),目的就是給具體的trace回調函數函數調用的信息,使trace回調函數能夠遞歸函數調用關系。
    • 在用棧進行參數傳遞時,被調用者都是用調用者的FP指針進行訪問的。

nop的跳轉流程

nop的跳轉流程和_mcount差不多,差別就是棧的設置以及保存,恢復,以及進入bl ftrace的時機不同。

在這里插入圖片描述

具體的ftrace操作

見文章《Linux-ftrace(內核調試工具)》

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/71185.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/71185.shtml
英文地址,請注明出處:http://en.pswp.cn/web/71185.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Qt互斥鎖(QMutex)的使用、QMutexLocker的使用

Qt互斥鎖【QMutex】的使用、QMutexLocker的使用 基于讀寫鎖(QReadWriteLock)的線程同步Chapter1 Qt互斥鎖(QMutex)的使用、QMutexLocker的使用一、QMutexLocker和QMutex實現示例圖二、QMutex和QMutexLocker的關系&#xff08;個人理解&#xff09;三、QMutex使用和QMutexLocker…

【無標題】Ubuntu22.04編譯視覺十四講slambook2 ch4時fmt庫的報錯

Ubuntu22.04編譯視覺十四講slambook2 ch4時fmt庫的報錯 cmake ..順利&#xff0c;make后出現如下報錯&#xff1a; in function std::make_unsigned<int>::type fmt::v8::detail::to_unsigned<int>(int): trajectoryError.cpp:(.text._ZN3fmt2v86detail11to_unsi…

SpringBoot ——簡單開發流程實戰

本文使用SpringBoot進行電商系統商品數據增刪改查的簡單開發流程。 本文目錄 一、創建Spring Boot項目二、配置數據庫連接三、創建實體類四、創建Repository接口五、創建Service層六、創建Controller層七、測試 一、創建Spring Boot項目 可以通過https://start.spring.io/或者…

fastadmin 后臺商品sku(vue)

先上個效果圖 首先先引入vue define([backend], function (Backend) {require.config({paths: {vue: /assets/jeekshopskugoods/libs/vue.min,skuimg: /assets/jeekshopskugoods/js/skuimg,skugoods: /assets/jeekshopskugoods/js/skugoods,layui: /assets/LayuiSpzj/layui/la…

LeetCode 718 - 最長重復子數組

LeetCode 718 - 最長重復子數組 是一個典型的數組和字符串問題&#xff0c;適合考察動態規劃、滑動窗口和二分查找等多種編程能力。掌握其多種解法及變體能夠有效提高處理字符串和數組算法的能力。 題目描述 輸入: 兩個整數數組 nums1 和 nums2。輸出: 兩個數組中存在的最長的…

LeetCode 0132.分割回文串 II:動態規劃

【LetMeFly】132.分割回文串 II&#xff1a;動態規劃 力扣題目鏈接&#xff1a;https://leetcode.cn/problems/palindrome-partitioning-ii/ 給你一個字符串 s&#xff0c;請你將 s 分割成一些子串&#xff0c;使每個子串都是回文串。 返回符合要求的 最少分割次數 。 示例 …

iOS 實現UIButton自動化點擊埋點

思路&#xff1a;我們HOOK UIControl的 addtarget:action:forControlEvents方法&#xff0c;交換UIControl的 addtarget:action:forControlEvents 方法的實現&#xff0c; 在交換的方法中添加原來響應的同時&#xff0c;再添加一個埋點響應&#xff0c;該響應方法實現了點擊埋點…

C++藍橋杯基礎篇(六)

片頭 嗨~小伙伴們&#xff0c;大家好&#xff01;今天我們來一起學習藍橋杯基礎篇&#xff08;六&#xff09;&#xff0c;練習相關的數組習題&#xff0c;準備好了嗎&#xff1f;咱們開始咯&#xff01; 第1題 數組的左方區域 這道題&#xff0c;實質上是找規律&#xff0c;…

git -學習筆記

目錄 基本操作語法 設置用戶和郵箱 版本回退 工作區和暫存區 撤銷修改 刪除與恢復 一工作區刪除了&#xff0c;但是暫存區沒刪除 二工作區誤刪了&#xff0c;暫存區還有 github-Git 連接 報錯解決-push遠程倉庫被拒絕 遠程庫 分支 分支沖突 儲藏分支 回到當前分…

Windows本地Docker+Open-WebUI部署DeepSeek

最近想在自己的電腦本地部署一下DeepSeek試試&#xff0c;由于不希望污染電腦的Windows環境&#xff0c;所以在wsl中安裝了ollama&#xff0c;使用ollama拉取DeepSeek模型。然后在Windows中安裝了Docker Desktop&#xff0c;在Docker中部署了Open-WebUI&#xff0c;最后再在Ope…

力扣785. 判斷二分圖

力扣785. 判斷二分圖 題目 題目解析及思路 題目要求將所有節點分成兩部分&#xff0c;每條邊的兩個端點都必須在不同集合中 二分圖&#xff1a;BFS/DFS/并查集 因為圖不一定聯通&#xff0c;所以枚舉所有點都做bfs(如果沒聯通的話) 代碼 class Solution { public:bool is…

springboot之集成Elasticsearch

目錄 二、Elasticsearch 是什么&#xff1f;三、Elasticsearch 安裝四、Springboot 集成 Elasticsearch 的方式五、創建項目集成 Elasticsearch 2.創建 Spring Initializr 項目 es &#xff08;3&#xff09;.新建實體類 User&#xff08;4&#xff09;.新建 dao 接口類 UserR…

[Lc滑動窗口_1] 長度最小的數組 | 無重復字符的最長子串 | 最大連續1的個數 III | 將 x 減到 0 的最小操作數

目錄 1. 長度最小的字數組 題解 代碼 ?2.無重復字符的最長子串 題解 代碼 3.最大連續1的個數 III 題解 代碼 4.將 x 減到 0 的最小操作數 題解 代碼 1. 長度最小的字數組 題目鏈接&#xff1a;209.長度最小的字數組 題目分析: 給定一個含有 n 個 正整數 的數組…

數據集筆記:新加坡 地鐵(MRT)和輕軌(LRT)票價

數據連接 data.gov.sg 2024 年 12 月 28 日起生效的新加坡地鐵票價 該數據集包含 MRT 和 LRT 票價的信息&#xff0c;包括&#xff1a; 票價類型&#xff08;Fare Type&#xff09;&#xff1a;成人票、學生票、老年人票、殘障人士票等。適用時間&#xff08;Applicable Tim…

湘潭大學計算機復試詳細攻略(調劑)

一&#xff0c;寫在前面的話 ① 首先&#xff0c;能完成考試初試來到這里的都是勇士。不管結果如何&#xff0c;不管成績如何。我都在這里真心的祝福你以后一帆風順。 ② 目前學歷貶值嚴重&#xff0c;如果是成績不理想的話&#xff0c;我建議能工作就去工作&#xff0c;工作不…

【前端基礎】Day 3 CSS-2

目錄 1. Emmet語法 1.1 快速生成HTML結構語法 1.2 快速生成CSS樣式語法 2. CSS的復合選擇器 2.1 后代選擇器 2.2 子選擇器 2.3 并集選擇器 2.4 偽類選擇器 2.4.1 鏈接偽類選擇器 2.4.2 focus偽類選擇器 2.5 復合選擇器總結 3. CSS的元素顯示模式 3.1 什么是元素顯示…

不同數據類型在數據庫和編程語言之間的對應關系表

不同數據類型在數據庫和編程語言之間的對應關系表 MySql 與 C# MySqlC#varcharstringbigintlongbigint unsignedulongintintint unsigneduintsmallintshortsmallint unsignedushortVARCHAR(36)GuidsmalldatetimeDateTimedateDateTimedatetimeDateTimetimestampDateTimefloatf…

RabbitMQ操作實戰

1.RabbitMQ安裝 RabbitMQ Windows 安裝、配置、使用 - 小白教程-騰訊云開發者社區-騰訊云下載erlang&#xff1a;http://www.erlang.org/downloads/https://cloud.tencent.com/developer/article/2192340 Windows 10安裝RabbitMQ及延時消息插件rabbitmq_delayed_message_exch…

DeepSeek教unity------UI元素長按響應

主要功能說明&#xff1a; ?長按檢測&#xff1a;通過記錄指針按下的時間&#xff0c;判斷是否達到 longClickTime&#xff0c;從而觸發長按事件。?狀態管理&#xff1a;使用 StateEnum 枚舉管理點擊項的當前狀態&#xff08;未按下、按下等待長按、長按已觸發&#xff09;。…

【北京迅為】itop-3568 開發板openharmony鴻蒙燒寫及測試-第2章OpenHarmony v3.2-Beta4版本測試

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工藝&#xff0c;搭載一顆四核Cortex-A55處理器和Mali G52 2EE 圖形處理器。RK3568 支持4K 解碼和 1080P 編碼&#xff0c;支持SATA/PCIE/USB3.0 外圍接口。RK3568內置獨立NPU&#xff0c;可用于輕量級人工…