1local suite = require("test_helper") 2local TestClang = {} 3 4function TestClang:test_probe_read1() 5 local text = [[ 6#include <linux/sched.h> 7#include <uapi/linux/ptrace.h> 8int count_sched(struct pt_regs *ctx, struct task_struct *prev) { 9 pid_t p = prev->pid; 10 return (p != -1); 11} 12]] 13 local b = BPF:new{text=text, debug=0} 14 local fn = b:load_func("count_sched", 'BPF_PROG_TYPE_KPROBE') 15end 16 17function TestClang:test_probe_read2() 18 local text = [[ 19#include <linux/sched.h> 20#include <uapi/linux/ptrace.h> 21int count_foo(struct pt_regs *ctx, unsigned long a, unsigned long b) { 22 return (a != b); 23} 24]] 25 local b = BPF:new{text=text, debug=0} 26 local fn = b:load_func("count_foo", 'BPF_PROG_TYPE_KPROBE') 27end 28 29function TestClang:test_probe_read_keys() 30 local text = [[ 31#include <uapi/linux/ptrace.h> 32#include <linux/blkdev.h> 33BPF_HASH(start, struct request *); 34int do_request(struct pt_regs *ctx, struct request *req) { 35 u64 ts = bpf_ktime_get_ns(); 36 start.update(&req, &ts); 37 return 0; 38} 39 40int do_completion(struct pt_regs *ctx, struct request *req) { 41 u64 *tsp = start.lookup(&req); 42 if (tsp != 0) { 43 start.delete(&req); 44 } 45 return 0; 46} 47 ]] 48 local b = BPF:new{text=text, debug=0} 49 local fns = b:load_funcs('BPF_PROG_TYPE_KPROBE') 50end 51 52function TestClang:test_sscanf() 53 local text = [[ 54BPF_HASH(stats, int, struct { u64 a; u64 b; u32 c:18; u32 d:14; struct { u32 a; u32 b; } s; }, 10); 55 56int foo(void *ctx) { 57 return 0; 58} 59]] 60 local b = BPF:new{text=text, debug=0} 61 local fn = b:load_func("foo", 'BPF_PROG_TYPE_KPROBE') 62 local t = b:get_table("stats") 63 local s1 = t:key_sprintf(2) 64 65 assert_equals(s1, "0x2") 66 67 local s2 = t:leaf_sprintf({{2, 3, 4, 1, {5, 6}}}) 68 local l = t:leaf_scanf(s2) 69 70 assert_equals(tonumber(l.a), 2) 71 assert_equals(tonumber(l.b), 3) 72 assert_equals(tonumber(l.c), 4) 73 assert_equals(tonumber(l.d), 1) 74 assert_equals(tonumber(l.s.a), 5) 75 assert_equals(tonumber(l.s.b), 6) 76end 77 78function TestClang:test_sscanf_array() 79 local text = [[ BPF_HASH(stats, int, struct { u32 a[3]; u32 b; }, 10); ]] 80 81 local b = BPF:new{text=text, debug=0} 82 local t = b:get_table("stats") 83 84 local s1 = t:key_sprintf(2) 85 assert_equals(s1, "0x2") 86 87 local s2 = t:leaf_sprintf({{{1, 2, 3}, 4}}) 88 assert_equals(s2, "{ [ 0x1 0x2 0x3 ] 0x4 }") 89 90 local l = t:leaf_scanf(s2) 91 assert_equals(l.a[0], 1) 92 assert_equals(l.a[1], 2) 93 assert_equals(l.a[2], 3) 94 assert_equals(l.b, 4) 95end 96 97function TestClang:test_iosnoop() 98 local text = [[ 99#include <linux/blkdev.h> 100#include <uapi/linux/ptrace.h> 101 102struct key_t { 103 struct request *req; 104}; 105 106BPF_HASH(start, struct key_t, u64, 1024); 107int do_request(struct pt_regs *ctx, struct request *req) { 108 struct key_t key = {}; 109 110 bpf_trace_printk("traced start %d\\n", req->__data_len); 111 112 return 0; 113} 114]] 115 116 local b = BPF:new{text=text, debug=0} 117 local fn = b:load_func("do_request", 'BPF_PROG_TYPE_KPROBE') 118end 119 120function TestClang:test_blk_start_request() 121 local text = [[ 122#include <linux/blkdev.h> 123#include <uapi/linux/ptrace.h> 124int do_request(struct pt_regs *ctx, int req) { 125 bpf_trace_printk("req ptr: 0x%x\n", req); 126 return 0; 127} 128]] 129 local b = BPF:new{text=text, debug=0} 130 local fn = b:load_func("do_request", 'BPF_PROG_TYPE_KPROBE') 131end 132 133function TestClang:test_bpf_hash() 134 local text = [[ 135BPF_HASH(table1); 136BPF_HASH(table2, u32); 137BPF_HASH(table3, u32, int); 138]] 139 local b = BPF:new{text=text, debug=0} 140end 141 142function TestClang:test_consecutive_probe_read() 143 local text = [[ 144#include <linux/fs.h> 145#include <linux/mount.h> 146BPF_HASH(table1, struct super_block *); 147int trace_entry(struct pt_regs *ctx, struct file *file) { 148 if (!file) return 0; 149 struct vfsmount *mnt = file->f_path.mnt; 150 if (mnt) { 151 struct super_block *k = mnt->mnt_sb; 152 u64 zero = 0; 153 table1.update(&k, &zero); 154 k = mnt->mnt_sb; 155 table1.update(&k, &zero); 156 } 157 158 return 0; 159} 160]] 161 local b = BPF:new{text=text, debug=0} 162 local fn = b:load_func("trace_entry", 'BPF_PROG_TYPE_KPROBE') 163end 164 165function TestClang:test_nested_probe_read() 166 local text = [[ 167#include <linux/fs.h> 168int trace_entry(struct pt_regs *ctx, struct file *file) { 169 if (!file) return 0; 170 const char *name = file->f_path.dentry->d_name.name; 171 bpf_trace_printk("%s\\n", name); 172 return 0; 173} 174]] 175 local b = BPF:new{text=text, debug=0} 176 local fn = b:load_func("trace_entry", 'BPF_PROG_TYPE_KPROBE') 177end 178 179function TestClang:test_char_array_probe() 180 local b = BPF:new{text=[[#include <linux/blkdev.h> 181int kprobe__blk_update_request(struct pt_regs *ctx, struct request *req) { 182 bpf_trace_printk("%s\\n", req->rq_disk->disk_name); 183 return 0; 184}]]} 185end 186 187function TestClang:test_probe_read_helper() 188 local b = BPF:new{text=[[ 189#include <linux/fs.h> 190static void print_file_name(struct file *file) { 191 if (!file) return; 192 const char *name = file->f_path.dentry->d_name.name; 193 bpf_trace_printk("%s\\n", name); 194} 195static void print_file_name2(int unused, struct file *file) { 196 print_file_name(file); 197} 198int trace_entry1(struct pt_regs *ctx, struct file *file) { 199 print_file_name(file); 200 return 0; 201} 202int trace_entry2(struct pt_regs *ctx, int unused, struct file *file) { 203 print_file_name2(unused, file); 204 return 0; 205} 206]]} 207 local fn1 = b:load_func("trace_entry1", 'BPF_PROG_TYPE_KPROBE') 208 local fn2 = b:load_func("trace_entry2", 'BPF_PROG_TYPE_KPROBE') 209end 210 211function TestClang:test_probe_struct_assign() 212 local b = BPF:new{text = [[ 213#include <uapi/linux/ptrace.h> 214struct args_t { 215 const char *filename; 216 int flags; 217 int mode; 218}; 219int kprobe__sys_open(struct pt_regs *ctx, const char *filename, 220 int flags, int mode) { 221 struct args_t args = {}; 222 args.filename = filename; 223 args.flags = flags; 224 args.mode = mode; 225 bpf_trace_printk("%s\\n", args.filename); 226 return 0; 227}; 228]]} 229end 230 231function TestClang:test_task_switch() 232 local b = BPF:new{text=[[ 233#include <uapi/linux/ptrace.h> 234#include <linux/sched.h> 235struct key_t { 236 u32 prev_pid; 237 u32 curr_pid; 238}; 239BPF_HASH(stats, struct key_t, u64, 1024); 240int kprobe__finish_task_switch(struct pt_regs *ctx, struct task_struct *prev) { 241 struct key_t key = {}; 242 u64 zero = 0, *val; 243 key.curr_pid = bpf_get_current_pid_tgid(); 244 key.prev_pid = prev->pid; 245 246 val = stats.lookup_or_init(&key, &zero); 247 (*val)++; 248 return 0; 249} 250]]} 251end 252 253function TestClang:test_probe_simple_assign() 254 local b = BPF:new{text=[[ 255#include <uapi/linux/ptrace.h> 256#include <linux/gfp.h> 257struct leaf { size_t size; }; 258BPF_HASH(simple_map, u32, struct leaf); 259int kprobe____kmalloc(struct pt_regs *ctx, size_t size) { 260 u32 pid = bpf_get_current_pid_tgid(); 261 struct leaf* leaf = simple_map.lookup(&pid); 262 if (leaf) 263 leaf->size += size; 264 return 0; 265}]]} 266end 267 268function TestClang:test_unop_probe_read() 269 local text = [[ 270#include <linux/blkdev.h> 271int trace_entry(struct pt_regs *ctx, struct request *req) { 272 if (!(req->bio->bi_flags & 1)) 273 return 1; 274 if (((req->bio->bi_flags))) 275 return 1; 276 return 0; 277} 278]] 279 local b = BPF:new{text=text} 280 local fn = b:load_func("trace_entry", 'BPF_PROG_TYPE_KPROBE') 281end 282 283function TestClang:test_complex_leaf_types() 284 local text = [[ 285struct list; 286struct list { 287 struct list *selfp; 288 struct list *another_selfp; 289 struct list *selfp_array[2]; 290}; 291struct empty { 292}; 293union emptyu { 294 struct empty *em1; 295 struct empty em2; 296 struct empty em3; 297 struct empty em4; 298}; 299BPF_ARRAY(t1, struct list, 1); 300BPF_ARRAY(t2, struct list *, 1); 301BPF_ARRAY(t3, union emptyu, 1); 302]] 303 local b = BPF:new{text=text} 304 local ffi = require("ffi") 305 306 -- TODO: ptrs? 307 assert_equals(ffi.sizeof(b:get_table("t3").c_leaf), 8) 308end 309 310function TestClang:test_cflags() 311 local text = [[ 312#ifndef MYFLAG 313#error "MYFLAG not set as expected" 314#endif 315]] 316 local b = BPF:new{text=text, cflags={"-DMYFLAG"}} 317end 318 319function TestClang:test_exported_maps() 320 local b1 = BPF{text=[[BPF_TABLE_PUBLIC("hash", int, int, table1, 10);]]} 321 local b2 = BPF{text=[[BPF_TABLE("extern", int, int, table1, 10);]]} 322end 323 324function TestClang:test_syntax_error() 325 assert_error_msg_contains( 326 "failed to compile BPF module", 327 BPF.new, 328 BPF, {text=[[int failure(void *ctx) { if (); return 0; }]]}) 329end 330 331suite("TestClang", TestClang) 332