#! /usr/bin/env stap /* Print a trace of the the last few statements (file:line numbers, along with selected local variables) that were executed within a given function, if it ends up returning with a given condition. (No trace is shown for functions that return with the condition false, demonstrating use of speculation tapset.) Usage: stap whythefail.stp PROC_OR_KERNEL FUNCTION_NAME CONDITION_EXPRESSION [$VARIABLE$] PROC_OR_KERNEL: the first part of the probe point, e.g.: 'kernel' 'module("foo")' or 'process("bar")' FUNCTION_NAME: the function name (assumed non-recursive) CONDITION: expression to evaluate at function return, e.g.: '$return != 0' or '1' or 'randint(100)<20' VARIABLE: optional context-variable string to print at each statement, e.g.: '$a_var$' or '@var("global")$' or (default) '$$vars' If the script is invoked with -c CMD or -x PID, probes are filtered for that process target-set (it and its descendants). e.g.: stap whythefail.stp kernel do_mlock '$return < 0' */ global specs% global counts probe $1 . function(@2) . call { if (target() && !target_set_pid(pid())) next; specs[tid()] = speculation() counts["entry"] <<< 1 } probe $1 . statement(@2 "@*:*") { if (target() && !target_set_pid(pid())) next; tokenize(pp(),"@"); fileline=tokenize("","@"); file=tokenize(fileline,":\""); line=tokenize("",":\""); speculate(specs[tid()], sprintf("%s[%d] %s:%s %s\n", execname(), tid(), file, line, %( $# >= 4 %? @4.": ".@choose_defined($4,"?") %: "$$vars: ".$$vars %) )) counts["statement"] <<< 1 } probe $1 . function(@2) . return { if (target() && !target_set_pid(pid())) next; if ($3) { printf("\n%s[%d] %s function(%s) $return: %s\n", execname(), tid(), @1, @2, $return$) commit(specs[tid()]) counts["exit-hit"] <<< 1 } else { discard(specs[tid()]) counts["exit-miss"] <<< 1 } } probe end,error { printf("\nstatistics:\n") foreach (reason+ in counts) { printf("%s count: %d\n", reason, @count(counts[reason])) } }