# We want these probes to fire as deterministically as possible so that # their outputs can easily be predicted and compared. Unfortunately this # is complicated by multiple facts, including # (1) the timer might be so fast that the probes don't have time to # fire and print something, # (2) the kprobe might print something after it is re-enabled, but # before the kretprobe is re-enabled, # (3) disabling a kretprobe won't stop an already running handler. # # To get around these issues, we use a simple state machine. The states # are as follow: # # 0 = cond disabled # 1 = cond enabled, but kprobe && kretprobe not yet enabled # 2 = cond enabled, kprobe enabled, kretprobe not yet enabled # 3 = cond enabled, kprobe && kretprobe enabled, nothing printed yet # 4 = cond enabled, 'hit' printed but not 'rethit' # 5 = cond enabled, 'rethit' printed global state = 1 global toggles = 0 probe kernel.function("vfs_read").call if (state > 0) { if (state == 3) { println("hit") state++; } else if (state == 1) { state++; } } probe kernel.function("vfs_read").return if (state > 0) { # ensure that nothing changed during the vfs_read body if (state != @entry(state)) next if (state == 4) { println("rethit") state++; } else if (state == 2) { state++; } } probe begin, end, error, kernel.function("*@workqueue.c"), process.begin, process.end, kernel.trace("*"), process("echo").function("*"), netfilter.pf("NFPROTO_IPV4").hook("NF_INET_LOCAL_IN")?, netfilter.pf("NFPROTO_IPV4").hook("NF_INET_LOCAL_OUT")?, perf.sw.cpu_clock.sample(1000000)?, timer.profile.tick? { if (state != 0 && state != 5) next # give probes more time to move through the states toggles++ if (toggles > 5000) exit() else { println("toggling") state = !state } } probe timer.s(360) { println("timed out") exit() }