Crash due to using a new Transformation Pass


I am new to llvm, I have written an llvm pass to insert a call to a specific function after each call Instruction.
This is the crash backtrace I got and I don’t understand the problem. (the code of the pass is included here if that might help)

Thank you in advance.

Stack dump:
0. Program arguments: opt-15 -load-pass-plugin lib/ --passes=instr-call instrumentcall.ll
#0 0x00007fcdb0f35451 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/lib/llvm-15/bin/../lib/
[#1]( 0x00007fcdb0f3318e llvm::sys::RunSignalHandlers() (/usr/lib/llvm-15/bin/../lib/
[#2]( 0x00007fcdb0f35976 (/usr/lib/llvm-15/bin/../lib/
[#3]( 0x00007fcdafb0a520 (/lib/x86_64-linux-gnu/
[#4]( 0x00007fcdb10c8340 llvm::Value::getName() const (/usr/lib/llvm-15/bin/../lib/
[#5]( 0x00007fcdad9ccb6c InstrumentCall::runOnModule(llvm::Module&) /home/ss/llvm-tutor/lib/InstrumentCall.cpp:74:82
[#6]( 0x00007fcdad9cce0e InstrumentCall::run(llvm::Module&, llvm::AnalysisManagerllvm::Module&) /home/ss/llvm-tutor/lib/InstrumentCall.cpp:97:30
[#7]( 0x00007fcdad9d4723 llvm::detail::PassModel<llvm::Module, InstrumentCall, llvm::PreservedAnalyses, llvm::AnalysisManagerllvm::Module>::run(llvm::Module&, llvm::AnalysisManagerllvm::Module&) /usr/include/llvm-15/llvm/IR/PassManagerInternal.h:89:3
[#8]( 0x00007fcdb10a61b9 llvm::PassManager<llvm::Module, llvm::AnalysisManagerllvm::Module>::run(llvm::Module&, llvm::AnalysisManagerllvm::Module&) (/usr/lib/llvm-15/bin/../lib/
[#9]( 0x0000562c08da8f37 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRefllvm::StringRef, llvm::ArrayRefllvm::PassPlugin, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool) (/usr/lib/llvm-15/bin/opt+0x22f37)
[#10]( 0x0000562c08dbac04 main (/usr/lib/llvm-15/bin/opt+0x34c04)
[#11]( 0x00007fcdafaf1d90 __libc_start_call_main ./csu/../sysdeps/nptl/libc_start_call_main.h:58:16
[#12]( 0x00007fcdafaf1e40 call_init ./csu/../csu/libc-start.c:128:20
[#13]( 0x00007fcdafaf1e40 __libc_start_main ./csu/../csu/libc-start.c:379:5
[#14]( 0x0000562c08da1905 _start (/usr/lib/llvm-15/bin/opt+0x1b905)
Segmentation fault (core dumped)

This is the code for my llvm pass :slight_smile:

#include "InstrumentCall.h"
#include "instrumentcall.c"

#include "llvm/IR/IRBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"

using namespace llvm;

#define DEBUG_TYPE "instr-call"

// InstrumentCall implementation
bool InstrumentCall::runOnModule(Module &M) {
  bool Instrumented = false;
  auto &CTX = M.getContext();
  // STEP 1: Inject the declaration of the function to call
  // -------------------------------------------------------
  llvm::FunctionType *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(CTX),       // return type
					false       // is varg function
  // STEP 2: Chose where to inject the instrumentation
  // -------------------------------------------------
  auto InstFunc = M.getOrInsertFunction("instrumentcall", FT);
  //auto InstFunc = Function::Create(FT, Function::ExternalLinkage, "instrumentcall", M);
  for (auto &F : M) {
    for(auto &B:F){ 
      for(auto &I:B){
          //errs() << "Instruction: "<< I << "\n";
            errs() << "Opcode: "<< I.getOpcodeName() << "\n";
          //errs() << "Instruction: "<< I << "\n";
          //errs() << "Opcode: "<< I.getOpcodeName() << "\n";
          StringRef called = dyn_cast<CallInst>(&I)->getCalledFunction()->getName();
          errs() << "Called Function: "<< called << "\n";
          // error in the IRBuilder constructor
            IRBuilder<> builder(&B);
            //Instruction *newInst = CallInst::Create(InstFunc, "");
            //B.getInstList().insert(((Instruction*)&I)->getIterator(), newInst);    
            Instrumented = true;
  return Instrumented;

PreservedAnalyses InstrumentCall::run(llvm::Module &M,
                                       llvm::ModuleAnalysisManager &) {
  bool Changed =  runOnModule(M);

  return (Changed ? llvm::PreservedAnalyses::none()
                  : llvm::PreservedAnalyses::all());

// New PM Registration
llvm::PassPluginLibraryInfo getInstrumentCallPluginInfo() {
          [](PassBuilder &PB) {
                [](StringRef Name, ModulePassManager &MPM,
                   ArrayRef<PassBuilder::PipelineElement>) {
                  if (Name == "instr-call") {
                    return true;
                  return false;

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

You’re modifying a block while using a range loop over it, which typically works poorly. You may want to try using make_early_inc_range

Thank you for your response. I added that but I still have the same issue.
Could it be because the function I am trying to call contains an in line assembly ?

I also have another issue where after I run the pass I can’t find the modifications on the input file !! Does anyone have an idea why?

Thank you in advance.

Yes. For inline asm the call target isn’t a function and getCalledFunction will return null

1 Like

Oh I didn’t know that thank you !! if it’s not a Function what would you recommend I use instead of getCalledFunction ?

Depends what you’re doing with it? Everything is a wrapper around getCalledOperand with type checks

I see !! Well, actually for now I am just attempting to insert function calls. The function I am trying to call is written in assembly.