@@ -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