跟踪程序流程图

安装pvtrace和Graphviz

1. 安装pvtrace

 
 
  1. $ mkdir -p ~/project1 && cd ~/project1
  2. $ wget http://www.mtjones.com/developerworks/pvtrace.zip
  3. $ unzip pvtrace.zip -d pvtrace
  4. $ cd pvtrace
  5. $ make
  6. $ sudo make install
  7.  
  8. # 查看pvtrace相关文件
  9. $ ls -1 pvtrace
  10. instrument.c
  11. Makefile
  12. stack.c
  13. stack.h
  14. symbols.c
  15. symbols.h
  16. trace.c

2. 安装graphviz

 
 
  1. $ sudo yum install graphviz

测试

在完成软件安装之后,编写一个测试程序(test.c),并进行测试。具体流程,如下:

1. 编辑测试文件test.c

 
 
  1. $ cd ~/project1
  2. $ cat << EOF > test.c
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5.  
  6. void test1()
  7. {
  8. printf("in test1.\n");
  9. }
  10.  
  11. void test2()
  12. {
  13. test1();
  14. printf("in test2.\n");
  15. }
  16.  
  17. void test3()
  18. {
  19. test1();
  20. test2();
  21.  
  22. printf("in test3.\n");
  23. }
  24.  
  25. int main(int argc, char *argv[])
  26. {
  27. printf("Hello wolrd.\n");
  28.  
  29. test1();
  30. test2();
  31. test3();
  32.  
  33. return 0;
  34. }
  35. EOF

2. 编译测试程序

 
 
  1. $ gcc -g -finstrument-functions test.c ./pvtrace/instrument.c -o test
  2.  
  3. 注意: 必须有`-g -finstrument-functions`选项,否则后续就采集不到信息了。

3. 执行程序,生成信息文件trace.txt

 
 
  1. $ ./test

4. 通过pvtrace、可执行文件及trace.txt,生成信息文件graph.dot

 
 
  1. $ pvtrace test

5. 通过dot工具将graph.dot,转为图像文件graph.png

 
 
  1. $ dot -Tpng graph.dot -o graph.png

6. 浏览生成的图片

最终生成的图形效果,如下:

为已有的项目生成函数调用图

可以通过以下步骤为已有的项目生成函数调用图:

1. 将pvtrace源代码中的instrument.c文件拷贝到项目中;

2. 增加对instrument.c文件的编译

3. 修改编译选项:增加-g -finstrument-functions

4. 修改连接选项:将instrument.o连接到可执行文件中

5. 执行你的程序

6. 用pvtrace及“你的可执行文件”处理trace.txt

7. 用dot生成函数调用关系图

以下是对redis-2.4.17版本的处理,然后生成redis-cli启动及一个set操作对应的函数调用关系图:

支持C++的扩展

目前pvtrace不支持C++代码,如果有人希望改进,一种可行的改进思路,如下:

1. 修改instrument.c文件,支持C++环境的编译;

2. 通过c++filt工具处理解析到的函数名标签,解析出实际的函数名: 为了支持继承、多态及函数重载等,C++编译时对函数名进行了特殊处理;

3. 采用合理的编码方式,确保步骤2中生成的函数名满足dot的语法(C++是用整个函数原型等信息来生成的函数签名的,所以步骤2中用c++filt翻译出来的是函数原型(包括名字空间等信息));

4. 增加函数调用先后顺序的标识。











目标建立 nginx的运行流程图 
参考https://www.ibm.com/developerworks/cn/linux/l-graphvis/ 
参考《深入剖析nginx》 
参考http://stackoverflow.com/questions/6344318/pure-javascript-graphviz-equivalent/14866384 
参考http://graphviz.org/content/cluster 
my_debug.h 

Java代码   收藏代码
  1. #ifndef MY_DEBUG_LENKY_H                                                                                                                                                  
  2. #define MY_DEBUG_LENKY_H  
  3. #include <stdio.h>  
  4. void enable_my_debug( void ) __attribute__((no_instrument_function));  
  5. void disable_my_debug( void ) __attribute__((no_instrument_function));  
  6. int get_my_debug_flag( void ) __attribute__((no_instrument_function));  
  7. void set_my_debug_flag( int ) __attribute__((no_instrument_function));  
  8. void main_constructor( void  ) __attribute__((no_instrument_function,constructor));  
  9. void main_destructor( void  ) __attribute__((no_instrument_function,destructor));  
  10. void __cyg_profile_func_enter( void *,void *  ) __attribute__((no_instrument_function));  
  11. void __cyg_profile_func_exit( void *,void *  ) __attribute__((no_instrument_function));  
  12.   
  13. #ifndef MY_DEBUG_MAIN  
  14. extern FILE *my_debug_fd;  
  15. #else  
  16. FILE *my_debug_fd;  
  17. #endif  
  18. #endif  

