当前位置: 首页 > news >正文

linux kprobe使用

使用场景

  • 监控某个内核函数是否被调用
  • 获取某个内核函数耗费的时间
  • 获取某个内核函数的入参
  • 获取某个内核函数的调用栈(dump_stack()
  • 获取某个内核函数的返回值

参数传递规则

x86平台对pt_regs的定义
arch/x86/include/asm/ptrace.h

// i386架构
#ifdef __i386__struct pt_regs {/** NB: 32-bit x86 CPUs are inconsistent as what happens in the* following cases (where %seg represents a segment register):** - pushl %seg: some do a 16-bit write and leave the high*   bits alone* - movl %seg, [mem]: some do a 16-bit write despite the movl* - IDT entry: some (e.g. 486) will leave the high bits of CS*   and (if applicable) SS undefined.** Fortunately, x86-32 doesn't read the high bits on POP or IRET,* so we can just treat all of the segment registers as 16-bit* values.*/unsigned long bx;unsigned long cx;unsigned long dx;unsigned long si;unsigned long di;unsigned long bp;unsigned long ax;unsigned short ds;unsigned short __dsh;unsigned short es;unsigned short __esh;unsigned short fs;unsigned short __fsh;/* On interrupt, gs and __gsh store the vector number. */unsigned short gs;unsigned short __gsh;/* On interrupt, this is the error code. */unsigned long orig_ax;unsigned long ip;unsigned short cs;unsigned short __csh;unsigned long flags;unsigned long sp;unsigned short ss; unsigned short __ssh;
};#else /* __i386__ */
// ia64
struct pt_regs {
/** C ABI says these regs are callee-preserved. They aren't saved on kernel entry* unless syscall needs a complete, fully filled "struct pt_regs".*/unsigned long r15;unsigned long r14;unsigned long r13;unsigned long r12;unsigned long bp;unsigned long bx;
/* These regs are callee-clobbered. Always saved on kernel entry. */unsigned long r11;unsigned long r10;unsigned long r9;unsigned long r8;unsigned long ax;unsigned long cx;unsigned long dx;unsigned long si;unsigned long di;
/** On syscall entry, this is syscall#. On CPU exception, this is error code.* On hw interrupt, it's IRQ number:*/unsigned long orig_ax;
/* Return frame for iretq */unsigned long ip;unsigned long cs;unsigned long flags;unsigned long sp;unsigned long ss;
/* top of stack page */
};#endif /* !__i386__ */

