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 的時候爲指定的幾個添加.

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