以下是10个使用eBPF、uprobes和Golang的代码案例示例:
- 监控函数调用次数:
package main
import (
"fmt"
"github.com/iovisor/gobpf/bcc"
)
const program = `
#include <uapi/linux/ptrace.h>
BPF_HASH(counts, u64);
int count_calls(struct pt_regs *ctx) {
u64 key = PT_REGS_IP(ctx);
u64* val = counts.lookup_or_init(&key, 0);
(*val)++;
return 0;
}
`
func main() {
module := bcc.NewModule(program, []string{})
defer module.Close()
uprobe, err := module.LoadUprobe("count_calls")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUprobe("/path/to/binary", "function_name", uprobe, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
perfMap, err := bcc.InitPerfMap(module.LookupTable("counts"), printOutput)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to initialize perf map: %v\n", err)
os.Exit(1)
}
perfMap.Start()
defer perfMap.Stop()
select {}
}
func printOutput() {
fmt.Println("Function called!")
}
- 统计函数执行时间:
package main
import (
"fmt"
"github.com/iovisor/gobpf/bcc"
)
const program = `
#include <uapi/linux/ptrace.h>
struct data_t {
u64 timestamp;
};
BPF_HASH(start, u32, struct data_t);
int trace_start(struct pt_regs *ctx) {
u32 pid = bpf_get_current_pid_tgid();
struct data_t data = {};
data.timestamp = bpf_ktime_get_ns();
start.update(&pid, &data);
return 0;
}
int trace_end(struct pt_regs *ctx) {
u32 pid = bpf_get_current_pid_tgid();
struct data_t* start_data = start.lookup(&pid);
if (start_data == 0) {
return 0;
}
u64 delta = bpf_ktime_get_ns() - start_data->timestamp;
bpf_trace_printk("%d: Execution time: %llu ns\\n", pid, delta / 1000);
start.delete(&pid);
return 0;
}
`
func main() {
module := bcc.NewModule(program, []string{})
defer module.Close()
uprobeStart, err := module.LoadUprobe("trace_start")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUprobe("/path/to/binary", "function_name", uprobeStart, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
uprobeEnd, err := module.LoadUprobe("trace_end")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUretprobe("/path/to/binary", "function_name", uprobeEnd, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
bcc.NewTable(module.TableId("start"), module).SetMaxEntries(4096)
table := bcc.NewTable(module.TableId("counts"), module)
channel := make(chan []byte)
module["output"].Attach(channel)
defer module["output"].Detach()
go func() {
for {
data := <-channel
fmt.Println(string(data))
}
}()
select {}
}
- 监控文件读写操作:
package main
import (
"fmt"
"github.com/iovisor/gobpf/bcc"
)
const program = `
#include <uapi/linux/ptrace.h>
#include <linux/fs.h>
BPF_HASH(counts, int);
int trace_read(struct pt_regs *ctx) {
int pid = bpf_get_current_pid_tgid();
counts.increment(pid);
return 0;
}
int trace_write(struct pt_regs *ctx) {
int pid = bpf_get_current_pid_tgid();
counts.increment(pid);
return 0;
}
`
func main() {
module := bcc.NewModule(program, []string{})
defer module.Close()
uprobeRead, err := module.LoadUprobe("trace_read")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUprobe("/path/to/binary", "read_function_name", uprobeRead, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
uprobeWrite, err := module.LoadUprobe("trace_write")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUprobe("/path/to/binary", "write_function_name", uprobeWrite, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
table := bcc.NewTable(module.TableId("counts"), module)
channel := make(chan []byte)
module["output"].Attach(channel)
defer module["output"].Detach()
go func() {
for {
data := <-channel
fmt.Println(string(data))
}
}()
select {}
}
- 检测网络数据包:
package main
import (
"fmt"
"github.com/iovisor/gobpf/bcc"
)
const program = `
#include <uapi/linux/ptrace.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
BPF_PERF_OUTPUT(events);
int trace_packet(struct __sk_buff *skb) {
u8* cursor = 0;
struct ethhdr* eth = bpf_hdr_pointer(skb);
if (eth->h_proto == htons(ETH_P_IP)) {
struct iphdr* ip = (struct iphdr *)(cursor + sizeof(struct ethhdr));
if (ip->protocol == IPPROTO_TCP) {
struct tcphdr* tcp = (struct tcphdr *)(cursor + sizeof(struct ethhdr) + sizeof(struct iphdr));
events.perf_submit(skb, skb->len);
}
}
return 0;
}
`
func main() {
module := bcc.NewModule(program, []string{})
defer module.Close()
uprobePacket, err := module.LoadUprobe("trace_packet")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUprobe("/path/to/binary", "packet_function_name", uprobePacket, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
table := bcc.NewTable(module.TableId("events"), module)
channel := make(chan []byte)
module["output"].Attach(channel)
defer module["output"].Detach()
go func() {
for {
data := <-channel
fmt.Println(string(data))
}
}()
select {}
}
- 监控文件IO耗时:
package main
import (
"fmt"
"github.com/iovisor/gobpf/bcc"
)
const program = `
#include <uapi/linux/ptrace.h>
#include <linux/blkdev.h>
BPF_HASH(start, u64);
int trace_start(struct pt_regs *ctx) {
u64 timestamp = bpf_ktime_get_ns();
start.update(&ctx->pid, ×tamp);
return 0;
}
int trace_end(struct pt_regs *ctx) {
u64* timestamp_ptr = start.lookup(&ctx->pid);
if (timestamp_ptr == NULL) {
return 0;
}
u64 delta = bpf_ktime_get_ns() - *timestamp_ptr;
bpf_trace_printk("%d: IO Time: %llu ns\\n", ctx->pid, delta / 1000);
start.delete(&ctx->pid);
return 0;
}
`
func main() {
module := bcc.NewModule(program, []string{})
defer module.Close()
uprobeStart, err := module.LoadUprobe("trace_start")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUprobe("/path/to/binary", "start_function_name", uprobeStart, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
uprobeEnd, err := module.LoadUprobe("trace_end")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUretprobe("/path/to/binary", "end_function_name", uprobeEnd, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
table := bcc.NewTable(module.TableId("counts"), module)
channel := make(chan []byte)
module["output"].Attach(channel)
defer module["output"].Detach()
go func() {
for {
data := <-channel
fmt.Println(string(data))
}
}()
select {}
}
- 检测TCP连接状态:
package main
import (
"fmt"
"github.com/iovisor/gobpf/bcc"
)
const program = `
#include <uapi/linux/ptrace.h>
#include <linux/tcp.h>
BPF_HASH(counts, u32);
int trace_tcp_state(struct pt_regs *ctx) {
u32 pid = bpf_get_current_pid_tgid();
struct tcp_sock* tp = (struct tcp_sock*)bpf_get_smp_processor_id();
if (tp == NULL) {
return 0;
}
u32 state = tp->state;
counts.increment(state);
return 0;
}
`
func main() {
module := bcc.NewModule(program, []string{})
defer module.Close()
uprobeState, err := module.LoadUprobe("trace_tcp_state")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUprobe("/path/to/binary", "tcp_function_name", uprobeState, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
table := bcc.NewTable(module.TableId("counts"), module)
channel := make(chan []byte)
module["output"].Attach(channel)
defer module["output"].Detach()
go func() {
for {
data := <-channel
fmt.Println(string(data))
}
}()
select {}
}
- 监控系统调用:
package main
import (
"fmt"
"github.com/iovisor/gobpf/bcc"
)
const program = `
#include <uapi/linux/ptrace.h>
BPF_HASH(counts, int);
int trace_syscall_entry(struct pt_regs *ctx) {
int pid = bpf_get_current_pid_tgid();
counts.increment(pid);
return 0;
}
`
func main() {
module := bcc.NewModule(program, []string{})
defer module.Close()
uprobeSyscallEntry, err := module.LoadUprobe("trace_syscall_entry")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUprobe("/path/to/binary", "__x64_sys_function_name", uprobeSyscallEntry, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
table := bcc.NewTable(module.TableId("counts"), module)
channel := make(chan []byte)
module["output"].Attach(channel)
defer module["output"].Detach()
go func() {
for {
data := <-channel
fmt.Println(string(data))
}
}()
select {}
}
- 跟踪内存分配和释放:
”`go package main
import (
"fmt"
"github.com/iovisor/gobpf/bcc"
)
const program = `
#include
BPF_HASH(counts, u64);
int trace_alloc(struct pt_regs *ctx) {
counts.increment(0);
return 0;
}
int trace_free(struct pt_regs *ctx) {
counts.decrement(0);
return 0;
} `
func main() {
module := bcc.NewModule(program, []string{})
defer module.Close()
uprobeAlloc, err := module.LoadUprobe("trace_alloc")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUprobe("/path/to/binary", "alloc_function_name", uprobeAlloc, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
uprobeFree, err := module.LoadUprobe("trace_free")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
os.Exit(1)
}
err = module.AttachUprobe("/path/to/binary", "free_function_name", uprobeFree, -1)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
os.Exit(1)
}
table := bcc.NewTable(module.TableId("counts"), module)
channel := make(chan []byte)
module["output"].Attach(channel)
defer module["output"].Detach<br/><br/><br/><font size=1 color=#CCCCCC>内容由零声教学AI助手提供,问题来源于学员提问</font>