Linux(ftrace)__mcount的实现原理

Linux 内核调试工具ftrace 之(_mcount的实现原理)

ftrace 是 Linux 内核中的一种跟踪工具,主要用于性能分析、调试和内核代码的执行跟踪。它通过在内核代码的关键点插入探针(probe)来记录函数调用和执行信息。这对于开发者排查问题、优化性能或者理解内核行为非常有用。

linux中主要支持两种ftrace的实现方式:

  1. _mcount机制,(主要在内核为5.10前版本)
  2. NOP指令动态插桩机制(主要在内核为5.10及以后版本),见文章《ftrace之双nop机制实现原理》

下面将分别深入介绍两种机制的实现原理:

一、_mcount机制的实现

 * Gcc with -pg will put the following code in the beginning of each function:*      mov x0, x30*      bl _mcount*	[function's body ...]* "bl _mcount" may be replaced to "bl ftrace_caller" or NOP if dynamic* ftrace is enabled.
  • gcc编译内核时加上 -pg 选项将会在每个支持被插桩的函数前面插入mov x0, x30bl _mcount指令。
  • 如果开启了动态插桩,那bl _mcount会被bl ftrace_callerNOP指令替换,当需要对该函数进行追踪时,将重新插入bl _mcount,取消追踪时会重新替换为bl ftrace_callerNOP指令。这样会降低ftrace对性能的损耗。

_mcount入口的分析

  1. 下面是实际的编译的驱动函数汇编代码:
    _mcount被插桩在函数的b74地址处(同样mov x0, x30也被插桩)。
0000000000000b58 <pcie_adc_ioctl>:b58:       a9bd7bfd        stp     x29, x30, [sp, #-48]!b5c:       910003fd        mov     x29, spb60:       a90153f3        stp     x19, x20, [sp, #16]b64:       d50320ff        xpaclrib68:       2a0103f4        mov     w20, w1b6c:       aa1e03e0        mov     x0, x30b70:       aa0203f3        mov     x19, x2b74:       94000000        bl      0 <_mcount>b78:       90000000        adrp    x0, 0 <__stack_chk_guard>b7c:       f9400001        ldr     x1, [x0]b80:       f90017e1        str     x1, [sp, #40]
  1. 插桩的两条指令并不是插入在函数的最前面第一、二地址处,而是在该函数将该函数的栈分配好以及保存好现场后再进行插桩。
  • 下述的三点是编译器默认的规定(x0-x8 and x18-x30 are live (x18 holds the Shadow Call Stack pointer), and x9-x17 are safe to clobber.)即:
    • 将父函数的FP、父函数的返回地址lr入栈(即x29x30)。
      • stp x29, x30, [sp, #-48]!保护FPlr以及函数栈的分配
    • x18~x28中后续函数体要用到的寄存器进行入栈保存,如果用不到则不用入栈保存
      • stp x19, x20, [sp, #16]
    • 如果x0~x7中为函数传参则也需要将对应的寄存器进行保存(一般保存到x18~x26寄存器中),参数的传递一般是前8个参数由x0~x7寄存器,后面的参数都有栈进行传递。所以在被调用函数中如果要用到调用者传入的寄存器中的参数就需要保存。
      • mov w20, w1
      • mov x19, x2
      • 由于在该函数中并没有用到第一个参数,所以编译器就进行优化了,没有进行x0寄存器值保存。
  • 在上面的现场保存后函数栈的分布如下图:

在这里插入图片描述

  1. 然后跳转到_mcount
.macro mcount_enterstp	x29, x30, [sp, #-16]!mov	x29, sp
.endm
SYM_FUNC_START(_mcount)mcount_enterldr_l	x2, ftrace_trace_functionadr	x0, ftrace_stubcmp	x0, x2			// if (ftrace_trace_functionb.eq	skip_ftrace_call	//     != ftrace_stub) {mcount_get_pc	x0		//       function's pcmcount_get_lr	x1		//       function's lr (= parent's pc)blr	x2			//   (*ftrace_trace_function)(pc, lr);skip_ftrace_call:			// }
#ifdef CONFIG_FUNCTION_GRAPH_TRACERldr_l	x2, ftrace_graph_returncmp	x0, x2			//   if ((ftrace_graph_returnb.ne	ftrace_graph_caller	//        != ftrace_stub)ldr_l	x2, ftrace_graph_entry	//     || (ftrace_graph_entryadr_l	x0, ftrace_graph_entry_stub //     != ftrace_graph_entry_stub))cmp	x0, x2b.ne	ftrace_graph_caller	//     ftrace_graph_caller();
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */mcount_exit
SYM_FUNC_END(_mcount)
  • 进去也是对x29, x30(FP 和 LR)进行保存(FP为栈基指针)

  • 这时候的栈分布如下图:

在这里插入图片描述

  • mcount_get_pc x0指令取到追踪函数B的地址的分析:
    • mcount_get_pc x0 -> ldr x0, [x29, #8]可以看出是FP_M + 8的地址处的值给x0,即LR_B给到x0,刚好LR_B就是B中bl _mcount指令下一条指令地址。
  • mcount_get_lr x1指令取到调用者函数的地址的分析:
    • mcount_get_lr x1 -> ldr x1, [x29] 以及 ldr x1, [x1, #8],可以看出第一条指令ldr x1, [x29]从FP_M的地址处取到内容FP_B存到x1中,然后第二条指令ldr x1, [x1, #8]从x1 + 8(= FP_B + 8)地址处取到内容LR_A给到x1,这样就取到了A的LR地址,即调用者函数的返回地址。
  1. 经过上面的分析可以看到对于调用者A以及被追踪者B函数的内容以及返回地址都可以拿到并保存。
  2. 接下来就是进入对应的追踪器执行。
    1. 保存必要的信息,比如LR_A、LR_B、FP_A、FP_B等,并做其他ftrace的信息处理,然后将BL到LR_B中继续执行完B函数(进入B函数时LR寄存器的地址为实际trace回调函数中的地址)。
    2. 当B函数执行完后,返回到trace回调函数,在trace函数中做该被追踪函数B的记录结尾,然后将直接返回到函数A继续执行了。
  3. 对于超过8个参数的参数读取也不受限制,直接通过父函数的FP指针访问(并没有破坏该函数的栈)。
    至此bl _mcount机制的实现原理已经解释完,其他的就是对ftrace具体回调函数中的一些工作,这里就不再说明(主要是记录函数调用运行的一些信息,并放入到ring buf中,开放应用层接口供应用层查看)。大致跳转流程图如下:

在这里插入图片描述

具体的ftrace操作

见文章《ftrace-内核调试工具》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/896601.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java注解(Annotation)

一、注解的定义 核心概念 注解是Java中一种特殊形式的“元数据”&#xff0c;用于为类、方法、字段、参数等代码元素附加说明信息。它不会直接影响代码逻辑&#xff0c;但可以通过编译器、框架或反射机制进行解析和处理。 与注释&#xff08;Comment&#xff09;的区别 注释&a…

tauri2+typescript+vue+vite+leaflet等的简单联合使用(一)

项目目标 主要的目的是学习tauri。 流程 1、搭建项目 2、简单的在项目使用leaflet 3、打包 准备项目 环境准备 废话不多说&#xff0c;直接开始 需要有准备能运行Rust的环境和Node&#xff0c;对于Rust可以参考下面这位大佬的文章&#xff0c;Node不必细说。 Rust 和…

深入解析 Svelte:下一代前端框架的革命

深入解析 Svelte&#xff1a;下一代前端框架的革命 1. Svelte 简介 Svelte 是一款前端框架&#xff0c;与 React、Vue 等传统框架不同&#xff0c;它采用 编译时&#xff08;Compile-time&#xff09; 方式来优化前端应用。它不像 React 或 Vue 依赖虚拟 DOM&#xff0c;而是…

关于流水线的理解

还是不太理解&#xff0c;我之前一直以为&#xff0c;对axis总线&#xff0c;每一级的寄存器就像fifo一样&#xff0c;一级一级的分级存储最后一级需要的数据。 像这张图&#xff0c;一开始是在解析axis流形式的数据包&#xff0c;数据包一直都能输入&#xff0c;所以valid一直…

Python代码之美:从规范到艺术

基础规范&#xff1a;代码的"颜值"很重要 &#x1f449;大礼包&#x1f381;&#xff1a;&#x1f448; PEP 8&#xff1a;不只是规范&#xff0c;是写作艺术 良好的代码格式就像优美的书法&#xff0c;让人赏心悦目。比如&#xff1a; # 不推荐的写法 def calcul…

【AI+智造】在阿里云Ubuntu 24.04上部署DeepSeek R1 14B的完整方案

作者&#xff1a;Odoo技术开发/资深信息化负责人 日期&#xff1a;2025年2月28日 一、部署背景与目标 DeepSeek R1作为国产大语言模型的代表&#xff0c;凭借其强化学习驱动的推理能力&#xff0c;在复杂任务&#xff08;如数学问题、编程逻辑&#xff09;中表现优异。本地化部…

8 SpringBoot进阶(上):AOP(面向切面编程技术)、AOP案例之统一操作日志

文章目录 前言1. AOP基础1.1 AOP概述: 什么是AOP?1.2 AOP快速入门1.3 Spring AOP核心中的相关术语(面试)2. AOP进阶2.1 通知类型2.1.1 @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行(通知的代码在业务方法之前和之后都有)2.1.2 @Before:前置通知,此…

【react】快速上手基础教程

目录 一、React 简介 1.什么是 React 2.React 核心特性 二、环境搭建 1. 创建 React 项目 2.关键配置 三、核心概念 1. JSX 语法 表达式嵌入 样式处理 2. 组件 (Component) 3. 状态 (State) 与属性 (Props) 4. 事件处理 合成事件&#xff08;SyntheticEvent) 5. …

七星棋牌 6 端 200 子游戏全开源修复版源码(乐豆 + 防沉迷 + 比赛场 + 控制)

七星棋牌源码 是一款运营级的棋牌产品&#xff0c;覆盖 湖南、湖北、山西、江苏、贵州 等 6 大省区&#xff0c;支持 安卓、iOS 双端&#xff0c;并且 全开源。这个版本是 修复优化后的二开版本&#xff0c;新增了 乐豆系统、比赛场模式、防沉迷机制、AI 智能控制 等功能&#…

【人工智能】Deepseek 与 Kimi 联袂:重塑 PPT 创作,开启智能演示新纪元

我的个人主页 我的专栏&#xff1a;人工智能领域、java-数据结构、Javase、C语言&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞&#x1f44d;收藏❤ 前言 在当今快节奏的工作与学习场景中&#xff0c;PPT 制作常常是一项耗时耗力的任务。从前期的资…

Kafka的高水位、低水位是什么概念?

Kafka 的 高水位&#xff08;High Watermark, HW&#xff09; 和 低水位&#xff08;Low Watermark, LW&#xff09; 是和数据存储、消费进度、日志清理等密切相关的重要概念。我们用一个 “蓄水池” 的比喻来形象地解释它们的作用。 1. Kafka 里的数据像一个蓄水池 Kafka 的数…

基于JAVA+Spring+mysql_快递管理系统源码+设计文档

文末获取源码数据库文档 感兴趣的可以先收藏&#xff0c;有毕设问题&#xff0c;项目以及论文撰写等问题都可以和博主沟通&#xff0c;尽最大努力帮助更多的人&#xff01; 摘 要 随着物流行业信息化的深入使得物流过程中货物的状态和变化透明化&#xff0c;现代信息化的接入使…

Python----数据分析(Numpy:安装,数组创建,切片和索引,数组的属性,数据类型,数组形状,数组的运算,基本函数)

一、 Numpy库简介 1.1、概念 NumPy(Numerical Python)是一个开源的Python科学计算库&#xff0c;旨在为Python提供 高性能的多维数组对象和一系列工具。NumPy数组是Python数据分析的基础&#xff0c;许多 其他的数据处理库&#xff08;如Pandas、SciPy&#xff09;都依赖于Num…

【SQL】MySQL中的字符串处理函数:concat 函数拼接字符串,COALESCE函数处理NULL字符串

MySQL中的字符串处理函数&#xff1a;concat 函数 一、concat &#xff08;&#xff09;函数 1.1、基本语法1.2、示例1.3、特殊用途 二、COALESCE&#xff08;&#xff09;函数 2.1、基本语法2.2、示例2.3、用途 三、进阶练习 3.1 条件和 SQL 语句3.2、解释 一、concat &…

windows下适用msvc编译ffmpeg 适用于ffmpeg-7.1

需要的工具: visual studio 2019 (可以是其他版本&#xff0c;只是本人电脑上装的为2019) msys2 ffmpeg-7.1源码 1. 修改msys2_shell.cmd 在msys2目录修改msys2_shell.cmd 打开后找到行set MSYS2_PATH_TYPEinherit 删除开头的rem 2. 运行msys2 运行x64 Native Tools Command …

2025年软考报名费用是多少?全国费用汇总!

软考报名时间终于确定了&#xff01;想要参加2025年软考的同学们注意啦&#xff01;特别是那些一年只有一次考试机会的科目&#xff0c;千万不要错过哦&#xff01;这里为大家整理了各地的报名时间、科目、费用等信息&#xff0c;快来看看吧&#xff01; 一、2025年软考时间安…

【LeetCode459】重复的子字符串

题目描述 给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 思路与算法 关键词&#xff1a;利用字符串的重复性质&#xff1b;字符串的拼接技巧&#xff1b;逆推法假设原始字符串 s 是由某个子串 sub 重复多次构成的。也就是说&#xff0c…

JAVA面试常见题_基础部分_Dubbo面试题(上)

Dubbo 支持哪些协议&#xff0c;每种协议的应用场景&#xff0c;优缺点&#xff1f; • dubbo&#xff1a; 单一长连接和 NIO 异步通讯&#xff0c;适合大并发小数据量的服务调用&#xff0c;以及消费者远大于提供者。传输协议 TCP&#xff0c;异步&#xff0c;Hessian 序列化…

掌握Git:从入门到精通的完整指南

Git是什么&#xff1f; Git是一个分布式版本控制系统&#xff0c;最初由Linus Torvalds在2005年为管理Linux内核开发而创建 它的主要功能是跟踪文件的更改&#xff0c;协调多个开发者之间的工作&#xff0c;并帮助团队高效地管理项目代码。Git不仅适用于大型开源项目&#xf…

数据安全_笔记系列05:数据合规与隐私保护(GDPR、CCPA、中国《数据安全法》)深度解析

数据安全_笔记系列05&#xff1a;数据合规与隐私保护&#xff08;GDPR、CCPA、中国《数据安全法》&#xff09;深度解析 在全球数据跨境流动和隐私保护强监管的背景下&#xff0c;企业需同时满足多法域合规要求。以下从 法规要点、核心差异、实施策略、跨境传输、典型案例 等维…