etrace 跟踪程序函数动态执行流程
Posted zengkefu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了etrace 跟踪程序函数动态执行流程相关的知识,希望对你有一定的参考价值。
https://github.com/elcritch/etrace 窗口1: 监控窗口,执行监控程序,显示监控结果 [[email protected] example]# pwd /root/etrace-master/example [[email protected] 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 [[email protected] example]# ../src/etrace crumble [[email protected] 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:执行程序
[[email protected] 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:显示程序监控结果
[[email protected] 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
原理:
[[email protected] 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
[[email protected] example]# make //执行原理
gcc -g -finstrument-functions --std=gnu99 -o crumble crumble.c ../src/ptrace.c
单窗口也可以显示跟踪结果
[[email protected] 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
[[email protected] 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\n", (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]\n"); return 0; } #ifdef PTRACE_REFERENCE_FUNCTION fprintf(TRACE,"%s %s %p\n", 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\n", 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 */
以上是关于etrace 跟踪程序函数动态执行流程的主要内容,如果未能解决你的问题,请参考以下文章