Быстрая обратная трассировка для генерации графа вызовов?

Я использую следующий подход для генерации графов вызовов.

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-ти с лишним байтов в файл.

Другие вопросы по тегам