2016-03-30 16 views
2

Ich versuche in einem LLVM-Durchgang, über eine Modulfunktionsliste mit der von llvm::Module::getFunctionList() zurückgegebenen Liste zu iterieren. Ich benutze eine Schleife wie diese:LLVM-Pass: Fehler beim Iterieren der Modulfunktionsliste

for (auto curFref = M->getFunctionList().begin(), 
       endFref = M->getFunctionList().end(); 
       curFref != endFref; ++curFref) { 
     errs() << "found function: " << curFref->getName() << "\n"; 
    } 

Die erste Iteration dieser Schleife eine Funktion ruft, wie erwartet, aber nicht das Ende der Liste erkennen und weiterhin nur in nachfolgenden Iterationen andere Objekte zu erhalten, die nicht funktioniert (wie von ihren getName() gemeldet), wie dieser Funktionsparameter. Nach ein paar Iterationen erreicht es wahrscheinlich etwas Müll (oder NULL) und stürzt bei einem Verweis auf die aktuelle "Funktions" -Referenz ab. Zum Beispiel für dieses Programm:

int foo(int k) { 
    int i, s = 0; 
    for (i = 0; i < k; ++i) 
     s += i; 
    return s; 
} 

Welche dieser IR-Code wird:

... 
; Function Attrs: nounwind uwtable 
define i32 @foo(i32 %k) #0 { 
entry: 
... 

Die Ausgabe würde wie folgt aussehen:

found function: foo 
found function: k 
found function: #0 0x00007f481f77c46e llvm::sys::PrintStackTrace(llvm::raw_ostream&) /home/me/work/llvm-3.8.0/lib/Support/Unix/Signals.inc:322:0 
... 

So können Sie sehen, dass nach richtig Iterieren über foo ging es weiter zu Objekten wie dem Parameter k.

Ich versuchte dies sowohl in einem Modul-Durchlauf (in der runOnModule()) als auch in einem Function-Durchlauf (mit F.getParent(), um das beinhaltende Modul abzufragen) und erhielt die gleichen Ergebnisse.

Das Problem wird auch auf LLVM 3.8.0 sowie LLVM 3.5.2 repliziert.

Eine Idee, was fehlt mir, dass ich nicht ordnungsgemäß über die zurückgegebene Funktionen Liste iterieren?

=====

EDIT:

Beachten Sie, dass das gleiche Verhalten bei der Verwendung von alternativer Iteration über die Funktionen eines Moduls angezeigt wird, wie wenn M.begin()/end() für den Iterator oder auch bei Verwendung von C++ 11 bereichsbasierte for loop: for (Function &curF: M) ....

Darüber hinaus verursachen M.getFunctionList().size() Segmentierungsfehler, während es versucht, über die Listenelemente zu iterieren. Es scheint also so, als ob die Liste der Funktionen tatsächlich korrupt ist. Aber das ist die Liste, die ich am Anfang von runOnModule() Einstiegspunkt bekomme. Es scheint also nicht etwas zu sein, das durch meinen Code gebrochen wurde.

======

EDIT 2:

Ich habe keine Ahnung, ob diese Dinge, aber mein LLVM Pass extern von dem LLVM Quellbaum als dynamisch ladbare Bibliothek gebaut wird und dann geladen opt mit der Befehlszeilenoption -load=foo.so.

+0

Die Antwort von @Chandler Carruth löste das Problem. Im Kern seiner Antwort empfahl er, LLVM mit Ninja/cmake zu erstellen, als ich LLVM mit make/configure erstellte. Der Wiederaufbau mit Ninja/cmake hat dieses Problem beseitigt. Während die Versionshinweise zu LLVM 3.8.0 darauf hindeuten, dass das Erstellen mit make/configure weiterhin unterstützt wird, deutet dieses Problem darauf hin, dass es irgendwie kaputt ist. – ElazarR

Antwort

2

ich bin einer der LLVM de Kern Entwickler.

Dies ist mit ziemlicher Sicherheit ein fehlerhaftes Auschecken von LLVM, ein falsch kompiliertes LLVM oder ein Problem mit der Tatsache, dass Ihr Pass als separates DSO erstellt wird (obwohl ich nicht sehe, wie das sein könnte).

zahlreiche Teile von LLVM verwenden M->functions() (oder M->begin() & M->end()) nur Funktionen iterieren. Diese Teile würden durchgehend ausfallen, wenn das Verhalten gebrochen wäre. Der einzige Unterschied zwischen diesen Mechanismen und dem direkten Zugriff auf die Funktionsliste als M->getFunctionList() besteht darin, ob die Liste änderbar ist. Für den Anwendungsfall, den Sie zeigen, sollten sie genau das gleiche Verhalten sein.

Ich würde vorschlagen, versuchen, die LLVM Testsuite zu laufen, um sicherzustellen, dass es richtig funktioniert. Wenn Sie den Ninja CMake Generator verwenden (wie ich würde empfehlen) zu LLVM bauen:

% ninja check-llvm 

Wenn dies nicht gelingt, vor allem wenn es in ähnlichen Bereichen abstürzt, dass ein extrem guten Indikatoren scheint, dass das Problem ist, etwas in Ihrer Kopie von LLVM.

Egal, SO ist kein großartiger Ort, um hier weitere Hilfe zu bekommen. Die Antwort auf die Frage ist "das sollte tatsächlich funktionieren" und ich habe den Code in LLVM überprüft und sehe keine offensichtlichen Erklärungen. Also mein Vorschlag wäre, das oben genannte zu versuchen, versuchen Sie eine frische Kopie von LLVM (vielleicht Spitze des Baums oder der neuesten Version). Stellen Sie sicher, dass Sie eine ausreichend moderne Host-Toolchain zum Erstellen von LLVM haben. Siehe diesen Abschnitt für Details: http://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library

