4

I want to see what functions are called in my user-space C99 program and in what order. Also, which parameters are given.

Can I do this with DTrace?

E.g. for program

int g(int a, int b) { puts("I'm g"); }
int f(int a, int b) { g(5+a,b);g(8+b,a);}
int main() {f(5,2);f(5,3);}

I wand see a text file with:

main(1,{"./a.out"})
 f(5,2);
  g(10,2);
   puts("I'm g");
  g(10,5);
   puts("I'm g");
 f(5,3);
  g(10,3);
   puts("I'm g");
  g(11,5);
   puts("I'm g");

I want not to modify my source and the program is really huge - 9 thousand of functions.

I have all sources; I have a program with debug info compiled into it, and gdb is able to print function parameters in backtrace.

Is the task solvable with DTrace?

My OS is one of BSD, Linux, MacOS, Solaris. I prefer Linux, but I can use any of listed OS.

Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
osgx
  • 90,338
  • 53
  • 357
  • 513

3 Answers3

1

Here's how you can do it with DTrace:

script='pid$target:a.out::entry,pid$target:a.out::return { trace(arg1); }'
dtrace -F -n "$script" -c ./a.out

The output of this command is like as follows on FreeBSD 14.0-CURRENT:

dtrace: description 'pid$target:a.out::entry,pid$target:a.out::return ' matched 17 probes
I'm g
I'm g
I'm g
I'm g
dtrace: pid 39275 has exited
CPU FUNCTION
  3  -> _start                                      34361917680
  3    -> handle_static_init                    140737488341872
  3    <- handle_static_init                            2108000
  3    -> main                                  140737488341872
  3      -> f                                                 2
  3        -> g                                               2
  3        <- g                                           32767
  3        -> g                                               5
  3        <- g                                           32767
  3      <- f                                                 0
  3      -> f                                                 3
  3        -> g                                               3
  3        <- g                                           32767
  3        -> g                                               5
  3        <- g                                           32767
  3      <- f                                                 0
  3    <- main                                                0
  3    -> __do_global_dtors_aux                 140737488351184
  3    <- __do_global_dtors_aux                               0

The annoying thing is that I've not found a way to print all the function arguments (see How do you print an associative array in DTrace?). A hacky workaround is to add trace(arg2), trace(arg3), etc. The problem is that for nonexistent arguments there will be garbage printed out.

Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
0

Yes, you can do this with dtrace. But you probably will never be able to do it on linux. I've tried multiple versions of the linux port of dtrace and it's never done what I wanted. In fact, it once caused a CPU panic. Download the dtrace toolkit from http://www.brendangregg.com/dtrace.html. Then set your PATH accordingly. Then execute this:

 dtruss -a yourprogram args...
osgx
  • 90,338
  • 53
  • 357
  • 513
Jeff Holt
  • 2,940
  • 3
  • 22
  • 29
  • Jeff, so this - `dtruss` - is the only command I need? My question is not limited to Linux, so if it works on Solaris, Mac OS, or FreeBSD - this is fine. But man page of dtruss says it will only show syscalls, but not usual functions from the `./myprogram` itself. – osgx May 08 '13 at 19:16
  • Doesn't dtruss only trace syscalls? – Nickolay Jun 22 '13 at 21:28
  • If you want to trace non-syscalls as well, you can use the `fbt` provider instead. To describe entry and exit of every userland function, use `fbt:::entry, fbt:::return` in your probe specifier. I'm not sure how you would print the arguments to everything though - I'd recommend taking a look at how the `dtruss` script does it. If it's enumerating all the syscalls and grouping them by shared argument type signatures, you will probably want to find another way to do it. – Dan Jun 28 '13 at 06:46
  • 1
    @osgx No, dtruss will only trace system calls just as gerty3000 says but the fbt provider won't do it either. You have no choice but to instrument your code with dtrace probes. At the time of my search, this is the first link I found showing you how to do it: http://www.ibm.com/developerworks/aix/library/au-dtraceprobes.html. If you want to run instrumented code on non-dtrace platforms, then I would recommend abstracting the macros so that on dtrace platforms it uses dtrace and on other platforms it uses something else. – Jeff Holt Aug 14 '13 at 16:37
  • jeff6times7, thanks. So, is actually your answer "No, you can't do it without instumenting"? – osgx Aug 14 '13 at 20:41
-3

Your question is exceedingly likely to be misguided. For any non-trivial program, printing the sequense of all function calls executed with their parameters will result in multi-MB or even multi-GB output, that you will not be able to make any sense of (too much detail for a human to understand).

That said, I don't believe you can achieve what you want with dtrace.

You might begin by using GCC -finstrument-functions flag, which would easily allow you to print function addresses on entry/exit to every function. You can then trivialy convert addresses into function names with addr2line. This gives you what you asked for (except parameters).

If the result doesn't prove to be too much detail, you can set a breakpoint on every function in GDB (with rb . command), and attach continue command to every breakpoint. This will result in a steady stream of breakpoints being hit (with parameters), but the execution will likely be at least 100 to 1000 times slower.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • 1
    Actually I already did something like this using gdb (calltrace). The output was very helpful. Multi-100MB file can be filtered and compared with another multi100MB file. http://stackoverflow.com/questions/311840/tool-to-trace-local-function-calls-in-linux/1980793#1980793 – osgx Aug 24 '11 at 08:53