1*427c07ddSAlexei Starovoitov // SPDX-License-Identifier: GPL-2.0 2*427c07ddSAlexei Starovoitov /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ 3*427c07ddSAlexei Starovoitov 4*427c07ddSAlexei Starovoitov #include <linux/bpf.h> 5*427c07ddSAlexei Starovoitov #include <bpf/bpf_helpers.h> 6*427c07ddSAlexei Starovoitov #include "bpf_misc.h" 7*427c07ddSAlexei Starovoitov 8*427c07ddSAlexei Starovoitov /* linear chain main -> A -> B */ 9*427c07ddSAlexei Starovoitov __naked __noinline __used 10*427c07ddSAlexei Starovoitov static unsigned long linear_b(void) 11*427c07ddSAlexei Starovoitov { 12*427c07ddSAlexei Starovoitov asm volatile ( 13*427c07ddSAlexei Starovoitov "r0 = 42;" 14*427c07ddSAlexei Starovoitov "exit;" 15*427c07ddSAlexei Starovoitov ); 16*427c07ddSAlexei Starovoitov } 17*427c07ddSAlexei Starovoitov 18*427c07ddSAlexei Starovoitov __naked __noinline __used 19*427c07ddSAlexei Starovoitov static unsigned long linear_a(void) 20*427c07ddSAlexei Starovoitov { 21*427c07ddSAlexei Starovoitov asm volatile ( 22*427c07ddSAlexei Starovoitov "call linear_b;" 23*427c07ddSAlexei Starovoitov "exit;" 24*427c07ddSAlexei Starovoitov ); 25*427c07ddSAlexei Starovoitov } 26*427c07ddSAlexei Starovoitov 27*427c07ddSAlexei Starovoitov SEC("?raw_tp") 28*427c07ddSAlexei Starovoitov __success __log_level(2) 29*427c07ddSAlexei Starovoitov __msg("topo_order[0] = linear_b") 30*427c07ddSAlexei Starovoitov __msg("topo_order[1] = linear_a") 31*427c07ddSAlexei Starovoitov __msg("topo_order[2] = topo_linear") 32*427c07ddSAlexei Starovoitov __naked int topo_linear(void) 33*427c07ddSAlexei Starovoitov { 34*427c07ddSAlexei Starovoitov asm volatile ( 35*427c07ddSAlexei Starovoitov "call linear_a;" 36*427c07ddSAlexei Starovoitov "exit;" 37*427c07ddSAlexei Starovoitov ); 38*427c07ddSAlexei Starovoitov } 39*427c07ddSAlexei Starovoitov 40*427c07ddSAlexei Starovoitov /* diamond main -> A, main -> B, A -> C, B -> C */ 41*427c07ddSAlexei Starovoitov __naked __noinline __used 42*427c07ddSAlexei Starovoitov static unsigned long diamond_c(void) 43*427c07ddSAlexei Starovoitov { 44*427c07ddSAlexei Starovoitov asm volatile ( 45*427c07ddSAlexei Starovoitov "r0 = 1;" 46*427c07ddSAlexei Starovoitov "exit;" 47*427c07ddSAlexei Starovoitov ); 48*427c07ddSAlexei Starovoitov } 49*427c07ddSAlexei Starovoitov 50*427c07ddSAlexei Starovoitov __naked __noinline __used 51*427c07ddSAlexei Starovoitov static unsigned long diamond_b(void) 52*427c07ddSAlexei Starovoitov { 53*427c07ddSAlexei Starovoitov asm volatile ( 54*427c07ddSAlexei Starovoitov "call diamond_c;" 55*427c07ddSAlexei Starovoitov "exit;" 56*427c07ddSAlexei Starovoitov ); 57*427c07ddSAlexei Starovoitov } 58*427c07ddSAlexei Starovoitov 59*427c07ddSAlexei Starovoitov __naked __noinline __used 60*427c07ddSAlexei Starovoitov static unsigned long diamond_a(void) 61*427c07ddSAlexei Starovoitov { 62*427c07ddSAlexei Starovoitov asm volatile ( 63*427c07ddSAlexei Starovoitov "call diamond_c;" 64*427c07ddSAlexei Starovoitov "exit;" 65*427c07ddSAlexei Starovoitov ); 66*427c07ddSAlexei Starovoitov } 67*427c07ddSAlexei Starovoitov 68*427c07ddSAlexei Starovoitov SEC("?raw_tp") 69*427c07ddSAlexei Starovoitov __success __log_level(2) 70*427c07ddSAlexei Starovoitov __msg("topo_order[0] = diamond_c") 71*427c07ddSAlexei Starovoitov __msg("topo_order[3] = topo_diamond") 72*427c07ddSAlexei Starovoitov __naked int topo_diamond(void) 73*427c07ddSAlexei Starovoitov { 74*427c07ddSAlexei Starovoitov asm volatile ( 75*427c07ddSAlexei Starovoitov "call diamond_a;" 76*427c07ddSAlexei Starovoitov "call diamond_b;" 77*427c07ddSAlexei Starovoitov "exit;" 78*427c07ddSAlexei Starovoitov ); 79*427c07ddSAlexei Starovoitov } 80*427c07ddSAlexei Starovoitov 81*427c07ddSAlexei Starovoitov /* main -> global_a (global) -> static_leaf (static, leaf) */ 82*427c07ddSAlexei Starovoitov __naked __noinline __used 83*427c07ddSAlexei Starovoitov static unsigned long static_leaf(void) 84*427c07ddSAlexei Starovoitov { 85*427c07ddSAlexei Starovoitov asm volatile ( 86*427c07ddSAlexei Starovoitov "r0 = 7;" 87*427c07ddSAlexei Starovoitov "exit;" 88*427c07ddSAlexei Starovoitov ); 89*427c07ddSAlexei Starovoitov } 90*427c07ddSAlexei Starovoitov 91*427c07ddSAlexei Starovoitov __noinline __used 92*427c07ddSAlexei Starovoitov int global_a(int x) 93*427c07ddSAlexei Starovoitov { 94*427c07ddSAlexei Starovoitov return static_leaf(); 95*427c07ddSAlexei Starovoitov } 96*427c07ddSAlexei Starovoitov 97*427c07ddSAlexei Starovoitov SEC("?raw_tp") 98*427c07ddSAlexei Starovoitov __success __log_level(2) 99*427c07ddSAlexei Starovoitov __msg("topo_order[0] = static_leaf") 100*427c07ddSAlexei Starovoitov __msg("topo_order[1] = global_a") 101*427c07ddSAlexei Starovoitov __msg("topo_order[2] = topo_mixed") 102*427c07ddSAlexei Starovoitov __naked int topo_mixed(void) 103*427c07ddSAlexei Starovoitov { 104*427c07ddSAlexei Starovoitov asm volatile ( 105*427c07ddSAlexei Starovoitov "r1 = 0;" 106*427c07ddSAlexei Starovoitov "call global_a;" 107*427c07ddSAlexei Starovoitov "exit;" 108*427c07ddSAlexei Starovoitov ); 109*427c07ddSAlexei Starovoitov } 110*427c07ddSAlexei Starovoitov 111*427c07ddSAlexei Starovoitov /* 112*427c07ddSAlexei Starovoitov * shared static callee from global and main: 113*427c07ddSAlexei Starovoitov * main -> shared_leaf (static) 114*427c07ddSAlexei Starovoitov * main -> global_b (global) -> shared_leaf (static) 115*427c07ddSAlexei Starovoitov */ 116*427c07ddSAlexei Starovoitov __naked __noinline __used 117*427c07ddSAlexei Starovoitov static unsigned long shared_leaf(void) 118*427c07ddSAlexei Starovoitov { 119*427c07ddSAlexei Starovoitov asm volatile ( 120*427c07ddSAlexei Starovoitov "r0 = 99;" 121*427c07ddSAlexei Starovoitov "exit;" 122*427c07ddSAlexei Starovoitov ); 123*427c07ddSAlexei Starovoitov } 124*427c07ddSAlexei Starovoitov 125*427c07ddSAlexei Starovoitov __noinline __used 126*427c07ddSAlexei Starovoitov int global_b(int x) 127*427c07ddSAlexei Starovoitov { 128*427c07ddSAlexei Starovoitov return shared_leaf(); 129*427c07ddSAlexei Starovoitov } 130*427c07ddSAlexei Starovoitov 131*427c07ddSAlexei Starovoitov SEC("?raw_tp") 132*427c07ddSAlexei Starovoitov __success __log_level(2) 133*427c07ddSAlexei Starovoitov __msg("topo_order[0] = shared_leaf") 134*427c07ddSAlexei Starovoitov __msg("topo_order[1] = global_b") 135*427c07ddSAlexei Starovoitov __msg("topo_order[2] = topo_shared") 136*427c07ddSAlexei Starovoitov __naked int topo_shared(void) 137*427c07ddSAlexei Starovoitov { 138*427c07ddSAlexei Starovoitov asm volatile ( 139*427c07ddSAlexei Starovoitov "call shared_leaf;" 140*427c07ddSAlexei Starovoitov "r1 = 0;" 141*427c07ddSAlexei Starovoitov "call global_b;" 142*427c07ddSAlexei Starovoitov "exit;" 143*427c07ddSAlexei Starovoitov ); 144*427c07ddSAlexei Starovoitov } 145*427c07ddSAlexei Starovoitov 146*427c07ddSAlexei Starovoitov /* duplicate calls to the same subprog */ 147*427c07ddSAlexei Starovoitov __naked __noinline __used 148*427c07ddSAlexei Starovoitov static unsigned long dup_leaf(void) 149*427c07ddSAlexei Starovoitov { 150*427c07ddSAlexei Starovoitov asm volatile ( 151*427c07ddSAlexei Starovoitov "r0 = 0;" 152*427c07ddSAlexei Starovoitov "exit;" 153*427c07ddSAlexei Starovoitov ); 154*427c07ddSAlexei Starovoitov } 155*427c07ddSAlexei Starovoitov 156*427c07ddSAlexei Starovoitov SEC("?raw_tp") 157*427c07ddSAlexei Starovoitov __success __log_level(2) 158*427c07ddSAlexei Starovoitov __msg("topo_order[0] = dup_leaf") 159*427c07ddSAlexei Starovoitov __msg("topo_order[1] = topo_dup_calls") 160*427c07ddSAlexei Starovoitov __naked int topo_dup_calls(void) 161*427c07ddSAlexei Starovoitov { 162*427c07ddSAlexei Starovoitov asm volatile ( 163*427c07ddSAlexei Starovoitov "call dup_leaf;" 164*427c07ddSAlexei Starovoitov "call dup_leaf;" 165*427c07ddSAlexei Starovoitov "exit;" 166*427c07ddSAlexei Starovoitov ); 167*427c07ddSAlexei Starovoitov } 168*427c07ddSAlexei Starovoitov 169*427c07ddSAlexei Starovoitov /* main calls bpf_loop() with loop_cb as the callback */ 170*427c07ddSAlexei Starovoitov static int loop_cb(int idx, void *ctx) 171*427c07ddSAlexei Starovoitov { 172*427c07ddSAlexei Starovoitov return 0; 173*427c07ddSAlexei Starovoitov } 174*427c07ddSAlexei Starovoitov 175*427c07ddSAlexei Starovoitov SEC("?raw_tp") 176*427c07ddSAlexei Starovoitov __success __log_level(2) 177*427c07ddSAlexei Starovoitov __msg("topo_order[0] = loop_cb") 178*427c07ddSAlexei Starovoitov __msg("topo_order[1] = topo_loop_cb") 179*427c07ddSAlexei Starovoitov int topo_loop_cb(void) 180*427c07ddSAlexei Starovoitov { 181*427c07ddSAlexei Starovoitov bpf_loop(1, loop_cb, NULL, 0); 182*427c07ddSAlexei Starovoitov return 0; 183*427c07ddSAlexei Starovoitov } 184*427c07ddSAlexei Starovoitov 185*427c07ddSAlexei Starovoitov /* 186*427c07ddSAlexei Starovoitov * bpf_loop callback calling another subprog 187*427c07ddSAlexei Starovoitov * main -> bpf_loop(callback=loop_cb2) -> loop_cb2 -> loop_cb2_leaf 188*427c07ddSAlexei Starovoitov */ 189*427c07ddSAlexei Starovoitov __naked __noinline __used 190*427c07ddSAlexei Starovoitov static unsigned long loop_cb2_leaf(void) 191*427c07ddSAlexei Starovoitov { 192*427c07ddSAlexei Starovoitov asm volatile ( 193*427c07ddSAlexei Starovoitov "r0 = 0;" 194*427c07ddSAlexei Starovoitov "exit;" 195*427c07ddSAlexei Starovoitov ); 196*427c07ddSAlexei Starovoitov } 197*427c07ddSAlexei Starovoitov 198*427c07ddSAlexei Starovoitov static int loop_cb2(int idx, void *ctx) 199*427c07ddSAlexei Starovoitov { 200*427c07ddSAlexei Starovoitov return loop_cb2_leaf(); 201*427c07ddSAlexei Starovoitov } 202*427c07ddSAlexei Starovoitov 203*427c07ddSAlexei Starovoitov SEC("?raw_tp") 204*427c07ddSAlexei Starovoitov __success __log_level(2) 205*427c07ddSAlexei Starovoitov __msg("topo_order[0] = loop_cb2_leaf") 206*427c07ddSAlexei Starovoitov __msg("topo_order[1] = loop_cb2") 207*427c07ddSAlexei Starovoitov __msg("topo_order[2] = topo_loop_cb_chain") 208*427c07ddSAlexei Starovoitov int topo_loop_cb_chain(void) 209*427c07ddSAlexei Starovoitov { 210*427c07ddSAlexei Starovoitov bpf_loop(1, loop_cb2, NULL, 0); 211*427c07ddSAlexei Starovoitov return 0; 212*427c07ddSAlexei Starovoitov } 213*427c07ddSAlexei Starovoitov 214*427c07ddSAlexei Starovoitov /* no calls (single subprog) */ 215*427c07ddSAlexei Starovoitov SEC("?raw_tp") 216*427c07ddSAlexei Starovoitov __success __log_level(2) 217*427c07ddSAlexei Starovoitov __msg("topo_order[0] = topo_no_calls") 218*427c07ddSAlexei Starovoitov __naked int topo_no_calls(void) 219*427c07ddSAlexei Starovoitov { 220*427c07ddSAlexei Starovoitov asm volatile ( 221*427c07ddSAlexei Starovoitov "r0 = 0;" 222*427c07ddSAlexei Starovoitov "exit;" 223*427c07ddSAlexei Starovoitov ); 224*427c07ddSAlexei Starovoitov } 225*427c07ddSAlexei Starovoitov 226*427c07ddSAlexei Starovoitov char _license[] SEC("license") = "GPL"; 227