Search code examples
c++clangllvm

How to load pass plugin in new pass manager?


I have written a pass-plugin for obfuscation and I would like to load this plugin using clang instead of opt in Windows. However, when I use the command .\bin\clang++.exe -O1 -Xclang -fpass-plugin='./BronyaObfus.dll' -passes=bogus-control-flow .\test.cpp -o .\a.exe, clang throws an error:

clang++: error: unknown argument: '-passes=bogus-control-flow'

Then I use .\bin\clang++.exe -O1 -Xclang -fpass-plugin='./BronyaObfus.dll' -mllvm --bogus-control-flow .\test.cpp -o .\a.exe

It didn't load the corresponding pass(bogus-control-flow) as expected, instead, it loaded all passes.

This is my registry code:

llvm::PassPluginLibraryInfo getBronyaObfusPluginInfo() {
  return {LLVM_PLUGIN_API_VERSION, "BronyaObfus", "v0.1", [](PassBuilder &PB) {
            PB.registerPipelineParsingCallback(
                [](StringRef PassName, FunctionPassManager &FPM, ...) {
                  if (PassName == "bogus-control-flow") {
                    FPM.addPass(BogusControlFlowPass());
                    return true;
                  }

                  if (PassName == "flattening") {
                    FPM.addPass(FlatteningPass());
                    return true;
                  }

                  if (PassName == "mba-obfuscation") {
                    FPM.addPass(MBAObfuscationPass());
                    return true;
                  }
                  return false;
                });

            PB.registerPipelineParsingCallback(
                [](StringRef PassName, ModulePassManager &MPM, ...) {
                  if (PassName == "string-obfuscation") {
                    MPM.addPass(StringObfuscationPass());
                    return true;
                  }
                  return false;
                });

            PB.registerPipelineStartEPCallback([](ModulePassManager &MPM,
                                                  OptimizationLevel Level) {
              MPM.addPass(StringObfuscationPass());

              FunctionPassManager FPM;
              FPM.addPass(BogusControlFlowPass());
              FPM.addPass(FlatteningPass());
              FPM.addPass(MBAObfuscationPass());

              MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
            });

          }};
}

extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
  return getBronyaObfusPluginInfo();
}

If I just want to load bogus-control-flow pass, how should I pass arguments to clang?


Solution

  • I also tried this, but it seems that it's not possible. It is only possible to add passes from a plugin to the optimization pass pipeline(Based on OptimizationLevel -O0, -O1, etc) . In your case you have all of your passes because, this is called:

    PB.registerPipelineStartEPCallback([](ModulePassManager &MPM,
                                          OptimizationLevel Level) {
      MPM.addPass(StringObfuscationPass());
    
      FunctionPassManager FPM;
      FPM.addPass(BogusControlFlowPass());
      FPM.addPass(FlatteningPass());
      FPM.addPass(MBAObfuscationPass());
    
      MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
    });
    
    

    What you can do is refactor your current plugin into smaller ones. For example bogus-control-flow.dll to only add BogusControlFlowPass pass:

    PB.registerPipelineStartEPCallback([](ModulePassManager &MPM,
                                          OptimizationLevel Level) {
      FunctionPassManager FPM;
      FPM.addPass(BogusControlFlowPass());
      MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
    });
    

    and then you can invoke it using: .\bin\clang++.exe -O1 -Xclang -fpass-plugin='bogus-control-flow.dll' .\test.cpp -o .\a.exe

    Let's say that you created plugins: foo.dll, bar.dll and tar.dll if you want to enable pass from foo.dll and bar.dll you would do that by providing: -Xclang -fpass-plugin=foo.dll -Xclang -fpass-plugin=bar.dll