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使用
使用场景 监控某个内核函数是否被调用获取某个内核函数耗费的时间获取某个内核函数的入参获取某个内核函数的调用栈(dump_stack())获取某个内核函数的返回值 参数传递规则 x86平台对pt_regs的定义 arch/x86/include/asm/ptrace.h // i386架构 #ifdef…...
2023年超全前端面试题-背完稳稳拿offer(欢迎补充)
HTML、CSS相关 HTML5 HTML5新特性 增强了表单,input新增了一些type: color----定义调色板 tel-----定义包含电话号码的输入域 email—定义包含email地址的输入域 search–定义搜索域 number–定义包含数值的输入域 date----定义选取日、月、年的输入域…...
python之web自动化测试框架
梳理下搭建web自动化框架的流程: 创建目录: cases:存放测试用例,unittest框架要求用例名必须以test开头,所以命名test_case.py test_case.py代码如下:继承unittest.TestCase类下面的方法setupclass(),te…...
算法笔记(十五)—— 动态规划(暴力递归到动态规划)习题训练!
通过递归到记忆化搜索再到严格表结构的动态规划 递归方法的评价:1. 单可变参数的维度;2. 可变参数的个数 记忆化搜索 在暴力递归中会存在很多的重复计算,可以使用存储结构来实现空间换时间。 严格表结构的动态规划 整理位置之间的依赖关系…...
云原生架构基础概念及应用办法
什么是云原生? 云原生是一种基于容器、微服务和自动化运维的软件开发和部署方法。它可以使应用程序更加高效、可靠和可扩展,适用于各种不同的云平台。 如果要更直接通俗的来解释下上面的概念。 云原生更准确来说就是一种文化,是一种潮流&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. 背景 当前,线上HBase集群的自动Major Compact是关闭的,我们选择在凌晨业务空闲的时候进行手动触发Major Compact,Compact工具就是在运维平台上对资源组、RS、表进行Major Compact。目前线上有2种版本的Compact程序:Compact_v1…...
【java代码审计】SQL注入
1 原理 没有正确的对用户的输入进行检查,将用户的输入以拼接的方式带入到SQL语句中,导致SQL注入。 2 产生SQL注入的原因 2.1 JDBC拼接不当造成SQL注入 前置知识: JDBC执行SQL语句的两种方式: PrepareStatement:会对…...
前置知识-辛 Runge-Kutta 方法
1.3.3 辛 Runge-Kutta 方法 将方程 ( 1.10.2 ) (1.10 .2) (1.10.2) 改写为 d z d x =...
require 与 import 两种引入模块方式到底有什么区别?
关于JavaScript 的模块化规范,可以移步至: 【JavaScript高级】模块化规范「一文让你彻底搞懂前端模块化规范 & 区别」 下面进入正题 require 与 import 两种引入模块方式,到底有什么区别呢? 大致可以分为以下几个方面&#…...
软考信息系统监理师备考建议
用好备考方法,两三个月就可以过的。信息系统监理师备考最好以教材和历年真题为主,教学视频模拟题为辅。考试介绍与复习建议:考试设置的科目包括:(1)信息系统工程监理基础知识,考试时间150分钟&a…...
第八届蓝桥杯省赛——4承压计算(二维数组,嵌套循环)
题目:X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。每块金属原料的外形、尺寸完全一致,但重量不同。金属材料被严格地堆放成金字塔形。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,于是想方设法给题目配上一些有关 oxx 的背景故事,使得它看起来不那么无趣。但有的时候却无法引入合适的小姐姐&…...
为什么需要学习shell、shell的作用
课程基于B站于超课程笔记 03 Shebang的正确玩法_哔哩哔哩_bilibili P1 shell的作用 P2 shell执行命令的流程 P3 Shebang的正确玩法 什么是shell及组成 shell概念 shelll组成 Shebang概念 /bin/sh /bin/bash一样,都是指向一个bash解释器 [rootlocalhost ~]#…...
pgsql-Create_ALTER_GRANT_REVOKE命令语法
pgsql-Create_ALTER_GRANT_REVOKE命令语法 资料 语法约定 CREATE ROLE ALTER ROLE GRANT授权 REVOKE回收授权 权限类型说明 语法约定 下面的约定被用于命令的大纲:方括弧([和])表示可选的部分(在 Tcl 命令里,使…...
【linux】:进程概念
文章目录 冯诺依曼体系结构一:操作系统二: 进程总结冯诺依曼体系结构 我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。 冯诺依曼体系如下图: 那么输入设备有哪些呢?…...
创建对象的方式和对属性的操作
javaScript支持多种编程范式,包括函数式编程和面向对象编程,javaScript的对象被设计成一组属性的无序集合,由key和value组成。 创建对象的两种方式 早期使用创建对象方式最多的是使用Object类,使用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引擎,lucene引擎直接使用相对复杂,有一定的学习成本,同样是使用Java编写,Elasticsearch使用的rest风格的进行交互,而数据呢则是以JSON的方式进行传输。学习…...
如何在VSCode、Vim和Emacs中配置Tern:提升JavaScript开发效率的完整指南
如何在VSCode、Vim和Emacs中配置Tern:提升JavaScript开发效率的完整指南 【免费下载链接】tern A JavaScript code analyzer for deep, cross-editor language support 项目地址: https://gitcode.com/gh_mirrors/te/tern Tern是一个强大的JavaScript代码分析…...
intv_ai_mk11绿色低碳:24GB显存低功耗运行,适合边缘AI服务器部署
intv_ai_mk11绿色低碳:24GB显存低功耗运行,适合边缘AI服务器部署 1. 模型概述 intv_ai_mk11是一款基于Llama架构的中等规模文本生成模型,专为边缘计算环境优化设计。该模型在保持高性能的同时,显著降低了硬件资源需求࿰…...
3个实用技巧快速解决城通网盘下载限速问题
3个实用技巧快速解决城通网盘下载限速问题 【免费下载链接】ctfileGet 获取城通网盘一次性直连地址 项目地址: https://gitcode.com/gh_mirrors/ct/ctfileGet 你是否曾经为了下载城通网盘上的文件而苦苦等待?面对几十KB/s的下载速度,看着进度条缓…...
《苍穹外卖》实战:从零到一构建高并发外卖系统核心笔记
1. 公共字段自动填充的工程化实践 第一次看到《苍穹外卖》项目里那些重复出现的创建人、创建时间、修改人、修改时间字段时,我就意识到这绝对是个需要优化的地方。每个实体类都手动维护这些字段,不仅容易出错,后期维护更是噩梦。好在Spring A…...
AI 路由暗藏漏洞,恶意攻击可盗取核心敏感信息
在 AI Agent 生态系统中,第三方 API 路由正成为一个关键却长期被忽视的攻击面。攻击者可悄无声息地将路由武器化,劫持工具调用、清空加密货币钱包,并大规模窃取敏感凭证。 随着 AI Agent 越来越多地自动化执行高风险任务(如运行代…...
2026届学术党必备的五大降AI率方案实际效果
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 就那些有着降低文本重复率需求的用户来讲,去挑选适宜的降重网站极为关键。这般类…...
2025届必备的降AI率助手推荐榜单
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 将维普系统针对 AI 生成内容的识别机制考虑进来,要降低 AI 检测率就得从文本特征…...
别浪费骁龙8 Gen3!手把手教你用旧手机+Termux搭建GPU加速的Linux开发机(附性能测试)
榨干骁龙8 Gen3性能:用旧手机打造便携Linux开发站的完整指南 手里那台吃灰的骁龙8 Gen3旗舰机,性能其实比多数轻薄本还强——不信?跑个Geekbench看看。去年花大几千买的机器,现在除了刷短视频就是当备用机,实在暴殄天物…...
逆向实战:手把手教你分析TikTok的X-Gorgon加密算法(附Unidg补环境技巧)
深度解析TikTok安全协议:X-Gorgon算法逆向工程实战指南 在移动应用安全研究领域,协议逆向工程始终是极具挑战性的技术方向。作为全球现象级短视频平台,TikTok采用的多层加密机制一直备受安全研究人员关注,其中X-Gorgon作为核心签名…...
从零搭建高性能BitTorrent Tracker:xbt-Tracker与Transmission实战指南
1. 为什么需要自建BitTorrent Tracker? 十年前我第一次接触私有种子时,完全依赖公共Tracker服务器。直到有次做项目需要分发大型数据集,公共Tracker频繁丢包导致传输中断,我才意识到自建Tracker的重要性。xbt-Tracker作为开源的高…...
