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 CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {

return llvm::make_unique< FuncnameChangeConsumer >(CI, &CI.getSourceManager());

}

bool ParseArgs(const CompilerInstance &CI, const std::vectorstd::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

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

Unfortunately it doesn’t work - maybe I’m missing something…

I added the getActionType method:

class FuncnameChangeAction: public PluginASTAction {

std::unique_ptr CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {

return llvm::make_unique< FuncnameChangeConsumer >(CI, &CI.getSourceManager());

}

bool ParseArgs(const CompilerInstance &CI, const std::vectorstd::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?

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

Working like a charm…

Thanks a lot!