C/C++ need a clever way to track function calls
Solution 1
Most compilers allow you to inject an instrumentation function before and after the function call.
In MSVC they are _penter
and _pexit
. A nice article: http://www.drdobbs.com/184403601.
In GCC you would use the -finstrument-functions
option, see the docs.
You can use debug libaries or map files to get more info.
Solution 2
A quite intrussive solution is using RAII to control the scope of the function. This will have a great impact in performance, but will be quite explicit in the logs without requiring the user to add instrumentation in all possible code paths that may leave the function:
class ScopeLogger {
public:
ScopeLogger( std::string const & msg ) : msg(msg)
{ std::cout << "Enter: " << msg << std::endl; }
~ScopeLogger()
{ std::cout << "Exit: " << msg << std::endl; }
std::string msg;
};
#if DEBUG
#define FUNCTION(x) ScopeLogger l_##x##_scope(x);
#endif
void foo( int value ) {
FUNCTION( __FUNCTION__ );
if ( value > 10 ) throw std::exception;
std::cout << "." << std::endl;
}
int main() {
foo(0); // Enter: foo\n.\nExit: foo
foo(100); // Enter: foo\nExit: foo
}
If the code is single threaded, you might even want to add a static variable with some indentation level to ScopedLogger
without adding too much to the already heavy performance impact:
class ScopeLogger {
public:
ScopeLogger( std::string const & msg ) : msg(msg)
{ std::cout << std::string(indent++,' ') << "Enter: " << msg << std::endl; }
~ScopeLogger()
{ std::cout << std::string(--indent,' ') << "Exit: " << msg << std::endl; }
std::string msg;
static int indent;
};
int ScopeLogger::indent = 0;
Solution 3
Since you are using GCC, you can also use linker function wrapping.
Link-Time Replacement / Wrapping
– GCC option: -Wl,--wrap,function_name
Basically, you can take a function called "function_name()" and wrap it with a function called "__wrap_function_name()". You can access the original function by calling "__real_function_name()".
Solution 4
#define BEGIN_FUNC(X) printf("Function %s Entered",X)
#define END_FUNC(X) printf("Function %s End",X)
foo()
{
BEGIN_FUNC(__func__);
//Your code here
END_FUNC(__func__);
}
I think if you write a macro like above and use it for every function as described then you can get the logs on the terminal.
Solution 5
You may want to look at Valgrind's Callgrind which can track function calls into a pretty graph. It will show function calls, but not the parameter or return values.
Comments
-
Matthew FL almost 2 years
I am looking for a clever way to track function calls and returns. I know I can use the debugger, but I would like a way to just have it print something out to the terminal when calling a function vs having to step through code.
I am thinking that I might be able to use the preprocessor, but I am not sure what would be the best way to go about this.
Or is there a way to use gdb to print out the information that would be useful, while not having to step through the code. -
Matthew FL almost 14 yearsYou would not happen tp know how to look up the function in the symbol table in gcc
-
David Rodríguez - dribeas almost 14 yearsThis is quite fragile. If you are programming c++, you are better off writing a small scope logger that will log on construction and on object destruction. Else you might see functions that are entered and never returned from if exceptions are thrown or if the user forgets to write the
END_FUC
macro in any returning code path. -
Praveen S almost 14 yearsWill it not help in debugging by seeing the logs? The OP stated any method to know call stack without using debugger. We can use this on every API of the executable and hence get the stack at any point of time.
-
Praveen S almost 14 years@Nyan- I think its implied when we say start and end of function calls that it has to be added before every return.
-
Stephen almost 14 yearsQuite intrusive, but less than Praveen's.
-
Jonathan Fischoff almost 14 yearsDo you want to find the name, or look up things like parameters etc. in the debug objects?
-
Mohamed Bana about 12 yearsDoes your code compile? Where is the contructor for
std::string
to make thisstd::string(indent++," ")
valid? -
David Rodríguez - dribeas about 12 years@bruce.banner: Good catch, that's what happens when you type into a webpage rather than in an editor and compile. The second argument must be a
char
, not achar*
(i.e. I mistakenly had double quotes where single quotes were required). At any rate, use this just as an idea, the code has other issues, including but probably not limited to thread safety (or the lack of it). -
reader about 9 yearsJust the name would be fine. #delay
-
Daniel Moodie over 8 yearslink Dl_info this_fn_info; dladdr( this_fn, &this_fn_info );
-
Michael over 8 years@DanielMoodie There is a "call site" parameter, can I use this to find the file and line number the call was made from, e.g. _FILE_ and _LINE_?