Reputation: 859
I want to see the code flow of a basic program such as below.
#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;
}
I want to see the complete sequence of function calls executed when this program is run. I tried using strace and ptrace, but they only list the system calls :( Any suggestions on how this can be done ?
Thanks in advance !!
Upvotes: 1
Views: 1890
Reputation: 25579
When you compile for profiling, using -pg
the compiler automatically inserts a call to a function named mcount
. This function is provided by a special library, and creates a database of all calls (with from-address and to-address, and a counter).
However, if you provide your own mcount function (be careful not to compile that with profiling enabled!) it can do whatever you like.
I've not tested this, and I don't really know what the mcount parameters are (although I'm sure it's not too hard to find out) but a sample implementation might look like this:
void mcount (void *to)
{
void *from = __builtin_return_address ();
printf ("call from %p to %p\n", from, to);
}
You can then use addr2line
to figure out what function contains what address.
There is a problem though: it only counts functions that have been compiled with profiling enabled, and this probably doesn't include the C library functions, such as printf.
However, if your system does have a profile enabled C library then you'll have to be very careful calling functions that might then call mcount
, or else you'll get an infinite loop. One solution would be to output the text manually using syscalls directly, maybe written in asm. Another solution would be to detect recursive calls and return without doing anything, but that'll be problematic in a multithreaded application, or even with signal handlers.
Upvotes: 0
Reputation: 4290
Have you access to a Mac, Solaris or FreeBSD machine?
They all have DTrace, and by using the appropriate provider, you can trace pretty much anything you want. If you have access to a machine with one of those OS's, have a look at the dtrace user guide (preferably find a downloadable pdf)
This might give you a script which does give a program trace:
http://www.dtracebook.com/index.php/Applications
or
http://www.brendangregg.com/dtrace.html
Upvotes: 0
Reputation: 97948
You can use gnu profiler gprof .
Compile it (main.cc) with -pg
flags:
gcc -pg main.cc -o main
Then execute it (./main
). Your binary will produce a file (gmon.out
). Then you can get the trace by using gprof:
gprof main gmon.out
with your example I get:
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]
this is not much info because your application is not complex.
If you want to trace system calls, try strace ./main
. The output is long, you'll see all the system calls:
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
....
Upvotes: 5
Reputation: 4290
This is not about a call trace, which has been answered, but I think that code contains a bug, which may be why you are asking.
close
should be fclose
, to match the fopen
close
is for file descriptors, not FILE*
which is returned by fopen
Upvotes: 2