• etrace 跟踪程序函数动态执行流程


    https://github.com/elcritch/etrace
    
    窗口1: 监控窗口,执行监控程序,显示监控结果
    
    [root@monitor example]# pwd
    /root/etrace-master/example
    
    [root@monitor example]# ll
    total 28
    -rwxr-xr-x 1 root root 16687 Jun  9 08:49 crumble
    -rw-r--r-- 1 root root  1644 Aug  7  2015 crumble.c
    -rw-r--r-- 1 root root   242 Aug  7  2015 Makefile
    
    [root@monitor example]# ../src/etrace crumble
    
    [root@monitor example]# ll
    total 28
    -rwxr-xr-x 1 root root 16687 Jun  9 08:49 crumble
    -rw-r--r-- 1 root root  1644 Aug  7  2015 crumble.c
    -rw-r--r-- 1 root root   242 Aug  7  2015 Makefile
    prw-r--r-- 1 root root     0 Jun  9 08:59 TRACE
    窗口2:执行程序
    [root@monitor example]# ./crumble
    buy 125 grams of sugar
    buy 125 grams of butter
    buy 200 grams of wheat
    buy 1 pinch of salt
    buy 5 pieces of apple
    skin apples and make little dices
    mix butter with sugar, wheat and salt
    put apples below
    put crumble on top
    put apple crumble in oven
    cook apple crumble at 220 degrees for 45 minutes

    窗口1:显示程序监控结果     //etrace跟据 TRACE 这个文件中的 记录的函数调用地址 查找对应 crumble中的函数符号名,并生调用图
    [root@monitor example]# ../src/etrace crumble

       --main
       |    --Crumble_make_apple_crumble
       |    |       --Crumble_buy_stuff
       |    |       |       --Crumble_buy
       |    |       |       --Crumble_buy (total: 5 times)
       |    |       --Crumble_prepare_apples
       |    |       |       --Crumble_skin_and_dice
       |    |       --Crumble_mix
       |    |       --Crumble_finalize
       |    |       |       --Crumble_put
       |    |       |       --Crumble_put (total: 2 times)
       |    |       --Crumble_cook
       |    |       |       --Crumble_put
       |    |       |       --Crumble_bake

    原理:
    [root@monitor example]# cat Makefile

    CC = gcc
    CFLAGS = -g -finstrument-functions --std=gnu99

    crumble: crumble.c ../src/ptrace.c
            $(CC) $(CFLAGS) -o crumble crumble.c ../src/ptrace.c

    run:
            touch TRACE ;
            ./crumble
            ../src/etrace crumble
            rm -f TRACE

    clean:
            rm -f crumble TRACE


    [root@monitor example]# make //执行原理
    gcc -g -finstrument-functions --std=gnu99 -o crumble crumble.c ../src/ptrace.c
    单窗口也可以显示跟踪结果
    [root@monitor example]# make run touch TRACE ; .
    /crumble buy 125 grams of sugar buy 125 grams of butter buy 200 grams of wheat buy 1 pinch of salt buy 5 pieces of apple skin apples and make little dices mix butter with sugar, wheat and salt put apples below put crumble on top put apple crumble in oven cook apple crumble at 220 degrees for 45 minutes ../src/etrace crumble --main | --Crumble_make_apple_crumble | | --Crumble_buy_stuff | | | --Crumble_buy | | | --Crumble_buy (total: 5 times) | | --Crumble_prepare_apples | | | --Crumble_skin_and_dice | | --Crumble_mix | | --Crumble_finalize | | | --Crumble_put | | | --Crumble_put (total: 2 times) | | --Crumble_cook | | | --Crumble_put | | | --Crumble_bake rm -f TRACE
    执行原理:
    [root@monitor example]# touch TRACE
    [root@monitor example]# ./crumble
    buy 125 grams of sugar
    buy 125 grams of butter
    buy 200 grams of wheat
    buy 1 pinch of salt
    buy 5 pieces of apple
    skin apples and make little dices
    mix butter with sugar, wheat and salt
    put apples below
    put crumble on top
    put apple crumble in oven
    cook apple crumble at 220 degrees for 45 minutes
    [root@monitor example]# ll total
    32 -rwxr-xr-x 1 root root 16687 Jun 9 09:17 crumble -rw-r--r-- 1 root root 1650 Jun 9 09:17 crumble.c -rw-r--r-- 1 root root 244 Jun 9 09:05 Makefile -rw-r--r-- 1 root root 563 Jun 9 09:17 TRACE
    [root@monitor example]# cat TRACE enter
    0x400beb enter 0x400b88 enter 0x400904 enter 0x4008a4 enter 0x400ba1 enter 0x400b3e enter 0x4008ba enter 0x400864 exit 0x400864 enter 0x400864 exit 0x400864 enter 0x400864 exit 0x400864 enter 0x400864 exit 0x400864 enter 0x400864 exit 0x400864 exit 0x4008ba enter 0x40096c enter 0x400940 exit 0x400940 exit 0x40096c enter 0x4009a4 exit 0x4009a4 enter 0x400a5a enter 0x400a0f exit 0x400a0f enter 0x400a0f exit 0x400a0f exit 0x400a5a enter 0x400af9 enter 0x400a0f exit 0x400a0f enter 0x400aa4 exit 0x400aa4 exit 0x400af9 exit 0x400b3e exit 0x400ba1 EXIT 6847
    0000000000400ba1 <main>:
      400ba1:       55                      push   %rbp
      400ba2:       48 89 e5                mov    %rsp,%rbp
      400ba5:       53                      push   %rbx
      400ba6:       48 83 ec 18             sub    $0x18,%rsp
      400baa:       89 7d ec                mov    %edi,-0x14(%rbp)
      400bad:       48 89 75 e0             mov    %rsi,-0x20(%rbp)
      400bb1:       48 8b 75 08             mov    0x8(%rbp),%rsi
      400bb5:       bf a1 0b 40 00          mov    $0x400ba1,%edi
      400bba:       e8 8e 01 00 00          callq  400d4d <__cyg_profile_func_enter>
      400bbf:       e8 7a ff ff ff          callq  400b3e <Crumble_make_apple_crumble>
      400bc4:       bb 00 00 00 00          mov    $0x0,%ebx
      400bc9:       48 8b 75 08             mov    0x8(%rbp),%rsi
      400bcd:       bf a1 0b 40 00          mov    $0x400ba1,%edi
      400bd2:       e8 99 01 00 00          callq  400d70 <__cyg_profile_func_exit>
      400bd7:       89 d8                   mov    %ebx,%eax
      400bd9:       48 83 c4 18             add    $0x18,%rsp
      400bdd:       5b                      pop    %rbx
      400bde:       c9                      leaveq 
      400bdf:       c3                      retq   
    [root@monitor src]# cat ptrace.c    //程序连接时加的额外代码
    
    /*-------------------------------------------------------------------------*/
    /**
      @file         ptrace.c
      @author       N. Devillard, V. Chudnovsky
      @date         March 2004
      @version      $Revision: 1.1.1.1 $
      @brief        Add tracing capability to any program compiled with gcc.
    
      This module is only compiled when using gcc and tracing has been
      activated. It allows the compiled program to output messages whenever
      a function is entered or exited.
    
      To activate this feature, your version of gcc must support
      the -finstrument-functions flag.
    
      When using ptrace on a dynamic library, you must set the
      PTRACE_REFERENCE_FUNCTION macro to be the name of a function in the
      library. The address of this function when loaded will be the first
      line output to the trace file and will permit the translation of the
      other entry and exit pointers to their symbolic names. You may set
      the macro PTRACE_INCLUDE with any #include directives needed for
      that function to be accesible to this source file.
    
      The printed messages yield function addresses, not human-readable
      names. To link both, you need to get a list of symbols from the
      program. There are many (unportable) ways of doing that, see the
      'etrace' project on freshmeat for more information about how to dig
      the information.
    */
    /*--------------------------------------------------------------------------*/
    
    /*
            $Id: ptrace.c,v 1.1.1.1 2004-03-16 20:00:07 ndevilla Exp $
            $Author: ndevilla $
            $Date: 2004-03-16 20:00:07 $
            $Revision: 1.1.1.1 $
    */
    
    #if (__GNUC__>2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ > 95))
    
    /*---------------------------------------------------------------------------
                                                                    Includes
     ---------------------------------------------------------------------------*/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/errno.h>
    
    /*---------------------------------------------------------------------------
                                                                User Macros
     ---------------------------------------------------------------------------*/
    #define PTRACE_PIPENAME  "TRACE"
    
    /* When using ptrace on a dynamic library, the following must be defined:
    
    #include "any files needed for PTRACE_REFERENCE_FUNCTION"
    #define PTRACE_REFERENCE_FUNCTION functionName
    
    `*/
    
    
    /*---------------------------------------------------------------------------
                                                                    Defines
     ---------------------------------------------------------------------------*/
    
    #define REFERENCE_OFFSET "REFERENCE:"
    #define FUNCTION_ENTRY   "enter"
    #define FUNCTION_EXIT    "exit"
    #define END_TRACE        "EXIT"
    #define __NON_INSTRUMENT_FUNCTION__    __attribute__((__no_instrument_function__))
    #define PTRACE_OFF        __NON_INSTRUMENT_FUNCTION__
    #define STR(_x)          #_x
    #define DEF(_x)          _x
    #define GET(_x,_y)       _x(_y)
    #define TRACE __GNU_PTRACE_FILE__
    /*---------------------------------------------------------------------------
                                                            Function codes
     ---------------------------------------------------------------------------*/
    
    /** Initial trace open */
    static FILE *__GNU_PTRACE_FILE__;
     
    
    /** Final trace close */
    static void
    __NON_INSTRUMENT_FUNCTION__
    gnu_ptrace_close(void)
    {
            fprintf(TRACE, END_TRACE " %ld
    ", (long)getpid());
    
            if (TRACE != NULL)
                fclose(TRACE);
            return ;
    }
    
    /** Trace initialization */
    static int
    __NON_INSTRUMENT_FUNCTION__
    gnu_ptrace_init(void)
    {
            struct stat sta;
        __GNU_PTRACE_FILE__ = NULL;
        
            /* See if a trace file exists */
            if (stat(PTRACE_PIPENAME, &sta) != 0) 
            {
                    /* No trace file: do not trace at all */
                    return 0;
            }
            else 
            {
                    /* trace file: open up trace file */
            if ((TRACE = fopen(PTRACE_PIPENAME, "a")) == NULL)
            {
                char *msg = strerror(errno);
                perror(msg);
                printf("[gnu_ptrace error]
    ");
                    return 0;
            }
    
            #ifdef PTRACE_REFERENCE_FUNCTION
            fprintf(TRACE,"%s %s %p
    ",
                      REFERENCE_OFFSET,
                      GET(STR,PTRACE_REFERENCE_FUNCTION),
                      (void *)GET(DEF,PTRACE_REFERENCE_FUNCTION));
            #endif
            
            /* Tracing requested: a trace file was found */
            atexit(gnu_ptrace_close);
            return 1;
        }
    }
    
    /** Function called by every function event */
    void
    __NON_INSTRUMENT_FUNCTION__
    gnu_ptrace(char * what, void * p)
    {
            static int first=1;
            static int active=1;
    
            if (active == 0)
                    return;
    
            if (first)
            {
                    active = gnu_ptrace_init();
            first = 0;
            
            if (active == 0)
                return;
            }
    
            fprintf(TRACE, "%s %p
    ", what, p);
        fflush(TRACE);
            return;
    }
    
    /** According to gcc documentation: called upon function entry */
    void
    __NON_INSTRUMENT_FUNCTION__
    __cyg_profile_func_enter(void *this_fn, void *call_site)
    {
            gnu_ptrace(FUNCTION_ENTRY, this_fn);
            (void)call_site;
    }
    
    /** According to gcc documentation: called upon function exit */
    void
    __NON_INSTRUMENT_FUNCTION__
    __cyg_profile_func_exit(void *this_fn, void *call_site)
    {
            gnu_ptrace(FUNCTION_EXIT, this_fn);
            (void)call_site;
    }
    
    #endif
    /* vim: set ts=4 et sw=4 tw=75 */
    执行原理:

    test.c
    #include <stdio.h>
    fun()
    {
    printf("this is test ");
    }
    main()
    {

    fun();

    }

    gcc test.c -g -otest
    00000000004004d4 <main>:
      4004d4:       55                      push   %rbp
      4004d5:       48 89 e5                mov    %rsp,%rbp
      4004d8:       b8 00 00 00 00          mov    $0x0,%eax
      4004dd:       e8 e2 ff ff ff          callq  4004c4 <fun>
      4004e2:       c9                      leaveq
      4004e3:       c3                      retq   
      4004e4:       90                      nop
      4004e5:       90                      nop
      4004e6:       90                      nop
      4004e7:       90                      nop
      4004e8:       90                      nop
      4004e9:       90                      nop
      4004ea:       90                      nop
      4004eb:       90                      nop
      4004ec:       90                      nop
      4004ed:       90                      nop
      4004ee:       90                      nop
      4004ef:       90                      nop




    gcc test.c -g  -finstrument-functions -otest

    00000000004005a0 <main>:
      4005a0:       55                      push   %rbp
      4005a1:       48 89 e5                mov    %rsp,%rbp
      4005a4:       48 8b 75 08             mov    0x8(%rbp),%rsi
      4005a8:       bf a0 05 40 00          mov    $0x4005a0,%edi
      4005ad:       e8 be fe ff ff          callq  400470 <__cyg_profile_func_enter@plt>
      4005b2:       b8 00 00 00 00          mov    $0x0,%eax
      4005b7:       e8 b8 ff ff ff          callq  400574 <fun>
      4005bc:       48 8b 75 08             mov    0x8(%rbp),%rsi
      4005c0:       bf a0 05 40 00          mov    $0x4005a0,%edi
      4005c5:       e8 b6 fe ff ff          callq  400480 <__cyg_profile_func_exit@plt>
      4005ca:       c9                      leaveq
      4005cb:       c3                      retq   
      4005cc:       90                      nop
      4005cd:       90                      nop
      4005ce:       90                      nop
      4005cf:       90                      nop







    gcc -g -finstrument-functions --std=gnu99 -otest test.c ../src/ptrace.c //ptrace.c 写函数进入或退去点到TRACE文件中(如果存在的话)//函数的首地址

    0000000000400840 <main>:
      400840:       55                      push   %rbp
      400841:       48 89 e5                mov    %rsp,%rbp
      400844:       53                      push   %rbx
      400845:       48 83 ec 08             sub    $0x8,%rsp
      400849:       48 8b 75 08             mov    0x8(%rbp),%rsi
      40084d:       bf 40 08 40 00          mov    $0x400840,%edi
      400852:       e8 96 01 00 00          callq  4009ed <__cyg_profile_func_enter>
      400857:       b8 00 00 00 00          mov    $0x0,%eax
      40085c:       e8 b3 ff ff ff          callq  400814 <fun>
      400861:       bb 00 00 00 00          mov    $0x0,%ebx
      400866:       48 8b 75 08             mov    0x8(%rbp),%rsi
      40086a:       bf 40 08 40 00          mov    $0x400840,%edi
      40086f:       e8 9c 01 00 00          callq  400a10 <__cyg_profile_func_exit>
      400874:       89 d8                   mov    %ebx,%eax
      400876:       48 83 c4 08             add    $0x8,%rsp
      40087a:       5b                      pop    %rbx
      40087b:       c9                      leaveq
      40087c:       c3                      retq   
      40087d:       90                      nop
      40087e:       90                      nop
      40087f:       90                      nop



    00000000004009ed <__cyg_profile_func_enter>:
      4009ed:       55                      push   %rbp
      4009ee:       48 89 e5                mov    %rsp,%rbp
      4009f1:       48 83 ec 10             sub    $0x10,%rsp
      4009f5:       48 89 7d f8             mov    %rdi,-0x8(%rbp)
      4009f9:       48 89 75 f0             mov    %rsi,-0x10(%rbp)
      4009fd:       48 8b 45 f8             mov    -0x8(%rbp),%rax
      400a01:       48 89 c6                mov    %rax,%rsi
      400a04:       bf a1 0b 40 00          mov    $0x400ba1,%edi
      400a09:       e8 5a ff ff ff          callq  400968 <gnu_ptrace>
      400a0e:       c9                      leaveq
      400a0f:       c3                      retq  

    0000000000400968 <gnu_ptrace>:
      400968:       55                      push   %rbp
      400969:       48 89 e5                mov    %rsp,%rbp
      40096c:       53                      push   %rbx
      40096d:       48 83 ec 18             sub    $0x18,%rsp
      400971:       48 89 7d e8             mov    %rdi,-0x18(%rbp)
      400975:       48 89 75 e0             mov    %rsi,-0x20(%rbp)
      400979:       8b 05 4d 06 20 00       mov    0x20064d(%rip),%eax        # 600fcc <active.3459>
      40097f:       85 c0                   test   %eax,%eax
      400981:       74 5f                   je     4009e2 <gnu_ptrace+0x7a>
      400983:       8b 05 47 06 20 00       mov    0x200647(%rip),%eax        # 600fd0 <first.3458>
      400989:       85 c0                   test   %eax,%eax
      40098b:       74 1f                   je     4009ac <gnu_ptrace+0x44>
      40098d:       e8 36 ff ff ff          callq  4008c8 <gnu_ptrace_init>
      400992:       89 05 34 06 20 00       mov    %eax,0x200634(%rip)        # 600fcc <active.3459>
      400998:       c7 05 2e 06 20 00 00    movl   $0x0,0x20062e(%rip)        # 600fd0 <first.3458>
      40099f:       00 00 00
      4009a2:       8b 05 24 06 20 00       mov    0x200624(%rip),%eax        # 600fcc <active.3459>
      4009a8:       85 c0                   test   %eax,%eax
      4009aa:       74 39                   je     4009e5 <gnu_ptrace+0x7d>
      4009ac:       bb 9a 0b 40 00          mov    $0x400b9a,%ebx
      4009b1:       48 8b 05 30 06 20 00    mov    0x200630(%rip),%rax        # 600fe8 <__GNU_PTRACE_FILE__>
      4009b8:       48 8b 4d e0             mov    -0x20(%rbp),%rcx
      4009bc:       48 8b 55 e8             mov    -0x18(%rbp),%rdx
      4009c0:       48 89 de                mov    %rbx,%rsi
      4009c3:       48 89 c7                mov    %rax,%rdi
      4009c6:       b8 00 00 00 00          mov    $0x0,%eax
      4009cb:       e8 40 fd ff ff          callq  400710 <fprintf@plt>
      4009d0:       48 8b 05 11 06 20 00    mov    0x200611(%rip),%rax        # 600fe8 <__GNU_PTRACE_FILE__>
      4009d7:       48 89 c7                mov    %rax,%rdi
      4009da:       e8 41 fd ff ff          callq  400720 <fflush@plt>
      4009df:       90                      nop
      4009e0:       eb 04                   jmp    4009e6 <gnu_ptrace+0x7e>
      4009e2:       90                      nop
      4009e3:       eb 01                   jmp    4009e6 <gnu_ptrace+0x7e>
      4009e5:       90                      nop
      4009e6:       48 83 c4 18             add    $0x18,%rsp
      4009ea:       5b                      pop    %rbx
      4009eb:       c9                      leaveq
      4009ec:       c3                      retq  

    [root@monitor example]# touch TRACE
    [root@monitor example]# ./test
    this is test
    [root@monitor example]# ll
    total 52
    -rwxr-xr-x 1 root root 16687 Jun  9 09:39 crumble
    -rw-r--r-- 1 root root  1651 Jun  9 09:28 crumble.c
    -rw-r--r-- 1 root root   244 Jun  9 09:05 Makefile
    -rwxr-xr-x 1 root root 13627 Jun  9 09:47 test
    -rw-r--r-- 1 root root    75 Jun  9 09:34 test.c
    -rw-r--r-- 1 root root    68 Jun  9 09:52 TRACE
    [root@monitor example]# cat TRACE
    enter 0x400840 // main进入
    enter 0x400814 // fun进入
    exit 0x400814 // fun退去
    exit 0x400840 // main退去
    EXIT 6993


  • 相关阅读:
    30分钟掌握ES6/ES2015核心内容[上和下], 不错的说
    根据HTML5 获取当前位置的经纬度【百度地图】【高德地图】
    vue2 入门 教程 单页应用最佳实战[*****]
    JavaScript如何比较两个数组的内容是否相同【转】
    推荐下:开源ckplayer 网页播放器, 跨平台(html5, mobile),flv, f4v, mp4, rtmp协议. webm, ogg, m3u8 !
    浅谈 Underscore.js 中 _.throttle 和 _.debounce 的差异[转]
    原生JavaScript插件开发[转]
    性能监控之Spotlight
    Jmeter(三十五)聚合报告
    Jmeter(三十四)Jmeter-Question之“Cookie获取”
  • 原文地址:https://www.cnblogs.com/zengkefu/p/5571961.html
Copyright © 2020-2023  润新知