2009-09-02 2 views
2

У меня есть приложение на C++, которое использует стороннюю библиотеку. Каждый раз здесь и там в моем коде есть звонки в эту библиотеку. Я хотел бы проследить все такие звонки.Как проследить все вызовы на предопределенный набор функций в C++?

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

Есть ли простой способ надежно сделать что-то подобное для вызовов во внешнюю библиотеку? Весь интерфейс к моей библиотеке - это .h-файл с прототипами функций, включенных в мой код.

ответ

0

Ну, вы можете просто добавить еще один слой поверх сторонних вызовов lib. Таким образом вы можете добавить любую сложную упаковку трассировки, которую вы хотите.

например.

struct trace 
{ 
    static void myfoo() { cout << "calling foo" << endl; foo(); } 
    // or 
    // static void myfoo() { if (_trace) {..} foo(); } 
}; 
4

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

Затем вы можете легко добавить свой код трассировки в функции обертки. Все, что меняется для вашего проекта, - это lib, с которым вы будете ссылаться.

Чтобы предотвратить определение нескольких символов, вы можете включить заголовок внешних библиотек в отдельное пространство имен.

РЕДАКТИРОВАТЬ:

В том числе внешнего заголовка ЛИЭС в пространстве имен не решает проблему символа. Вы должны использовать макрос в своем заголовке, который переименовывает исходную функцию и каждое вхождение в ваш код. Используйте что-то вроде этого для нового заголовка библиотеки обертка:

#define originalExportedFunction WRAPPED_originalExportedFunction 

extern "C" int originalExportedFunction(int); 

Ваша реализация в обертке Lib, то может выглядеть следующим образом:

extern "C" int WRAPPED_originalExportedFunction(int i) 
{ 
    //trace code here... 
    return originalExportedFunction(i); 
} 
+1

Если вы включаете заголовки внутри пространства имен, символы, определенные в заголовке, будут находиться в другом пространстве имен с символами, определенными в библиотеке. –

+0

@Jon: Вы правы, использование пространства имен не решает проблему символа. Но в качестве альтернативы вы всегда можете использовать макрос aproach, который переименовывает вызываемую функцию и позволяет вашей библиотеке экспортировать имя переименованной функции. Затем переименованная функция вызовет исходную функцию, и нет конфликта символов. –

3

Если вам случится работать в использовании/Linux Unix

ltrace

для отслеживания вызовов библиотек,

Трассирование

для системных вызовов. Тем не менее, это команды без кода. Вы также можете посмотреть valgrind с параметром -callgrind для профиля.

0

Поскольку вы, похоже, знаете функции, которые хотите вызвать (и сигнатуры для этих вызовов), вы все равно можете использовать идею оболочки макросов/классов. Что-то вроде:

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; 

} 
0

Попробуйте создать макрос для всех интерфейсов apis, например. Пусть апи вызывается как:

obj->run_first(var1); 

Затем создайте ниже макрос:

#define obj->run_first(args) \ 
    dumptimestamp(__FUNCTION__, __LINE__); \ 
    obj->run_first(args);     \ 
    dumptimestamp(__FUNCTION__, __LINE__); 

Вы можете генерировать список подобных макросов из файла заголовка Lib, как это имеет список всех методов интерфейса ,

dumptimestamp сбрасывает временную метку вместе с функциями и номерами строк.

0

Если вы не хотите менять свой код, то есть способ сделать это с помощью контрольно-измерительной аппаратуры. Если вы заинтересованы в этом случае, обратите внимание на хорошем динамическом бинарный приборный инструментарии под названием PIN (поддерживается Intel):

http://www.pintool.org/downloads.html

С PIN, вы можете вставить свой собственный код на функции вход/выход. Одним из примеров может быть захватывая таНос/бесплатно:

http://www.pintool.org/docs/29972/Pin/html/index.html#FindSymbol

Это совершенно другой способ отслеживания вызовов функций. Но стоит взглянуть.

Смежные вопросы