17

I want to add some code before every function call to do some checking. The only way I know is:

#define SOME_CODE printf("doing something...");

class testObject
{
void function1()
{
 SOME_CODE
 ...
}
void function2()
{
 SOME_CODE
 ...
}
}

Is there a cleaner way to achieve this? I'm looking for a method so I don't have add "SOME_CODE" to every function manually.

Christophe
  • 851
  • 1
  • 8
  • 19

6 Answers6

13

For gcc there's a similar solution to the MSVC one someone else posted as an answer:

#include <iostream>
int depth=-1;
extern "C" {
    void __cyg_profile_func_enter (void *, void *) __attribute__((no_instrument_function));
    void __cyg_profile_func_exit (void *, void *) __attribute__((no_instrument_function));
    void __cyg_profile_func_enter (void *func,  void *caller)
    {
        depth++;
    }


    void __cyg_profile_func_exit (void *func, void *caller)
    {
        depth--;
    }
}

class Foo {
public:
    void bar() {
        std::cout << "bar: " << depth << std::endl;
    }
};

int main() {
    Foo f;
    f.bar();
    return 0;
}

Compile with g++ -Wall -Wextra -finstrument-functions. Be careful not to call an instrumented function from within the instrument hooks though! (See the man page for ways of excluding things)

Flexo
  • 87,323
  • 22
  • 191
  • 272
  • 2
    If you use a thread-local variable to prevent re-entry into __cyg_profile_func_enter()/__cyg_profile_func_exit(), you do not have to worry about calling instrumented functions. – Adisak Apr 19 '12 at 19:33
  • @gnz I haven't tested it. With clang you could probably write a compiler plugin that does way more sophisticated stuff if you wanted though. – Flexo Nov 11 '13 at 19:12
  • 1
    @Flexo yes it does work. But excluding files is not implemented yet so you cannot use e.g. the std library inside `__cyg_profile_func_enter()`/`__cyg_profile_func_exit()`. – gnzlbg Nov 11 '13 at 21:14
  • @Flexo how do I make this code snippet part of a larger application so I can take advantage of __cyg_profile_func_enter()/__cyg_profile_func_exit() – cross Apr 28 '16 at 19:13
  • @cross you need to compile every translation unit with `-finstrument functions` and then supply one implementation in one translation unit for the actual instrumentation enter/exit functions – Flexo Apr 28 '16 at 22:08
  • @Flexo the implementation has to be written in a class (header file) `#include`d in every other class? – cross Apr 29 '16 at 07:57
  • Nope, just visible to the linker exactly once. – Flexo Apr 29 '16 at 09:42
  • @Flexo can you consider these questions posted by me related to the current one: http://stackoverflow.com/questions/36896140/chronological-trace-of-function-calls-in-c-using-etrace , http://stackoverflow.com/questions/36910918/how-to-compile-a-cpp-and-then-link-it-to-a-shared-library – cross Apr 29 '16 at 17:24
12

It depends on the compiler you're using. I'm using DevStudio 2005 and, from the online help there's this compiler command line option:

/Gh (Enable _penter Hook Function)

Causes a call to the _penter function at the start of every method or function.

The _penter function is not part of any library and it is up to you to provide a definition for _penter.

Unless you plan to explicitly call _penter, you do not need to provide a prototype. The function must appear as if it had the following prototype, and it must push the content of all registers on entry and pop the unchanged content on exit:

void __declspec(naked) _cdecl _penter( void );
Skizz
  • 69,698
  • 10
  • 71
  • 108
7

What you are looking for is called "code instrumentation" and I gave a talk at GDC 2012 on manual and compiler-automated instrumentation (click here for code samples).

There are a number of ways to do what you want. Wrapper functions, Detours and Trampolines, or CAI (compiler-automated instrumentation) which is _penter() / __cyg_profile_func_enter() methods mentioned in other answers.

All of these as well as some other instrumentation methods are detailed in the PDF's linked above.

Adisak
  • 6,708
  • 38
  • 46
6

Depending on what you're hoping to achieve as a result of this you can sort of make something (easily enough for free functions or static member functions) in C++ with functor objects which wrap real calls, e.g.:

#include <iostream>

template<void f(void)>
struct Wrap {
   void operator()() const {
      std::cout << "Pre call hook" << std::endl;
      f();
   }
};

namespace {
   void test_func() {
      std::cout << "Real function" << std::endl;
   }
}

const Wrap<&test_func> wrapped_test_func = {};

