Инструментарий кода C / C ++ с использованием LLVM - PullRequest
11 голосов
/ 18 октября 2011

Я хочу записать проход LLVM для прибора при каждом доступе к памяти. Вот что я пытаюсь сделать.

Учитывая любую программу на C / C ++ (например, приведенную ниже), я пытаюсь вставить вызовы какой-либо функции до и после каждой инструкции, которая читает / записывает в / из памяти. Например, рассмотрим приведенную ниже программу на C ++ (Account.cpp)

#include <stdio.h>

class Account {
int balance;

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

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 <stdio.h>

class Account 
{
  int balance;

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

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 () может быть любой функцией, такой как получение текущего системного времени или увеличение счетчика ... и так далее.

Пожалуйста, дайте мне примеры (исходный код, учебные пособия и т. Д.) И инструкции по его запуску. Я прочитал учебник о том, как сделать LLVM Pass, данный на http://llvm.org/docs/WritingAnLLVMPass.html,, но не смог понять, как написать пропуск для указанной выше проблемы.

Ответы [ 2 ]

8 голосов
/ 20 октября 2011

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

Сначала вы должны знать, почему вы хотите адаптировать компилятор (или статический анализатор).Это стоящая цель, но у нее есть недостатки (в частности, не нужно переопределять некоторые операторы или другие конструкции в вашей программе на C ++).

Основной момент при расширении компилятора (будь то GCC или LLVM или что-то еще)) вы, вероятно, должны обрабатывать все его внутреннее представление (и вы, вероятно, не сможете пропустить его части, если у вас нет очень узко определенной проблемы).Для GCC это означает обработку более 100 видов Tree и почти 20 видов Gimple: в среднем конце GCC Tree представляют операнды и объявления, а gimple представляют инструкции.Преимущество этого подхода состоит в том, что после того, как вы это сделаете, ваше расширение сможет обрабатывать любое программное обеспечение, приемлемое для компилятора.Недостатком является сложность внутренних представлений компиляторов (что объясняется сложностью определений исходных языков C & C ++, принятых компиляторами, а также сложностью генерируемого ими целевого машинного кода и увеличивающимся расстояниеммежду исходным и целевым языками).

Так что взломать общий компилятор (будь то GCC или LLVM) или статический анализатор (например, Frama-C) - довольно большая задача (более месяца работы,не несколько дней).Работать только с крошечными C ++ программами, которые вы показываете, не стоит.Но это определенно стоит усилий, если вы имеете дело с большими исходными базами программного обеспечения.

С уважением

3 голосов
/ 20 декабря 2011

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

class ThePass : public llvm::BasicBlockPass {
  public:
  ThePass() : BasicBlockPass() {}
  virtual bool runOnBasicBlock(llvm::BasicBlock &bb);
};
bool ThePass::runOnBasicBlock(BasicBlock &bb) {
  bool retval = false;
  for (BasicBlock::iterator bbit = bb.begin(), bbie = bb.end(); bbit != bbie;
   ++bbit) { // Make loop work given updates
   Instruction *i = bbit;

   CallInst * beforeCall = // INSERT THIS
   beforeCall->insertBefore(i);

   if (!i->isTerminator()) {
      CallInst * afterCall = // INSERT THIS
      afterCall->insertAfter(i);
   }
  }
  return retval;
}

Надеюсь, это поможет!

...