在余老大(http://blog.yufeng.info/)的指引下开始学习SystemTap了。
最近要追查MySQL中一个耗时函数的调用栈,刚好用到这个神器。在1.3版本中自带的tapset中有 print_ubacktrace 和 sprint_ubacktrace 这两个函数。输出的格式是 “函数名+地址 [进程名]“。 为了得到函数名,要作字符串处理。
早上在tapset中发现了另外一个函数print_ubacktrace_brief, 输出格式是 “函数名+地址”。
因此想到如果能有个函数只输出函数名就好了,依葫芦画瓢可以自定义函数如下。
function sprint_ubacktrace_func () %{ /* unprivileged */ /* pragma:uprobes */ /* pragma:vma */ assert_is_myproc(); /* use task_pt_regs, CONTEXT->regs might be kernel regs, or not set. */ if (current->mm) { struct pt_regs *uregs; int valid; if (CONTEXT->regs && (CONTEXT->regflags & _STP_REGS_USER_FLAG)) { uregs = CONTEXT->regs; valid = 1; } else { uregs = task_pt_regs(current); valid = _stp_task_pt_regs_valid(current, uregs); } if (uregs) { _stp_stack_sprint (THIS->__retvalue, MAXSTRINGLEN, _STP_SYM_SYMBOL|_STP_SYM_POST_SPACE, uregs, CONTEXT->pi, MAXTRACE, current, CONTEXT->ri, valid); return; } } strlcpy (THIS->__retvalue, "", MAXSTRINGLEN); %}
其实重点就是_stp_stack_sprint函数的第三个参数,自己定义不同的宏有不同的效果。简单例子中进程ex_stack调用顺序为 main -> p1 -> p2 -> p3 -> p4,则在 process(“ex_stack”).function(“p4”).call 中调用上面这个函数,返回值为
" p4 p3 p2 p1 main xxxx(空格隔开)"
直接显示省了字符串处理J
另外,脚本中使用这函数的话,记得带-g.