Instrumenting C/C++ codes using LLVM

Я только что прочитал о проекте LLVM и о том, что его можно использовать для статического анализа кодов C/C++ с помощью анализатора Clang, который является передней частью LLVM. Я хотел узнать, возможно ли извлечь все обращения к памяти (переменные, как локальные, так и глобальные) в исходном коде с помощью LLVM.

Есть ли какая-нибудь встроенная библиотека в LLVM, которую я мог бы использовать для извлечения этой информации. Если нет, пожалуйста, подскажите, как написать функции для этого (существующий исходный код, ссылка, учебник, пример...). Из того, что я думал, это то, что я сначала конвертирую исходный код в LLVM bc, а затем использую его для анализа, но не знаю точно, как это сделать.


Я пытался выяснить, какой IR я должен использовать для своей цели (абстрактное синтаксическое дерево (AST) Clang или промежуточное представление (IR) SSA LLVM. ), но так и не смог понять, какой из них использовать. Вот что я пытаюсь сделать. В любой программе на C/C++ (как в приведенной ниже) я пытаюсь вставить вызовы некоторых функций до и после каждой инструкции, которая читает/пишет в/из памяти. Для примера рассмотрим нижеприведенную программу на C++ (Account.cpp)

#include 

class Account {
  int balance;

public:
  Account(int b) {
    balance = b;
  }

  int read() {
    int r;
    r = balance;
    return r;
  }

  void deposit(int n) {
    balance = balance + n;
  }

  void withdraw(int n) {
    int r = read();
    balance = r - n;
  }
};

int main () {
  Account* a = new Account(10);
  a->deposit(1);
  a->withdraw(2);
  delete a;
}

Итак, после инструментализации моя программа должна выглядеть так:

#include 

class Account {
  int balance;

public:
  Account(int b) {
    balance = b;
  }

  int read() {
    int r;
    foo();
    r = balance;
    foo();
    return r;
  }

  void deposit(int n) {
    foo();
    balance = balance + n;
    foo();
  }

  void withdraw(int n) {
    foo();
    int r = read();
    foo();
    foo();
    balance = r - n;
    foo();
  }
};

int main () {
  Account* a = new Account(10);
  a->deposit(1);
  a->withdraw(2);
  delete a;
}

где foo() может быть любой функцией, например, получить текущее системное время или увеличить счетчик... и так далее. Я понимаю, что для вставки функций, подобных вышеуказанным, мне нужно сначала получить IR, а затем запустить инструментальный проход на IR, который вставит такие вызовы в IR, но я не очень понимаю, как этого добиться. Пожалуйста, подскажите на примерах, как это сделать.

Также я понимаю, что после компиляции программы в IR, будет очень сложно получить 1:1 отображение между моей оригинальной программой и инструментальным IR. Итак, возможно ли отразить изменения, сделанные в IR (из-за инструментария), в оригинальной программе.

Для того, чтобы начать разбираться с LLVM pass и как сделать его самостоятельно, я посмотрел пример pass, который добавляет проверки во время выполнения к загрузкам и сохранениям LLVM IR, SAFECode's load/store instrumentation pass (http://llvm.org/viewvc/llvm-project/safecode/trunk/include/safecode/LoadStoreChecks.h?view=markup и http://llvm.org/viewvc/llvm-project/safecode/trunk/lib/InsertPoolChecks/LoadStoreChecks.cpp?view=markup). Но я не смог понять, как запустить этот проход. Пожалуйста, дайте мне шаги, как запустить этот проход в какой-нибудь программе, скажем, в вышеприведенном Account.cpp.

17
задан Ivan Perevezentsev 8 December 2015 в 23:14
поделиться