my_debug.c 
Java代码   收藏代码
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. /* Function prototypes with attributes */  
  5. void main_constructor( void )  
  6.     __attribute__ ((no_instrument_function, constructor));  
  7.   
  8. void main_destructor( void )  
  9.     __attribute__ ((no_instrument_function, destructor));  
  10.   
  11. void __cyg_profile_func_enter( void *, void * )   
  12.     __attribute__ ((no_instrument_function));  
  13.   
  14. void __cyg_profile_func_exit( void *, void * )   
  15.     __attribute__ ((no_instrument_function));  
  16.   
  17.   
  18. static FILE *fp;  
  19.   
  20.   
  21. void main_constructor( void )  
  22. {  
  23.   fp = fopen( "/usr/local/nginx_sendfile/sbin/trace.txt""w" );  
  24.   if (fp == NULL) exit(-1);  
  25. }  
  26.   
  27.   
  28. void main_deconstructor( void )  
  29. {  
  30.   fclose( fp );  
  31. }  
  32.   
  33.   
  34. void __cyg_profile_func_enter( void *thisvoid *callsite )  
  35. {  
  36.   fprintf(fp, "E%p\n", (int *)this);  
  37. }  
  38.   
  39.   
  40. void __cyg_profile_func_exit( void *thisvoid *callsite )  
  41. {  
  42.   fprintf(fp, "X%p\n", (int *)this);  
  43. }  

把my_debug.c和my_debug.h放到nginx的src/core/目录下 
./configure后修改ojbs/Makefile文件 
Java代码   收藏代码
  1. CFLAGS =  -pipe  -O -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror -g -finstrument-functions  
  2. ...  
  3. 18 CORE_DEPS = src/core/nginx.h \  
  4. 19     src/core/my_debug.h \   
  5. .....  
  6.   84 HTTP_DEPS = src/http/ngx_http.h \  
  7.   85     src/core/my_debug.h \  
  8. ....  
  9.   
  10.  105 objs/nginx: objs/src/core/nginx.o \  
  11.  106     objs/src/core/my_debug.o \    
  12. ......  
  13.  216     $(LINK) -o objs/nginx \  
  14.  217     objs/src/core/nginx.o \  
  15.  218     objs/src/core/my_debug.o \   
  16. ......  
  17.  331 objs/src/core/my_debug.o:   $(CORE_DEPS) src/core/my_debug.c                                                                                                         
  18.  332     $(CC) -c $(CFLAGS) $(CORE_INCS) \  
  19.  333         -o objs/src/core/my_debug.o \  
  20.  334         src/core/my_debug.c  

make&&make install后 
启动nginx,生成 
/usr/local/nginx_sendfile/sbin/trace.txt 
文件类似 
Java代码   收藏代码
  1. [root@haoning sbin]# head trace.txt   
  2. E0x403f88  
  3. E0x41f5ac  
  4. X0x41f5ac  
  5. E0x403f88  
  6. X0x403f88  
  7. E0x410425  
  8. E0x40ff83  
  9. E0x40fa71  
  10. X0x40fa71  
  11. E0x40ad4b  

使用https://www.ibm.com/developerworks/cn/linux/l-graphvis/中的pvtrace 
修改代码 
symbols.h 中的 
Java代码   收藏代码
  1. 13 #define MAX_FUNCTIONS       20000  
  2. 14 #define MAX_FUNCTION_NAME   5000   

