diff options
Diffstat (limited to 'bolt/lib/Core/BinaryFunction.cpp')
| -rw-r--r-- | bolt/lib/Core/BinaryFunction.cpp | 236 |
1 files changed, 130 insertions, 106 deletions
diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index 0ac47a53a446..54f2f9d972a4 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -880,9 +880,9 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size, // internal function addresses to escape the function scope - we // consider it a tail call. if (opts::Verbosity >= 1) { - errs() << "BOLT-WARNING: no section for address 0x" - << Twine::utohexstr(ArrayStart) << " referenced from function " - << *this << '\n'; + BC.errs() << "BOLT-WARNING: no section for address 0x" + << Twine::utohexstr(ArrayStart) << " referenced from function " + << *this << '\n'; } return IndirectBranchType::POSSIBLE_TAIL_CALL; } @@ -899,11 +899,11 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size, if (BC.getSectionForAddress(ArrayStart)->isWritable()) return IndirectBranchType::UNKNOWN; - outs() << "BOLT-INFO: fixed indirect branch detected in " << *this - << " at 0x" << Twine::utohexstr(getAddress() + Offset) - << " referencing data at 0x" << Twine::utohexstr(ArrayStart) - << " the destination value is 0x" << Twine::utohexstr(*Value) - << '\n'; + BC.outs() << "BOLT-INFO: fixed indirect branch detected in " << *this + << " at 0x" << Twine::utohexstr(getAddress() + Offset) + << " referencing data at 0x" << Twine::utohexstr(ArrayStart) + << " the destination value is 0x" << Twine::utohexstr(*Value) + << '\n'; TargetAddress = *Value; return BranchType; @@ -1021,28 +1021,29 @@ bool BinaryFunction::isZeroPaddingAt(uint64_t Offset) const { return true; } -void BinaryFunction::handlePCRelOperand(MCInst &Instruction, uint64_t Address, - uint64_t Size) { +Error BinaryFunction::handlePCRelOperand(MCInst &Instruction, uint64_t Address, + uint64_t Size) { auto &MIB = BC.MIB; uint64_t TargetAddress = 0; if (!MIB->evaluateMemOperandTarget(Instruction, TargetAddress, Address, Size)) { - errs() << "BOLT-ERROR: PC-relative operand can't be evaluated:\n"; - BC.InstPrinter->printInst(&Instruction, 0, "", *BC.STI, errs()); - errs() << '\n'; - Instruction.dump_pretty(errs(), BC.InstPrinter.get()); - errs() << '\n'; - errs() << "BOLT-ERROR: cannot handle PC-relative operand at 0x" - << Twine::utohexstr(Address) << ". Skipping function " << *this - << ".\n"; + std::string Msg; + raw_string_ostream SS(Msg); + SS << "BOLT-ERROR: PC-relative operand can't be evaluated:\n"; + BC.InstPrinter->printInst(&Instruction, 0, "", *BC.STI, SS); + SS << '\n'; + Instruction.dump_pretty(SS, BC.InstPrinter.get()); + SS << '\n'; + SS << "BOLT-ERROR: cannot handle PC-relative operand at 0x" + << Twine::utohexstr(Address) << ". Skipping function " << *this << ".\n"; if (BC.HasRelocations) - exit(1); + return createFatalBOLTError(Msg); IsSimple = false; - return; + return createNonFatalBOLTError(Msg); } if (TargetAddress == 0 && opts::Verbosity >= 1) { - outs() << "BOLT-INFO: PC-relative operand is zero in function " << *this - << '\n'; + BC.outs() << "BOLT-INFO: PC-relative operand is zero in function " << *this + << '\n'; } const MCSymbol *TargetSymbol; @@ -1054,6 +1055,7 @@ void BinaryFunction::handlePCRelOperand(MCInst &Instruction, uint64_t Address, Instruction, TargetSymbol, static_cast<int64_t>(TargetOffset), &*BC.Ctx); (void)ReplaceSuccess; assert(ReplaceSuccess && "Failed to replace mem operand with symbol+off."); + return Error::success(); } MCSymbol *BinaryFunction::handleExternalReference(MCInst &Instruction, @@ -1066,9 +1068,9 @@ MCSymbol *BinaryFunction::handleExternalReference(MCInst &Instruction, const uint64_t AbsoluteInstrAddr = getAddress() + Offset; BC.addInterproceduralReference(this, TargetAddress); if (opts::Verbosity >= 2 && !IsCall && Size == 2 && !BC.HasRelocations) { - errs() << "BOLT-WARNING: relaxed tail call detected at 0x" - << Twine::utohexstr(AbsoluteInstrAddr) << " in function " << *this - << ". Code size will be increased.\n"; + BC.errs() << "BOLT-WARNING: relaxed tail call detected at 0x" + << Twine::utohexstr(AbsoluteInstrAddr) << " in function " << *this + << ". Code size will be increased.\n"; } assert(!MIB->isTailCall(Instruction) && @@ -1082,9 +1084,9 @@ MCSymbol *BinaryFunction::handleExternalReference(MCInst &Instruction, assert(MIB->isConditionalBranch(Instruction) && "unknown tail call instruction"); if (opts::Verbosity >= 2) { - errs() << "BOLT-WARNING: conditional tail call detected in " - << "function " << *this << " at 0x" - << Twine::utohexstr(AbsoluteInstrAddr) << ".\n"; + BC.errs() << "BOLT-WARNING: conditional tail call detected in " + << "function " << *this << " at 0x" + << Twine::utohexstr(AbsoluteInstrAddr) << ".\n"; } } IsCall = true; @@ -1094,8 +1096,8 @@ MCSymbol *BinaryFunction::handleExternalReference(MCInst &Instruction, // We actually see calls to address 0 in presence of weak // symbols originating from libraries. This code is never meant // to be executed. - outs() << "BOLT-INFO: Function " << *this - << " has a call to address zero.\n"; + BC.outs() << "BOLT-INFO: Function " << *this + << " has a call to address zero.\n"; } return BC.getOrCreateGlobalSymbol(TargetAddress, "FUNCat"); @@ -1164,7 +1166,7 @@ void BinaryFunction::handleAArch64IndirectCall(MCInst &Instruction, } } -bool BinaryFunction::disassemble() { +Error BinaryFunction::disassemble() { NamedRegionTimer T("disassemble", "Disassemble function", "buildfuncs", "Build Binary Functions", opts::TimeBuild); ErrorOr<ArrayRef<uint8_t>> ErrorOrFunctionData = getData(); @@ -1208,10 +1210,11 @@ bool BinaryFunction::disassemble() { if (isZeroPaddingAt(Offset)) break; - errs() << "BOLT-WARNING: unable to disassemble instruction at offset 0x" - << Twine::utohexstr(Offset) << " (address 0x" - << Twine::utohexstr(AbsoluteInstrAddr) << ") in function " << *this - << '\n'; + BC.errs() + << "BOLT-WARNING: unable to disassemble instruction at offset 0x" + << Twine::utohexstr(Offset) << " (address 0x" + << Twine::utohexstr(AbsoluteInstrAddr) << ") in function " << *this + << '\n'; // Some AVX-512 instructions could not be disassembled at all. if (BC.HasRelocations && opts::TrapOnAVX512 && BC.isX86()) { setTrapOnEntry(); @@ -1227,10 +1230,10 @@ bool BinaryFunction::disassemble() { if (opts::CheckEncoding && !BC.MIB->isBranch(Instruction) && !BC.MIB->isCall(Instruction) && !BC.MIB->isNoop(Instruction)) { if (!BC.validateInstructionEncoding(FunctionData.slice(Offset, Size))) { - errs() << "BOLT-WARNING: mismatching LLVM encoding detected in " - << "function " << *this << " for instruction :\n"; - BC.printInstruction(errs(), Instruction, AbsoluteInstrAddr); - errs() << '\n'; + BC.errs() << "BOLT-WARNING: mismatching LLVM encoding detected in " + << "function " << *this << " for instruction :\n"; + BC.printInstruction(BC.errs(), Instruction, AbsoluteInstrAddr); + BC.errs() << '\n'; } } @@ -1243,10 +1246,10 @@ bool BinaryFunction::disassemble() { } if (!BC.validateInstructionEncoding(FunctionData.slice(Offset, Size))) { - errs() << "BOLT-WARNING: internal assembler/disassembler error " - "detected for AVX512 instruction:\n"; - BC.printInstruction(errs(), Instruction, AbsoluteInstrAddr); - errs() << " in function " << *this << '\n'; + BC.errs() << "BOLT-WARNING: internal assembler/disassembler error " + "detected for AVX512 instruction:\n"; + BC.printInstruction(BC.errs(), Instruction, AbsoluteInstrAddr); + BC.errs() << " in function " << *this << '\n'; setIgnored(); break; } @@ -1282,9 +1285,9 @@ bool BinaryFunction::disassemble() { // function, so preserve the function as is for now. PreserveNops = true; } else { - errs() << "BOLT-WARNING: internal call detected at 0x" - << Twine::utohexstr(AbsoluteInstrAddr) << " in function " - << *this << ". Skipping.\n"; + BC.errs() << "BOLT-WARNING: internal call detected at 0x" + << Twine::utohexstr(AbsoluteInstrAddr) + << " in function " << *this << ". Skipping.\n"; IsSimple = false; } } @@ -1332,8 +1335,19 @@ bool BinaryFunction::disassemble() { if (MIB->isIndirectBranch(Instruction)) handleIndirectBranch(Instruction, Size, Offset); // Indirect call. We only need to fix it if the operand is RIP-relative. - if (IsSimple && MIB->hasPCRelOperand(Instruction)) - handlePCRelOperand(Instruction, AbsoluteInstrAddr, Size); + if (IsSimple && MIB->hasPCRelOperand(Instruction)) { + if (auto NewE = handleErrors( + handlePCRelOperand(Instruction, AbsoluteInstrAddr, Size), + [&](const BOLTError &E) -> Error { + if (E.isFatal()) + return Error(std::make_unique<BOLTError>(std::move(E))); + if (!E.getMessage().empty()) + E.log(BC.errs()); + return Error::success(); + })) { + return Error(std::move(NewE)); + } + } if (BC.isAArch64()) handleAArch64IndirectCall(Instruction, Offset); @@ -1372,8 +1386,18 @@ bool BinaryFunction::disassemble() { UsedReloc = true; } - if (!BC.isRISCV() && MIB->hasPCRelOperand(Instruction) && !UsedReloc) - handlePCRelOperand(Instruction, AbsoluteInstrAddr, Size); + if (!BC.isRISCV() && MIB->hasPCRelOperand(Instruction) && !UsedReloc) { + if (auto NewE = handleErrors( + handlePCRelOperand(Instruction, AbsoluteInstrAddr, Size), + [&](const BOLTError &E) -> Error { + if (E.isFatal()) + return Error(std::make_unique<BOLTError>(std::move(E))); + if (!E.getMessage().empty()) + E.log(BC.errs()); + return Error::success(); + })) + return Error(std::move(NewE)); + } } add_instruction: @@ -1413,12 +1437,12 @@ add_instruction: if (!IsSimple) { clearList(Instructions); - return false; + return createNonFatalBOLTError(""); } updateState(State::Disassembled); - return true; + return Error::success(); } bool BinaryFunction::scanExternalRefs() { @@ -1467,10 +1491,11 @@ bool BinaryFunction::scanExternalRefs() { FunctionData.slice(Offset), AbsoluteInstrAddr, nulls())) { if (opts::Verbosity >= 1 && !isZeroPaddingAt(Offset)) { - errs() << "BOLT-WARNING: unable to disassemble instruction at offset 0x" - << Twine::utohexstr(Offset) << " (address 0x" - << Twine::utohexstr(AbsoluteInstrAddr) << ") in function " - << *this << '\n'; + BC.errs() + << "BOLT-WARNING: unable to disassemble instruction at offset 0x" + << Twine::utohexstr(Offset) << " (address 0x" + << Twine::utohexstr(AbsoluteInstrAddr) << ") in function " << *this + << '\n'; } Success = false; DisassemblyFailed = true; @@ -1598,7 +1623,7 @@ bool BinaryFunction::scanExternalRefs() { HasExternalRefRelocations = true; if (opts::Verbosity >= 1 && !Success) - outs() << "BOLT-INFO: failed to scan refs for " << *this << '\n'; + BC.outs() << "BOLT-INFO: failed to scan refs for " << *this << '\n'; return Success; } @@ -1631,9 +1656,9 @@ void BinaryFunction::postProcessEntryPoints() { if (BC.isAArch64() && Offset == getSize()) continue; - errs() << "BOLT-WARNING: reference in the middle of instruction " - "detected in function " - << *this << " at offset 0x" << Twine::utohexstr(Offset) << '\n'; + BC.errs() << "BOLT-WARNING: reference in the middle of instruction " + "detected in function " + << *this << " at offset 0x" << Twine::utohexstr(Offset) << '\n'; if (BC.HasRelocations) setIgnored(); setSimple(false); @@ -1647,9 +1672,9 @@ void BinaryFunction::postProcessJumpTables() { JumpTable &JT = *JTI.second; if (JT.Type == JumpTable::JTT_PIC && opts::JumpTables == JTS_BASIC) { opts::JumpTables = JTS_MOVE; - outs() << "BOLT-INFO: forcing -jump-tables=move as PIC jump table was " - "detected in function " - << *this << '\n'; + BC.outs() << "BOLT-INFO: forcing -jump-tables=move as PIC jump table was " + "detected in function " + << *this << '\n'; } const uint64_t BDSize = BC.getBinaryDataAtAddress(JT.getAddress())->getSize(); @@ -1764,15 +1789,15 @@ bool BinaryFunction::validateExternallyReferencedOffsets() { continue; if (opts::Verbosity >= 1) { - errs() << "BOLT-WARNING: unclaimed data to code reference (possibly " - << "an unrecognized jump table entry) to " << BB->getName() - << " in " << *this << "\n"; + BC.errs() << "BOLT-WARNING: unclaimed data to code reference (possibly " + << "an unrecognized jump table entry) to " << BB->getName() + << " in " << *this << "\n"; } auto L = BC.scopeLock(); addEntryPoint(*BB); } else { - errs() << "BOLT-WARNING: unknown data to code reference to offset " - << Twine::utohexstr(Destination) << " in " << *this << "\n"; + BC.errs() << "BOLT-WARNING: unknown data to code reference to offset " + << Twine::utohexstr(Destination) << " in " << *this << "\n"; setIgnored(); } HasUnclaimedReference = true; @@ -1872,9 +1897,9 @@ bool BinaryFunction::postProcessIndirectBranches( } if (opts::Verbosity >= 2) { - outs() << "BOLT-INFO: rejected potential indirect tail call in " - << "function " << *this << " in basic block " << BB.getName() - << ".\n"; + BC.outs() << "BOLT-INFO: rejected potential indirect tail call in " + << "function " << *this << " in basic block " << BB.getName() + << ".\n"; LLVM_DEBUG(BC.printInstructions(dbgs(), BB.begin(), BB.end(), BB.getOffset(), this, true)); } @@ -1946,17 +1971,17 @@ void BinaryFunction::recomputeLandingPads() { } } -bool BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) { +Error BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) { auto &MIB = BC.MIB; if (!isSimple()) { assert(!BC.HasRelocations && "cannot process file with non-simple function in relocs mode"); - return false; + return createNonFatalBOLTError(""); } if (CurrentState != State::Disassembled) - return false; + return createNonFatalBOLTError(""); assert(BasicBlocks.empty() && "basic block list should be empty"); assert((Labels.find(getFirstInstructionOffset()) != Labels.end()) && @@ -2093,7 +2118,7 @@ bool BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) { if (BasicBlocks.empty()) { setSimple(false); - return false; + return createNonFatalBOLTError(""); } // Intermediate dump. @@ -2111,11 +2136,12 @@ bool BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) { BinaryBasicBlock *ToBB = getBasicBlockAtOffset(Branch.second); if (!FromBB || !ToBB) { if (!FromBB) - errs() << "BOLT-ERROR: cannot find BB containing the branch.\n"; + BC.errs() << "BOLT-ERROR: cannot find BB containing the branch.\n"; if (!ToBB) - errs() << "BOLT-ERROR: cannot find BB containing branch destination.\n"; - BC.exitWithBugReport("disassembly failed - inconsistent branch found.", - *this); + BC.errs() + << "BOLT-ERROR: cannot find BB containing branch destination.\n"; + return createFatalBOLTError(BC.generateBugReportMessage( + "disassembly failed - inconsistent branch found.", *this)); } FromBB->addSuccessor(ToBB); @@ -2193,8 +2219,8 @@ bool BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) { // Make any necessary adjustments for indirect branches. if (!postProcessIndirectBranches(AllocatorId)) { if (opts::Verbosity) { - errs() << "BOLT-WARNING: failed to post-process indirect branches for " - << *this << '\n'; + BC.errs() << "BOLT-WARNING: failed to post-process indirect branches for " + << *this << '\n'; } // In relocation mode we want to keep processing the function but avoid // optimizing it. @@ -2204,7 +2230,7 @@ bool BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) { clearList(ExternallyReferencedOffsets); clearList(UnknownIndirectBranchOffsets); - return true; + return Error::success(); } void BinaryFunction::postProcessCFG() { @@ -3034,10 +3060,6 @@ static std::string constructFilename(std::string Filename, Annotation.insert(0, "-"); if (Filename.size() + Annotation.size() + Suffix.size() > MAX_PATH) { assert(Suffix.size() + Annotation.size() <= MAX_PATH); - if (opts::Verbosity >= 1) { - errs() << "BOLT-WARNING: Filename \"" << Filename << Annotation << Suffix - << "\" exceeds the " << MAX_PATH << " size limit, truncating.\n"; - } Filename.resize(MAX_PATH - (Suffix.size() + Annotation.size())); } Filename += Annotation; @@ -3162,16 +3184,17 @@ void BinaryFunction::viewGraph() const { SmallString<MAX_PATH> Filename; if (std::error_code EC = sys::fs::createTemporaryFile("bolt-cfg", "dot", Filename)) { - errs() << "BOLT-ERROR: " << EC.message() << ", unable to create " - << " bolt-cfg-XXXXX.dot temporary file.\n"; + BC.errs() << "BOLT-ERROR: " << EC.message() << ", unable to create " + << " bolt-cfg-XXXXX.dot temporary file.\n"; return; } dumpGraphToFile(std::string(Filename)); if (DisplayGraph(Filename)) - errs() << "BOLT-ERROR: Can't display " << Filename << " with graphviz.\n"; + BC.errs() << "BOLT-ERROR: Can't display " << Filename + << " with graphviz.\n"; if (std::error_code EC = sys::fs::remove(Filename)) { - errs() << "BOLT-WARNING: " << EC.message() << ", failed to remove " - << Filename << "\n"; + BC.errs() << "BOLT-WARNING: " << EC.message() << ", failed to remove " + << Filename << "\n"; } } @@ -3181,7 +3204,7 @@ void BinaryFunction::dumpGraphForPass(std::string Annotation) const { std::string Filename = constructFilename(getPrintName(), Annotation, ".dot"); if (opts::Verbosity >= 1) - outs() << "BOLT-INFO: dumping CFG to " << Filename << "\n"; + BC.outs() << "BOLT-INFO: dumping CFG to " << Filename << "\n"; dumpGraphToFile(Filename); } @@ -3190,8 +3213,8 @@ void BinaryFunction::dumpGraphToFile(std::string Filename) const { raw_fd_ostream of(Filename, EC, sys::fs::OF_None); if (EC) { if (opts::Verbosity >= 1) { - errs() << "BOLT-WARNING: " << EC.message() << ", unable to open " - << Filename << " for output.\n"; + BC.errs() << "BOLT-WARNING: " << EC.message() << ", unable to open " + << Filename << " for output.\n"; } return; } @@ -3213,8 +3236,8 @@ bool BinaryFunction::validateCFG() const { // Make sure all blocks in CFG are valid. auto validateBlock = [this](const BinaryBasicBlock *BB, StringRef Desc) { if (!BB->isValid()) { - errs() << "BOLT-ERROR: deleted " << Desc << " " << BB->getName() - << " detected in:\n"; + BC.errs() << "BOLT-ERROR: deleted " << Desc << " " << BB->getName() + << " detected in:\n"; this->dump(); return false; } @@ -3241,8 +3264,8 @@ bool BinaryFunction::validateCFG() const { std::unordered_set<const BinaryBasicBlock *> BBLandingPads; for (const BinaryBasicBlock *LP : BB->landing_pads()) { if (BBLandingPads.count(LP)) { - errs() << "BOLT-ERROR: duplicate landing pad detected in" - << BB->getName() << " in function " << *this << '\n'; + BC.errs() << "BOLT-ERROR: duplicate landing pad detected in" + << BB->getName() << " in function " << *this << '\n'; return false; } BBLandingPads.insert(LP); @@ -3251,8 +3274,8 @@ bool BinaryFunction::validateCFG() const { std::unordered_set<const BinaryBasicBlock *> BBThrowers; for (const BinaryBasicBlock *Thrower : BB->throwers()) { if (BBThrowers.count(Thrower)) { - errs() << "BOLT-ERROR: duplicate thrower detected in" << BB->getName() - << " in function " << *this << '\n'; + BC.errs() << "BOLT-ERROR: duplicate thrower detected in" + << BB->getName() << " in function " << *this << '\n'; return false; } BBThrowers.insert(Thrower); @@ -3260,17 +3283,18 @@ bool BinaryFunction::validateCFG() const { for (const BinaryBasicBlock *LPBlock : BB->landing_pads()) { if (!llvm::is_contained(LPBlock->throwers(), BB)) { - errs() << "BOLT-ERROR: inconsistent landing pad detected in " << *this - << ": " << BB->getName() << " is in LandingPads but not in " - << LPBlock->getName() << " Throwers\n"; + BC.errs() << "BOLT-ERROR: inconsistent landing pad detected in " + << *this << ": " << BB->getName() + << " is in LandingPads but not in " << LPBlock->getName() + << " Throwers\n"; return false; } } for (const BinaryBasicBlock *Thrower : BB->throwers()) { if (!llvm::is_contained(Thrower->landing_pads(), BB)) { - errs() << "BOLT-ERROR: inconsistent thrower detected in " << *this - << ": " << BB->getName() << " is in Throwers list but not in " - << Thrower->getName() << " LandingPads\n"; + BC.errs() << "BOLT-ERROR: inconsistent thrower detected in " << *this + << ": " << BB->getName() << " is in Throwers list but not in " + << Thrower->getName() << " LandingPads\n"; return false; } } |
