Instrumentation du code C / C ++ à l’aide de LLVM

Je veux écrire une passe LLVM pour instrumenter chaque access mémoire. Voici ce que j’essaie de faire.

Avec n’importe quel programme C / C ++ (comme celui donné ci-dessous), j’essaie d’insérer des appels à une fonction avant et après chaque instruction qui lit / écrit dans / à partir de la mémoire. Par exemple, considérons le programme C ++ ci-dessous (Account.cpp)

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

Donc, après l’instrumentation, mon programme devrait ressembler à:

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

où foo () peut être n’importe quelle fonction, comme obtenir l’heure système actuelle ou incrémenter un compteur, etc.

S’il vous plaît, donnez-moi des exemples (code source, tutoriels, etc.) et des instructions sur la façon de l’exécuter. J’ai lu le tutoriel sur la création d’un laissez-passer LLVM sur http://llvm.org/docs/WritingAnLLVMPass.html , mais je ne pouvais pas comprendre comment écrire un laissez-passer pour le problème ci-dessus.

Essayez quelque chose comme ceci: (vous devez remplir les blancs et faire fonctionner la boucle d’iterator malgré le fait que des éléments soient insérés)

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

J’espère que cela t’aides!

Je ne connais pas très bien LLVM, mais je connais un peu mieux GCC (et ses plugins) car je suis l’auteur principal de GCC MELT (langage de haut niveau spécifique au domaine pour étendre GCC). pourrait utiliser pour votre problème). Je vais donc essayer de répondre en termes généraux.

Vous devez d’abord savoir pourquoi vous souhaitez adapter un compilateur (ou un parsingur statique). C’est un objective louable, mais qui présente des inconvénients (notamment la redéfinition de certains opérateurs ou d’autres constructions dans votre programme C ++).

Le point principal lors de l’extension d’un compilateur (que ce soit GCC ou LLVM ou autre) est que vous devez très probablement gérer l’ensemble de sa représentation interne (et vous ne pouvez probablement pas en ignorer certaines parties, sauf si vous avez un problème défini très étroit). Pour GCC, cela signifie gérer plus de 100 types d’arbres et près de 20 types de Gimple-s: dans l’extrémité centrale de GCC, les arborescences représentent les opérandes et les déclarations, et les joyaux représentent les instructions. L’avantage de cette approche est qu’une fois que vous avez fait cela, votre extension devrait être capable de gérer n’importe quel logiciel acceptable par le compilateur. L’inconvénient est la complexité des représentations internes des compilateurs (ce qui s’explique par la complexité des définitions des langages sources C & C ++ acceptés par les compilateurs, par la complexité du code machine cible qu’ils génèrent et par la distance croissante entre les langues source et cible).

Donc, pirater un compilateur général (que ce soit GCC ou LLVM), ou un parsingur statique (comme Frama-C), est une tâche assez lourde (plus d’un mois de travail, pas quelques jours). Ne traiter que de minuscules programmes C ++, comme vous le montrez, cela ne vaut pas la peine. Mais cela vaut vraiment la peine si vous vous adressez à de grandes bases de logiciels sources.

Cordialement