[cfe-dev] AST modifications that apply to the binary

John Brawn via cfe-dev cfe-dev at lists.llvm.org
Thu Dec 1 10:07:01 PST 2016


What's happening here is some slightly non-obvious behaviour in how ASTConsumers are used.
In brief:
* Adding a PluginASTAction means we get a MultiplexConsumer whose list of consumers
    is FuncnameChangeAction then the main action
* This means that for each of the HandleXXX functions it calls the HandleXXX function on the
   FuncnameChangeAction then the main action
* clang::parseAST is where it ultimately ends up using the MultiplexConsumer and there it
    calls HandleTopLevelDecl on each DeclGroup then calls HandleTranslationUnit
* You've done your transformation in HandleTranslationUnit, but CodeGenAction generates code
    in HandleTopLevelDecl, so though your HandleTranslationUnit is called before the CodeGenAction's
    HandleTranslationUnit it doesn't matter because the code has already been generated.
* Doing the transformation in HandleTopLevelDecl works

(I myself didn't realise that this would happen, I only figured it out by running clang in a debugger,
setting breakpoints at various places and trying to figure out what was going on.)

John

From: Ori Zaig [mailto:oriz at mellanox.com]
Sent: 28 November 2016 12:58
To: John Brawn
Cc: Eran Jakoby; nd; cfe-dev at lists.llvm.org
Subject: RE: AST modifications that apply to the binary

Unfortunately it doesn't work - maybe I'm missing something...

I added the getActionType method:

class FuncnameChangeAction: public PluginASTAction {
                std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {
                                return llvm::make_unique< FuncnameChangeConsumer >(CI, &CI.getSourceManager());
                }

                bool ParseArgs(const CompilerInstance &CI, const std::vector<std::string> &args) override {
                                return true;
                }

virtual ActionType getActionType() override { return AddBeforeMainAction; }
};

And used the below command line:
clang++ -Xclang -load -Xclang ModifyFunc.so -Xclang -add-plugin -Xclang modify-func -c some_code.cpp -o some_code.o

And yet, changes were not reflected in the binary (some_code.o) or even in IR

Any other ideas please?

From: John Brawn [mailto:John.Brawn at arm.com]
Sent: Wednesday, November 23, 2016 7:14 PM
To: Ori Zaig <oriz at mellanox.com<mailto:oriz at mellanox.com>>
Cc: Eran Jakoby <eranj at mellanox.com<mailto:eranj at mellanox.com>>; nd <nd at arm.com<mailto:nd at arm.com>>; cfe-dev at lists.llvm.org<mailto:cfe-dev at lists.llvm.org>
Subject: RE: AST modifications that apply to the binary

By default a PluginASTAction will replace the main AST action (if you use -plugin pluginname on the
cc1 command line) or go after the main AST action (if you use -add-plugin pluginname on the cc1
command line), where the "main AST action" is "generate an object file" if using -c, "generate
assembly" is using -S, etc.

If you want the PluginASTAction to go before the main AST action, i.e. you want it to change the
AST in a way that will affect the compiled output, then define a getActionType method in the
PluginASTAction which returns AddBeforeMainAction.

John

From: cfe-dev [mailto:cfe-dev-bounces at lists.llvm.org] On Behalf Of Ori Zaig via cfe-dev
Sent: 20 November 2016 16:49
To: cfe-dev at lists.llvm.org<mailto:cfe-dev at lists.llvm.org>
Cc: Eran Jakoby
Subject: [cfe-dev] AST modifications that apply to the binary

Hi all

Is there any possible making AST modification that finally will be reflected in the binary?
I tried doing that via plugin, for instance changing a method name (let's say turn foo() to my_foo() ) such:

class FuncnameChangeVisitor : public RecursiveASTVisitor< FuncnameChangeVisitor > {
private:
                ASTContext *m_context;
public:
                /* some code */

                bool VisitFunctionDecl(FunctionDecl *f) {
                                DeclarationNameInfo newNameInfo(f->getNameInfo());
                                DeclarationName origName(f->getDeclName());
                                std::string newName("my_");
                                newName += origName.getAsString();
                                IdentifierInfo& newNameIdInfo(m_context->Idents.get(StringRef(newName.c_str())));
                                f->setDeclName(DeclarationName(&newNameIdInfo));
                                return true;
                }
};

class FuncnameChangeConsumer: public ASTConsumer {
private:
                FuncnameChangeVisitor m_visitor;
public:
                /* some code*/
                virtual void HandleTranslationUnit(ASTContext &Cntx) {
                                m_visitor.TraverseDecl(Cntx.getTranslationUnitDecl());
                }
};

class FuncnameChangeAction: public PluginASTAction {
                std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {
                                return llvm::make_unique< FuncnameChangeConsumer >(CI, &CI.getSourceManager());
                }

                bool ParseArgs(const CompilerInstance &CI, const std::vector<std::string> &args) override {
                                return true;
                }
};

static FrontendPluginRegistry::Add< FuncnameChangeAction > reg("modify-func", "add my_ prefix to funtions");


But in vain... I understood that the IR and hence the binary are generated regardless the plugins

And if there isn't a way to do so, is there another way via Clang to make code-modifications that affect the binary, which are not source-to-source compilation?

Tnx

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20161201/2733d1d7/attachment.html>


More information about the cfe-dev mailing list