1212
1313#include "../include/bpftimeruntime.h"
1414
15+
16+ // 线程参数映射
17+ struct {
18+ __uint (type , BPF_MAP_TYPE_HASH );
19+ __uint (max_entries , 10240 );
20+ __type (key , u64 ); // pid_tgid
21+ __type (value , struct thread_create_args );
22+ } thread_create_args_map SEC (".maps" );
23+
1524struct {
16- __uint (type , BPF_MAP_TYPE_HASH );
17- __uint (max_entries , 100000 );
18- __type (key , u64 );
19- __type (value , struct alloc_info );
25+ __uint (type , BPF_MAP_TYPE_HASH );
26+ __uint (max_entries , 100000 );
27+ __type (key , u64 );
28+ __type (value , struct alloc_info );
2029} allocs_map SEC (".maps" );
2130
2231struct {
23- __uint (type , BPF_MAP_TYPE_HASH );
24- __uint (max_entries , 10240 );
25- __type (key , u32 );
26- __type (value , struct mem_stats );
32+ __uint (type , BPF_MAP_TYPE_HASH );
33+ __uint (max_entries , 10240 );
34+ __type (key , u32 );
35+ __type (value , struct mem_stats );
2736} stats_map SEC (".maps" );
2837
2938// 存储线程信息的 map
3039struct {
31- __uint (type , BPF_MAP_TYPE_HASH );
32- __uint (max_entries , 102400 );
33- __type (key , u32 ); // tid as key
34- __type (value , struct proc_info );
40+ __uint (type , BPF_MAP_TYPE_HASH );
41+ __uint (max_entries , 102400 );
42+ __type (key , u32 ); // tid as key
43+ __type (value , struct proc_info );
3544} thread_map SEC (".maps" );
3645
3746struct {
38- __uint (type , BPF_MAP_TYPE_HASH );
39- __uint (max_entries , 10240 );
40- __type (key , u32 );
41- __type (value , struct proc_info );
47+ __uint (type , BPF_MAP_TYPE_HASH );
48+ __uint (max_entries , 10240 );
49+ __type (key , u32 );
50+ __type (value , struct proc_info );
4251} process_map SEC (".maps" );
4352
4453// 用于处理多线程同步的自旋锁映射
4554struct {
46- __uint (type , BPF_MAP_TYPE_HASH );
47- __uint (max_entries , 10240 );
48- __type (key , u32 );
49- __type (value , u32 );
55+ __uint (type , BPF_MAP_TYPE_HASH );
56+ __uint (max_entries , 10240 );
57+ __type (key , u32 );
58+ __type (value , u32 );
5059} locks SEC (".maps" );
5160// 钩住OpenMP并行区域创建函数
52- SEC ("uprobe//usr/lib/x86_64-linux-gnu/libgomp.so.1:GOMP_parallel" )
53- int uprobe_omp_parallel (struct pt_regs * ctx ) {
54- u64 pid_tgid = bpf_get_current_pid_tgid ();
55- u32 pid = pid_tgid >> 32 ;
56- void * fn = (void * )PT_REGS_PARM1 (ctx ); // 并行区域函数指针
57- void * data = (void * )PT_REGS_PARM2 (ctx ); // 用户数据指针
58- unsigned num_threads = (unsigned )PT_REGS_PARM3 (ctx ); // 线程数量
59-
60- // 更新进程信息中的线程计数
61- struct proc_info * proc_info = bpf_map_lookup_elem (& process_map , & pid );
62- if (proc_info ) {
63- proc_info -> thread_count += num_threads ;
64- bpf_map_update_elem (& process_map , & pid , proc_info , BPF_ANY );
65- }
66-
67- return 0 ;
68- }
69-
70- // 钩住GOMP_single_start函数 - 用于single构造
71- SEC ("uprobe//usr/lib/x86_64-linux-gnu/libgomp.so.1:GOMP_single_start" )
72- int uprobe_omp_single_start (struct pt_regs * ctx ) {
73- u64 pid_tgid = bpf_get_current_pid_tgid ();
74- u32 pid = pid_tgid >> 32 ;
75- u32 tid = (u32 )pid_tgid ;
76- // 返回值表示该线程是否执行single区域
77- return 0 ;
78- }
79-
80- // 钩住GOMP_single_start的返回值
81- SEC ("uretprobe//usr/lib/x86_64-linux-gnu/libgomp.so.1:GOMP_single_start" )
82- int uretprobe_omp_single_start (struct pt_regs * ctx ) {
83- u64 pid_tgid = bpf_get_current_pid_tgid ();
84- u32 pid = pid_tgid >> 32 ;
85- u32 tid = (u32 )pid_tgid ;
86- bool is_selected = (bool )PT_REGS_RC (ctx );
87-
88-
89- return 0 ;
90- }
91-
92- // OpenMP临界区钩子
93- SEC ("uprobe//usr/lib/x86_64-linux-gnu/libgomp.so.1:GOMP_critical_start" )
94- int uprobe_omp_critical_start (struct pt_regs * ctx ) {
95- u64 pid_tgid = bpf_get_current_pid_tgid ();
96- u32 pid = pid_tgid >> 32 ;
97- u32 tid = (u32 )pid_tgid ;
98-
99-
100- // 记录线程进入临界区
101- u32 locked = 1 ;
102- bpf_map_update_elem (& locks , & tid , & locked , BPF_ANY );
103-
104- struct proc_info * item = bpf_map_lookup_elem (& thread_map , & tid );
105- if (item ) {
106- item -> is_locked = 1 ;
107- bpf_map_update_elem (& thread_map , & tid , item , BPF_ANY );
108- }
109-
110- return 0 ;
111- }
112-
113- SEC ("uprobe//usr/lib/x86_64-linux-gnu/libgomp.so.1:GOMP_critical_end" )
114- int uprobe_omp_critical_end (struct pt_regs * ctx ) {
115- u64 pid_tgid = bpf_get_current_pid_tgid ();
116- u32 pid = pid_tgid >> 32 ;
117- u32 tid = (u32 )pid_tgid ;
118-
119-
120- // 记录线程离开临界区
121- u32 locked = 0 ;
122- bpf_map_update_elem (& locks , & tid , & locked , BPF_ANY );
123-
124- struct proc_info * item = bpf_map_lookup_elem (& thread_map , & tid );
125- if (item ) {
126- item -> is_locked = 0 ;
127- bpf_map_update_elem (& thread_map , & tid , item , BPF_ANY );
128- }
129-
130- return 0 ;
131- }
132-
133- // OpenMP屏障同步点
134- SEC ("uprobe//usr/lib/x86_64-linux-gnu/libgomp.so.1:GOMP_barrier" )
135- int uprobe_omp_barrier (struct pt_regs * ctx ) {
136- u64 pid_tgid = bpf_get_current_pid_tgid ();
137- u32 pid = pid_tgid >> 32 ;
138- u32 tid = (u32 )pid_tgid ;
139-
140-
141- return 0 ;
142- }
143-
144- // 线程同步:获取OpenMP锁
145- SEC ("uprobe//usr/lib/x86_64-linux-gnu/libgomp.so.1:omp_set_lock" )
146- int uprobe_omp_set_lock (struct pt_regs * ctx ) {
147- u64 pid_tgid = bpf_get_current_pid_tgid ();
148- u32 pid = pid_tgid >> 32 ;
149- u32 tid = (u32 )pid_tgid ;
150- void * lock = (void * )PT_REGS_PARM1 (ctx );
151-
152-
153- // 记录线程获取锁
154- u32 locked = 1 ;
155- bpf_map_update_elem (& locks , & tid , & locked , BPF_ANY );
156-
157- return 0 ;
158- }
159-
160- // 线程同步:释放OpenMP锁
161- SEC ("uprobe//usr/lib/x86_64-linux-gnu/libgomp.so.1:omp_unset_lock" )
162- int uprobe_omp_unset_lock (struct pt_regs * ctx ) {
163- u64 pid_tgid = bpf_get_current_pid_tgid ();
164- u32 pid = pid_tgid >> 32 ;
165- u32 tid = (u32 )pid_tgid ;
166- void * lock = (void * )PT_REGS_PARM1 (ctx );
167-
168-
169- // 记录线程释放锁
170- u32 locked = 0 ;
171- bpf_map_update_elem (& locks , & tid , & locked , BPF_ANY );
172-
173- return 0 ;
174- }
175- // C++标准库线程创建函数的钩子
176- SEC ("uprobe//usr/lib/gcc/x86_64-linux-gnu/14/libstdc++.so:_ZNSt6thread15_M_start_threadESt10unique_ptrINS_6_StateESt14default_deleteIS1_EEPFvvE" )
177- int uprobe_cxx_thread_start (struct pt_regs * ctx ) {
178- u64 pid_tgid = bpf_get_current_pid_tgid ();
179- u32 pid = pid_tgid >> 32 ;
180- u32 tid = (u32 )pid_tgid ;
181-
182- // 获取函数参数(注意:在BPF中我们不能直接访问complex C++对象的内部)
183- // 我们只能获取到原始指针
184- void * thread_state_ptr = (void * )PT_REGS_PARM1 (ctx ); // unique_ptr参数
185- void * thread_func_ptr = (void * )PT_REGS_PARM2 (ctx ); // 函数指针参数
186-
187-
188- // 记录线程创建事件到临时映射,供返回探针使用
189- struct {
190- u32 parent_pid ;
191- u64 create_time ;
192- } thread_info = {
193- .parent_pid = pid ,
194- .create_time = bpf_ktime_get_ns (),
195- };
196-
197- bpf_map_update_elem (& allocs_map , & pid_tgid , & thread_info , BPF_ANY );
198-
199- return 0 ;
200- }
20161
202- // C++标准库线程创建函数的返回钩子
203- SEC ("uretprobe//usr/lib/gcc/x86_64-linux-gnu/14/libstdc++.so:_ZNSt6thread15_M_start_threadESt10unique_ptrINS_6_StateESt14default_deleteIS1_EEPFvvE" )
204- int uretprobe_cxx_thread_start (struct pt_regs * ctx ) {
205- u64 pid_tgid = bpf_get_current_pid_tgid ();
206- u32 pid = pid_tgid >> 32 ;
207-
208- // 获取之前保存的信息
209- void * thread_info_ptr = bpf_map_lookup_elem (& allocs_map , & pid_tgid );
210- if (!thread_info_ptr ) {
211- return 0 ;
212- }
213-
214- // 注意:C++线程创建函数不直接返回线程ID
215- // 需要在后续步骤中捕获(比如通过pthread_create的返回值)
216-
217- // 在这里,我们可以增加进程的线程计数
218- struct proc_info * proc_info = bpf_map_lookup_elem (& process_map , & pid );
219- if (proc_info ) {
220- proc_info -> thread_count ++ ;
221- bpf_map_update_elem (& process_map , & pid , proc_info , BPF_ANY );
222- }
223-
224- // 清理临时信息
225- bpf_map_delete_elem (& allocs_map , & pid_tgid );
226-
227- return 0 ;
228- }
22962// mmap的uprobe钩子
23063SEC ("uprobe//usr/lib/x86_64-linux-gnu/libc.so.6:mmap" )
23164int uprobe_mmap (struct pt_regs * ctx ) {
@@ -926,4 +759,90 @@ int uretprobe_pthread_mutex_trylock(struct pt_regs *ctx) {
926759
927760 return 0 ;
928761}
762+
763+ SEC ("uprobe//lib/x86_64-linux-gnu/libc.so.6:pthread_create" )
764+ int pthread_create_probe (struct pt_regs * ctx )
765+ {
766+ u64 pid_tgid = bpf_get_current_pid_tgid ();
767+ u32 pid = pid_tgid >> 32 ;
768+
769+ // 获取新线程的 ID(通过第一个参数)
770+ unsigned long * thread_ptr ;
771+ bpf_probe_read (& thread_ptr , sizeof (thread_ptr ),
772+ (void * )& PT_REGS_PARM1 (ctx ));
773+
774+
775+ if (thread_ptr ) {
776+ // 创建新的线程信息
777+ struct thread_create_args thread_info = {
778+ .thread_ptr = thread_ptr ,
779+ .attr = NULL ,
780+ .start_routine = NULL ,
781+ .arg = NULL ,
782+ };
783+ bpf_printk ("pthread_create_probe: pid: %d thread_ptr: %lx\n" , pid ,
784+ (unsigned long )thread_ptr );
785+ // 更新线程计数
786+ struct proc_info * parent_info =
787+ bpf_map_lookup_elem (& process_map , & pid );
788+ if (parent_info ) {
789+ // __sync_fetch_and_add(&parent_info->thread_count, 1);
790+ parent_info -> thread_count += 1 ;
791+ }
792+
793+ // 注意:我们需要在 return probe 中获取实际的线程 ID
794+ // 这里先保存父进程信息
795+ bpf_map_update_elem (& thread_create_args_map , & pid_tgid ,
796+ & thread_info , BPF_ANY );
797+ }
798+
799+ return 0 ;
800+ }
801+ SEC ("uretprobe//lib/x86_64-linux-gnu/libc.so.6:pthread_create" )
802+ int pthread_create_return_probe (struct pt_regs * ctx )
803+ {
804+ u64 pid_tgid = bpf_get_current_pid_tgid ();
805+ u32 pid = pid_tgid >> 32 ;
806+
807+ // 获取 pthread_create 的返回值
808+ int ret = PT_REGS_RC (ctx );
809+
810+ // 如果 pthread_create 成功(返回0)
811+ if (ret == 0 ) {
812+ struct thread_create_args * args =
813+ bpf_map_lookup_elem (& thread_create_args_map , & pid_tgid );
814+ if (args ) {
815+ // 获取线程指针
816+ void * * thread_ptrs = args -> thread_ptr ;
817+
818+ // 读取新创建的线程ID
819+ if (thread_ptrs ) {
820+ u64 thread_id = 0 ;
821+ // 正确读取 pthread_t 类型的值
822+ bpf_probe_read (& thread_id , sizeof (thread_id ), thread_ptrs );
823+
824+ if (thread_id != 0 ) {
825+ // 使用实际的线程ID更新信息
826+ struct proc_info updated_info ;
827+ updated_info .parent_pid = pid ;
828+ updated_info .current_pid = pid ;
829+ updated_info .current_tid = thread_id ;
830+ updated_info .create_time = bpf_ktime_get_ns ();
831+
832+ // 使用 %lu 或 %lx 格式打印无符号长整型
833+ bpf_printk ("pthread_create_return_probe: pid: %d thread_id: %lu (0x%lx)\n" ,
834+ pid , thread_id , thread_id );
835+
836+ // 将线程信息添加到进程映射中
837+ bpf_map_update_elem (& thread_map , & thread_id , & updated_info , BPF_ANY );
838+ }
839+ }
840+
841+ // 清理参数映射
842+ bpf_map_delete_elem (& thread_create_args_map , & pid_tgid );
843+ }
844+ }
845+
846+ return 0 ;
847+ }
929848char _license [] SEC ("license" ) = "GPL" ;
0 commit comments