44
55#ifdef __x86_64__
66
7+ #define _GNU_SOURCE
8+ #include <sched.h>
79#include <unistd.h>
810#include <asm/ptrace.h>
911#include <linux/compiler.h>
@@ -936,6 +938,88 @@ static void test_uprobe_error(void)
936938 ASSERT_EQ (errno , EPROTO , "errno" );
937939}
938940
941+ __attribute__((aligned (16 )))
942+ __nocf_check __weak __naked void uprobe_fork_test (void )
943+ {
944+ asm volatile (
945+ ".byte 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00\n" /* nop10 */
946+ "ret\n"
947+ );
948+ }
949+
950+ static int child_func (void * arg )
951+ {
952+ struct uprobe_syscall_executed * skel = arg ;
953+
954+ /* Make sure the child's probe is still there and optimized.. */
955+ if (memcmp (uprobe_fork_test , lea_rsp , sizeof (lea_rsp )))
956+ _exit (1 );
957+
958+ skel -> bss -> pid = getpid ();
959+
960+ /* .. and it executes properly. */
961+ uprobe_fork_test ();
962+
963+ if (skel -> bss -> executed != 3 )
964+ _exit (2 );
965+
966+ _exit (0 );
967+ }
968+
969+ static void test_uprobe_fork_optimized (bool clone_vm )
970+ {
971+ struct uprobe_syscall_executed * skel = NULL ;
972+ struct bpf_link * link = NULL ;
973+ unsigned long offset ;
974+ int pid , status , err ;
975+ char stack [65535 ];
976+
977+ offset = get_uprobe_offset (& uprobe_fork_test );
978+ if (!ASSERT_GE (offset , 0 , "get_uprobe_offset" ))
979+ return ;
980+
981+ skel = uprobe_syscall_executed__open_and_load ();
982+ if (!ASSERT_OK_PTR (skel , "open_and_load" ))
983+ goto cleanup ;
984+
985+ link = bpf_program__attach_uprobe_opts (skel -> progs .test_uprobe ,
986+ -1 , "/proc/self/exe" , offset , NULL );
987+ if (!ASSERT_OK_PTR (link , "attach_uprobe" ))
988+ goto cleanup ;
989+
990+ skel -> bss -> pid = getpid ();
991+
992+ /* Trigger optimization of uprobe in uprobe_fork_test. */
993+ uprobe_fork_test ();
994+ uprobe_fork_test ();
995+
996+ /* Make sure it got optimied. */
997+ if (!ASSERT_OK (memcmp (uprobe_fork_test , lea_rsp , sizeof (lea_rsp )), "optimized" ))
998+ goto cleanup ;
999+
1000+ if (clone_vm ) {
1001+ pid = clone (child_func , stack + sizeof (stack ), CLONE_VM |SIGCHLD , skel );
1002+ if (!ASSERT_GT (pid , 0 , "clone" ))
1003+ goto cleanup ;
1004+ } else {
1005+ pid = fork ();
1006+ if (!ASSERT_GE (pid , 0 , "fork" ))
1007+ goto cleanup ;
1008+ if (pid == 0 )
1009+ child_func (skel );
1010+ }
1011+
1012+ /* Wait for the child and verify it exited properly with 0. */
1013+ err = waitpid (pid , & status , 0 );
1014+ if (ASSERT_EQ (err , pid , "waitpid" )) {
1015+ ASSERT_EQ (WIFEXITED (status ), 1 , "child_exited" );
1016+ ASSERT_EQ (WEXITSTATUS (status ), 0 , "child_exit_code" );
1017+ }
1018+
1019+ cleanup :
1020+ uprobe_syscall_executed__destroy (skel );
1021+ }
1022+
9391023static void __test_uprobe_syscall (void )
9401024{
9411025 if (test__start_subtest ("uretprobe_regs_equal" ))
@@ -956,6 +1040,10 @@ static void __test_uprobe_syscall(void)
9561040 test_uprobe_race ();
9571041 if (test__start_subtest ("uprobe_red_zone" ))
9581042 test_uprobe_red_zone ();
1043+ if (test__start_subtest ("uprobe_optimized_fork" ))
1044+ test_uprobe_fork_optimized (false);
1045+ if (test__start_subtest ("uprobe_optimized_clone_vm" ))
1046+ test_uprobe_fork_optimized (true);
9591047 if (test__start_subtest ("uprobe_error" ))
9601048 test_uprobe_error ();
9611049 if (test__start_subtest ("uprobe_regs_equal" ))
0 commit comments