LLVM代码求助:获取CallInst返回值并传参时运行崩溃
解决LLVM Pass中获取CallInst返回值并传递时的崩溃问题
看起来你在编写LLVM函数Pass时遇到了段错误,从错误栈能直接定位到问题出在DebugLoc::getLine()的调用上。我来帮你拆解问题原因,再给出修复方案:
崩溃的直接原因
你的代码里直接调用I.getDebugLoc().getLine(),但不是所有LLVM指令都携带调试信息。当某个CallInst没有调试信息时,getDebugLoc()会返回一个"Unknown"状态的DebugLoc对象,这时调用getLine()或getCol()会访问内部空指针,直接触发段错误——这就是错误栈指向_ZNK4llvm8DebugLoc7getLineEv的原因。
除此之外,代码还有几个潜在问题,也可能引发运行时错误:
- 直接把
CallInst*作为参数传给hook1:如果原调用是返回void的函数,ci本身没有返回值;如果返回类型不是i32,还会出现类型不匹配的问题。 - IRBuilder的插入点设置冗余,可能导致插入位置不符合预期。
修复后的代码
下面是调整后的代码,解决了上述所有问题:
if (auto* ci = dyn_cast<CallInst>(&I)) { // 合并isa和dyn_cast,写法更简洁高效 // 先检查调试信息是否有效,避免空指针访问 DebugLoc debugLoc = ci->getDebugLoc(); int line = 0, col = 0; if (!debugLoc.isUnknown()) { line = debugLoc.getLine(); col = debugLoc.getCol(); } else { // 没有调试信息时,可设置默认值,也可根据需求直接跳过该指令 line = -1; col = -1; } LLVMContext& ctx = F.getContext(); Type* i32Ty = Type::getInt32Ty(ctx); Value* lineVal = ConstantInt::get(i32Ty, line, true); Value* colVal = ConstantInt::get(i32Ty, col, true); // 处理CallInst的返回值,确保和hook1的int参数类型匹配 Value* callRetVal = ci; if (ci->getType()->isVoidTy()) { // 如果原函数返回void,用默认i32值替代返回值 callRetVal = ConstantInt::get(i32Ty, 0, true); } else { // 如果返回类型不是i32,执行整数类型转换 if (callRetVal->getType() != i32Ty) { callRetVal = CastInst::CreateIntegerCast( callRetVal, i32Ty, true, "cast_to_i32", ci ); } } // 构造参数并插入hook调用 ArrayRef<Value*> hookArgs = {lineVal, colVal, callRetVal}; IRBuilder<> builder(ci->getNextNode()); // 明确将调用插入在原CallInst之后 builder.CreateCall(hook1, hookArgs); }
关键修复点说明
- DebugLoc有效性检查:通过
!debugLoc.isUnknown()判断调试信息是否存在,仅在有效时才调用getLine()和getCol()。 - 返回值类型适配:
- 针对返回
void的函数,用默认i32值替代返回值; - 针对非
i32的返回类型,通过CreateIntegerCast转换为i32,确保和hook1的参数类型匹配(hook1接受int类型,对应LLVM的i32类型)。
- 针对返回
- 简化IRBuilder使用:直接将插入点设为原
CallInst的下一个节点,避免冗余的插入点设置。 - 使用ArrayRef:用LLVM原生的
ArrayRef替代C风格数组,更符合LLVM API的使用习惯,也更安全。
额外建议
如果你的场景中,没有调试信息的指令不需要处理,可以直接在debugLoc.isUnknown()时continue跳过,这样能避免不必要的默认值处理。
内容的提问来源于stack exchange,提问作者vnhsgan
相关产品推荐
相关产品推荐

