@@ -9021,6 +9021,7 @@ struct bpf_link_perf {
90219021};
90229022
90239023static  int  remove_kprobe_event_legacy (const  char  * probe_name , bool  retprobe );
9024+ static  int  remove_uprobe_event_legacy (const  char  * probe_name , bool  retprobe );
90249025
90259026static  int  bpf_link_perf_detach (struct  bpf_link  * link )
90269027{
@@ -9034,11 +9035,14 @@ static int bpf_link_perf_detach(struct bpf_link *link)
90349035		close (perf_link -> perf_event_fd );
90359036	close (link -> fd );
90369037
9037- 	/* legacy kprobe needs to be removed after perf event fd closure */ 
9038+ 	/* legacy uprobe/ kprobe needs to be removed after perf event fd closure */ 
90389039	if  (perf_link -> legacy_probe_name ) {
90399040		if  (perf_link -> legacy_is_kprobe ) {
90409041			err  =  remove_kprobe_event_legacy (perf_link -> legacy_probe_name ,
90419042							 perf_link -> legacy_is_retprobe );
9043+ 		} else  {
9044+ 			err  =  remove_uprobe_event_legacy (perf_link -> legacy_probe_name ,
9045+ 							 perf_link -> legacy_is_retprobe );
90429046		}
90439047	}
90449048
@@ -9450,17 +9454,96 @@ static struct bpf_link *attach_kprobe(const struct bpf_program *prog)
94509454	return  link ;
94519455}
94529456
9457+ static  void  gen_uprobe_legacy_event_name (char  * buf , size_t  buf_sz ,
9458+ 					 const  char  * binary_path , uint64_t  offset )
9459+ {
9460+ 	int  i ;
9461+ 
9462+ 	snprintf (buf , buf_sz , "libbpf_%u_%s_0x%zx" , getpid (), binary_path , (size_t )offset );
9463+ 
9464+ 	/* sanitize binary_path in the probe name */ 
9465+ 	for  (i  =  0 ; buf [i ]; i ++ ) {
9466+ 		if  (!isalnum (buf [i ]))
9467+ 			buf [i ] =  '_' ;
9468+ 	}
9469+ }
9470+ 
9471+ static  inline  int  add_uprobe_event_legacy (const  char  * probe_name , bool  retprobe ,
9472+ 					  const  char  * binary_path , size_t  offset )
9473+ {
9474+ 	const  char  * file  =  "/sys/kernel/debug/tracing/uprobe_events" ;
9475+ 
9476+ 	return  append_to_file (file , "%c:%s/%s %s:0x%zx" ,
9477+ 			      retprobe  ? 'r'  : 'p' ,
9478+ 			      retprobe  ? "uretprobes"  : "uprobes" ,
9479+ 			      probe_name , binary_path , offset );
9480+ }
9481+ 
9482+ static  inline  int  remove_uprobe_event_legacy (const  char  * probe_name , bool  retprobe )
9483+ {
9484+ 	const  char  * file  =  "/sys/kernel/debug/tracing/uprobe_events" ;
9485+ 
9486+ 	return  append_to_file (file , "-:%s/%s" , retprobe  ? "uretprobes"  : "uprobes" , probe_name );
9487+ }
9488+ 
9489+ static  int  determine_uprobe_perf_type_legacy (const  char  * probe_name , bool  retprobe )
9490+ {
9491+ 	char  file [512 ];
9492+ 
9493+ 	snprintf (file , sizeof (file ),
9494+ 		 "/sys/kernel/debug/tracing/events/%s/%s/id" ,
9495+ 		 retprobe  ? "uretprobes"  : "uprobes" , probe_name );
9496+ 
9497+ 	return  parse_uint_from_file (file , "%d\n" );
9498+ }
9499+ 
9500+ static  int  perf_event_uprobe_open_legacy (const  char  * probe_name , bool  retprobe ,
9501+ 					 const  char  * binary_path , size_t  offset , int  pid )
9502+ {
9503+ 	struct  perf_event_attr  attr ;
9504+ 	int  type , pfd , err ;
9505+ 
9506+ 	err  =  add_uprobe_event_legacy (probe_name , retprobe , binary_path , offset );
9507+ 	if  (err  <  0 ) {
9508+ 		pr_warn ("failed to add legacy uprobe event for %s:0x%zx: %d\n" ,
9509+ 			binary_path , (size_t )offset , err );
9510+ 		return  err ;
9511+ 	}
9512+ 	type  =  determine_uprobe_perf_type_legacy (probe_name , retprobe );
9513+ 	if  (type  <  0 ) {
9514+ 		pr_warn ("failed to determine legacy uprobe event id for %s:0x%zx: %d\n" ,
9515+ 			binary_path , offset , err );
9516+ 		return  type ;
9517+ 	}
9518+ 
9519+ 	memset (& attr , 0 , sizeof (attr ));
9520+ 	attr .size  =  sizeof (attr );
9521+ 	attr .config  =  type ;
9522+ 	attr .type  =  PERF_TYPE_TRACEPOINT ;
9523+ 
9524+ 	pfd  =  syscall (__NR_perf_event_open , & attr ,
9525+ 		      pid  <  0  ? -1  : pid , /* pid */ 
9526+ 		      pid  ==  -1  ? 0  : -1 , /* cpu */ 
9527+ 		      -1  /* group_fd */ ,  PERF_FLAG_FD_CLOEXEC );
9528+ 	if  (pfd  <  0 ) {
9529+ 		err  =  - errno ;
9530+ 		pr_warn ("legacy uprobe perf_event_open() failed: %d\n" , err );
9531+ 		return  err ;
9532+ 	}
9533+ 	return  pfd ;
9534+ }
9535+ 
94539536LIBBPF_API  struct  bpf_link  * 
94549537bpf_program__attach_uprobe_opts (const  struct  bpf_program  * prog , pid_t  pid ,
94559538				const  char  * binary_path , size_t  func_offset ,
94569539				const  struct  bpf_uprobe_opts  * opts )
94579540{
94589541	DECLARE_LIBBPF_OPTS (bpf_perf_event_opts , pe_opts );
9459- 	char  errmsg [STRERR_BUFSIZE ];
9542+ 	char  errmsg [STRERR_BUFSIZE ],  * legacy_probe   =   NULL ;
94609543	struct  bpf_link  * link ;
94619544	size_t  ref_ctr_off ;
94629545	int  pfd , err ;
9463- 	bool  retprobe ;
9546+ 	bool  retprobe ,  legacy ;
94649547
94659548	if  (!OPTS_VALID (opts , bpf_uprobe_opts ))
94669549		return  libbpf_err_ptr (- EINVAL );
@@ -9469,15 +9552,35 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid,
94699552	ref_ctr_off  =  OPTS_GET (opts , ref_ctr_offset , 0 );
94709553	pe_opts .bpf_cookie  =  OPTS_GET (opts , bpf_cookie , 0 );
94719554
9472- 	pfd  =  perf_event_open_probe (true /* uprobe */ , retprobe , binary_path ,
9473- 				    func_offset , pid , ref_ctr_off );
9555+ 	legacy  =  determine_uprobe_perf_type () <  0 ;
9556+ 	if  (!legacy ) {
9557+ 		pfd  =  perf_event_open_probe (true /* uprobe */ , retprobe , binary_path ,
9558+ 					    func_offset , pid , ref_ctr_off );
9559+ 	} else  {
9560+ 		char  probe_name [512 ];
9561+ 
9562+ 		if  (ref_ctr_off )
9563+ 			return  libbpf_err_ptr (- EINVAL );
9564+ 
9565+ 		gen_uprobe_legacy_event_name (probe_name , sizeof (probe_name ),
9566+ 					     binary_path , func_offset );
9567+ 
9568+ 		legacy_probe  =  strdup (probe_name );
9569+ 		if  (!legacy_probe )
9570+ 			return  libbpf_err_ptr (- ENOMEM );
9571+ 
9572+ 		pfd  =  perf_event_uprobe_open_legacy (legacy_probe , retprobe ,
9573+ 						    binary_path , func_offset , pid );
9574+ 	}
94749575	if  (pfd  <  0 ) {
9576+ 		err  =  - errno ;
94759577		pr_warn ("prog '%s': failed to create %s '%s:0x%zx' perf event: %s\n" ,
94769578			prog -> name , retprobe  ? "uretprobe"  : "uprobe" ,
94779579			binary_path , func_offset ,
9478- 			libbpf_strerror_r (pfd , errmsg , sizeof (errmsg )));
9479- 		return   libbpf_err_ptr ( pfd ) ;
9580+ 			libbpf_strerror_r (err , errmsg , sizeof (errmsg )));
9581+ 		goto  err_out ;
94809582	}
9583+ 
94819584	link  =  bpf_program__attach_perf_event_opts (prog , pfd , & pe_opts );
94829585	err  =  libbpf_get_error (link );
94839586	if  (err ) {
@@ -9486,9 +9589,20 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid,
94869589			prog -> name , retprobe  ? "uretprobe"  : "uprobe" ,
94879590			binary_path , func_offset ,
94889591			libbpf_strerror_r (err , errmsg , sizeof (errmsg )));
9489- 		return  libbpf_err_ptr (err );
9592+ 		goto err_out ;
9593+ 	}
9594+ 	if  (legacy ) {
9595+ 		struct  bpf_link_perf  * perf_link  =  container_of (link , struct  bpf_link_perf , link );
9596+ 
9597+ 		perf_link -> legacy_probe_name  =  legacy_probe ;
9598+ 		perf_link -> legacy_is_kprobe  =  false;
9599+ 		perf_link -> legacy_is_retprobe  =  retprobe ;
94909600	}
94919601	return  link ;
9602+ err_out :
9603+ 	free (legacy_probe );
9604+ 	return  libbpf_err_ptr (err );
9605+ 
94929606}
94939607
94949608struct  bpf_link  * bpf_program__attach_uprobe (const  struct  bpf_program  * prog ,
0 commit comments