英文:
how to get goroutine id with ebpf
问题
我使用cilium ebpf包来编写一个用于获取goroutine id的ebpf程序,但是失败了。我的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;
};
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; // 这里就是goroutine id!
};
当我运行程序时,cat /sys/kernel/debug/tracing/trace_pipe
输出如下,得到了错误的goroutine 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
根据你的描述,你认为问题的关键在于将golang结构体g转换为goroutine.h时出错。你是否需要帮助?
英文:
I use cilium ebpf pakage to write a ebpf program for getting the goroutine id.
but failed. my uprobe.c like this :
I think the key problem is that golang struct g trans to goroutine.h is wrong. can anyone help?
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!
};
When I run my program , cat /sys/kernel/debug/tracing/trace_pipe output like this , get the wrong 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
得分: 1
我找到了一个解决方案:
-
我的 Golang 版本是 1.17.2,amd64 架构。amd64 架构使用以下 9 个寄存器来传递整数参数和结果:RAX、RBX、RCX、RDI、RSI、R8、R9、R10、R11。
-
在 Go 1.17.2 中,runtime.newproc1 函数有 5 个参数。callergp *g 是第 4 个参数。当我使用 gdb 调试我的用户空间程序时,它使用 rdi 寄存器来保存 callergp *g 的指针地址。所以使用 PT_REGS_PARM1 是正确的方式,因为 (#define PT_REGS_PARM1(x) ((x)->rdi))。
-
最后,代码如下:
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;
}
英文:
I found a solution:
-
my golang version is 1.17.2, amd64. and the amd64 architecture uses the following sequence of 9 registers for integer arguments and results:
RAX, RBX, RCX, RDI, RSI, R8, R9, R10, R11 -
runtime.newproc1 which in go 1.17.2 has 5 args. callergp *g is the 4th. when I gdb my userspace program, it use rdi register to save ptr addr of callergp *g.
so use PT_REGS_PARM1 is the right way. because (#define PT_REGS_PARM1(x) ((x)->rdi)) -
after all, the code like this :
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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论