土法炼钢兴趣小组的算法知识备份

【操作系统百科】kprobe、uprobe 与 fprobe

文章导航

分类入口
os
标签入口
#kprobe#uprobe#fprobe#usdt#dynamic-tracing

目录

动态探针让你在任意内核/用户函数上挂钩——不需要重新编译,不需要重启。

一、先看图

flowchart TD
    KPROBE[kprobe<br/>内核函数探针] --> INT3[int3 断点<br/>或 ftrace]
    UPROBE[uprobe<br/>用户态探针] --> BKPT[断点指令<br/>替换用户代码]
    FPROBE[fprobe<br/>基于 ftrace] --> FTRACE[ftrace 框架<br/>批量高效]

    INT3 --> HANDLER[回调函数<br/>或 BPF 程序]
    BKPT --> HANDLER
    FTRACE --> HANDLER

    classDef kern fill:#388bfd22,stroke:#388bfd,color:#adbac7;
    classDef user fill:#3fb95022,stroke:#3fb950,color:#adbac7;
    class KPROBE,INT3,FPROBE,FTRACE kern
    class UPROBE,BKPT user
    class HANDLER kern

二、kprobe

2.1 原理

  1. 保存目标地址的原始指令
  2. 替换为 int3(x86)断点
  3. 触发时 → 执行 pre_handler → 单步执行原始指令 → 执行 post_handler

2.2 使用

# 通过 tracefs
echo 'p:myprobe do_sys_openat2 filename=+0(%si):string' > \
    /sys/kernel/debug/tracing/kprobe_events
echo 1 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enable
cat /sys/kernel/debug/tracing/trace

2.3 kretprobe

echo 'r:myret do_sys_openat2 $retval' > \
    /sys/kernel/debug/tracing/kprobe_events

捕获函数返回值 → 通过替换返回地址实现。

三、fprobe(推荐)

基于 ftrace → 不需要 int3 → 更高效:

struct fprobe fp = {
    .entry_handler = my_handler,
};
register_fprobe(&fp, "do_sys_openat2", NULL);

fprobe 支持批量注册 → 适合 BPF 大规模追踪。

四、uprobe

4.1 原理

  1. 在 ELF 文件中找到目标函数偏移
  2. 运行时替换为断点指令
  3. 触发时 → 陷入内核 → 执行回调 → 恢复

4.2 使用

echo 'p:myuprobe /usr/lib/libc.so.6:malloc size=%di' > \
    /sys/kernel/debug/tracing/uprobe_events
echo 1 > /sys/kernel/debug/tracing/events/uprobes/myuprobe/enable

4.3 USDT

User Statically-Defined Tracing → 应用程序预埋探针:

bpftrace -e 'usdt:/usr/lib/libc.so.6:memory_malloc_retry { printf("retry\n"); }'

五、BPF 联动

SEC("kprobe/do_sys_openat2")
int BPF_KPROBE(trace_open, int dfd, struct filename *name)
{
    bpf_printk("open: %s\n", name->name);
    return 0;
}

BPF + kprobe/uprobe 是最常用的动态追踪组合。

六、性能开销

探针类型 单次开销(x86_64)
kprobe (int3) ~100-200ns
fprobe (ftrace) ~30-50ns
uprobe ~1-3μs
tracepoint ~50-100ns

uprobe 开销最高 → 涉及用户态/内核态切换。

七、安全限制

# 非 root 用户限制
sysctl kernel.perf_event_paranoid=2     # 限制 perf
sysctl kernel.kptr_restrict=1           # 隐藏内核指针

lockdown 模式 → kprobe 可能被禁用。

八、常见陷阱

九、观察

cat /sys/kernel/debug/kprobes/list      # 已注册 kprobe
cat /sys/kernel/debug/tracing/uprobe_events

# bpftrace 示例
bpftrace -e 'kprobe:vfs_read { @[comm] = count(); }'
bpftrace -e 'kretprobe:vfs_read { @bytes = hist(retval); }'
bpftrace -e 'uprobe:/usr/bin/bash:readline { printf("readline\n"); }'

十、小结


参考文献

工具


上一篇eBPF 核心 下一篇kdump 与 crash

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-27 · os

【操作系统百科】内存回收

Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。

2026-04-28 · os

【操作系统百科】交换

swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。

2026-05-03 · os

【操作系统百科】Slab/SLUB 分配器

buddy 只管页粒度(4K+),内核大多数对象只有几十到几百字节。slab/SLUB 在 buddy 之上做对象级缓存。本文讲 slab 历史、SLUB 接手、SLOB 退场、kmem_cache、per-CPU cache、KASAN 集成。

2026-05-07 · os

【操作系统百科】用户态分配器

glibc malloc、tcmalloc、jemalloc、mimalloc 各有哲学。本文讲 arena、thread cache、size class、madvise 返还策略、碎片与 RSS 膨胀、如何根据负载选分配器。


By .