Я хотел бы проследить вызовы до некоторой сторонней библиотеки, которые выполняются из другой сторонней библиотеки.
Пример: Я хочу проследить вызовы до библиотеки A. Мое приложение статически связывает библиотеку B, которая в свою очередь статически связана с библиотекой A. Так в основном то, что я имею, является libAB.a
В случае динамического подключения я мог записать библиотеку A2 с обертками для функций, которые я хочу к трассировке библиотеки A и использую LD_PRELOAD=A2.so. Затем мои обертки назовут вместо этого, и я буду видеть трассировку. В моем случае я не могу использовать динамическое подключение.
Действительно ли возможно достигнуть того же статического подключения использования?
В идеальном случае я хотел бы связать свое приложение с libAB.a и библиотекой трассировки libA2.a и получить трассировку.
Спасибо,
Robusta
Хорошо, я нашел :)
man ld
--wrap symbol
Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to "__wrap_symbol". Any undefined ref‐
erence to "__real_symbol" will be resolved to symbol.
This can be used to provide a wrapper for a system function. The wrapper function should be called "__wrap_symbol". If it
wishes to call the system function, it should call "__real_symbol".
Here is a trivial example:
void *
__wrap_malloc (size_t c)
{
printf ("malloc called with %zu\n", c);
return __real_malloc (c);
}
If you link other code with this file using --wrap malloc, then all calls to "malloc" will call the function "__wrap_malloc"
instead. The call to "__real_malloc" in "__wrap_malloc" will call the real "malloc" function.
Ну, это похоже на тупик:)
Но я думаю, что вы можете решить эту проблему с помощью макросов. Хотя это решение может быть не чистым и работать не во всех ситуациях.
Вы можете попробовать следующее:
void functionFromLibA();
#define functionFromLibA() trace(); functionFromLibA()
int main()
{
functionFromLibA();
}
Это будет расширено до:
void myfunc();
int main()
{
trace(); functionFromLibA();
}
РЕДАКТИРОВАТЬ: Но обратите внимание, что для этого решения все объявления прототипов функций должны выполняться до определения макросов. В противном случае прототипы также будут расширены при предварительной обработке.
В зависимости от того, насколько важна производительность, вы могли бы сделать это с помощью gdb ... (Установите точку останова для всех функций, которые вам интересны, и запишите трассировку стека ... но это включает в себя обучение сценарию gdb)
Там а также такие вещи, как Oprofile http://oprofile.sourceforge.net/ , LTTng http://lttng.org/ и perf (поставляется с последними ядрами в исходном коде ядра, в tools / perf / вам нужно его скомпилировать, на Ubuntu я думаю, что он находится в пакете linux-tools)
Я не могу сказать вам, как добиться того, чего вы хотите, с помощью любого из этих инструментов, но oprofile и LTTng содержат много документации и активное сообщество пользователей.