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_try_init(&key, &zero); 247 if (val) { 248 (*val)++; 249 } 250 return 0; 251} 252]]} 253end 254 255function TestClang:test_probe_simple_assign() 256 local b = BPF:new{text=[[ 257#include <uapi/linux/ptrace.h> 258#include <linux/gfp.h> 259struct leaf { size_t size; }; 260BPF_HASH(simple_map, u32, struct leaf); 261int kprobe____kmalloc(struct pt_regs *ctx, size_t size) { 262 u32 pid = bpf_get_current_pid_tgid(); 263 struct leaf* leaf = simple_map.lookup(&pid); 264 if (leaf) 265 leaf->size += size; 266 return 0; 267}]]} 268end 269 270function TestClang:test_unop_probe_read() 271 local text = [[ 272#include <linux/blkdev.h> 273int trace_entry(struct pt_regs *ctx, struct request *req) { 274 if (!(req->bio->bi_flags & 1)) 275 return 1; 276 if (((req->bio->bi_flags))) 277 return 1; 278 return 0; 279} 280]] 281 local b = BPF:new{text=text} 282 local fn = b:load_func("trace_entry", 'BPF_PROG_TYPE_KPROBE') 283end 284 285function TestClang:test_complex_leaf_types() 286 local text = [[ 287struct list; 288struct list { 289 struct list *selfp; 290 struct list *another_selfp; 291 struct list *selfp_array[2]; 292}; 293struct empty { 294}; 295union emptyu { 296 struct empty *em1; 297 struct empty em2; 298 struct empty em3; 299 struct empty em4; 300}; 301BPF_ARRAY(t1, struct list, 1); 302BPF_ARRAY(t2, struct list *, 1); 303BPF_ARRAY(t3, union emptyu, 1); 304]] 305 local b = BPF:new{text=text} 306 local ffi = require("ffi") 307 308 -- TODO: ptrs? 309 assert_equals(ffi.sizeof(b:get_table("t3").c_leaf), 8) 310end 311 312function TestClang:test_cflags() 313 local text = [[ 314#ifndef MYFLAG 315#error "MYFLAG not set as expected" 316#endif 317]] 318 local b = BPF:new{text=text, cflags={"-DMYFLAG"}} 319end 320 321function TestClang:test_exported_maps() 322 local b1 = BPF{text=[[BPF_TABLE_PUBLIC("hash", int, int, table1, 10);]]} 323 local b2 = BPF{text=[[BPF_TABLE("extern", int, int, table1, 10);]]} 324end 325 326function TestClang:test_syntax_error() 327 assert_error_msg_contains( 328 "failed to compile BPF module", 329 BPF.new, 330 BPF, {text=[[int failure(void *ctx) { if (); return 0; }]]}) 331end 332 333suite("TestClang", TestClang) 334