You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用bpf_program__attach_uprobe_multi附加多Uprobe遇无效参数错误求助

问题描述

我需要对指定可执行文件中匹配op_*模式的函数做调用计数,尝试使用新推出的bpf_program__attach_uprobe_multi API,但找不到相关示例。现有代码执行时触发「无效参数」错误,在libbpf中添加打印后确认路径、模式、变量均正常读取到(libbpf日志显示:函数模式op_*,路径/data/expr/operations,匹配到2个函数,偏移量4521、4538),但仍报错:

libbpf: prog 'test_uprobe': failed to attach multi-uprobe: Invalid argument

当前使用的内核BPF代码如下:

// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
int main(int argc, char **argv)
{
        size_t offset1;
        size_t offset2;
        int err, i;
        char filename[256];
        pid_t pid;
        struct bpf_object *obj = NULL;
        struct bpf_program *prog[2];
        static struct bpf_link *bpflinks[2];
        static struct bpf_link *ubpflinks[2];

        if (argc < 2) {
                printf("Error return \n");
                return 0;
        }
        pid = strtoul(argv[1], NULL, 10);
        snprintf(filename, 256, "/proc/%d/exe", pid);
       

        offset1 = get_elf_func_offset("/data/expr/operations", "op_add");
        offset2 = get_elf_func_offset("/data/expr/operations", "op_sub");
       
        snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]);
        obj = bpf_object__open_file(filename, NULL);
        if (libbpf_get_error(obj)) {
                fprintf(stderr, "ERROR: opening BPF object file failed\n");
                obj = NULL;
                goto cleanup;
        }
    
          /* load BPF program */
        if (bpf_object__load(obj)) {
                fprintf(stderr, "ERROR: loading BPF object file failed\n");
                goto cleanup;
        }
        prog[0] = bpf_object__find_program_by_name(obj, "handle_uprobe_ref_ctr");
       // prog[1] = bpf_object__find_program_by_name(obj, "handle_uretprobe_ref_ctr");

        ubpflinks[0] =
                bpf_program__attach_uprobe(prog[0], false /* not uretprobe */,
                                pid, "/data/expr/operations" , offset1);
        if (!ubpflinks[0])
                printf("failed at link0\n");

        ubpflinks[1] =
                bpf_program__attach_uprobe(prog[0], false /* not uretprobe */,
                                pid, "/data/expr/operations" , offset2);
        if (!ubpflinks[1])
                printf("failed at link1\n");
//      bpflinks[0] = bpf_program__attach(prog[0]);  // do we need to attach already probes attached
       


        getchar();
cleanup:
        bpf_link__destroy(ubpflinks[0]);
        bpf_link__destroy(ubpflinks[1]);
        return -err;
}


char LICENSE[] SEC("license") = "Dual BSD/GPL";

SEC("uprobe")
int handle_uprobe_ref_ctr(struct pt_regs *ctx)
{
    
   const char fmt_str[] = "function fp %lld ip %lld\n";
   bpf_trace_printk(fmt_str, sizeof(fmt_str), (void *)PT_REGS_FP(ctx));

        return 0;
}

SEC("uretprobe")
int handle_uretprobe_ref_ctr(struct pt_regs *ctx)
{
        bpf_printk("handle_uretprobe_ref_ctr \n");
        return 0;
}

排查方向与修复方案

1. 内核版本兼容性检查

bpf_program__attach_uprobe_multi是内核5.19才引入的API,如果你的内核版本低于该版本,调用必然返回「无效参数」错误。执行uname -r查看内核版本,若版本不足需升级内核。

2. 正确使用bpf_program__attach_uprobe_multi API

你当前代码使用的是单个探针的bpf_program__attach_uprobe,切换到多探针API时需按以下方式调用,必须初始化opts.sz字段(libbpf用于识别结构体版本,遗漏会导致参数错误):

struct bpf_uprobe_multi_opts opts = {
    .sz = sizeof(opts),
    .binary_path = "/data/expr/operations",
    .func_pattern = "op_*", // 直接用通配符,无需手动获取偏移
    .pid = pid, // 传0监控所有进程,指定pid则只监控目标进程
    .is_retprobe = false, // false对应uprobe,true对应uretprobe
};

ubpflinks[0] = bpf_program__attach_uprobe_multi(prog[0], &opts);
if (libbpf_get_error(ubpflinks[0])) {
    fprintf(stderr, "Failed to attach multi-uprobe: %s\n", strerror(errno));
    ubpflinks[0] = NULL;
    goto cleanup;
}

3. 权限验证

挂载uprobe需要足够权限,需以root用户运行程序,或给程序添加必要capability:

sudo setcap cap_bpf,cap_perfmon+ep ./your_executable

4. 二进制文件符号检查

确保/data/expr/operations包含完整的符号表,libbpf需要通过符号解析匹配op_*函数。执行nm /data/expr/operations | grep op_,如果无法看到op_add和op_sub符号,说明二进制被剥离了符号信息,需要重新编译保留符号。

5. 程序类型匹配

确认BPF程序的SEC段与挂载类型一致:

  • 挂载普通uprobe时,BPF程序需标记为SEC("uprobe")
  • 挂载uretprobe时,BPF程序需标记为SEC("uretprobe"),同时API调用中is_retprobe设为true

内容的提问来源于stack exchange,提问作者nullptr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 22:05:59