1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
NAME it mutates the passed variable
PROG macro inc($x) { $x += 1; } begin { $a = 1; inc($a); print($a); }
EXPECT 2
NAME it assigns to the last expression
PROG macro inc($x) { $x += 1; $x } begin { $a = 1; $b = inc($a); print(($a, $b)); }
EXPECT (2, 2)
NAME it mutates the passed non-scalar map
PROG macro set(@x) { @x[1] = 2; } begin { @a[1] = 1; set(@a); }
EXPECT @a[1]: 2
NAME it mutates the passed scalar map
PROG macro set(@x) { @x = 2; } begin { @a = 1; set(@a); }
EXPECT @a: 2
NAME it renames internal variables
PROG macro add(x) { let $y; if (true) { $y = 1 } x + $y } begin { print(add(1)); }
EXPECT 2
NAME it reads the passed map
PROG macro get(@x) { 1 + @x[1] } begin { @a[1] = 1; print(get(@a)); }
EXPECT 2
NAME it can have side effects
PROG macro print_me($x) { print(("me", $x)); } begin { $a = 1; print_me($a); }
EXPECT (me, 1)
NAME it can exit early
PROG macro early() { exit(); } begin { early(); print(1); }
EXPECT_NONE 1
NAME it can call other macros as expressions
PROG macro add1(x) { x + 1 } macro add2(y) { y + add1(y) } macro add3(z) { z + add2(z) } begin { print(add3(1)); }
EXPECT 4
NAME it can call other macros as statements
PROG macro add1($x) { $x += 1; } macro add2($y) { add1($y); $y += 1; } macro add3($z) { add2($z); $z += 1; } begin { $a = 1; add3($a); print($a); }
EXPECT 4
NAME builtin wrapper definition order does not matter
PROG macro add2(x) { x + add1(x) } macro add3(x) { x + add2(x) } macro add1(x) { x + 1 } begin { print(add3(1)); }
EXPECT 4
NAME it accepts arbitrary expressions without variables or maps
PROG macro add_one(x) { x + 1 } begin { $a = 1; print(add_one(1 + 1)); }
EXPECT 3
NAME it accepts arbitrary expressions with variables
PROG macro add_one(x) { x + 1 } begin { $a = 1; print(add_one($a + 1)); }
EXPECT 3
NAME it accepts arbitrary expressions with variables nested
PROG macro add_two(x) { x + 2 } macro add_one(x) { add_two(x + 1) + 1 } begin { $a = 1; print(add_one($a + 1)); }
EXPECT 6
NAME it accepts arbitrary expressions with maps
PROG macro add_one(x) { x + 1 } begin { @a = 1; print(add_one(@a + 1)); }
EXPECT 3
NAME can call the same macro multiple times
PROG macro inc($x) { $x += 1; } begin { $a = 1; inc($a); inc($a); inc($a); print($a); }
EXPECT 4
NAME for loops can be in macros
PROG macro loop_map(@a) { let $x = 1; for ($kv : @a) { $x += $kv.1;} $x } begin { @x[1] = 5; @x[2] = 10; print(loop_map(@x)); }
EXPECT 16
NAME it works in nested scopes
PROG macro add1($x) { $x + 1 } macro add2($x) { $x + 2 } begin { $a = 1; if ($a == 1) { print(add2($a)); } else { print(add1($a)); } }
EXPECT 3
NAME it re-names variables to prevent collision
PROG macro inc(x) { $y = x + 1; $y } begin { $y = 2; $z = inc(5); print(($y, $z)); }
EXPECT (2, 6)
NAME it re-names decl variables to prevent collision
PROG macro inc(x) { let $y = x + 1; $y } begin { $y = 2; $z = inc(5); print(($y, $z)); }
EXPECT (2, 6)
NAME it can be part of an expression passed to a macro
PROG macro add_one(x) { x + 1 } begin { $a = add_one(add_one(1) + 1); print($a); }
EXPECT 4
NAME it expands idents if there is a matching macro
PROG macro one() { $x = 1; $x } begin { $a = one; print($a); }
EXPECT 1
NAME it replaces the passed in expression in multiple expression locations
PROG macro inc(x) { $y = x + 1; $z = x + 2; $y + $z } begin { $y = 2; print(inc({ $y +=1; $y })); }
EXPECT 10
NAME it replaces the passed in expression in multiple expression statement locations
PROG macro side_effects(x) { x; x; x; } begin { side_effects({ printf("hi") }); }
EXPECT hihihi
NAME the same macro can be called multiple times in a passed expression
PROG macro add_one(x) { x + 1 } begin { print(add_one(add_one(add_one(1)))); }
EXPECT 4
NAME macro arg idents take precedence over macros with no arguments
PROG macro add() { 2 } macro ident(add) { add } begin { print(ident(1)); }
EXPECT 1
# This is more of a regression test for clone that wasn't cloning the Iterable node
NAME macro replaces all instances
PROG macro first_key(@x) { let $x; for ($k : @x) { $x = $k.0; break; } $x } begin { @a[1] = 0; @b[2] = 0; print((first_key(@a), first_key(@b))); }
EXPECT (1, 2)
# Test builtins
NAME builtin wrapper comm
PROG begin { if (__builtin_comm == comm() && __builtin_comm == comm) { print(comm); } }
EXPECT bpftrace
NAME builtin wrapper cgroup
PROG begin { if (__builtin_cgroup == cgroup() && __builtin_cgroup == cgroup) { printf("SUCCESS %llu\n", cgroup); } }
EXPECT_REGEX SUCCESS [0-9]+
NAME builtin wrapper cpid
RUN {{BPFTRACE}} -e 'begin { if (__builtin_cpid == cpid() && __builtin_cpid == cpid) { printf("SUCCESS %llu\n", cpid); } }' -c './testprogs/syscall nanosleep 1e9'
EXPECT_REGEX SUCCESS [0-9]+
TIMEOUT 3
NAME builtin wrapper cpu
PROG begin { if (__builtin_cpu == cpu() && __builtin_cpu == cpu) { printf("SUCCESS %llu\n", cpu); } }
EXPECT_REGEX SUCCESS [0-9]+
NAME builtin wrapper curtask
PROG begin { if (__builtin_curtask == curtask() && __builtin_curtask == curtask) { printf("SUCCESS %llu\n", curtask); } }
EXPECT_REGEX SUCCESS [0-9]+
NAME builtin wrapper elapsed
PROG begin { printf("SUCCESS1 %llu\n", __builtin_elapsed); printf("SUCCESS2 %llu\n", elapsed); printf("SUCCESS3 %llu\n", elapsed()); }
EXPECT_REGEX SUCCESS1 [0-9]+
EXPECT_REGEX SUCCESS2 [0-9]+
EXPECT_REGEX SUCCESS3 [0-9]+
NAME builtin wrapper func
PROG k:vfs_read { if (__builtin_func == func() && __builtin_func == func) { print(func); } exit(); }
EXPECT vfs_read
AFTER ./testprogs/syscall read
NAME builtin wrapper gid
PROG begin { if (__builtin_gid == gid() && __builtin_gid == gid) { print(gid); } }
EXPECT_REGEX [0-9][0-9]*
NAME builtin wrapper jiffies
PROG begin { if (__builtin_jiffies == jiffies() && __builtin_jiffies == jiffies) { printf("SUCCESS %llu\n", jiffies);} }
EXPECT_REGEX SUCCESS [0-9]+
REQUIRES_FEATURE jiffies64
MIN_KERNEL 5.9
NAME builtin wrapper ncpus
PROG begin { if (__builtin_ncpus == ncpus() && __builtin_ncpus == ncpus) { print(ncpus); } }
EXPECT_REGEX ^[1-9][0-9]*$
NAME builtin wrapper numaid
PROG begin { if (__builtin_numaid == numaid() && __builtin_numaid == numaid) { printf("SUCCESS %d\n", numaid); } }
EXPECT_REGEX SUCCESS [0-9]+
NAME builtin wrapper probe
PROG k:do_nanosleep { if (__builtin_probe == probe() && __builtin_probe == probe) { print(probe); } exit(); }
EXPECT kprobe:do_nanosleep
AFTER ./testprogs/syscall nanosleep 1e8
NAME builtin wrapper rand
PROG begin { printf("SUCCESS1 %llu\n", __builtin_rand); printf("SUCCESS2 %llu\n", rand); printf("SUCCESS3 %llu\n", rand()); }
EXPECT_REGEX SUCCESS1 [0-9]+
EXPECT_REGEX SUCCESS2 [0-9]+
EXPECT_REGEX SUCCESS3 [0-9]+
NAME builtin wrapper retval
PROG kretprobe:vfs_read { if (__builtin_retval == retval() && __builtin_retval == retval) { printf("SUCCESS %d\n", retval); exit(); } }
EXPECT_REGEX SUCCESS .*
AFTER ./testprogs/syscall read
NAME builtin wrapper uid
PROG begin { if (__builtin_uid == uid() && __builtin_uid == uid) { printf("SUCCESS %d\n", uid); } }
EXPECT_REGEX SUCCESS [0-9]+
NAME builtin wrapper usermode
PROG begin { if (__builtin_usermode == usermode() && __builtin_usermode == usermode) { printf("SUCCESS %d\n", usermode); } }
EXPECT_REGEX SUCCESS 1
ARCH x86_64
NAME builtin wrapper username
PROG begin { if (__builtin_username == username() && __builtin_username == username) { printf("SUCCESS %s\n", username); } }
EXPECT_REGEX SUCCESS .*
|