callgrind logic maintains the stack incrementally. This implies that it has to understand the calling convention of all what is on the stack, detect the
calls and the returns.
You might compare with the valgrind unwinder and the gdb unwinder using gdb+vgdb.
Start valgrind with: valgrind --vgdb-error=0 --vgdb=full ....
Put a breakpoint in the C code called by the interpreter language,
and continue the execution.
When breakpoint is encountered, compare the result of the 2 following
gdb commands:
- backtrace
- monitor v.info scheduler
The above will show if gdb and/or valgrind unwinders are working properly.
You can try to understand what callgrind does by using some valgrind
debugging options, e.g.
valgrind --tool=callgrind -v -v -v -d -d -d --ct-verbose=3
(adjust the nr of -v/-d/verbosity to your taste).
And of course, in case you have an old version of valgrind, you might
try with the last release or even the git repository, even if I doubt
something recently changed in this area.