int main() {
   wrapped_test_func();
   return 0;
}

Clearly this needs some more work to be generic enough e.g. C++0x variadic templates or lots of overloads. Making it work nicely with member functions is also more fiddly.

I've sketched an outline for a (non-intrusive) way of doing this for member functions too:

#include <iostream>

template<class C, void (C::*F)()>
class WrapMem {
   C& inst;
public:
   WrapMem(C& inst) : inst(inst) {}

   void operator()() {
      std::cout << "Pre (method) call hook" << std::endl;
      ((inst).*(F))();
   }

   void operator()() const {
      std::cout << "Pre (method, const) call hook" << std::endl;
      ((inst).*(F))();
   }
};

class Foo {
public:
   void method() { std::cout << "Method called" << std::endl; }
   void otherstuff() {}
};

class FooWrapped : private Foo  {
public:
   FooWrapped() : method(*this) {}
   using Foo::otherstuff;
   WrapMem<Foo,&Foo::method> method;
};

int main() {
   FooWrapped f;
   f.otherstuff();
   f.method();
   return 0;
}

You could also skip the private inheritance and using to expose non-wrapped methods, but you need to be careful about destructors and it's easy to accidentally bypass if you do that. (e.g. implicit cast for reference to base). The non-intrusive way is also limited to only working for the public interface and not for internal calls either.

With C++11 you can get perfect forwarding and also reduce the construction of the wrapping objects to a simple macro that takes the class and member function name and deduces the rest for you, e.g.:

#include <iostream>
#include <utility>

template <typename Ret, typename ...Args>
struct Wrapper {
  template <class C, Ret (C::*F)(Args...)> 
  class MemberFn {
    C& inst;
  public:
    MemberFn(C& inst) : inst(inst) {}
    MemberFn& operator=(const MemberFn&) = delete;

    Ret operator()(Args&& ...args) {
      return ((inst).*(F))(std::forward<Args>(args)...);
    }

    Ret operator()(Args&& ...args) const {
      return ((inst).*(F))(std::forward<Args>(args)...);
    }
  };
};

template <typename T>
struct deduce_memfn;
template <typename C, typename R, typename... Args>
struct deduce_memfn<R (C::*)(Args...)> {
  template <R(C::*F)(Args...)> 
  static typename Wrapper<R, Args...>::template MemberFn<C, F> make();
};

template <typename T>
decltype(deduce_memfn<T>()) deduce(T);

template <typename T>
struct workaround : T {}; // Clang 3.0 doesn't let me write decltype(deduce(&Class::Method))::make...

#define WRAP_MEMBER_FN(Class, Method) decltype(workaround<decltype(deduce(&Class::Method))>::make<&Class::Method>()) Method = *this

class Foo {
public:
  Foo(int);
  double method(int& v) { return -(v -= 100) * 10.2; }
  void otherstuff();
};

class WrappedFoo : private Foo {
public:
  using Foo::Foo; // Delegate the constructor (C++11)
  WRAP_MEMBER_FN(Foo, method);
  using Foo::otherstuff;
};

int main() {
  WrappedFoo f(0);
  int i = 101;
  std::cout << f.method(i) << "\n";
  std::cout << i << "\n";
}

(Note: this deduction won't work with overloads) This was tested with Clang 3.0.

Flexo
  • 87,323
  • 22
  • 191
  • 272
  • I'm going to give this a try and work it out some more. This gives me more freedom about which functions actually need to run the extra code without forcing *every* function to run it. – Christophe Feb 23 '11 at 19:35
  • If you want to do this on a large scale you can problaby get boost to help with a lot of the leg work. (I'm thinking boost::typeof and boost::function/boost::bind) – Flexo Feb 23 '11 at 21:02
  • You could simplify the C++11 stuff I added if you were willing to accept that the template would take the *type* of the member function pointer instead of the actual member function pointer as it's parameter. – Flexo Jul 12 '12 at 11:38
1

A fair number of profilers (and similar tools) can/will do things like this. It's actually easier at the binary level than the source code level. At the source code level, it's sufficiently difficult that for most practical purposes you might as well treat it as impossible.

Depending on the compiler you're using, there's a pretty fair chance that it has a flag to support such insertions -- usually present primarily to support the profilers and such I mentioned above.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

As someone said in a comment, it is a typical use case of aspect / feature programming. You can try this to use aspect / feature programming with c++.

my2c

neuro
  • 14,948
  • 3
  • 36
  • 59