首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >eBPF: raw_tracepoint参数

eBPF: raw_tracepoint参数
EN

Stack Overflow用户
提问于 2022-01-10 13:01:02
回答 1查看 683关注 0票数 2

我正在进入eBPF编程,并希望使用原始跟踪点,但我并不真正理解如何使用它们和如何正确地访问参数。我希望有任何帮助和提示,以记录。

我的问题:

  1. 如何使用raw_tracepoint而不是跟踪点从syscall获取参数?
  2. 顺便问一下:原始跟踪点的uint16_t common_type;是什么?

系统: Ubuntu 2004,内核5.4泛型,x86_64

解释/实例:

我从“普通跟踪点”sys_enter_kill开始,在这里我可以使用来自sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_kill/format的参数创建结构

代码语言:javascript
复制
// sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_kill/format
// name: sys_enter_kill
// ID: 184
// format:
//  field:unsigned short common_type;   offset:0;   size:2; signed:0;
//  field:unsigned char common_flags;   offset:2;   size:1; signed:0;
//  field:unsigned char common_preempt_count;   offset:3;   size:1;signed:0;
//  field:int common_pid;   offset:4;   size:4; signed:1;

//  field:int __syscall_nr; offset:8;   size:4; signed:1;
//  field:pid_t pid;    offset:16;  size:8; signed:0;
//  field:int sig;  offset:24;  size:8; signed:0;

struct syscalls_enter_kill_args
{
    unsigned short common_type;
    unsigned char common_flags;
    unsigned char common_preempt_count;
    int common_pid;

    long syscall_nr;
    long pid;
    long sig;
};

SEC("tracepoint/xxx")
int main_entry(struct syscalls_enter_kill_args *ctx)
{
    if(ctx->sig != 9)
        return 0;
    u64 pid_tgid = bpf_get_current_pid_tgid();
    u32 pid = pid_tgid;
    bpf_printk("Catched function call; PID = : %d.\n", pid);
    return 0;
}

这个简单的bpf程序只是输出一些文本,每当一个杀死信号被调用。它只记录SIGKILL,不是SIGINT,SIGQUIT,.现在,我想对原始跟踪点sys_enter执行相同的功能。

代码语言:javascript
复制
// sudo cat /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/format
// name: sys_enter
// ID: 22
// format:
//  field:unsigned short common_type;   offset:0;   size:2; signed:0;
//  field:unsigned char common_flags;   offset:2;   size:1; signed:0;
//  field:unsigned char common_preempt_count;   offset:3;   size:1;signed:0;
//  field:int common_pid;   offset:4;   size:4; signed:1;

//  field:long id;  offset:8;   size:8; signed:1;
//  field:unsigned long args[6];    offset:16;  size:48;    signed:0;


struct sys_enter_args
{
    uint16_t common_type;
    uint8_t common_flags;
    uint8_t common_preempt_count;
    int32_t common_pid;
    int64_t id;
    uint64_t args[6];   // Je 4 Bytes
};

SEC("raw_tracepoint/xxx")
int main_entry_raw(struct sys_enter_args *ctx)
{
    if(ctx->id != SYS_kill)    // 62
        return 0;

    u64 pid_tgid = bpf_get_current_pid_tgid();
    u32 pid = pid_tgid;
    bpf_printk("Catched function call; PID = : %d.\n", pid);
    bpf_printk("  type: %u\n", ctx->common_type);
    bpf_printk("  id: %u\n", ctx->id);

    uint64_t* args = ctx->args;
    uint64_t arg3 = 0;
    bpf_probe_read(&arg3, sizeof(uint64_t), args + 3);
    bpf_printk("  Arg3: %u \n", arg3);
}

我想,我可能会收到信号(SIGKILL/SIGINT/SIGQUIT/.)通过field:int sig; offset:24; size:8; signed:0;args[]:Offset=24 => Byte 3;大小8 =>类型u64 =无符号的long。但是,这不会产生有用的值。那么,我如何获得信号的值,我可以在跟踪点和raw_tracepoint中访问该信号?

谢谢你帮忙!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-10 20:10:31

我想我是根据这个文章算出来的。

raw_tracepoint程序的ctx是struct bpf_raw_tracepoint_args。在bpf.h中定义为

代码语言:javascript
复制
struct bpf_raw_tracepoint_args {
    __u64 args[0];
};

所以基本上只是一组数字/指针。这些参数的含义取决于如何定义跟踪点原型。在查看源代码时,我们发现了跟踪点定义

代码语言:javascript
复制
TRACE_EVENT_FN(sys_enter,

    TP_PROTO(struct pt_regs *regs, long id),

    TP_ARGS(regs, id),

    TP_STRUCT__entry(
        __field(    long,       id      )
        __array(    unsigned long,  args,   6   )
    ),

    TP_fast_assign(
        __entry->id = id;
        syscall_get_arguments(current, regs, __entry->args);
    ),

    TP_printk("NR %ld (%lx, %lx, %lx, %lx, %lx, %lx)",
          __entry->id,
          __entry->args[0], __entry->args[1], __entry->args[2],
          __entry->args[3], __entry->args[4], __entry->args[5]),

    syscall_regfunc, syscall_unregfunc
);

让我们关注TP_PROTO(struct pt_regs *regs, long id),这意味着args[0]struct pt_regs *regsargs[1]long idstruct pt_regs是调用sys_enter时的CPU寄存器的副本。id是syscall的ID。

我们可以从CPU寄存器中提取syscall的参数。系统V指定哪些参数应该存在于哪个CPU寄存器中。为了让我们的生活更轻松,libbpf定义了tracing.h

所以,如果相信这应该是一个正确的计划:

代码语言:javascript
复制
SEC("raw_tracepoint/sys_enter")
int main_entry_raw(struct bpf_raw_tracepoint_args *ctx)
{
    unsigned long syscall_id = ctx->args[1];
    struct pt_regs *regs;

    if(syscall_id != SYS_kill)    // 62
        return 0;

    regs = (struct pt_regs *)ctx->args[0];
    
    u64 pid_tgid = bpf_get_current_pid_tgid();
    u32 pid = pid_tgid;
    bpf_printk("Catched function call; PID = : %d.\n", pid);
    bpf_printk("  id: %u\n", syscall_id);

    uint64_t arg3 = 0;
    bpf_probe_read(&arg3, sizeof(uint64_t), PT_REGS_PARM3(regs));
    bpf_printk("  Arg3: %u \n", arg3);
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70652825

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档