如何使用ebpf获得例程id



我使用cilium ebpf包编写了一个ebpf程序来获取例程id。但失败了。我的根是这样的:我认为关键的问题是golang struct转换成goroutine是错误的。有人能帮忙吗?

uprobe.c

SEC("uprobe/runtime.newproc1")
int uprobe_runtime_newproc1(struct pt_regs *ctx) {
u32 key     = 2;
u64 initval = 1, *valp;
valp = bpf_map_lookup_elem(&uprobe_map, &key);
if (!valp) {
bpf_map_update_elem(&uprobe_map, &key, &initval, BPF_ANY);
return 0;
}
__sync_fetch_and_add(valp, 1);
struct g* goroutine_struct = (void *)PT_REGS_PARM4(ctx);
// retrieve output parameter
s64 goid = 0;
bpf_probe_read(&goid, sizeof(goid), &goroutine_struct->goid);
bpf_printk("bpf_printk bpf_probe_read goroutine_struct->goid: %lld", goid);

struct g gs;
bpf_probe_read(&gs, sizeof(gs), (void *)PT_REGS_PARM4(ctx));
bpf_printk("bpf_printk bpf_probe_read goroutine_struct.goid: %lld", gs.goid);
// test
void* ptr = (void *)PT_REGS_PARM4(ctx);
s64 goid2 = 0;
bpf_probe_read(&goid2, sizeof(goid2), (void *)(ptr+152));
bpf_printk("bpf_printk bpf_probe_read goid2: %lld", goid2);
return 0;
}

goroutine.h

#include "common.h"

struct stack  {
u64 lo;
u64 hi;
};
struct gobuf  {
u64 sp;
u64 pc;
u64 g;
u64 ctxt;
u64 ret;
u64 lr;
u64 bp;
};

/*
go version go1.17.2 linux/amd64
type stack struct {
lo uintptr
hi uintptr
}
type gobuf struct {
sp   uintptr
pc   uintptr
g    uintptr
ctxt uintptr
ret  uintptr
lr   uintptr
bp   uintptr
}
type g struct { 
stack       stack   // offset known to runtime/cgo
stackguard0 uintptr // offset known to liblink
stackguard1 uintptr // offset known to liblink
_panic    *_panic // innermost panic - offset known to liblink
_defer    *_defer // innermost defer
m         *m      // current m; offset known to arm liblink
sched     gobuf
syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc
syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc
stktopsp  uintptr // expected sp at top of stack, to check in traceback

param        unsafe.Pointer
atomicstatus uint32
stackLock    uint32 // sigprof/scang lock; TODO: fold in to atomicstatus
goid         int64
}
*/
struct g {
struct stack stack;
u64 stackguard0;
u64 stackguard1;
u64 _panic;
u64 _defer;
u64 m;
struct gobuf sched ;
u64 syscallsp;
u64 syscallpc;
u64 stktopsp;
u64 param;
u32 atomicstatus;
u32 stackLock;
s64 goid;          // Here it is!
};

当我运行我的程序时,cat/sys/kernel/debug/tracing/trace_pipe输出如下,得到错误的go id:

<...>-1336127 [000] d... 20113210.986990: bpf_trace_printk: bpf_printk bpf_probe_read goroutine_struct->goid: 4938558469562467144
<...>-1336127 [000] d... 20113210.986998: bpf_trace_printk: bpf_printk bpf_probe_read goroutine_struct.goid: 4938558469562467144
<...>-1336127 [000] d... 20113210.986998: bpf_trace_printk: bpf_printk bpf_probe_read goid2: 4938558469562467144
Blockquote

我找到了一个解决方案:

  1. 我的golang版本是1.17.2,amd64。amd64架构使用以下9个寄存器的整数参数和结果序列:rx, RBX, rx, RDI, RSI, R8, R9, R10, R11

  2. 运行时。Newproc1在go 1.17.2中有5个参数。Callergp *g排名第四。当我gdb我的用户空间程序,它使用rdi寄存器保存ptr地址的callergp *g。所以使用PT_REGS_PARM1是正确的方法。因为(# define PT_REGS_PARM1 (x) (x)→(rdi)

  3. 毕竟代码是这样的:

SEC("uprobe/runtime.newproc1")
int uprobe_runtime_newproc1(struct pt_regs *ctx) {
u32 key     = 2;
u64 initval = 1, *valp;

valp = bpf_map_lookup_elem(&uprobe_map, &key);
if (!valp) {
bpf_map_update_elem(&uprobe_map, &key, &initval, BPF_ANY);
return 0;
}
__sync_fetch_and_add(valp, 1);

// retrieve output parameter
struct g gs;
bpf_probe_read(&gs, sizeof(gs), (void *)PT_REGS_PARM1(ctx));
bpf_printk("uprobe_runtime_newproc1 bpf_printk bpf_probe_read goroutine_struct.goid: %lld", gs.goid);

return 0;
}

相关内容

  • 没有找到相关文章

最新更新