eBPF挂载函数小结

挂载函数小结

1.bpf_program__attach_kprobe

struct bpf_link *bpf_program__attach_kprobe(const struct bpf_program *prog,
					    bool retprobe,
					    const char *func_name)
{
	DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts,
		.retprobe = retprobe,
	);

	return bpf_program__attach_kprobe_opts(prog, func_name, &opts);
}

这个函数是用来动态挂载函数的, 第一个参数为bpf_program指针类型的,指向了要挂载的bpf程序,第二个参数是一个bool类型,如果为true,则代表是返回探测点kretprobe,否则是kprobe。第三个参数是一个字符串,表示要附加的bpf程序的函数名称。

2.bpf_program__attach_tracepoint

struct bpf_link *bpf_program__attach_tracepoint(const struct bpf_program *prog,
						const char *tp_category,
						const char *tp_name)
{
	return bpf_program__attach_tracepoint_opts(prog, tp_category, tp_name, NULL);
}

这个函数是用来将一个 BPF 程序附加到内核中的一个追踪点,有三个参数,第一个参数为bpf_program指针类型的,指向了要挂载的bpf程序,第二个参数指定追踪点的类别,第三个参数指定给定类别中追踪点的名称。

内核中追踪点类型及名称在/sys/kernel/debug/tracing/events/下面查看

在这里插入图片描述

静态跟踪点(tracepoint),在用户空间也被称为USDT(用户静态定义跟踪)探针,是应用程序感兴趣的特定位置,可以在其中挂载跟踪器来检查数据和代码执行情况。

3.挂载uprobe

//函数原型
struct bpf_link * bpf_program__attach_uprobe (const struct bpf_program *prog, bool retprobe, pid_t pid, const char *binary_path, size_t func_offset)
//描述
bpf_program__attach_uprobe() attaches a BPF program to the userspace function which is found by binary path and offset. You can optionally specify a particular proccess to attach to. You can also optionally attach the program to the function exit instead of entry.

// 参数
prog – BPF program to attach

retprobe – Attach to function exit

pid – Process ID to attach the uprobe to, 0 for self (own process), -1 for all processes

binary_path – Path to binary that contains the function symbol //可通过/proc/pid/maps找到

func_offset – Offset within the binary of the function symbol

//返回值
Reference to the newly created BPF link; or NULL is returned on error, error code is stored in errno

4.挂载usdt探针

定义USDT探针

在C或C++应用程序中,可以使用DTrace或SystemTap的API定义USDT探针,如下通过 sudo apt-get install systemtap-sdt-dev 安装之后,就能通过使用宏来定义usdt,最多可以包含有12个参数。

在这里插入图片描述

例子:

// test_usdt.c

#include <stdio.h>
#include <sys/sdt.h>

int main() {
    // 触发 USDT 跟踪点
    DTRACE_PROBE2(provider_name, probe_name, 123, "Hello");
    
    return 0;
}

在这里插入图片描述

USDT动态挂载函数的详细用法

bpf_program__attach_usdt() is just like bpf_program__attach_uprobe_opts() except it covers USDT (User-space Statically Defined Tracepoint) attachment, instead of attaching to user-space function entry or exit.

//函数原型
struct bpf_link *bpf_program__attach_usdt(const struct bpf_program *prog,
                                          pid_t pid, const char *binary_path,
					  const char *usdt_provider, const char *usdt_name,
					  const struct bpf_usdt_opts *opts)
//参数
prog – BPF program to attach

pid – Process ID to attach the uprobe to, 0 for self (own process), -1 for all processes

binary_path – Path to binary that contains provided USDT probe

usdt_provider – USDT provider name

usdt_name – USDT probe name

opts – Options for altering program attachment

//返回值
Reference to the newly created BPF link; or NULL is returned on error, error code is stored in errno

provider及name

测试程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

// 线程函数
void *thread_function(void *arg) {
    while (1) {
        // 打印当前线程的pid
        printf("Thread PID: %d\n", getpid());
        // 等待一秒
        sleep(1);
    }
    pthread_exit(NULL);
}

// 创建线程的函数
void create_thread() {
    pthread_t thread;
    int rc;

    // 创建线程
    rc = pthread_create(&thread, NULL, thread_function, NULL);
    if (rc) {
        fprintf(stderr, "Error: pthread_create() failed with code %d\n", rc);
        exit(EXIT_FAILURE);
    }
}

int main() {
    // 打印主进程的pid
    printf("Main process PID: %d\n", getpid());

    // 调用函数创建线程
    create_thread();

    // 主进程死循环打印pid
    while (1) {
        printf("Main process PID: %d\n", getpid());
        // 等待一秒
        sleep(1);
    }

    return 0;
}

编译并运行上述测试文件pth,其进程号为67709,于是打开了 /proc/67709/maps 文件,该文件包含了进程地址空间的内存映射信息。首先复制其包含.libc.so.6的行,并保存,代码如下,下图中还打印了该二进制路径bin_path。

static int get_path(char *path,int pid)
{
    char mode[16], line[128], buf[64];
    size_t seg_start, seg_end, seg_off;
    FILE *f;
    int i = 0;

    sprintf(buf, "/proc/%d/maps", pid);
    f = fopen(buf, "r");
    if (!f)
        return -1;

    while (fscanf(f, "%zx-%zx %s %zx %*s %*d%[^\n]\n",
            &seg_start, &seg_end, mode, &seg_off, line) == 5) {
        i = 0;
        while (isblank(line[i]))
            i++;
        if (strstr(line + i, "libc.so.6")) {
            break;
        }
    }

    strcpy(path, line + i);
    fclose(f);
    return 0;
}

在这里插入图片描述

接着,通过readelf -n bin_path 来查看链接文件的追踪点

在这里插入图片描述

在用户态修改代码为

 // probe a USDT tracepoint
        char bin_path[128];
        std::string func = probe;
        int err = get_path(bin_path,pid);
        CHECK_ERR(err, "Fail to get lib path");
        skel->links.handle_usdt  =
            bpf_program__attach_usdt(skel->progs.handle_usdt,pid,bin_path,"libc",strList[2].c_str(),NULL);
        CHECK_ERR(!skel->links.handle_usdt, "Fail to attach usdt");
        return 0;

bpf.c 增加一个挂载usdt的

SEC("usdt")
int handle_usdt(void *ctx)
{
    return handle_func(ctx);
}

下面是探测 pthread_create USDT 跟踪点的调用栈等相关信息

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值