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.rhkb.cn/news/26644.html

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

相关文章

网络层IP协议

基本概念 主机&#xff1a;有IP地址&#xff0c;但是不进行路由控制的设备。 路由器&#xff1a;有IP地址&#xff0c;又能进行路由控制。 节点&#xff1a;主机和路由器的统称。 协议头格式 4位版本号&#xff1a;指定IP协议的版本。对于IPv4来说&#xff0c;就是4 4位首…

计算机毕业设计SpringBoot+Vue.js在线课程管理系统(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

【腾讯云】AI驱动TDSQL-C Serveress 数据库技术实战营-如何是从0到1体验电商可视化分析小助手得统计功能,一句话就能输出目标统计图

欢迎来到《小5讲堂》 这是《腾讯云》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景效果图流程图创建数据库 基本信息数据库配置设置密码控制台开…

Java里的ArrayList和LinkedList有什么区别?

大家好&#xff0c;我是锋哥。今天分享关于【Java里的ArrayList和LinkedList有什么区别&#xff1f;】面试题。希望对大家有帮助&#xff1b; Java里的ArrayList和LinkedList有什么区别&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 ArrayList 和 Lin…

盛京开源社区加入 GitCode,书写东北开源生态新篇章

在数字化转型与开源技术蓬勃发展的浪潮下&#xff0c;开源社区已成为推动技术创新的核心力量。盛京开源社区&#xff08;SJOSC&#xff09;作为沈阳地区的开源交流平台&#xff0c;始终致力于连接开发者、企业及高校&#xff0c;构建区域技术生态圈。 现在&#xff0c;盛京开源…

SQL Server 创建用户并授权

创建用户前需要有一个数据库&#xff0c;创建数据库命令如下&#xff1a; CREATE DATABASE [数据库名称]; CREATE DATABASE database1;一、创建登录用户 方式1&#xff1a;SQL命令 命令格式&#xff1a;CREATE LOGIN [用户名] WITH PASSWORD ‘密码’; 例如&#xff0c;创…

vue3:三项目增加404页面

一、路由添加 1、官网地址 带参数的动态路由匹配 | Vue Routerhttps://router.vuejs.org/zh/guide/essentials/dynamic-matching.html 2、复制核心语句 { path: /:pathMatch(.*)*, name: NotFound, component: NotFound } 3、粘贴到路由index.js中 4、建立页面 在view文件夹…

GitCode 助力 JeeSite:开启企业级快速开发新篇章

项目仓库&#xff08;点击阅读原文链接可直达前端仓库&#xff09; https://gitcode.com/thinkgem/jeesite 企业级快速开发的得力助手&#xff1a;JeeSite 快速开发平台 JeeSite 不仅仅是一个普通的后台开发框架&#xff0c;而是一套全面的企业级快速开发解决方案。后端基于 …

矽电股份业绩下滑:毛利率也欠佳,应收账款攀升回款比率放缓

《港湾商业观察》施子夫 近期&#xff0c;矽电半导体设备&#xff08;深圳&#xff09;股份有限公司&#xff08;以下简称&#xff0c;矽电股份&#xff09;的深交所IPO注册获得生效。 公开信息显示&#xff0c;2022年6月&#xff0c;矽电股份的创业板IPO获受理&#xff0c;保…

MySQL实现文档全文搜索,分词匹配多段落重排展示,知识库搜索原理分享

一、背景 在文档搜索场景中&#xff0c;高效精准的搜索功能至关重要&#xff0c;能提升检索效率&#xff0c;为用户提供精准、快速的信息获取体验&#xff0c;提高工作效率。在文档管理系统里&#xff0c;全文搜索是非常重要的功能之一。随着文档数量增长&#xff0c;如何快速…

十、大数据资源平台功能架构

一、大数据资源平台的功能架构图总体结构 大数据资源平台功能架构图 关键组件&#xff1a; 1.用户&#xff08;顶行&#xff09; 此部分标识与平台交互的各种利益相关者。 其中包括&#xff1a; 市领导 各部门分析师 区政府 外部组织 公民 开发人员 运营经理 2.功能模…

现代前端框架渲染机制深度解析:虚拟DOM到编译时优化

引言&#xff1a;前端框架的性能进化论 TikTok Web将React 18迁移至Vue 3后&#xff0c;点击响应延迟降低42%&#xff0c;内存占用减少35%。Shopify采用Svelte重构核心交互模块&#xff0c;首帧渲染速度提升580%。Discord在Next.js 14中启用React Server Components后&#xf…

【子网掩码计算器:Python + Tkinter 实现】

子网掩码计算器&#xff1a;Python Tkinter 实现 引言代码功能概述代码实现思路1. 界面设计2. 功能实现3. 事件处理 子网掩码计算器实现步骤1. 导入必要的库2. 定义主窗口类 SubnetCalculatorApp3. 创建菜单栏4. 创建界面组件5. 判断 IP 地址类别6. 计算子网信息7. 其他功能函…

视频推拉流EasyDSS点播平台云端录像播放异常问题的排查与解决

EasyDSS视频直播点播平台是一个功能全面的系统&#xff0c;提供视频转码、点播、直播、视频推拉流以及H.265视频播放等一站式服务。该平台与RTMP高清摄像头配合使用&#xff0c;能够接收无人机设备的实时视频流&#xff0c;实现无人机视频推流直播和巡检等多种应用。 最近&…

android 文本控件显示滑动条并自动滑动到最底部

文本框滑动需要增加控件 设置属性显示滑动条垂直滑动 显示滑动条 自动滚动到最后一行&#xff1a; private ScrollView mscrollView; mOutput.setMovementMethod(ScrollingMovementMethod.getInstance()); mscrollView (ScrollView) findViewById(R.id.scrollview); mscrol…

#渗透测试#批量漏洞挖掘#某图创图书馆集群管理系统updOpuserPw SQL注入(CVE-2021-44321)

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

1.C语言初识

C语言初识 C语言初识基础知识hello world数据类型变量、常量变量命名变量分类变量的使用变量的作用域 常量字符字符串转义字符 选择语句循环语句 函数&#xff1b;数组函数数组数组下标 操作符操作符算术操作符移位操作符、位操作符赋值操作符单目操作符关系操作符逻辑操作符条…

Redis通用命令

目录 Redis客户端 ​编辑Redis核心命令 Redis通用命令 keys exists del expire ttl type 总结 Redis客户端 Redis也是一个基于客户端-服务器结构的程序&#xff0c;为什么说也呢&#xff1f;因为MySQL也是一个基于客户端服务器的结构。 Redis客户端可以和服务器在…

第49天:Web开发-JavaEE应用SpringBoot栈模版注入ThymeleafFreemarkerVelocity

#知识点 1、安全开发-JavaEE-开发框架-SpringBoot&路由&传参 2、安全开发-JavaEE-模版引擎-Thymeleaf&Freemarker&Velocity 一、开发框架-SpringBoot 参考&#xff1a;https://springdoc.cn/spring-boot/ 访问SpringBoot创建的网站 1、路由映射 RequestMapping…

腾讯云扩容记录

腾讯云扩容&#xff1a; sudo yum install -y cloud-utils-growpart 安装扩容工具 sudo file -s /dev/vda1 有数据 sudo LC_ALLen_US.UTF-8 growpart /dev/vda 1 sudo resize2fs /dev/vda1 df -Th 完毕 以下是对执行的命令的详细解释以及背后的原理&#xff1a; 1. 安装 cloud…