从4.18的内核版本bpf的相关源码/tools/testing/selftests/bpf/bpf_helpers.h中可以窥探x86结构和`arm``架构函数参数传递规则。

#if defined(bpf_target_x86)
#define PT_REGS_PARM1(x) ((x)->di)
#define PT_REGS_PARM2(x) ((x)->si)
#define PT_REGS_PARM3(x) ((x)->dx)
#define PT_REGS_PARM4(x) ((x)->cx)
#define PT_REGS_PARM5(x) ((x)->r8)
#define PT_REGS_RET(x) ((x)->sp)
#define PT_REGS_FP(x) ((x)->bp)
#define PT_REGS_RC(x) ((x)->ax)
#define PT_REGS_SP(x) ((x)->sp)
#define PT_REGS_IP(x) ((x)->ip)#elif defined(bpf_target_arm64)
#define PT_REGS_PARM1(x) ((x)->regs[0])
#define PT_REGS_PARM2(x) ((x)->regs[1])
#define PT_REGS_PARM3(x) ((x)->regs[2])
#define PT_REGS_PARM4(x) ((x)->regs[3])
#define PT_REGS_PARM5(x) ((x)->regs[4])
#define PT_REGS_RET(x) ((x)->regs[30])
#define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */
#define PT_REGS_RC(x) ((x)->regs[0])
#define PT_REGS_SP(x) ((x)->sp)
#define PT_REGS_IP(x) ((x)->pc)

/samples/bpf/test_overhead_kprobe_kern.c

// 使用示例
SEC("kprobe/__set_task_comm")
int prog(struct pt_regs *ctx)
{struct signal_struct *signal;struct task_struct *tsk;char oldcomm[16] = {};char newcomm[16] = {};u16 oom_score_adj;u32 pid;tsk = (void *)PT_REGS_PARM1(ctx);pid = _(tsk->pid);bpf_probe_read(oldcomm, sizeof(oldcomm), &tsk->comm);bpf_probe_read(newcomm, sizeof(newcomm), (void *)PT_REGS_PARM2(ctx));signal = _(tsk->signal);oom_score_adj = _(signal->oom_score_adj);return 0;
}// 函数原型
/** These functions flushes out all traces of the currently running executable* so that a new one can be started*/
void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec)
{task_lock(tsk);trace_task_rename(tsk, buf);strlcpy(tsk->comm, buf, sizeof(tsk->comm));task_unlock(tsk);perf_event_comm(tsk, exec);
}
  • x86架构寄存器约定与函数参数传递
    在 X86_64 架构中,寄存器的约定如上,当调用一个函数的时候,RDI 寄存器用于传递第一个参数,RSI 寄存器用于传递第二个寄存器,依次类推,R9 寄存器传递第六个参数, 函数返回值保存在 RAX 寄存器中。那么如果函数的参数超过六个,那么多余的参数参数如何传递? 在 X86_64 架构中,函数大于 6 个参数的参数通过堆栈进行传输。

其中RDI对应pt_regs结构体中的di,其他寄存器依次类推。

  • ARM架构寄存器约定与函数参数传递
    在 ARM64 架构中,使用 X0-X7 寄存器传递参数,第一个参数通过 X0 寄存器传递,第二个参数通过 X1 寄存器传递,以此类推. 返回值存储在 X0 寄存器中。

使用实例

/samples/kprobes/kprobe_example.c

/** NOTE: This example is works on x86 and powerpc.* Here's a sample kernel module showing the use of kprobes to dump a* stack trace and selected registers when _do_fork() is called.** For more information on theory of operation of kprobes, see* Documentation/kprobes.txt** You will see the trace data in /var/log/messages and on the console* whenever _do_fork() is invoked to create a new process.*/#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>#define MAX_SYMBOL_LEN	64
static char symbol[MAX_SYMBOL_LEN] = "_do_fork";
module_param_string(symbol, symbol, sizeof(symbol), 0644);/* For each probe you need to allocate a kprobe structure */
static struct kprobe kp = {.symbol_name	= symbol,
};/* kprobe pre_handler: called just before the probed instruction is executed */
static int handler_pre(struct kprobe *p, struct pt_regs *regs)
{
#ifdef CONFIG_X86pr_info("<%s> pre_handler: p->addr = 0x%p, ip = %lx, flags = 0x%lx\n",p->symbol_name, p->addr, regs->ip, regs->flags);
#endif
#ifdef CONFIG_PPCpr_info("<%s> pre_handler: p->addr = 0x%p, nip = 0x%lx, msr = 0x%lx\n",p->symbol_name, p->addr, regs->nip, regs->msr);
#endif
#ifdef CONFIG_MIPSpr_info("<%s> pre_handler: p->addr = 0x%p, epc = 0x%lx, status = 0x%lx\n",p->symbol_name, p->addr, regs->cp0_epc, regs->cp0_status);
#endif
#ifdef CONFIG_ARM64pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx,"" pstate = 0x%lx\n",p->symbol_name, p->addr, (long)regs->pc, (long)regs->pstate);
#endif
#ifdef CONFIG_S390pr_info("<%s> pre_handler: p->addr, 0x%p, ip = 0x%lx, flags = 0x%lx\n",p->symbol_name, p->addr, regs->psw.addr, regs->flags);
#endif/* A dump_stack() here will give a stack backtrace */return 0;
}/* kprobe post_handler: called after the probed instruction is executed */
static void handler_post(struct kprobe *p, struct pt_regs *regs,unsigned long flags)
{
#ifdef CONFIG_X86pr_info("<%s> post_handler: p->addr = 0x%p, flags = 0x%lx\n",p->symbol_name, p->addr, regs->flags);
#endif
#ifdef CONFIG_PPCpr_info("<%s> post_handler: p->addr = 0x%p, msr = 0x%lx\n",p->symbol_name, p->addr, regs->msr);
#endif
#ifdef CONFIG_MIPSpr_info("<%s> post_handler: p->addr = 0x%p, status = 0x%lx\n",p->symbol_name, p->addr, regs->cp0_status);
#endif
#ifdef CONFIG_ARM64pr_info("<%s> post_handler: p->addr = 0x%p, pstate = 0x%lx\n",p->symbol_name, p->addr, (long)regs->pstate);
#endif
#ifdef CONFIG_S390pr_info("<%s> pre_handler: p->addr, 0x%p, flags = 0x%lx\n",p->symbol_name, p->addr, regs->flags);
#endif
}/** fault_handler: this is called if an exception is generated for any* instruction within the pre- or post-handler, or when Kprobes* single-steps the probed instruction.*/
static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{pr_info("fault_handler: p->addr = 0x%p, trap #%dn", p->addr, trapnr);/* Return 0 because we don't handle the fault. */return 0;
}static int __init kprobe_init(void)
{int ret;kp.pre_handler = handler_pre;kp.post_handler = handler_post;kp.fault_handler = handler_fault;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;
}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");
obj-m := kprobe.okprobe-y += kprobe_example.oBASEINCLUDE ?= /lib/modules/`uname -r`/buildall:$(MAKE) -C $(BASEINCLUDE) M=$(PWD) modules;clean:$(MAKE) -C $(BASEINCLUDE) M=$(PWD) clean;rm -f *.ko;
```

