Автоматическое добавление журналов входа/выхода в проект
У меня есть сторонний исходный код, который я должен исследовать. Я хочу посмотреть, в каком порядке вызываются функции, но я не хочу тратить время на ввод текста:
printf("Entered into %s", __FUNCTION__)
и
printf("Exited from %s", __FUNCTION__)
для каждой функции, и я не хочу касаться какого-либо исходного файла.
Есть ли у вас предложения? Есть ли флаг компилятора, который автоматически делает это для меня?
Пояснения к комментариям:
- Я буду перекрестно скомпилировать источник, чтобы запустить его на ARM.
- Я скомпилирую его с помощью gcc.
- Я не хочу анализировать статический код. Я хочу отслеживать время выполнения. Так что doxygen не облегчит мою жизнь.
- У меня есть источник, и я могу его скомпилировать.
- Я не хочу использовать Aspect Oriented Programming.
EDIT:
Я обнаружил, что команда "frame" в приглашении gdb печатает текущий фрейм (или имя функции, которое вы могли бы сказать) в этот момент времени. Возможно, возможно (используя скрипты gdb) вызывать команду "frame" каждый раз, когда вызывается функция. Как вы думаете?
Ответы
Ответ 1
Помимо обычных методов отладки и аспектно-ориентированного программирования, вы также можете вводить свои собственные инструментальные функции, используя параметры командной строки gcc -finstrument-functions
. Вам нужно будет реализовать свои собственные функции __cyg_profile_func_enter()
и __cyg_profile_func_exit()
(объявите их как extern "C"
в С++).
Они предоставляют средства для отслеживания того, какая функция была вызвана откуда. Однако интерфейс немного сложно использовать, поскольку адрес вызываемой функции и его сайт вызова передаются вместо имени функции, например. Вы можете регистрировать адреса, а затем вытаскивать соответствующие имена из таблицы символов, используя что-то вроде objdump --syms
или nm
, если, конечно, символы не были удалены из соответствующих двоичных файлов.
Это может быть проще использовать gdb
. YMMV.:)
Ответ 2
Вы сказали "и я не хочу прикасаться к любому исходному файлу"... честная игра, если вы позволите script сделать это за вас?
Запустите это на всех ваших .cpp файлах
sed 's/^{/{ENTRY/'
Чтобы преобразовать их в это:
void foo()
{ENTRY
// code here
}
Поместите это в заголовок, который может быть # включен в каждую единицу:
#define ENTRY EntryRaiiObject obj ## __LINE__ (__FUNCTION__);
struct EntryRaiiObject {
EntryRaiiObject(const char *f) : f_(f) { printf("Entered into %s", f_); }
~EntryRaiiObject() { printf("Exited from %s", f_); }
const char *f_;
};
Вам может понадобиться стать sed
script. Вы также можете поместить макрос ENTRY в другое место, которое вы хотите зондировать, например, глубоко глубоко вложенную внутреннюю область функции.
Ответ 3
Использовать /Gh (Включить функцию _penter Hook) и /GH (Enable _pexit Hook Function) компиляторы (если вы можете скомпилировать источники)
ПРИМЕЧАНИЕ. Вы не сможете использовать эти макросы. См. здесь ( "вам нужно будет получить адрес функции (в регистре EIP) и сравнить его с адресами в файле карты, который может быть сгенерирован по линкеру (при условии, что переполнение не произошло). Это будет очень медленно, хотя." )
Ответ 4
Согласитесь с Уильямом, используйте gdb, чтобы увидеть поток времени выполнения.
Есть некоторый статический анализатор кода, который может определить, какие функции вызывают, и который может дать вам некоторый график потока вызовов. Одним из инструментов является "Понять С++" (поддержка C/С++), но это не бесплатно. Но вы можете найти похожие инструменты.
Ответ 5
Если вы используете gcc, флаг волшебного компилятора -g. Компилируйте с помощью отладочных символов, запустите программу под gdb и создайте трассировки стека. Вы также можете использовать ptrace, но, вероятно, гораздо проще просто использовать gdb.