-
Notifications
You must be signed in to change notification settings - Fork 303
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is a simple example of using BPF iterators, which iterates over all tasks on the host. Signed-off-by: Jordan Rome <[email protected]>
- Loading branch information
Showing
6 changed files
with
220 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,5 +10,6 @@ | |
/sockfilter | ||
/tc | ||
/ksyscall | ||
/task_iter | ||
/cmake-build-debug/ | ||
/cmake-build-release/ | ||
/cmake-build-release/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause | ||
/* Copyright (c) 2023 Meta */ | ||
#include "vmlinux.h" | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
#include <bpf/bpf_core_read.h> | ||
#include "task_iter.h" | ||
|
||
char LICENSE[] SEC("license") = "Dual BSD/GPL"; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); | ||
__uint(max_entries, 1); | ||
__type(key, __u32); | ||
__type(value, struct task_info); | ||
} task_info_buf SEC(".maps"); | ||
|
||
struct task_struct___post514 { | ||
unsigned int __state; | ||
} __attribute__((preserve_access_index)); | ||
|
||
struct task_struct___pre514 { | ||
long state; | ||
} __attribute__((preserve_access_index)); | ||
|
||
static __u32 get_task_state(void *arg) | ||
{ | ||
if (bpf_core_field_exists(struct task_struct___pre514, state)) { | ||
struct task_struct___pre514 *task = arg; | ||
return task->state; | ||
} else { | ||
struct task_struct___post514 *task = arg; | ||
return task->__state; | ||
} | ||
} | ||
|
||
static __u32 zero = 0; | ||
|
||
SEC("iter/task") | ||
int get_tasks(struct bpf_iter__task *ctx) | ||
{ | ||
struct seq_file *seq = ctx->meta->seq; | ||
struct task_struct *task = ctx->task; | ||
struct task_info *t; | ||
long res; | ||
|
||
if (!task) { | ||
return 0; | ||
} | ||
|
||
t = bpf_map_lookup_elem(&task_info_buf, &zero); | ||
if (!t) { | ||
return 0; | ||
} | ||
|
||
t->pid = task->tgid; | ||
t->tid = task->pid; | ||
t->state = get_task_state(task); | ||
|
||
bpf_probe_read_kernel_str(t->comm, TASK_COMM_LEN, task->comm); | ||
|
||
res = bpf_get_task_stack(task, t->kstack, sizeof(__u64) * MAX_STACK_LEN, 0); | ||
t->kstack_len = res <= 0 ? res : res / sizeof(t->kstack[0]); | ||
|
||
bpf_seq_write(seq, t, sizeof(struct task_info)); | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | ||
/* Copyright (c) 2023 Meta */ | ||
#include <argp.h> | ||
#include <signal.h> | ||
#include <stdio.h> | ||
#include <sys/resource.h> | ||
#include <bpf/bpf.h> | ||
#include <bpf/libbpf.h> | ||
#include <unistd.h> | ||
#include "task_iter.h" | ||
#include "task_iter.skel.h" | ||
|
||
static struct env { | ||
bool verbose; | ||
} env; | ||
|
||
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) | ||
{ | ||
if (level == LIBBPF_DEBUG && !env.verbose) | ||
return 0; | ||
return vfprintf(stderr, format, args); | ||
} | ||
|
||
static volatile bool exiting = false; | ||
|
||
static void sig_handler(int sig) | ||
{ | ||
exiting = true; | ||
} | ||
|
||
static const char *get_task_state(__u32 state) | ||
{ | ||
// taken from | ||
// https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h#L85 | ||
// there are a lot more states not covered here but these are common ones | ||
switch (state) { | ||
case 0x0000: | ||
return "RUNNING"; | ||
case 0x0001: | ||
return "INTERRUPTIBLE"; | ||
case 0x0002: | ||
return "UNINTERRUPTIBLE"; | ||
case 0x0200: | ||
return "WAKING"; | ||
case 0x0400: | ||
return "NOLOAD"; | ||
case 0x0402: | ||
return "IDLE"; | ||
case 0x0800: | ||
return "NEW"; | ||
default: | ||
return "<unknown>"; | ||
} | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
struct task_iter_bpf *skel; | ||
struct task_info buf; | ||
int get_tasks_fd; | ||
ssize_t ret; | ||
int err; | ||
|
||
/* Set up libbpf errors and debug info callback */ | ||
libbpf_set_print(libbpf_print_fn); | ||
|
||
/* Cleaner handling of Ctrl-C */ | ||
signal(SIGINT, sig_handler); | ||
signal(SIGTERM, sig_handler); | ||
|
||
/* Open, load, and verify BPF application */ | ||
skel = task_iter_bpf__open_and_load(); | ||
if (!skel) { | ||
fprintf(stderr, "Failed to open and load BPF skeleton\n"); | ||
goto cleanup; | ||
} | ||
|
||
/* Attach tracepoints */ | ||
err = task_iter_bpf__attach(skel); | ||
if (err) { | ||
fprintf(stderr, "Failed to attach BPF skeleton\n"); | ||
goto cleanup; | ||
} | ||
|
||
get_tasks_fd = bpf_iter_create(bpf_link__fd(skel->links.get_tasks)); | ||
if (get_tasks_fd < 0) { | ||
err = -1; | ||
fprintf(stderr, "Failed to create iter\n"); | ||
goto cleanup; | ||
} | ||
|
||
while (true) { | ||
ret = read(get_tasks_fd, &buf, sizeof(struct task_info)); | ||
if (ret < 0) { | ||
if (errno == EAGAIN) { | ||
continue; | ||
} | ||
err = -errno; | ||
break; | ||
} | ||
if (ret == 0) { | ||
break; | ||
} | ||
if (buf.kstack_len <= 0) { | ||
printf("Error getting kernel stack for task. Task Info. Pid: %d. Process Name: %s. Kernel Stack Error: %d. State: %s \n", | ||
buf.pid, buf.comm, buf.kstack_len, get_task_state(buf.state)); | ||
} else { | ||
printf("Task Info. Pid: %d. Process Name: %s. Kernel Stack Len: %d. State: %s \n", | ||
buf.pid, buf.comm, buf.kstack_len, get_task_state(buf.state)); | ||
} | ||
} | ||
|
||
cleanup: | ||
/* Clean up */ | ||
close(get_tasks_fd); | ||
task_iter_bpf__destroy(skel); | ||
|
||
return err < 0 ? -err : 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ | ||
/* Copyright (c) 2023 Meta */ | ||
|
||
#define TASK_COMM_LEN 16 | ||
#define MAX_STACK_LEN 127 | ||
|
||
struct task_info { | ||
pid_t pid; | ||
pid_t tid; | ||
__u32 state; | ||
char comm[TASK_COMM_LEN]; | ||
|
||
int kstack_len; | ||
|
||
__u64 kstack[MAX_STACK_LEN]; | ||
}; |