相关文章:

linux kprobe使用

使用场景 监控某个内核函数是否被调用获取某个内核函数耗费的时间获取某个内核函数的入参获取某个内核函数的调用栈&#xff08;dump_stack()&#xff09;获取某个内核函数的返回值 参数传递规则 x86平台对pt_regs的定义 arch/x86/include/asm/ptrace.h // i386架构 #ifdef…...

2023年超全前端面试题-背完稳稳拿offer(欢迎补充)

HTML、CSS相关 HTML5 HTML5新特性 增强了表单&#xff0c;input新增了一些type&#xff1a; color----定义调色板 tel-----定义包含电话号码的输入域 email—定义包含email地址的输入域 search–定义搜索域 number–定义包含数值的输入域 date----定义选取日、月、年的输入域…...

python之web自动化测试框架

梳理下搭建web自动化框架的流程&#xff1a; 创建目录&#xff1a; cases&#xff1a;存放测试用例&#xff0c;unittest框架要求用例名必须以test开头&#xff0c;所以命名test_case.py test_case.py代码如下&#xff1a;继承unittest.TestCase类下面的方法setupclass(),te…...

算法笔记(十五)—— 动态规划(暴力递归到动态规划)习题训练!

通过递归到记忆化搜索再到严格表结构的动态规划 递归方法的评价&#xff1a;1. 单可变参数的维度&#xff1b;2. 可变参数的个数 记忆化搜索 在暴力递归中会存在很多的重复计算&#xff0c;可以使用存储结构来实现空间换时间。 严格表结构的动态规划 整理位置之间的依赖关系…...

云原生架构基础概念及应用办法

什么是云原生&#xff1f; 云原生是一种基于容器、微服务和自动化运维的软件开发和部署方法。它可以使应用程序更加高效、可靠和可扩展&#xff0c;适用于各种不同的云平台。 如果要更直接通俗的来解释下上面的概念。 云原生更准确来说就是一种文化&#xff0c;是一种潮流&a…...

RedisTemplate 的基本使用手把手教

下载实例源码 使用步骤 1、引入 spring-boot-starter-data-redis 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency>2、在 application.yml 配置 R…...

Hbase -- Compact工具梳理

1. 背景 当前&#xff0c;线上HBase集群的自动Major Compact是关闭的&#xff0c;我们选择在凌晨业务空闲的时候进行手动触发Major Compact&#xff0c;Compact工具就是在运维平台上对资源组、RS、表进行Major Compact。目前线上有2种版本的Compact程序&#xff1a;Compact_v1…...

【java代码审计】SQL注入

1 原理 没有正确的对用户的输入进行检查&#xff0c;将用户的输入以拼接的方式带入到SQL语句中&#xff0c;导致SQL注入。 2 产生SQL注入的原因 2.1 JDBC拼接不当造成SQL注入 前置知识&#xff1a; JDBC执行SQL语句的两种方式&#xff1a; PrepareStatement&#xff1a;会对…...

前置知识-辛 Runge-Kutta 方法

1.3.3 辛 Runge-Kutta 方法 将方程 ( 1.10.2 ) (1.10 .2) (1.10.2) 改写为 d z d x =...

require 与 import 两种引入模块方式到底有什么区别?