否函数太多会报错 
pvtrace nginx 
会得到 
graph.dot 
dot -Tjpg graph.dot -o graph.jpg 
生成jpg, 
这个.dot也可以用 
http://www.tuidaoba.com/html/graphviz/ 
生成svg的图 
根据dot的格式生成svg图的js为 
Java代码   收藏代码
  1. <html>  
  2. <head>  
  3.     <meta charset="utf-8">  
  4.     <title>Viz.js</title>  
  5. </head>  
  6. <body>  
  7. <script type="text/vnd.graphviz"  id="cluster">  
  8. digraph G {  
  9.     subgraph cluster_0 {  
  10.         style=filled;  
  11.         color=lightgrey;  
  12.         node [style=filled,color=white];  
  13.         a0 -> a1 -> a2 -> a3;  
  14.         label = "process #1";  
  15.     }  
  16.     subgraph cluster_1 {  
  17.         node [style=filled];  
  18.         b0 -> b1 -> b2 -> b3;  
  19.         label = "process #2";  
  20.         color=blue  
  21.     }  
  22.     start -> a0;  
  23.     start -> b0;  
  24.     a1 -> b3;  
  25.     b2 -> a3;  
  26.     a3 -> a0;  
  27.     a3 -> end;  
  28.     b3 -> end;  
  29.     start [shape=Mdiamond];  
  30.     end [shape=Msquare];  
  31. }  
  32. </script>  
  33.   <script src="viz.js"></script>  
  34.   <script>  
  35.       function inspect(s) {  
  36.         return "<pre>" + s.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;") + "</pre>"  
  37.       }  
  38.       function src(id) {  
  39.         return document.getElementById(id).innerHTML;  
  40.       }  
  41.       function example(id, format, engine) {  
  42.         var result;  
  43.         try {  
  44.           result = Viz(src(id), format, engine);  
  45.           if (format === "svg")  
  46.             return result;  
  47.           else  
  48.             return inspect(result);  
  49.         } catch(e) {  
  50.           return inspect(e.toString());  
  51.         }  
  52.       }  
  53.       document.body.innerHTML += "<h1>Cluster (svg output)</h1>";  
  54.       document.body.innerHTML += example("cluster""svg");  
  55.       </script>  
  56. </body>  
  57. </html>  

结果如图 


附件中 
graph.dot.jpg 下载后改成graph.dot用文本打开可以看到dot文件内容 

nginx.conf前面要加上 
master_process off;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在安全网上逛的时候,突然发现一篇很好的文章!详细阐述了当前流行的api hook技术,rootkit技术和主动防御技术,涉及到深入的操作系统知识,需要一定的功底才能看懂,真的很不错,可以说是一篇难得的教程!现摘选如下: 一. 黑匣子的原理 对于一般用户而言,一个程序从开始运行直到结束,这期间内都做过什么,并不是我们需要关心的事情,他们只要听到播放器里的音乐、看到电影画面、和远方的朋友用通讯工具聊天就可以了,有谁会去关心从用户点击播放器程序图标到音乐响起的时间里,这个程序具体做了什么事情呢?然而,如果面对的程序是恶意软件之流,用户就不得不关心一下它到底对自己的计算机造成什么影响了。 程序在运行期间所进行的操作被称为“程序行为”(Action),一般泛指程序进行的相对表现较明显的操作,例如创建读写文件、访问注册表、连接网络等,而在这些操作之外做的程序内部运算、判断、逻辑等操作并不是我们需要关心的,除非是对它进行复杂的分析如逆向工程。对程序行为进行监视记录的过程就是“跟踪”(Tracing),如果要进一步深入,则要使用调试器(Debugger)环境进行汇编级的指令分析,这就是“调试”(Debugging),也可视为更全面的跟踪,因为调试过程可观察到整个程序里的运算和每一步过程。 也许很多用户会觉得,这些复杂技术距离我们很远,甚至会想像为需要复杂设备和程序才能完成,其实,这些技术的应用范围,一直就在我们身边。如果你正在使用一款防毒产品,那么你系统里执行的程序就已经处于被记录行为的状态了;如果你使用HIPS产品,就会更强烈的感受到程序运行被监视着;如果你正在使用调试器,那就不用我说了吧…… 在Windows系统里,至少有三种技术可以实现程序行为的记录,甚至控制程序的某些行为,分别是“虚拟机”(VM)、“API钩子”(API Hooking)和“API跟踪”(API Tracing)。 应用广泛的虚拟机技术 经常提到的虚拟机技术有两种,一种是普遍应用上的虚拟机技术,它是通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统,此类虚拟机的概念比较广泛,可以是一种使用软件模拟一个完整的计算机硬件环境技术如VMWare,也可以是介于硬件和编译程序之间的交互介质,如Java虚拟机等;另一种则是反病毒产品中使用的“通用解密器”技术,为了检测一些复杂或者代码加密的病毒,杀毒引擎必须让它运行起来以便自我暴露危险程序行为,但是如果病毒真的在用户计算机里运行了,就违背反病毒产品的初衷了,因此反病毒产品也采取了一种虚拟环境检测方法,这就是虚拟机技术,但是这个技术并非是为病毒提供一套计算机仿真系统,这样就太庞大复杂和消耗资源了,这种虚拟机是指杀毒引擎模拟出一个仿真CPU,这个“CPU”具备和真正CPU等同的指令分析功能,杀毒引擎将待检测的程序代码读入“CPU”中逐条指令循环执行,直到出现特定情况才结束工作,在这个过程中探知程序是否具备病毒行为特征或者暴露出病毒特征码。这就是杀毒引擎的“虚拟机技术”,它的目的就是让程序文件在没有实际运行的情况下得到运行后的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值