Быстрая обратная трассировка для генерации графа вызовов?
Я использую следующий подход для генерации графов вызовов.
https://github.com/tarun27sh/gdb_graphs
Но GDB резко (х100) замедляется обратным следом. Есть ли гораздо более быстрый способ генерировать графы вызовов?
2 ответа
Есть ли гораздо более быстрый способ генерировать графы вызовов?
Конечно, есть (использование GDB для этого совершенно неуместно).
Самое простое решение - использовать GCC -finstrument-functions
вставлять вызов при каждом входе и выходе функции и реализовывать сбор данных в этих "введенных" функциях. Здесь есть пример.
Поскольку вы публикуете этот вопрос на SO и помечаете его как llvm, я предполагаю, что это означает, что вы ищете решение для программирования с использованием LLVM.
Напишите пропуск, который преобразует каждую функцию в вашей программе, чтобы добавить три новые инструкции перед каждым вызовом. Что-то вроде этого:
struct RecordCallGraph : public PassInfoMixin<RecordCallGraph> {
RecordCallGraph() = default;
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
};
Вам нужно реализовать этот run(), который будет содержать около 15 строк кода. Сканирование основных блоков в функции, проверка каждой инструкции isa<CallBase>
и если это так, то вставьте немного дополнительного кода перед CallBase. (CallBase - это базовый класс инструкций, которые вызывают функции.) Вы вставляете вызов в новую функцию, void emitTraceInfo(char* caller, char* called)
или что-то типа того. Так как LLVM IR безопасен для типов, вам нужно вызвать&F
) и вызываемая функция (callBase->getCalledValue()
) на правильный тип для вашей функции (char*
в примере).
Самый простой способ получить этот бросок, вероятно, будет CastInst::Create(CastInst::BitCast, &F, charStarType, "", callBase)
, который создает новый бросок из &F
в charStarType
и вставляет его непосредственно перед callBase
,
Наконец вы должны реализовать свой новый emitTraceInfo
и свяжите это в программу. Он будет вызываться каждый раз, когда одна функция вызывает другую, и может записывать вызов. Вы найдете это примерно в сто раз быстрее, чем GDB. Самая медленная часть может состоять в записи 16-ти с лишним байтов в файл.