Skip to content

Commit 91811a2

Browse files
committed
Add a kprobe example and a tracepoint example.
1 parent dbb5efe commit 91811a2

2 files changed

Lines changed: 152 additions & 0 deletions

File tree

examples/kprobe_do_exit.ks

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Kprobe Example: Monitor process exit events
2+
//
3+
// This example demonstrates how to use kprobe to intercept and monitor
4+
// the do_exit() kernel function, which is called when a process exits.
5+
// We print the exit code parameter to see why processes are exiting.
6+
7+
// Target kernel function signature:
8+
// do_exit(code: u64) -> void
9+
//
10+
// The 'code' parameter contains the exit status/signal that caused
11+
// the process to exit.
12+
13+
14+
@kprobe("do_exit")
15+
fn do_exit(code: u64) -> void {
16+
// Print the exit code parameter
17+
// This will show us the exit status/signal for the exiting process
18+
print("Process exiting with code: %u", code)
19+
return 0
20+
}
21+
22+
fn main() -> i32 {
23+
var prog = load(do_exit)
24+
var result = attach(prog, "do_exit", 0)
25+
26+
if (result == 0) {
27+
print("kprobe program attached to do_exit successfully")
28+
print("Monitoring process exits...")
29+
30+
// In a real scenario, you would wait for events or run for a specific time
31+
// For this example, we'll just clean up immediately
32+
33+
// Detach the program
34+
detach(prog)
35+
print("kprobe program detached")
36+
} else {
37+
print("Failed to attach kprobe program")
38+
return 1
39+
}
40+
41+
return 0
42+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Tracepoint Example: Monitor process scheduling events
2+
//
3+
// This example demonstrates how to use tracepoint to monitor the sched_switch
4+
// kernel tracepoint, which is triggered every time the kernel switches between
5+
// processes. This allows us to track context switches and understand process
6+
// scheduling behavior.
7+
8+
// Tracepoint event signature:
9+
// Tracepoint event: sched/sched_switch -> fn(*trace_event_raw_sched_switch) -> i32
10+
//
11+
// The sched_switch tracepoint provides information about:
12+
// - The process being switched out (prev_*)
13+
// - The process being switched in (next_*)
14+
// - Process priorities, PIDs, and scheduling states
15+
16+
// @kernel_only - This struct is only for eBPF compilation, not userspace
17+
struct trace_entry {
18+
type: u16,
19+
flags: u8,
20+
preempt_count: u8,
21+
pid: u32,
22+
}
23+
24+
// @kernel_only - This struct is only for eBPF compilation, not userspace
25+
struct trace_event_raw_sched_switch {
26+
ent: trace_entry,
27+
prev_comm: u8[16],
28+
prev_pid: u32,
29+
prev_prio: u32,
30+
prev_state: u64,
31+
next_comm: u8[16],
32+
next_pid: u32,
33+
next_prio: u32,
34+
__data: u8[0],
35+
}
36+
37+
// unknown btf_trace_sched_switch (placeholder)
38+
39+
@tracepoint("sched/sched_switch")
40+
fn sched_sched_switch_handler(ctx: *trace_event_raw_sched_switch) -> i32 {
41+
// Extract process information from the context switch event
42+
var prev_pid = ctx->prev_pid
43+
var next_pid = ctx->next_pid
44+
var prev_prio = ctx->prev_prio
45+
var next_prio = ctx->next_prio
46+
var prev_state = ctx->prev_state
47+
48+
print("SCHED_SWITCH: prev_pid=%u -> next_pid=%u", prev_pid, next_pid)
49+
50+
print(" Priorities: prev_prio=%u, next_prio=%u", prev_prio, next_prio)
51+
52+
// Decode and print the previous task's state
53+
// Process states (simplified representation):
54+
// 0 = TASK_RUNNING, 1 = TASK_INTERRUPTIBLE, 2 = TASK_UNINTERRUPTIBLE
55+
if (prev_state == 0) {
56+
print(" Previous task state: RUNNING")
57+
} else if (prev_state == 1) {
58+
print(" Previous task state: INTERRUPTIBLE")
59+
} else if (prev_state == 2) {
60+
print(" Previous task state: UNINTERRUPTIBLE")
61+
} else {
62+
print(" Previous task state: OTHER (%lu)", prev_state)
63+
}
64+
65+
// Note: Process command names (prev_comm/next_comm) are available in the context
66+
// but require special eBPF helpers to safely access as strings.
67+
// For this example, we focus on the numerical data which is readily accessible.
68+
69+
// Track interesting scheduling events
70+
if (prev_pid == 0) {
71+
print(" --> Switching FROM idle process (swapper)")
72+
}
73+
if (next_pid == 0) {
74+
print(" --> Switching TO idle process (swapper)")
75+
}
76+
77+
// Detect high priority processes
78+
if (next_prio < 10) {
79+
print(" --> High priority process scheduled (prio=%u)", next_prio)
80+
}
81+
82+
return 0
83+
}
84+
85+
fn main() -> i32 {
86+
print("Starting sched_switch tracepoint monitoring...")
87+
print("This will track all process scheduling events in the kernel")
88+
89+
var prog = load(sched_sched_switch_handler)
90+
91+
// Attach tracepoint to target kernel event
92+
var result = attach(prog, "sched/sched_switch", 0)
93+
94+
if (result == 0) {
95+
print("sched_switch tracepoint program attached successfully")
96+
97+
// In a real scenario, you would wait for events or run for a specific time
98+
// For this example, we'll just clean up after a brief moment
99+
100+
// Detach the program
101+
detach(prog)
102+
print("sched_switch tracepoint program detached")
103+
} else {
104+
print("Failed to attach sched_switch tracepoint program")
105+
print("Make sure you have sufficient privileges (root) and the kernel supports tracepoints")
106+
return 1
107+
}
108+
109+
return 0
110+
}

0 commit comments

Comments
 (0)