我想看一下基本程序的代码流程,如下所示。
#include<stdio.h>
int main ()
{
FILE *fptr = fopen("/mnt/myfilesystem/test.txt", "r");
if(fptr) {
printf("open successful\n");
fclose(fptr);
}
else
printf("open failed\n");
return 0;
}
我希望看到运行此程序时执行的完整函数调用序列。 我尝试使用strace和ptrace,但他们只列出系统调用:( 关于如何做到这一点的任何建议?
提前致谢!!
答案 0 :(得分:5)
您可以使用gnu profiler gprof。
使用-pg
标志编译它(main.cc):
gcc -pg main.cc -o main
然后执行它(./main
)。您的二进制文件将生成一个文件(gmon.out
)。然后,您可以使用gprof:
gprof main gmon.out
我的例子我得到了:
index % time self children called name
0.00 0.00 1/1 __do_global_ctors_aux [9]
[7] 0.0 0.00 0.00 1 global constructors keyed to main [7]
0.00 0.00 1/1 __static_initialization_and_destruction_0(int, int) [8]
-----------------------------------------------
0.00 0.00 1/1 global constructors keyed to main [7]
[8] 0.0 0.00 0.00 1 __static_initialization_and_destruction_0(int, int) [8]
这个信息不多,因为您的应用程序并不复杂。
如果要跟踪系统调用,请尝试strace ./main
。输出很长,您将看到所有系统调用:
execve("", [""], [/* 26 vars */]) = 0
brk(0) = 0x877f000
access("", F_OK) = -1 ENOENT
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7748000
access("", R_OK) = -1 ENOENT
open("", O_RDONLY) = -1 ENOENT
open("", O_RDONLY) = -1 ENOENT
stat64("", 0xbfdc4a18) = -1 ENOENT
open("", O_RDONLY) = -1 ENOENT
stat64("", {st_mode=S_IFDIR|0755, st_size=6104, ...}) = 0
open("", O_RDONLY) = -1 ENOENT
open("", O_RDONLY) = 3
....
答案 1 :(得分:3)
听起来你想要ltrace。
答案 2 :(得分:2)
这不是一个已经回答的呼叫追踪,但我认为该代码包含一个错误,这可能是你问的原因。
close
应为fclose
,以匹配fopen
close
用于文件描述符,而不是由FILE*
fopen
答案 3 :(得分:0)
您是否可以访问Mac,Solaris或FreeBSD计算机?
他们都有DTrace,通过使用适当的提供程序,您可以追踪任何您想要的东西。如果您可以访问具有其中一个操作系统的计算机,请查看dtrace用户指南(最好找到可下载的pdf)
这可能会为您提供一个脚本,它可以提供程序跟踪:
http://www.dtracebook.com/index.php/Applications
要么
http://www.brendangregg.com/dtrace.html
答案 4 :(得分:0)
静态编译和反汇编。
答案 5 :(得分:0)
编译进行性能分析时,使用-pg
编译器会自动插入对名为mcount
的函数的调用。此函数由特殊库提供,并创建所有调用的数据库(具有from-address和to-address以及计数器)。
但是,如果你提供自己的mcount函数(小心不来编译启用了性能分析!)它可以做你喜欢的任何事情。
我没有测试过这个,我真的不知道mcount参数是什么(虽然我确定它不是很难找到)但是示例实现可能如下所示:
void mcount (void *to)
{
void *from = __builtin_return_address ();
printf ("call from %p to %p\n", from, to);
}
然后,您可以使用addr2line
来确定哪个函数包含哪个地址。
但是存在一个问题:它只计算已启用分析编译的函数,而可能不包含C库函数,例如printf。
但是,如果您的系统确实启用了配置文件C库,那么您必须非常小心地调用可能会调用mcount
的函数,否则您将得到一个无限循环。一种解决方案是直接使用系统调用手动输出文本,也可以用asm编写。另一种解决方案是检测递归调用并返回而不做任何事情,但这在多线程应用程序中甚至是信号处理程序中都会出现问题。