关于JavaScript 的模块化规范&#xff0c;可以移步至&#xff1a; 【JavaScript高级】模块化规范「一文让你彻底搞懂前端模块化规范 & 区别」 下面进入正题 require 与 import 两种引入模块方式&#xff0c;到底有什么区别呢&#xff1f; 大致可以分为以下几个方面&#…...

软考信息系统监理师备考建议

用好备考方法&#xff0c;两三个月就可以过的。信息系统监理师备考最好以教材和历年真题为主&#xff0c;教学视频模拟题为辅。考试介绍与复习建议&#xff1a;考试设置的科目包括&#xff1a;&#xff08;1&#xff09;信息系统工程监理基础知识&#xff0c;考试时间150分钟&a…...

第八届蓝桥杯省赛——4承压计算(二维数组,嵌套循环)

题目&#xff1a;X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。每块金属原料的外形、尺寸完全一致&#xff0c;但重量不同。金属材料被严格地堆放成金字塔形。7 5 8 7 8 8 9 2 7 2 8 1 4 9 1 8 1 8 8 4 1 7 9 6 1 4 5 4 5 6 5 5 6 9 5 6 5 5 4 7 9 3 5 5 1 7 5 7 9 7 4…...

【ECNU】3645. 莫干山奇遇(C++)

目录 题目 输入格式 输出格式 样例 提示 思路 代码 题目 单点时限: 2.0 sec 内存限制: 512 MB 出题人当然是希望出的题目有关 oxx&#xff0c;于是想方设法给题目配上一些有关 oxx 的背景故事&#xff0c;使得它看起来不那么无趣。但有的时候却无法引入合适的小姐姐&…...

为什么需要学习shell、shell的作用

课程基于B站于超课程笔记 03 Shebang的正确玩法_哔哩哔哩_bilibili P1 shell的作用 P2 shell执行命令的流程 P3 Shebang的正确玩法 什么是shell及组成 shell概念 shelll组成 Shebang概念 /bin/sh /bin/bash一样&#xff0c;都是指向一个bash解释器 [rootlocalhost ~]#…...

pgsql-Create_ALTER_GRANT_REVOKE命令语法

pgsql-Create_ALTER_GRANT_REVOKE命令语法 资料 语法约定 CREATE ROLE ALTER ROLE GRANT授权 REVOKE回收授权 权限类型说明 语法约定 下面的约定被用于命令的大纲&#xff1a;方括弧&#xff08;[和]&#xff09;表示可选的部分&#xff08;在 Tcl 命令里&#xff0c;使…...

【linux】:进程概念

文章目录 冯诺依曼体系结构一&#xff1a;操作系统二: 进程总结冯诺依曼体系结构 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系。 冯诺依曼体系如下图&#xff1a; 那么输入设备有哪些呢&#xff1f…...

创建对象的方式和对属性的操作

javaScript支持多种编程范式&#xff0c;包括函数式编程和面向对象编程&#xff0c;javaScript的对象被设计成一组属性的无序集合&#xff0c;由key和value组成。 创建对象的两种方式 早期使用创建对象方式最多的是使用Object类&#xff0c;使用new关键字来创建一个对象&…...

GO时间相关操作说明

文章目录 GO时间相关操作时间转换成字符串字符串转换成时间时间戳和时间操作时间比较操作时间增加和减少操作休眠操作time.AfterFunc操作time.NewTicker操作GO时间相关操作 ​ GO语言在使用时间转换的时候会用到2006-01-02 15:04:05 这是固定参数写法,类似java语言中的yyyy-M…...

选择和分支结构

选择和分支结构选择和分支结构一、复习问答二、选择结构2.1 基础选择结构2.2 if-else结构2.3 多重if结构2.4 嵌套if结构三、分支结构四、局部变量选择和分支结构 一、复习问答 1、Java中基本数据类型 2、类型的转换的两种情形 3、数据类型提升的规则 二、选择结构 2.1 基础选…...

Elasticsearch总结笔记

文章目录简介类型增删改查操作索引原理简介 底层使用的lucene引擎&#xff0c;lucene引擎直接使用相对复杂&#xff0c;有一定的学习成本&#xff0c;同样是使用Java编写&#xff0c;Elasticsearch使用的rest风格的进行交互&#xff0c;而数据呢则是以JSON的方式进行传输。学习…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...