sharptooth
sharptooth

Reputation: 170549

How to trace all calls to a predefined set of functions in C++?

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

Answers (6)

minjang
minjang

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

Java Spring Coder
Java Spring Coder

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

Frank Bollack
Frank Bollack

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

ezpz
ezpz

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

count0
count0

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

AndersK
AndersK

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

Related Questions