@@ -9021,6 +9021,7 @@ struct bpf_link_perf {
9021
9021
};
9022
9022
9023
9023
static int remove_kprobe_event_legacy (const char * probe_name , bool retprobe );
9024
+ static int remove_uprobe_event_legacy (const char * probe_name , bool retprobe );
9024
9025
9025
9026
static int bpf_link_perf_detach (struct bpf_link * link )
9026
9027
{
@@ -9034,11 +9035,14 @@ static int bpf_link_perf_detach(struct bpf_link *link)
9034
9035
close (perf_link -> perf_event_fd );
9035
9036
close (link -> fd );
9036
9037
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 */
9038
9039
if (perf_link -> legacy_probe_name ) {
9039
9040
if (perf_link -> legacy_is_kprobe ) {
9040
9041
err = remove_kprobe_event_legacy (perf_link -> legacy_probe_name ,
9041
9042
perf_link -> legacy_is_retprobe );
9043
+ } else {
9044
+ err = remove_uprobe_event_legacy (perf_link -> legacy_probe_name ,
9045
+ perf_link -> legacy_is_retprobe );
9042
9046
}
9043
9047
}
9044
9048
@@ -9450,17 +9454,96 @@ static struct bpf_link *attach_kprobe(const struct bpf_program *prog)
9450
9454
return link ;
9451
9455
}
9452
9456
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
+
9453
9536
LIBBPF_API struct bpf_link *
9454
9537
bpf_program__attach_uprobe_opts (const struct bpf_program * prog , pid_t pid ,
9455
9538
const char * binary_path , size_t func_offset ,
9456
9539
const struct bpf_uprobe_opts * opts )
9457
9540
{
9458
9541
DECLARE_LIBBPF_OPTS (bpf_perf_event_opts , pe_opts );
9459
- char errmsg [STRERR_BUFSIZE ];
9542
+ char errmsg [STRERR_BUFSIZE ], * legacy_probe = NULL ;
9460
9543
struct bpf_link * link ;
9461
9544
size_t ref_ctr_off ;
9462
9545
int pfd , err ;
9463
- bool retprobe ;
9546
+ bool retprobe , legacy ;
9464
9547
9465
9548
if (!OPTS_VALID (opts , bpf_uprobe_opts ))
9466
9549
return libbpf_err_ptr (- EINVAL );
@@ -9469,15 +9552,35 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid,
9469
9552
ref_ctr_off = OPTS_GET (opts , ref_ctr_offset , 0 );
9470
9553
pe_opts .bpf_cookie = OPTS_GET (opts , bpf_cookie , 0 );
9471
9554
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
+ }
9474
9575
if (pfd < 0 ) {
9576
+ err = - errno ;
9475
9577
pr_warn ("prog '%s': failed to create %s '%s:0x%zx' perf event: %s\n" ,
9476
9578
prog -> name , retprobe ? "uretprobe" : "uprobe" ,
9477
9579
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 ;
9480
9582
}
9583
+
9481
9584
link = bpf_program__attach_perf_event_opts (prog , pfd , & pe_opts );
9482
9585
err = libbpf_get_error (link );
9483
9586
if (err ) {
@@ -9486,9 +9589,20 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid,
9486
9589
prog -> name , retprobe ? "uretprobe" : "uprobe" ,
9487
9590
binary_path , func_offset ,
9488
9591
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 ;
9490
9600
}
9491
9601
return link ;
9602
+ err_out :
9603
+ free (legacy_probe );
9604
+ return libbpf_err_ptr (err );
9605
+
9492
9606
}
9493
9607
9494
9608
struct bpf_link * bpf_program__attach_uprobe (const struct bpf_program * prog ,
0 commit comments