1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2019 Facebook
3 #include <linux/sched.h>
4 #include <linux/ptrace.h>
9 #include <bpf/bpf_helpers.h>
11 #define FUNCTION_NAME_LEN 64
12 #define FILE_NAME_LEN 128
13 #define TASK_COMM_LEN 16
16 int PyThreadState_frame
;
17 int PyThreadState_thread
;
18 int PyFrameObject_back
;
19 int PyFrameObject_code
;
20 int PyFrameObject_lineno
;
21 int PyCodeObject_filename
;
22 int PyCodeObject_name
;
28 uintptr_t current_state_addr
;
29 uintptr_t tls_key_addr
;
39 char name
[FUNCTION_NAME_LEN
];
40 char file
[FILE_NAME_LEN
];
46 char comm
[TASK_COMM_LEN
];
47 int32_t kernel_stack_id
;
48 int32_t user_stack_id
;
53 int32_t stack
[STACK_MAX_LEN
];
64 void* f_back
; // PyFrameObject.f_back, previous frame
65 void* f_code
; // PyFrameObject.f_code, pointer to PyCodeObject
66 void* co_filename
; // PyCodeObject.co_filename
67 void* co_name
; // PyCodeObject.co_name
75 static void *get_thread_state(void *tls_base
, PidData
*pidData
)
80 bpf_probe_read_user(&key
, sizeof(key
), (void*)(long)pidData
->tls_key_addr
);
81 bpf_probe_read_user(&thread_state
, sizeof(thread_state
),
82 tls_base
+ 0x310 + key
* 0x10 + 0x08);
86 static __always_inline
bool get_frame_data(void *frame_ptr
, PidData
*pidData
,
87 FrameData
*frame
, Symbol
*symbol
)
89 // read data from PyFrameObject
90 bpf_probe_read_user(&frame
->f_back
,
91 sizeof(frame
->f_back
),
92 frame_ptr
+ pidData
->offsets
.PyFrameObject_back
);
93 bpf_probe_read_user(&frame
->f_code
,
94 sizeof(frame
->f_code
),
95 frame_ptr
+ pidData
->offsets
.PyFrameObject_code
);
97 // read data from PyCodeObject
100 bpf_probe_read_user(&frame
->co_filename
,
101 sizeof(frame
->co_filename
),
102 frame
->f_code
+ pidData
->offsets
.PyCodeObject_filename
);
103 bpf_probe_read_user(&frame
->co_name
,
104 sizeof(frame
->co_name
),
105 frame
->f_code
+ pidData
->offsets
.PyCodeObject_name
);
106 // read actual names into symbol
107 if (frame
->co_filename
)
108 bpf_probe_read_user_str(&symbol
->file
,
109 sizeof(symbol
->file
),
111 pidData
->offsets
.String_data
);
113 bpf_probe_read_user_str(&symbol
->name
,
114 sizeof(symbol
->name
),
116 pidData
->offsets
.String_data
);
121 __uint(type
, BPF_MAP_TYPE_HASH
);
122 __uint(max_entries
, 1);
124 __type(value
, PidData
);
125 } pidmap
SEC(".maps");
128 __uint(type
, BPF_MAP_TYPE_HASH
);
129 __uint(max_entries
, 1);
131 __type(value
, Event
);
132 } eventmap
SEC(".maps");
135 __uint(type
, BPF_MAP_TYPE_HASH
);
136 __uint(max_entries
, 1);
139 } symbolmap
SEC(".maps");
142 __uint(type
, BPF_MAP_TYPE_ARRAY
);
143 __uint(max_entries
, 1);
145 __type(value
, Stats
);
146 } statsmap
SEC(".maps");
149 __uint(type
, BPF_MAP_TYPE_PERF_EVENT_ARRAY
);
150 __uint(max_entries
, 32);
151 __uint(key_size
, sizeof(int));
152 __uint(value_size
, sizeof(int));
153 } perfmap
SEC(".maps");
156 __uint(type
, BPF_MAP_TYPE_STACK_TRACE
);
157 __uint(max_entries
, 1000);
158 __uint(key_size
, sizeof(int));
159 __uint(value_size
, sizeof(long long) * 127);
160 } stackmap
SEC(".maps");
164 #elif defined(SUBPROGS)
167 static __always_inline
169 int __on_event(struct bpf_raw_tracepoint_args
*ctx
)
171 uint64_t pid_tgid
= bpf_get_current_pid_tgid();
172 pid_t pid
= (pid_t
)(pid_tgid
>> 32);
173 PidData
* pidData
= bpf_map_lookup_elem(&pidmap
, &pid
);
178 Event
* event
= bpf_map_lookup_elem(&eventmap
, &zero
);
184 event
->tid
= (pid_t
)pid_tgid
;
185 bpf_get_current_comm(&event
->comm
, sizeof(event
->comm
));
187 event
->user_stack_id
= bpf_get_stackid(ctx
, &stackmap
, BPF_F_USER_STACK
);
188 event
->kernel_stack_id
= bpf_get_stackid(ctx
, &stackmap
, 0);
190 void* thread_state_current
= (void*)0;
191 bpf_probe_read_user(&thread_state_current
,
192 sizeof(thread_state_current
),
193 (void*)(long)pidData
->current_state_addr
);
195 struct task_struct
* task
= (struct task_struct
*)bpf_get_current_task();
196 void* tls_base
= (void*)task
;
198 void* thread_state
= pidData
->use_tls
? get_thread_state(tls_base
, pidData
)
199 : thread_state_current
;
200 event
->thread_current
= thread_state
== thread_state_current
;
202 if (pidData
->use_tls
) {
203 uint64_t pthread_created
;
204 uint64_t pthread_self
;
205 bpf_probe_read_user(&pthread_self
, sizeof(pthread_self
),
208 bpf_probe_read_user(&pthread_created
,
209 sizeof(pthread_created
),
211 pidData
->offsets
.PyThreadState_thread
);
212 event
->pthread_match
= pthread_created
== pthread_self
;
214 event
->pthread_match
= 1;
217 if (event
->pthread_match
|| !pidData
->use_tls
) {
221 int cur_cpu
= bpf_get_smp_processor_id();
223 bpf_probe_read_user(&frame_ptr
,
226 pidData
->offsets
.PyThreadState_frame
);
228 int32_t* symbol_counter
= bpf_map_lookup_elem(&symbolmap
, &sym
);
229 if (symbol_counter
== NULL
)
232 #pragma clang loop unroll(disable)
234 #pragma clang loop unroll(full)
236 /* Unwind python stack */
237 for (int i
= 0; i
< STACK_MAX_LEN
; ++i
) {
238 if (frame_ptr
&& get_frame_data(frame_ptr
, pidData
, &frame
, &sym
)) {
239 int32_t new_symbol_id
= *symbol_counter
* 64 + cur_cpu
;
240 int32_t *symbol_id
= bpf_map_lookup_elem(&symbolmap
, &sym
);
242 bpf_map_update_elem(&symbolmap
, &sym
, &zero
, 0);
243 symbol_id
= bpf_map_lookup_elem(&symbolmap
, &sym
);
247 if (*symbol_id
== new_symbol_id
)
249 event
->stack
[i
] = *symbol_id
;
250 event
->stack_len
= i
+ 1;
251 frame_ptr
= frame
.f_back
;
254 event
->stack_complete
= frame_ptr
== NULL
;
256 event
->stack_complete
= 1;
259 Stats
* stats
= bpf_map_lookup_elem(&statsmap
, &zero
);
264 bpf_perf_event_output(ctx
, &perfmap
, 0, event
, offsetof(Event
, metadata
));
268 SEC("raw_tracepoint/kfree_skb")
269 int on_event(struct bpf_raw_tracepoint_args
* ctx
)
272 ret
|= __on_event(ctx
);
273 ret
|= __on_event(ctx
);
274 ret
|= __on_event(ctx
);
275 ret
|= __on_event(ctx
);
276 ret
|= __on_event(ctx
);
280 char _license
[] SEC("license") = "GPL";