Wenn alle Stricke reißen, versuchen die Entwickler auf der Mailingliste Annäherung: http://lists.llvm.org/mailman/listinfo/llvm-dev

Oder den IRC-Kanal versuchen: http://llvm.org/docs/#irc

hoffe, das hilft!

+0

Ich habe keinen Zweifel, dass dieser Iterator für Module innerhalb des LLVM-Projekts funktioniert. Aber in meinem Fall baue ich mein Modul pass als gemeinsames Objekt und lade es mit der Option '-load' von 'opt'. Ich vermute also, dass dieser Anwendungsfall ein Problem haben könnte (d. H., Alles in LLVM könnte funktionieren, während dieser Anwendungsfall unterbrochen ist). Ich erstelle auch das gemeinsam genutzte Objekt pass extern mit meinem eigenen Makefile und verlasse mich dabei auf Kompilierungsflags, die von 'llvm-config --cppflags' bereitgestellt werden. Es könnte also sein, dass die 'llvm-config --cppflags' Ausgabe sich von den Flags unterscheidet, die für den internen Build verwendet werden. Wissen Sie, ob diese Anwendungsfälle getestet werden? – ElazarR

+0

Es scheint, dass Ihre Empfehlung, mit Ninja zu bauen, die "Magie" tat. Meine ursprüngliche LLVM Build verwendet konfigurieren/machen. Während es offiziell in 3.8.0 noch unterstützt wird, scheint es Probleme zu haben. Die Neuerstellung von LLVM mit Ninja und das Erstellen meines Modul-Passes mit dem gleichen Makefile gegen die aktualisierte (Ninja) LLVM behob das Problem. Ich denke, dass make-based Build von LLVM nicht wirklich unterstützt wird, obwohl die Versionshinweise darauf hinwiesen, dass es nur von 3.9 unterstützt wird. Vielen Dank. – ElazarR

0

Haben Sie jemals versucht M->begin() und M->end() zu verwenden, statt M->getFunctionList().begin() und M->getFunctionList().end()? Das ist für mich in Ordnung.

+0

'M-> begin()/end()' sind nur eine eingeschränkte Version von 'M-> getFunctionsList(). Begin()/end()'. Jedenfalls habe ich auch den einfachen Iterator ausprobiert und die gleichen unglücklichen Ergebnisse erzielt. – ElazarR

0

Ist es möglich, dass Ihre Eingabe irgendwie fehlerhaft ist? Versuchen Sie llvm::verifyModule zuerst darauf (von Verifier.h) laufen und sehen, was Sie bekommen - oder opt -verify darauf laufen, sollte das gleiche sein.Möglicherweise interessiert Sie auch die Befehlszeilenoption -verify-each für opt.

+0

Das Problem wird auf jedem von mir getesteten Modul reproduziert. Alle meine Input-Module werden aus C-Code mit dem folgenden Befehl generiert: 'clang -c-emit-llvm -o foo-preopt.bc foo.c' und dann' opt -mem2reg -lic -S -o foo.ll foo -preopt.bc'. Wenn also ein Modul beschädigt ist, ist es ein Ergebnis von 'clang' oder dem Standard' opt' Durchlauf.Wie auch immer, '-verify' meldet kein Problem. Ich verwende stabile Versionen von LLVM. – ElazarR

+0

@ElazarR eine andere Idee: Stellen Sie sicher, dass Sie den Klang verwenden, der mit opt ​​erstellt wurde, und nicht den Klang, der mit dem Betriebssystem geliefert wird. – Oak

+0

Ich bin konsistent mit den LLVM-Tools, die ich verwende. Eigentlich habe ich vermieden, clang/LLVM-Pakete in meinem Betriebssystem zu installieren. Ich verwende nur clang/LLVM, das ich aus dem Quellcode der jeweiligen Releases erstellt habe, und ich gebe einen expliziten Pfad zu jedem Tool an. – ElazarR

0

Wenn Sie das folgende registrieren Ihren Pass verwenden:

char SkeletonPass::ID = 0; 

// Automatically enable the pass. 
// This pass is taken from Adrian Samson Template project http://adriansampson.net/blog/clangpass.html 
static void registerSkeletonPass(const PassManagerBuilder &, 
         legacy::PassManagerBase &PM) { 
    PM.add(new SkeletonPass()); 
} 
static RegisterStandardPasses 
    RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible, 
       registerSkeletonPass); 

Dies funktioniert nur für FunctionPass/BasicBlockPass, ist eine Lösung kanonische Pass wie üblich ohne Trick wie folgt zu verwenden: -

char SkeletonPass::ID = 0; 
static RegisterPass<SkeletonPass> X("passname","Pass Name Analysis"); 
static void registerPass(const PassManagerBuilder &, 
         legacy::PassManagerBase &PM) { 
    PM.add(new SkeletonPass()); 
} 
static RegisterStandardPasses 
     RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible, 
         registerPass); 

und führen Sie Ihren Pass mit dem folgenden Befehl:

$ clang -c -O1 -emit-llvm programs/hello.cpp -o programs/hello.bc 
$ opt -load build/Debug/libCallgraph.so -passname programs/hello.bc 
+0

Leider löst das das Problem nicht. Das Iterieren über M.getFunctionList() gibt immer noch Elemente zurück, die mit der ersten Funktion im Modul beginnen und mit Nichtfunktionssymbolen (Objekten) fortfahren, z. B. die Parameter dieser Funktion (wie ich in meiner Frage berichte). Tatsächlich meldet isa () diese Objekte (Funktionsparameter) als Funktionsobjekte. Es scheint also so, als ob im gegebenen Iterator etwas völlig falsch ist. – ElazarR

Verwandte Themen