etrace 跟踪程序函数动态执行流程
https://github.com/elcritch/etrace 窗口1: 监控窗口,执行监控程序,显示监控结果 [root@monitor example]# pwd
/root/etrace-master/example [root@monitor example]# ll
total
-rwxr-xr-x root root Jun : crumble
-rw-r--r-- root root Aug crumble.c
-rw-r--r-- root root Aug Makefile [root@monitor example]# ../src/etrace crumble [root@monitor example]# ll
total
-rwxr-xr-x root root Jun : crumble
-rw-r--r-- root root Aug crumble.c
-rw-r--r-- root root Aug Makefile
prw-r--r-- root root Jun : 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 grams of sugar
buy grams of butter
buy grams of wheat
buy pinch of salt
buy 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 degrees for minutes
../src/etrace crumble \--main
| \--Crumble_make_apple_crumble
| | \--Crumble_buy_stuff
| | | \--Crumble_buy
| | | \--Crumble_buy (total: times)
| | \--Crumble_prepare_apples
| | | \--Crumble_skin_and_dice
| | \--Crumble_mix
| | \--Crumble_finalize
| | | \--Crumble_put
| | | \--Crumble_put (total: times)
| | \--Crumble_cook
| | | \--Crumble_put
| | | \--Crumble_bake
rm -f TRACE
执行原理:
[root@monitor example]# touch TRACE
[root@monitor example]# ./crumble
buy grams of sugar
buy grams of butter
buy grams of wheat
buy pinch of salt
buy 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 degrees for minutes
[root@monitor example]# ll
total
-rwxr-xr-x root root Jun : crumble
-rw-r--r-- root root Jun : crumble.c
-rw-r--r-- root root Jun : Makefile
-rw-r--r-- root root Jun : 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
0000000000400ba1 <main>:
400ba1: push %rbp
400ba2: e5 mov %rsp,%rbp
400ba5: push %rbx
400ba6: ec sub $0x18,%rsp
400baa: 7d ec mov %edi,-0x14(%rbp)
400bad: e0 mov %rsi,-0x20(%rbp)
400bb1: 8b mov 0x8(%rbp),%rsi
400bb5: bf a1 0b mov $0x400ba1,%edi
400bba: e8 8e callq 400d4d <__cyg_profile_func_enter>
400bbf: e8 7a ff ff ff callq 400b3e <Crumble_make_apple_crumble>
400bc4: bb mov $0x0,%ebx
400bc9: 8b mov 0x8(%rbp),%rsi
400bcd: bf a1 0b mov $0x400ba1,%edi
400bd2: e8 callq 400d70 <__cyg_profile_func_exit>
400bd7: d8 mov %ebx,%eax
400bd9: c4 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\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) != )
{
/* No trace file: do not trace at all */
return ;
}
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 ;
} #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 ;
}
} /** Function called by every function event */
void
__NON_INSTRUMENT_FUNCTION__
gnu_ptrace(char * what, void * p)
{
static int first=;
static int active=; if (active == )
return; if (first)
{
active = gnu_ptrace_init();
first = ; if (active == )
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 */
执行原理: test.c
#include <stdio.h>
fun()
{
printf("this is test\n");
}
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
etrace 跟踪程序函数动态执行流程的更多相关文章
- Dalvik模式下System.loadLibrary函数的执行流程分析
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/78212010 Android逆向分析的过程中免不了碰到Android so被加固的 ...
- Java基础毕向东day05 对象与对象的区别,匿名内部类,函数的执行流程。
1.Car c = new Car(); Car c2 = new Car(); 1> c 和 c2之间的区别? public static void main(String[] args) { ...
- python编程系列---多个装饰器装饰一个函数的执行流程
首先看一个例子 ''' 多个装饰器装饰一个函数 ''' # 定义第一个装饰器 def set_func1(func): def wrapper1(*args,**kwargs): print('装饰内 ...
- 自定义函数动态执行SQL语句
Oracle 动态SQL有两种写法:用 DBMS_SQL 或 execute immediate,建议使用后者. DDL 和 DML Sql代码 收藏代码 /*** DDL ***/ begin EX ...
- 从 mian 函数开始一步一步分析 nginx 执行流程(二)
如不做特殊说明,本博客所使用的 nginx 源码版本是 1.0.14,[] 中是代码所在的文件! 上一个博客中我们将 main 函数执行流程分析完,到最后一步调用 ngx_master_process ...
- 【转载】MFC 程序入口和执行流程
原文链接: http://www.cnblogs.com/liuweilinlin/archive/2012/08/16/2643272.html 一 MFC程序执行过程剖析 1)我们知道在WIN32 ...
- android invalidate 执行流程详解
invalidate()函数的主要作用是请求View树进行重绘,该函数可以由应用程序调用,或者由系统函数间接 调用,例如setEnable(), setSelected(), setVisiblity ...
- MFC 程序入口和执行流程
MFC(微软基础类库)以C++类的形式封装了Windows API,给开发者提供了便利,但是初学者常常会疑惑MFC程序的入口在哪里?下面给大家简单介绍一下MFC 程序入口和执行流程. 一 MFC程序执 ...
- 【转】MFC 程序入口和执行流程
一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用 ...
随机推荐
- opencv 构造训练器
D:/face 构造face训练器为例 一:样本创建 训练样本分为正例样本和反例样本,其中正例样本是指待检目标样本,反例样本指其它任意图片. 负样本可以来自于任意的图片,但这些图片不能包含目标特征 ...
- C语言-06数据类型-05 总结
一.基本数据类型1.int1> long int.long:8个字节 %ld2> short int.short:2个字节 %d %i3> unsigned int.unsigned ...
- vs2015安装没有wim32
刚开始在官网上下载VS2015没在意太多,选择了默认安装,结果是没有win64的,所以就不能写c代码.默认安装很多库都没有,所以要什么都得下载.转载一篇文章
- CSS3随笔系列之transform(一)—— transform-origin
transform-origin属性平时似乎用得很少,它决定了变换时依赖的原点.基本的属性特性可以参考CSS手册. 如果在H5动画项目中,用到旋转的话,它还是不能小觑的. 假如我们做一个秋千效果 其实 ...
- jquery事件之event.target用法详解
1. 定义和用法: 显示哪个 DOM 元素触发了事件: $("p, button, h1, h2").click(function(event){ $("div" ...
- 自定义JSON配置器
比如要写个专门处理float类型的方法,然后注册到JSON配置器中,具体如下: 配置器代码如下: import java.math.RoundingMode; import java.text.Num ...
- QT的父子Widget之间消息的传递(如果子类没有accept或ignore该事件,则该事件会被传递给其父亲——Qlabel与QPushButton的处理就不一样)
以前我一直以为:在父widget上摆一个子widget后,当click子widget时:只会进入到子widget的相关事件处理函数中,比如进入到mousePressEvent()中, 而不会进入到父w ...
- java基础随笔-overload和override
今天重温了一下方法重载和方法重写. 首先是方法重写(override)的几点要求: 1.必须继承父类或者实现某接口的方法. 2.方法名称和参数必须和父类(或者实现的接口方法)完全一致. 3.重写的修饰 ...
- mysql表分区、查看分区
原文地址:http://blog.csdn.net/feihong247/article/details/7885199 一. mysql分区简介 数据库分区 数据库分区是一种物理数据库设 ...
- Node.js权威指南 (10) - Node.js中的错误处理与断言处理
10.1 使用domain模块处理错误 / 272 10.1.1 domain模块概述 / 272 10.1.2 创建并使用Domain对象 / 274 10.1.3 隐式绑定与显式绑定 / 276 ...