C / C ++ нужен умный способ отслеживать вызовы функций - PullRequest
6 голосов
/ 23 июля 2010

Я ищу умный способ отследить вызовы функций и их возврат. Я знаю, что могу использовать отладчик, но мне бы хотелось, чтобы он просто выводил что-то на терминал при вызове функции, а не пошагово просматривал код.
Я думаю, что я мог бы использовать препроцессор, но я не уверен, что будет лучшим способом для этого.
Или есть способ использовать gdb для распечатки информации, которая была бы полезна, без необходимости проходить через код.

Ответы [ 9 ]

14 голосов
/ 23 июля 2010

Большинство компиляторов позволяют вводить функцию инструментария до и после вызова функции.

в msvc они _penter и _pexit
хорошая статья http://www.drdobbs.com/184403601

в gcc вы бы использовали -finstrument-functions
http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Code-Gen-Options.html

Вы можете использовать отладочные библиотеки или файлы карт для получения дополнительной информации.

4 голосов
/ 20 апреля 2012

Так как вы используете GCC, вы также можете использовать перенос функции компоновщика.

Link-Time Replacement / Wrapping
– GCC option: -Wl,--wrap,function_name

По сути, вы можете взять функцию с именем "function_name ()" и обернуть ее функцией "__wrap_function_name ()". Вы можете получить доступ к исходной функции, вызвав "__real_function_name ()".

4 голосов
/ 23 июля 2010

Довольно интрузивное решение использует RAII для управления областью действия функции. Это окажет большое влияние на производительность, но будет весьма явным в журналах, не требуя от пользователя добавлять инструментарий во все возможные пути кода, которые могут покинуть функцию:

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
}

Если код однопоточный, вы можете даже добавить статическую переменную с некоторым уровнем отступа к ScopedLogger, не добавляя слишком много к и без того сильному влиянию на производительность:

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;
3 голосов
/ 23 июля 2010

Возможно, вы захотите взглянуть на Callgrind от Valgrind , который может отслеживать вызовы функций в симпатичном графике. Он покажет вызовы функций, но не параметр или возвращаемые значения.

3 голосов
/ 23 июля 2010
#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__);


}

Я думаю, что если вы напишите макрос, как описано выше, и будете использовать его для каждой функции, как описано, вы сможете получить логи на терминале.

2 голосов
/ 23 июля 2010

Или есть способ использовать gdb для распечатки информации, которая была бы полезной, без необходимости проходить через код

ДаУстановите точку останова только для тех функций, которые вам действительно нужны.Используйте «продолжить», пока не доберетесь до этих функций или пока ваша программа не выйдет из строя.Затем используйте «backtrace» (или «bt»), чтобы получить трассировку стека.

1 голос
/ 23 июля 2010

Если вам нужно автоматизировать это, вы можете взглянуть на TARGET_ASM_FUNCTION_END_PROLOGUE и TARGET_ASM_FUNCTION_BEGIN_EPILOGUE.Это ловушки компилятора, которые позволят вам указать части сборки, которые будут отправляться вместе с обычным прологом / эпилогом функции - в вашем случае вы будете использовать их для генерации небольшой сборки для регистрации входа / выхода из рассматриваемой функции,Вы также можете посмотреть на FUNCTION_PROFILE и / или PROFILE_HOOK (например, на: http://gcc.gnu.org/onlinedocs/gccint/Function-Entry.html).

0 голосов
/ 20 апреля 2012

Некоторое время назад я слушал лекцию о аспектно-ориентированном программировании , которая включает в себя то, что вы хотите достичь. Может быть, поиск по этому слову поможет.

0 голосов
/ 23 июля 2010

Существует макрос __FUNCTION__ (ссылка) , используемый для определения того, в каком методе (в формате Class::Method) вы находитесь, но это больше ручной процесс.

Однако, когда мне недавно понадобилась та же самая информация о трассировке, я не смог найти автоматический метод.

...