2011-10-18 14 views
10

Quiero escribir un pase LLVM al instrumento en cada acceso a la memoria. Esto es lo que estoy tratando de hacer.Instrumenting C/C++ code using LLVM

Dado cualquier programa C/C++ (como el que figura a continuación), estoy tratando de insertar llamadas a alguna función, antes y después de cada instrucción que lee/escribe a/desde la memoria. Por ejemplo, consideremos el siguiente programa 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; 
} 

Así que después de la instrumentación mi programa debe verse como:

#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; 
} 

donde foo() puede ser cualquier función como obtener la hora actual del sistema o incrementar un contador ... etc.

Por favor, dame ejemplos (código fuente, tutoriales, etc.) y pasos sobre cómo ejecutarlo. He leído el tutorial sobre cómo hacer un pase LLVM en http://llvm.org/docs/WritingAnLLVMPass.html, pero no pude entender cómo escribir un pase para el problema anterior.

+0

Bueno, probablemente podría sobrecargar al operador no solo para realizar las funciones de suma, resta, asignación, sino también para llamar a su función personalizada. – vishakvkt

+0

¿Por qué quiere agregar estas funciones? Si desea depurar su programa hay mejores métodos disponibles. – tune2fs

+0

Iba a votar para cerrar esta pregunta como un duplicado de http: // stackoverflow.com/questions/7526550/instrumenting-c-c-codes-using-llvm (es decir, mira los títulos) y noté que eras el autor de ambos. ¿Cómo espera que los usuarios de StackOverflow le den respuestas esta vez que no le dieron la última vez (excepto que lo haga por usted, lo que no ocurrirá)? –

Respuesta

3

intentar algo como esto: (es necesario rellenar los espacios en blanco y hacer el trabajo del lazo iterador a pesar del hecho de que los elementos se insertan)

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; 
} 

Espero que esto ayude!

+0

No debe hacerlo antes y después de cada instrucción, sino solo para 'store' y' load' para punteros genuinos (no los 'alloca's locales reducibles). –

+0

Debería regresar verdadero desde la función runOnBasicBlock para indicar que se han cambiado las instrucciones en el bloque básico. – ConfusedAboutCPP

8

No estoy muy familiarizado con LLVM, pero estoy un poco más familiarizado con GCC (y su maquinaria de complementos), ya que soy el autor principal de GCC MELT (un lenguaje de dominio de alto nivel para extender GCC, que la forma en que podrías usar para tu problema). Entonces intentaré responder en términos generales.

Primero debe saber por qué quiere adaptar un compilador (o un analizador estático). Es un objetivo que vale la pena, pero tiene inconvenientes (en particular, w.r.t redefine algunos operadores u otros constructos en su programa C++).

El punto principal al extender un compilador (ya sea GCC o LLVM u otra cosa) es que muy probablemente deba manejar toda su representación interna (y probablemente no pueda omitir partes, a menos que tenga un problema definido muy estrecho) Para GCC, significa manejar los más de 100 tipos de Tree-s y casi 20 tipos de Gimple-s: en GCC middle end, los tree-s representan los operandos y las declaraciones, y los gimple-s representan las instrucciones. La ventaja de este enfoque es que una vez que haya hecho eso, su extensión debería poder manejar cualquier software aceptable por el compilador. El inconveniente es la complejidad de las representaciones internas de los compiladores (que es explicable por la complejidad de las definiciones de los lenguajes fuente C++ C & aceptados por los compiladores, y por la complejidad del código máquina objetivo que están generando, y por la distancia creciente entre los idiomas de origen &).

piratear un compilador general (ya sea GCC o LLVM), o un analizador estático (como Frama-C), es una tarea bastante grande (más de un mes de trabajo, no pocos días). Para tratar solo con pequeños programas en C++ como los que muestra, no vale la pena. Pero definitivamente vale la pena el esfuerzo si se puede tratar con grandes bases de software fuente.

Saludos