1 /*
2 * Copyright (c) Facebook, Inc.
3 * Licensed under the Apache License, Version 2.0 (the "License")
4 *
5 * Usage:
6 * ./TaskIterator
7 *
8 * BPF task iterator is available since linux 5.8.
9 * This example shows how to dump all threads in the system with
10 * bpf iterator. An example output likes below:
11 * tid comm
12 * 1 systemd
13 * 2 kthreadd
14 * 3 rcu_gp
15 * 4 rcu_par_gp
16 * 6 kworker/0:0H
17 * ...
18 * 2613386 sleep
19 * 2613474 GetCountersCPU6
20 * 2613587 GetCountersCPU7
21 * 2613621 CPUThreadPool69
22 * 2613906 GetCountersCPU5
23 * 2614140 GetCountersCPU2
24 * 2614193 CfgrExtension56
25 * 2614449 ruby-timer-thr
26 * 2614529 chef-client
27 * 2615122 systemd-hostnam
28 * ...
29 * 2608477 sudo
30 * 2608478 TaskIterator
31 */
32
33 #include <unistd.h>
34 #include <fstream>
35 #include <iostream>
36 #include <string>
37
38 #include "bcc_version.h"
39 #include "BPF.h"
40
41 const std::string BPF_PROGRAM = R"(
42 #include <linux/bpf.h>
43 #include <linux/seq_file.h>
44 #include <linux/sched.h>
45
46 /* the structure is defined in .c file, so explicitly define
47 * the structure here.
48 */
49 struct bpf_iter__task {
50 union {
51 struct bpf_iter_meta *meta;
52 };
53 union {
54 struct task_struct *task;
55 };
56 };
57
58 struct info_t {
59 int tid;
60 char comm[TASK_COMM_LEN];
61 };
62
63 BPF_ITER(task) {
64 struct seq_file *seq = ctx->meta->seq;
65 struct task_struct *task = ctx->task;
66 struct info_t info = {};
67
68 if (task == (void *)0)
69 return 0;
70
71 info.tid = task->pid;
72 __builtin_memcpy(&info.comm, task->comm, sizeof(info.comm));
73 bpf_seq_write(seq, &info, sizeof(info));
74
75 return 0;
76 }
77 )";
78
79 // linux/sched.h
80 #define TASK_COMM_LEN 16
81
82 struct info_t {
83 int tid;
84 char comm[TASK_COMM_LEN];
85 };
86
main()87 int main() {
88 ebpf::BPF bpf;
89 auto res = bpf.init(BPF_PROGRAM);
90 if (!res.ok()) {
91 std::cerr << res.msg() << std::endl;
92 return 1;
93 }
94
95 int prog_fd;
96 res = bpf.load_func("bpf_iter__task", BPF_PROG_TYPE_TRACING, prog_fd);
97 if (!res.ok()) {
98 std::cerr << res.msg() << std::endl;
99 return 1;
100 }
101
102 int link_fd = bcc_iter_attach(prog_fd, NULL, 0);
103 if (link_fd < 0) {
104 std::cerr << "bcc_iter_attach failed: " << link_fd << std::endl;
105 return 1;
106 }
107
108 int iter_fd = bcc_iter_create(link_fd);
109 if (iter_fd < 0) {
110 std::cerr << "bcc_iter_create failed: " << iter_fd << std::endl;
111 close(link_fd);
112 return 1;
113 }
114
115 // Header.
116 printf("tid\tcomm\n");
117
118 struct info_t info[20];
119 int len, leftover = 0, info_size = 20 * sizeof(struct info_t);
120 while ((len = read(iter_fd, (char *)info + leftover, info_size - leftover))) {
121 if (len < 0) {
122 if (len == -EAGAIN)
123 continue;
124 std::cerr << "read failed: " << len << std::endl;
125 break;
126 }
127
128 int num_info = len / sizeof(struct info_t);
129 for (int i = 0; i < num_info; i++) {
130 printf("%d\t%s\n", info[i].tid, info[i].comm);
131 }
132
133 leftover = len % sizeof(struct info_t);
134 if (num_info > 0)
135 memcpy(info, (void *)&info[num_info], leftover);
136 }
137
138 close(iter_fd);
139 close(link_fd);
140 return 0;
141 }
142