diff --git a/defaultarch.cpp b/defaultarch.cpp index cd87f6206..11c756225 100644 --- a/defaultarch.cpp +++ b/defaultarch.cpp @@ -16,6 +16,37 @@ static bool GetNextFunctionAfterAddress(Ref data, Ref plat return nextFunc != nullptr; } +static bool IsZeroConstant(LowLevelILInstruction expr) +{ + return ((expr.operation == LLIL_CONST) || (expr.operation == LLIL_CONST_PTR)) && (expr.GetConstant() == 0); +} + + +static bool IsConstantPointer(LowLevelILInstruction expr, uint64_t value) +{ + return ((expr.operation == LLIL_CONST) || (expr.operation == LLIL_CONST_PTR)) && ((uint64_t)expr.GetConstant() == value); +} + + +static bool IsReturnAddressRegisterExpr(LowLevelILInstruction expr, const set& returnAddressRegisters) +{ + switch (expr.operation) + { + case LLIL_REG: + return returnAddressRegisters.count(expr.GetSourceRegister()) != 0; + case LLIL_ADD: + return (IsReturnAddressRegisterExpr(expr.GetLeftExpr(), returnAddressRegisters) + && IsZeroConstant(expr.GetRightExpr())) + || (IsZeroConstant(expr.GetLeftExpr()) + && IsReturnAddressRegisterExpr(expr.GetRightExpr(), returnAddressRegisters)); + case LLIL_SUB: + return IsReturnAddressRegisterExpr(expr.GetLeftExpr(), returnAddressRegisters) + && IsZeroConstant(expr.GetRightExpr()); + default: + return false; + } +} + void Architecture::DefaultAnalyzeBasicBlocks(Function* function, BasicBlockAnalysisContext& context) { @@ -992,7 +1023,18 @@ void FunctionLifterContext::CheckForInlinedCall(BasicBlock* block, size_t instrC m_function->MarkLabel(start); m_function->ReplaceExpr(lastInstr.exprIndex, m_function->Goto(start, lastInstr)); - if (lastInstr.operation == LLIL_CALL) + set returnAddressRegisters; + for (size_t instrIndex = instrCountBefore; instrIndex < instrCountAfter - 1; instrIndex++) + { + LowLevelILInstruction instr = m_function->GetInstruction(instrIndex); + if (instr.operation != LLIL_SET_REG) + continue; + + if (IsConstantPointer(instr.GetSourceExpr(), addr)) + returnAddressRegisters.insert(instr.GetDestRegister()); + } + + if (lastInstr.operation == LLIL_CALL && returnAddressRegisters.empty()) { // Set up return address according to the architecture // TODO: Handle architectures that use a nonstandard way of calling functions @@ -1024,6 +1066,7 @@ void FunctionLifterContext::CheckForInlinedCall(BasicBlock* block, size_t instrC } // Copy the inlined code from the target function + Ref callArch = block->GetArchitecture(); auto blocks = PrepareToCopyForeignFunction(targetIL); auto unresolvedIndirectBranches = targetFunc->GetUnresolvedIndirectBranches(); auto sourceLocation = inlineDuringAnalysis == InlineUsingCallAddress ? ILSourceLocation(lastInstr) : ILSourceLocation(); @@ -1046,6 +1089,13 @@ void FunctionLifterContext::CheckForInlinedCall(BasicBlock* block, size_t instrC m_function->AddInstruction(instr.GetDestExpr().CopyTo(m_function, sourceLocation)); m_function->AddInstruction(m_function->Goto(end, sourceLocation)); } + else if (lastInstr.operation == LLIL_CALL && instr.operation == LLIL_JUMP + && (block->GetArchitecture() == callArch) + && (IsConstantPointer(instr.GetDestExpr(), addr) + || IsReturnAddressRegisterExpr(instr.GetDestExpr(), returnAddressRegisters))) + { + m_function->AddInstruction(m_function->Goto(end, sourceLocation)); + } else if (lastInstr.operation == LLIL_CALL && instr.operation == LLIL_JUMP && block->GetOutgoingEdges().empty() && (unresolvedIndirectBranches.count(loc) == 0)) {