c++ 为函数添加 hook

  1. 说明

    • 功能

      • 程序最前和最后添加函数调用.
    • 参考

      (gdb) disassemble main
      Dump of assembler code for function main():
        0x0000000000400567 <+0>:     push   %rbp
        0x0000000000400568 <+1>:     mov    %rsp,%rbp
        0x000000000040056b <+4>:     push   %rbx
        0x000000000040056c <+5>:     mov    0x8(%rbp),%rax
        0x0000000000400570 <+9>:     mov    %rax,%rsi
        0x0000000000400573 <+12>:    mov    $0x400567,%edi
        0x0000000000400578 <+17>:    callq  0x40050d <__cyg_profile_func_enter(void*, void*)>
        0x000000000040057d <+22>:    callq  0x40053f <show()>
        0x0000000000400582 <+27>:    mov    $0x0,%ebx
        0x0000000000400587 <+32>:    mov    0x8(%rbp),%rax
        0x000000000040058b <+36>:    mov    %rax,%rsi
        0x000000000040058e <+39>:    mov    $0x400567,%edi
        0x0000000000400593 <+44>:    callq  0x400526 <__cyg_profile_func_exit(void*, void*)>
        0x0000000000400598 <+49>:    mov    %ebx,%eax
        0x000000000040059a <+51>:    pop    %rbx
        0x000000000040059b <+52>:    pop    %rbp
        0x000000000040059c <+53>:    retq
      
      

      可以看到最前和最后都添加了。

  2. 参考

    • 原文

      • gnu,搜索-finstrument-functions
    • 说明

      Generate instrumentation calls for entry and exit to functions. Just after function entry and just before function exit, the following profiling functions are called with the address of the current function and its call site. (On some platforms, __builtin_return_address does not work beyond the current function, so the call site information may not be available to the profiling functions otherwise.)
      
      void __cyg_profile_func_enter (void *this_fn,
                                    void *call_site);
      void __cyg_profile_func_exit  (void *this_fn,
                                    void *call_site);
      The first argument is the address of the start of the current function, which may be looked up exactly in the symbol table.
      
      This instrumentation is also done for functions expanded inline in other functions. The profiling calls indicate where, conceptually, the inline function is entered and exited. This means that addressable versions of such functions must be available. If all your uses of a function are expanded inline, this may mean an additional expansion of code size. If you use extern inline in your C code, an addressable version of such functions must be provided. (This is normally the case anyway, but if you get lucky and the optimizer always expands the functions inline, you might have gotten away without providing static copies.)
      
      A function may be given the attribute no_instrument_function, in which case this instrumentation is not done. This can be used, for example, for the profiling functions listed above, high-priority interrupt routines, and any functions from which the profiling functions cannot safely be called (perhaps signal handlers, if the profiling routines generate output or allocate memory)
      
      原文 翻译
      Generate instrumentation calls for entry and exit to functions. Just after function entry and just before function exit, the following profiling functions are called with the address of the current function and its call site. 在函数最前和最后添加两个统计函数调用指令(查看上面案例),在进入函数和退出的函数调用,参数是上一层的函数(即被检测函数),以及再上上层函数,(即被检测函数的上层),(简而言之就上堆栈,共三层.)
      The first argument is the address of the start of the current function, which may be looked up exactly in the symbol table. 第一个参数地址一般可以在符号表中查到对应地址。
      其他 这个机制适用于inline,同时inline之后会增加代码体积.inline还会遇到一些问题.
      使用 需要添加属性来规避添加. 即这两个函数必然需要的. 否则会造成堆栈溢出,从而导致段错误.
  3. 使用场景

    • 普通

      • 用于检测用户定义函数.
      • 即编译的时候添加.
    • 默认

      • 将给所有的用户定义函数添加.
    • 规避

      • -finstrument-functions-exclude-file-list=file,file,…文件规避,files是一个字符串,只要其是某个头文件的子串,里面的函数就不会添加.
      • -finstrument-functions-exclude-function-list=sym,sym,…,函数规避,符号是函数符号的子串也不会添加.
    • 属性规避

      
      #define ATTR __attribute__((no_instrument_function))
      
      void ATTR __cyg_profile_func_exit (void *this_fn,void *call_site);
      void ATTR __cyg_profile_func_enter (void *this_fn,void *call_site);
      
      void __cyg_profile_func_enter (void *this_fn,void *call_site) {
         int a=0;
         a++;
      }
      
      void __cyg_profile_func_exit (void *this_fn,void *call_site) {
         int b = 0;
         b++;
      }
      
      void show() {
      }
      
      int main() {
         show();
      }
      
      

      添加函数属性规避给函数添加指令.

    • 少数几个使用

      • 可以使用C++局部变量,加类的构造和析构机制实现。

可以在编译.o 的时候为指定的几个添加.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章