Heng30的博客
搜索 分类 关于 订阅

如何使用bcc跟踪调试内核?

2025-02-14

BCC(BPF Compiler Collection)是一个用于创建高效内核跟踪和操作的工具包,基于 eBPF(extended Berkeley Packet Filter)技术。eBPF允许用户在不修改内核源代码或加载内核模块的情况下,安全地运行自定义代码。BCC简化了eBPF程序的开发,提供了高级语言接口(如PythonLua)和丰富的工具集。

核心特点

  • 简化开发:BCC提供了 PythonLua等高级语言接口,开发者无需直接编写复杂的eBPF内核代码。

  • 丰富的工具集:BCC自带许多现成的工具,用于性能分析、网络监控、系统调试等场景。

  • 动态加载:eBPF程序可以动态加载到内核中,无需重启系统。

  • 安全性:eBPF程序在加载前会经过验证器检查,确保不会导致内核崩溃或安全问题。

主要组件

  • 前端:通常使用Python编写,用于定义eBPF程序的行为和数据处理逻辑。

  • 后端:eBPF程序本身,用C语言编写,运行在内核中。

工具集

  • opensnoop:跟踪文件打开操作。

  • execsnoop:跟踪进程创建。

  • tcplife:跟踪TCP连接的生命周期。

  • funccount:统计函数调用次数。

  • 更多的工具使用方法可以参考bcc github文档

bcc 工具

如何安装?

  • ubuntu 24.04安装依赖

    sudo apt install -y bison build-essential cmake         \
             flex git libedit-dev libllvm15t64 llvm-15-dev  \
             libclang-15-dev python3 zlib1g-dev libelf-dev  \
             libfl-dev bpfcc-tools python3-bpfcc arping     \
             netperf iperf3 python3-setuptools libpolly-15-dev
    
  • 编译并安装

    git clone https://github.com/iovisor/bcc.git
    mkdir bcc/build && cd bcc/build
    cmake .. -DCMAKE_INSTALL_PREFIX=/usr && make -j 4
    sudo make install
    
  • 检查是否安装成功

    sudo ln -s /usr/bin/python3 /usr/bin/python
    sudo /usr/share/bcc/tools/execsnoop
    

例子

# hello.py
# 打印系统调用次数

from bcc import BPF
import time

# 定义 BPF 程序代码
prog = """
#include <uapi/linux/ptrace.h>

// 定义一个哈希映射,用于统计系统调用次数
BPF_HASH(call_count);

// 定义一个跟踪点处理函数,当任何系统调用发生时触发
int trace_syscall(struct pt_regs *ctx) {
    u64 pid = bpf_get_current_pid_tgid();
    u64 zero = 0, *value;

    // 获取系统调用号
    u64 syscall_nr = ctx->ax;

    // 在哈希映射中查找当前系统调用号的计数
    value = call_count.lookup_or_init(&syscall_nr, &zero);

    (*value)++;

    return 0;
}
"""

# 加载 BPF 程序
b = BPF(text=prog)

# 附加跟踪点到所有系统调用入口
b.attach_kprobe(event="__x64_sys_execve", fn_name="trace_syscall")

# 打印每个系统调用的计数
try:
    while True:
        flag = False
        time.sleep(1)

        for k, v in b["call_count"].items():
            flag = True
            print("System call {} was called {} times".format(k.value, v.value))

        if flag:
            print("=========================================")
except KeyboardInterrupt:
    pass
  • 运行sudo python3 hello.py

  • 运行ls命令,触发系统调用事件

  • 输出结果

System call 18446637894762375360 was called 4 times
System call 18446637894762364928 was called 1 times
System call 18446637895101393088 was called 2 times
System call 18446637894655617216 was called 5 times
System call 18446637897968210304 was called 1 times

排错

  • 检查内核配置
    • grep CONFIG_KPROBES /boot/config-$(uname -r)

      CONFIG_KPROBES=y
      
    • grep CONFIG_BPF /boot/config-$(uname -r)

      CONFIG_BPF=y
      

参考

希望上面的内容对你有所帮助。