插桩 可以利用 clang/gcc 的 -finstrument-functions
编译参数,使得每个函数都会在出口和入口以此执行 __cyg_profile_func_enter
函数和 __cyg_profile_func_exit
函数。
使用 dladdr 将函数的地址转换成符号
hook.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <dlfcn.h> #include <stdio.h> #include <cxxabi.h> inline const char * get_funcname (const char * src) { int status = 99 ; const char * f = abi::__cxa_demangle(src, nullptr , nullptr , &status); return f == nullptr ? src : f; } extern "C" void __cyg_profile_func_enter(void * func, void * caller) { Dl_info info1, info2; if (dladdr (func, &info1) & dladdr (caller, &info2)) { fprintf (stdout, "enter func: %s father: %s\n" , get_funcname (info1.dli_sname), get_funcname (info2.dli_sname)); } } extern "C" void __cyg_profile_func_exit(void * func, void * caller) { Dl_info info1, info2; if (dladdr (func, &info1) & dladdr (caller, &info2)) { fprintf (stdout, "exit func: %s father: %s\n" , get_funcname (info1.dli_sname), get_funcname (info2.dli_sname)); } }
main.cpp
1 2 3 4 5 6 7 8 9 10 void func_02 () {}void func_01 () { func_02 (); } int main () { func_01 (); return 0 ; }
编译 hook.cpp 如:g++ hook.cpp -c
然后链接到要被插桩的项目或代码中:g++ main.cpp hook.o -g -finstrument-functions -ldl -rdynamic
输出:
1 2 3 4 5 6 enter func: main father: __libc_start_main enter func: func_01() father: main enter func: func_02() father: func_01() exit func: func_02() father: func_01() exit func: func_01() father: main exit func: main father: __libc_start_main