Reputation: 170549
I have a C++ application that uses a third-party library. Every here and there in my code there're calls to that library. I would like to trace all such calls.
It would be easy if those were functions in my code - I would insert a macro that would obtain the current function name and time of call start and pass those to a local object constructor, then on function exit the object would be destroyed and trace the necessary data. The macro would expand to an empty string for configurations where I don't need tracing to eliminate the associated overhead.
Is there some easy way to reliably do something similar for calls to an external library? All the interface to the library I have is the .h file with functions prototypes included into my code.
Upvotes: 2
Views: 1457
Reputation: 9070
If you don't want to change your code, then there is a way to do such thing by instrumentation. If you're interested in this way, take a look at a nice dynamic-binary instrumentation toolkit called PIN (maintained by Intel):
http://www.pintool.org/downloads.html
With PIN, you can insert your own code on function entry/exit. One example would be capturing malloc/free:
http://www.pintool.org/docs/29972/Pin/html/index.html#FindSymbol
This is quite different way to trace the function calls. But, it's worth to take a look.
Upvotes: 0
Reputation: 1027
Try to create a macro for all interface apis e.g. Suppose the api is being called as:
obj->run_first(var1);
Then create below macro:
#define obj->run_first(args) \
dumptimestamp(__FUNCTION__, __LINE__); \
obj->run_first(args); \
dumptimestamp(__FUNCTION__, __LINE__);
You can generate the list of similar macros from a lib's header file as it has the list of all interface methods.
dumptimestamp
will dump the timestamp along with the function and line numbers.
Upvotes: 0
Reputation: 25206
You could try writing a wrapper library that exposes the same interface and internally redirects the calls to the original lib.
Then you can easily add your trace code to the wrapper functions. All that changes for your project is the lib your are going to link against.
To prevent multiple symbols being defined, you can include the external libs header inside a separate namespace.
EDIT:
Including the external libs header in a namespace does not solve the symbol problem. You have to use a macro in your header that renames the original function and every occurrence in your code. Use something like this for new wrapper library header:
#define originalExportedFunction WRAPPED_originalExportedFunction
extern "C" int originalExportedFunction(int);
Your implementation in the wrapper lib then might look like:
extern "C" int WRAPPED_originalExportedFunction(int i)
{
//trace code here...
return originalExportedFunction(i);
}
Upvotes: 4
Reputation: 12047
Since you seem to know the functions you want to call (and the signatures for those calls) you can still use your macro/class wrapper idea. Something like:
typedef void (*pfun)(int);
class Foo {
pfun call;
public:
Foo(pfun p) : call(p) {}
void operator()(int x) {
std::cout << "Start trace..." << std::endl;
(*call)(x);
std::cout << "End trace" << std::endl;
}
};
void bar (int x) {
std::cout << "In bar: " << x << std::endl;
}
int main () {
Foo foo(&bar);
foo (42);
return 0;
}
Upvotes: 0
Reputation: 2621
If you happen to work under unix/linux use
ltrace
to track library calls,
strace
for system calls. These are commands no in code solution though. You can also look at valgrind with the -callgrind option to profile.
Upvotes: 3
Reputation: 36092
Well you could just add another layer on top of the 3rd party lib calls. That way you can add whatever sophisticated tracing wrapping you want.
e.g.
struct trace
{
static void myfoo() { cout << "calling foo" << endl; foo(); }
// or
// static void myfoo() { if (_trace) {..} foo(); }
};
Upvotes: 0