138639a81SMaksim Panchenko //===- bolt/Rewrite/LinuxKernelRewriter.cpp -------------------------------===// 238639a81SMaksim Panchenko // 338639a81SMaksim Panchenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 438639a81SMaksim Panchenko // See https://llvm.org/LICENSE.txt for license information. 538639a81SMaksim Panchenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 638639a81SMaksim Panchenko // 738639a81SMaksim Panchenko //===----------------------------------------------------------------------===// 838639a81SMaksim Panchenko // 938639a81SMaksim Panchenko // Support for updating Linux Kernel metadata. 1038639a81SMaksim Panchenko // 1138639a81SMaksim Panchenko //===----------------------------------------------------------------------===// 1238639a81SMaksim Panchenko 1338639a81SMaksim Panchenko #include "bolt/Core/BinaryFunction.h" 1438639a81SMaksim Panchenko #include "bolt/Rewrite/MetadataRewriter.h" 1538639a81SMaksim Panchenko #include "bolt/Rewrite/MetadataRewriters.h" 1638639a81SMaksim Panchenko #include "bolt/Utils/CommandLineOpts.h" 176b1cf004SMaksim Panchenko #include "llvm/ADT/ArrayRef.h" 18ccf0c8daSMaksim Panchenko #include "llvm/ADT/DenseSet.h" 196b1cf004SMaksim Panchenko #include "llvm/MC/MCDisassembler/MCDisassembler.h" 205a298871SMaksim Panchenko #include "llvm/Support/BinaryStreamWriter.h" 2138639a81SMaksim Panchenko #include "llvm/Support/CommandLine.h" 225a298871SMaksim Panchenko #include "llvm/Support/Debug.h" 2338639a81SMaksim Panchenko #include "llvm/Support/Errc.h" 24*6e8a1a45SFranklin #include "llvm/Support/ErrorOr.h" 25*6e8a1a45SFranklin #include <regex> 2638639a81SMaksim Panchenko 275a298871SMaksim Panchenko #define DEBUG_TYPE "bolt-linux" 285a298871SMaksim Panchenko 2938639a81SMaksim Panchenko using namespace llvm; 3038639a81SMaksim Panchenko using namespace bolt; 3138639a81SMaksim Panchenko 32e6724cbdSMaksim Panchenko namespace opts { 33ec4ddc28SMaksim Panchenko 34e6724cbdSMaksim Panchenko static cl::opt<bool> 35143afb40SMaksim Panchenko AltInstHasPadLen("alt-inst-has-padlen", 36143afb40SMaksim Panchenko cl::desc("specify that .altinstructions has padlen field"), 37143afb40SMaksim Panchenko cl::init(false), cl::Hidden, cl::cat(BoltCategory)); 38143afb40SMaksim Panchenko 39143afb40SMaksim Panchenko static cl::opt<uint32_t> 40143afb40SMaksim Panchenko AltInstFeatureSize("alt-inst-feature-size", 41143afb40SMaksim Panchenko cl::desc("size of feature field in .altinstructions"), 42143afb40SMaksim Panchenko cl::init(2), cl::Hidden, cl::cat(BoltCategory)); 43143afb40SMaksim Panchenko 44143afb40SMaksim Panchenko static cl::opt<bool> 45143afb40SMaksim Panchenko DumpAltInstructions("dump-alt-instructions", 46143afb40SMaksim Panchenko cl::desc("dump Linux alternative instructions info"), 47143afb40SMaksim Panchenko cl::init(false), cl::Hidden, cl::cat(BoltCategory)); 48143afb40SMaksim Panchenko 49143afb40SMaksim Panchenko static cl::opt<bool> 50ccf0c8daSMaksim Panchenko DumpExceptions("dump-linux-exceptions", 51ccf0c8daSMaksim Panchenko cl::desc("dump Linux kernel exception table"), 52ccf0c8daSMaksim Panchenko cl::init(false), cl::Hidden, cl::cat(BoltCategory)); 53ec4ddc28SMaksim Panchenko 54ec4ddc28SMaksim Panchenko static cl::opt<bool> 55ec4ddc28SMaksim Panchenko DumpORC("dump-orc", cl::desc("dump raw ORC unwind information (sorted)"), 56ec4ddc28SMaksim Panchenko cl::init(false), cl::Hidden, cl::cat(BoltCategory)); 57ec4ddc28SMaksim Panchenko 58f51ade25SMaksim Panchenko static cl::opt<bool> DumpParavirtualPatchSites( 59f51ade25SMaksim Panchenko "dump-para-sites", cl::desc("dump Linux kernel paravitual patch sites"), 60f51ade25SMaksim Panchenko cl::init(false), cl::Hidden, cl::cat(BoltCategory)); 61f51ade25SMaksim Panchenko 62fd32e744SMaksim Panchenko static cl::opt<bool> 63fd32e744SMaksim Panchenko DumpPCIFixups("dump-pci-fixups", 64fd32e744SMaksim Panchenko cl::desc("dump Linux kernel PCI fixup table"), 65fd32e744SMaksim Panchenko cl::init(false), cl::Hidden, cl::cat(BoltCategory)); 66fd32e744SMaksim Panchenko 6799b4532bSMaksim Panchenko static cl::opt<bool> DumpSMPLocks("dump-smp-locks", 6899b4532bSMaksim Panchenko cl::desc("dump Linux kernel SMP locks"), 6999b4532bSMaksim Panchenko cl::init(false), cl::Hidden, 7099b4532bSMaksim Panchenko cl::cat(BoltCategory)); 7199b4532bSMaksim Panchenko 722646dccaSMaksim Panchenko static cl::opt<bool> DumpStaticCalls("dump-static-calls", 732646dccaSMaksim Panchenko cl::desc("dump Linux kernel static calls"), 742646dccaSMaksim Panchenko cl::init(false), cl::Hidden, 752646dccaSMaksim Panchenko cl::cat(BoltCategory)); 762646dccaSMaksim Panchenko 77ccf0c8daSMaksim Panchenko static cl::opt<bool> 786b1cf004SMaksim Panchenko DumpStaticKeys("dump-static-keys", 796b1cf004SMaksim Panchenko cl::desc("dump Linux kernel static keys jump table"), 806b1cf004SMaksim Panchenko cl::init(false), cl::Hidden, cl::cat(BoltCategory)); 816b1cf004SMaksim Panchenko 826b1cf004SMaksim Panchenko static cl::opt<bool> LongJumpLabels( 836b1cf004SMaksim Panchenko "long-jump-labels", 846b1cf004SMaksim Panchenko cl::desc("always use long jumps/nops for Linux kernel static keys"), 856b1cf004SMaksim Panchenko cl::init(false), cl::Hidden, cl::cat(BoltCategory)); 866b1cf004SMaksim Panchenko 876b1cf004SMaksim Panchenko static cl::opt<bool> 88ccf0c8daSMaksim Panchenko PrintORC("print-orc", 89ccf0c8daSMaksim Panchenko cl::desc("print ORC unwind information for instructions"), 90ccf0c8daSMaksim Panchenko cl::init(true), cl::Hidden, cl::cat(BoltCategory)); 91ccf0c8daSMaksim Panchenko 92ec4ddc28SMaksim Panchenko } // namespace opts 9338639a81SMaksim Panchenko 94*6e8a1a45SFranklin /// Linux kernel version 95*6e8a1a45SFranklin struct LKVersion { 96*6e8a1a45SFranklin LKVersion() {} 97*6e8a1a45SFranklin LKVersion(unsigned Major, unsigned Minor, unsigned Rev) 98*6e8a1a45SFranklin : Major(Major), Minor(Minor), Rev(Rev) {} 99*6e8a1a45SFranklin 100*6e8a1a45SFranklin bool operator<(const LKVersion &Other) const { 101*6e8a1a45SFranklin return std::make_tuple(Major, Minor, Rev) < 102*6e8a1a45SFranklin std::make_tuple(Other.Major, Other.Minor, Other.Rev); 103*6e8a1a45SFranklin } 104*6e8a1a45SFranklin 105*6e8a1a45SFranklin bool operator>(const LKVersion &Other) const { return Other < *this; } 106*6e8a1a45SFranklin 107*6e8a1a45SFranklin bool operator<=(const LKVersion &Other) const { return !(*this > Other); } 108*6e8a1a45SFranklin 109*6e8a1a45SFranklin bool operator>=(const LKVersion &Other) const { return !(*this < Other); } 110*6e8a1a45SFranklin 111*6e8a1a45SFranklin bool operator==(const LKVersion &Other) const { 112*6e8a1a45SFranklin return Major == Other.Major && Minor == Other.Minor && Rev == Other.Rev; 113*6e8a1a45SFranklin } 114*6e8a1a45SFranklin 115*6e8a1a45SFranklin bool operator!=(const LKVersion &Other) const { return !(*this == Other); } 116*6e8a1a45SFranklin 117*6e8a1a45SFranklin unsigned Major{0}; 118*6e8a1a45SFranklin unsigned Minor{0}; 119*6e8a1a45SFranklin unsigned Rev{0}; 120*6e8a1a45SFranklin }; 121*6e8a1a45SFranklin 122e6724cbdSMaksim Panchenko /// Linux Kernel supports stack unwinding using ORC (oops rewind capability). 123e6724cbdSMaksim Panchenko /// ORC state at every IP can be described by the following data structure. 124e6724cbdSMaksim Panchenko struct ORCState { 125e6724cbdSMaksim Panchenko int16_t SPOffset; 126e6724cbdSMaksim Panchenko int16_t BPOffset; 127e6724cbdSMaksim Panchenko int16_t Info; 128e6724cbdSMaksim Panchenko 129e6724cbdSMaksim Panchenko bool operator==(const ORCState &Other) const { 130e6724cbdSMaksim Panchenko return SPOffset == Other.SPOffset && BPOffset == Other.BPOffset && 131e6724cbdSMaksim Panchenko Info == Other.Info; 132e6724cbdSMaksim Panchenko } 133e6724cbdSMaksim Panchenko 134e6724cbdSMaksim Panchenko bool operator!=(const ORCState &Other) const { return !(*this == Other); } 135e6724cbdSMaksim Panchenko }; 136e6724cbdSMaksim Panchenko 1375a298871SMaksim Panchenko /// Section terminator ORC entry. 1385a298871SMaksim Panchenko static ORCState NullORC = {0, 0, 0}; 1395a298871SMaksim Panchenko 140e6724cbdSMaksim Panchenko /// Basic printer for ORC entry. It does not provide the same level of 141e6724cbdSMaksim Panchenko /// information as objtool (for now). 142e6724cbdSMaksim Panchenko inline raw_ostream &operator<<(raw_ostream &OS, const ORCState &E) { 1435a298871SMaksim Panchenko if (!opts::PrintORC) 1445a298871SMaksim Panchenko return OS; 1455a298871SMaksim Panchenko if (E != NullORC) 146e6724cbdSMaksim Panchenko OS << format("{sp: %d, bp: %d, info: 0x%x}", E.SPOffset, E.BPOffset, 147e6724cbdSMaksim Panchenko E.Info); 1485a298871SMaksim Panchenko else 1495a298871SMaksim Panchenko OS << "{terminator}"; 1505a298871SMaksim Panchenko 151e6724cbdSMaksim Panchenko return OS; 152e6724cbdSMaksim Panchenko } 153e6724cbdSMaksim Panchenko 154e6724cbdSMaksim Panchenko namespace { 155e6724cbdSMaksim Panchenko 15621684e38SMaksim Panchenko /// Extension to DataExtractor that supports reading addresses stored in 15721684e38SMaksim Panchenko /// PC-relative format. 15821684e38SMaksim Panchenko class AddressExtractor : public DataExtractor { 15921684e38SMaksim Panchenko uint64_t DataAddress; 16021684e38SMaksim Panchenko 16121684e38SMaksim Panchenko public: 16221684e38SMaksim Panchenko AddressExtractor(StringRef Data, uint64_t DataAddress, bool IsLittleEndian, 16321684e38SMaksim Panchenko uint8_t AddressSize) 16421684e38SMaksim Panchenko : DataExtractor(Data, IsLittleEndian, AddressSize), 16521684e38SMaksim Panchenko DataAddress(DataAddress) {} 16621684e38SMaksim Panchenko 16721684e38SMaksim Panchenko /// Extract 32-bit PC-relative address/pointer. 16821684e38SMaksim Panchenko uint64_t getPCRelAddress32(Cursor &C) { 16921684e38SMaksim Panchenko const uint64_t Base = DataAddress + C.tell(); 17021684e38SMaksim Panchenko return Base + (int32_t)getU32(C); 17121684e38SMaksim Panchenko } 17221684e38SMaksim Panchenko 17321684e38SMaksim Panchenko /// Extract 64-bit PC-relative address/pointer. 17421684e38SMaksim Panchenko uint64_t getPCRelAddress64(Cursor &C) { 17521684e38SMaksim Panchenko const uint64_t Base = DataAddress + C.tell(); 17621684e38SMaksim Panchenko return Base + (int64_t)getU64(C); 17721684e38SMaksim Panchenko } 17821684e38SMaksim Panchenko }; 17921684e38SMaksim Panchenko 180e6724cbdSMaksim Panchenko class LinuxKernelRewriter final : public MetadataRewriter { 181*6e8a1a45SFranklin LKVersion LinuxKernelVersion; 182*6e8a1a45SFranklin 18399b4532bSMaksim Panchenko /// Information required for updating metadata referencing an instruction. 18499b4532bSMaksim Panchenko struct InstructionFixup { 18599b4532bSMaksim Panchenko BinarySection &Section; // Section referencing the instruction. 18699b4532bSMaksim Panchenko uint64_t Offset; // Offset in the section above. 18799b4532bSMaksim Panchenko BinaryFunction &BF; // Function containing the instruction. 18899b4532bSMaksim Panchenko MCSymbol &Label; // Label marking the instruction. 18999b4532bSMaksim Panchenko bool IsPCRelative; // If the reference type is relative. 19038639a81SMaksim Panchenko }; 19199b4532bSMaksim Panchenko std::vector<InstructionFixup> Fixups; 19238639a81SMaksim Panchenko 19399b4532bSMaksim Panchenko /// Size of an entry in .smp_locks section. 19499b4532bSMaksim Panchenko static constexpr size_t SMP_LOCKS_ENTRY_SIZE = 4; 19538639a81SMaksim Panchenko 196e6724cbdSMaksim Panchenko /// Linux ORC sections. 197e6724cbdSMaksim Panchenko ErrorOr<BinarySection &> ORCUnwindSection = std::errc::bad_address; 198e6724cbdSMaksim Panchenko ErrorOr<BinarySection &> ORCUnwindIPSection = std::errc::bad_address; 199e6724cbdSMaksim Panchenko 200e6724cbdSMaksim Panchenko /// Size of entries in ORC sections. 201e6724cbdSMaksim Panchenko static constexpr size_t ORC_UNWIND_ENTRY_SIZE = 6; 202e6724cbdSMaksim Panchenko static constexpr size_t ORC_UNWIND_IP_ENTRY_SIZE = 4; 203e6724cbdSMaksim Panchenko 204e6724cbdSMaksim Panchenko struct ORCListEntry { 205e6724cbdSMaksim Panchenko uint64_t IP; /// Instruction address. 206e6724cbdSMaksim Panchenko BinaryFunction *BF; /// Binary function corresponding to the entry. 207e6724cbdSMaksim Panchenko ORCState ORC; /// Stack unwind info in ORC format. 208ec4ddc28SMaksim Panchenko 2095a298871SMaksim Panchenko /// ORC entries are sorted by their IPs. Terminator entries (NullORC) 2105a298871SMaksim Panchenko /// should precede other entries with the same address. 211ec4ddc28SMaksim Panchenko bool operator<(const ORCListEntry &Other) const { 212ec4ddc28SMaksim Panchenko if (IP < Other.IP) 213ec4ddc28SMaksim Panchenko return 1; 214ec4ddc28SMaksim Panchenko if (IP > Other.IP) 215ec4ddc28SMaksim Panchenko return 0; 2160fc791cdSMaksim Panchenko return ORC == NullORC && Other.ORC != NullORC; 217ec4ddc28SMaksim Panchenko } 218e6724cbdSMaksim Panchenko }; 219e6724cbdSMaksim Panchenko 220e6724cbdSMaksim Panchenko using ORCListType = std::vector<ORCListEntry>; 221e6724cbdSMaksim Panchenko ORCListType ORCEntries; 222e6724cbdSMaksim Panchenko 2235a298871SMaksim Panchenko /// Number of entries in the input file ORC sections. 2245a298871SMaksim Panchenko uint64_t NumORCEntries = 0; 2255a298871SMaksim Panchenko 2266b1cf004SMaksim Panchenko /// Section containing static keys jump table. 2276b1cf004SMaksim Panchenko ErrorOr<BinarySection &> StaticKeysJumpSection = std::errc::bad_address; 2286b1cf004SMaksim Panchenko uint64_t StaticKeysJumpTableAddress = 0; 2296b1cf004SMaksim Panchenko static constexpr size_t STATIC_KEYS_JUMP_ENTRY_SIZE = 8; 2306b1cf004SMaksim Panchenko 2316b1cf004SMaksim Panchenko struct JumpInfoEntry { 2326b1cf004SMaksim Panchenko bool Likely; 2336b1cf004SMaksim Panchenko bool InitValue; 2346b1cf004SMaksim Panchenko }; 2356b1cf004SMaksim Panchenko SmallVector<JumpInfoEntry, 16> JumpInfo; 2366b1cf004SMaksim Panchenko 2376b1cf004SMaksim Panchenko /// Static key entries that need nop conversion. 2386b1cf004SMaksim Panchenko DenseSet<uint32_t> NopIDs; 2396b1cf004SMaksim Panchenko 2402646dccaSMaksim Panchenko /// Section containing static call table. 2412646dccaSMaksim Panchenko ErrorOr<BinarySection &> StaticCallSection = std::errc::bad_address; 2422646dccaSMaksim Panchenko uint64_t StaticCallTableAddress = 0; 2432646dccaSMaksim Panchenko static constexpr size_t STATIC_CALL_ENTRY_SIZE = 8; 2442646dccaSMaksim Panchenko 2452646dccaSMaksim Panchenko struct StaticCallInfo { 2462646dccaSMaksim Panchenko uint32_t ID; /// Identifier of the entry in the table. 2472646dccaSMaksim Panchenko BinaryFunction *Function; /// Function containing associated call. 2482646dccaSMaksim Panchenko MCSymbol *Label; /// Label attached to the call. 2492646dccaSMaksim Panchenko }; 2502646dccaSMaksim Panchenko using StaticCallListType = std::vector<StaticCallInfo>; 2512646dccaSMaksim Panchenko StaticCallListType StaticCallEntries; 2522646dccaSMaksim Panchenko 253ccf0c8daSMaksim Panchenko /// Section containing the Linux exception table. 254ccf0c8daSMaksim Panchenko ErrorOr<BinarySection &> ExceptionsSection = std::errc::bad_address; 255ccf0c8daSMaksim Panchenko static constexpr size_t EXCEPTION_TABLE_ENTRY_SIZE = 12; 256ccf0c8daSMaksim Panchenko 257ccf0c8daSMaksim Panchenko /// Functions with exception handling code. 258ccf0c8daSMaksim Panchenko DenseSet<BinaryFunction *> FunctionsWithExceptions; 259ccf0c8daSMaksim Panchenko 260f51ade25SMaksim Panchenko /// Section with paravirtual patch sites. 261f51ade25SMaksim Panchenko ErrorOr<BinarySection &> ParavirtualPatchSection = std::errc::bad_address; 262f51ade25SMaksim Panchenko 263f51ade25SMaksim Panchenko /// Alignment of paravirtual patch structures. 264f51ade25SMaksim Panchenko static constexpr size_t PARA_PATCH_ALIGN = 8; 265f51ade25SMaksim Panchenko 266143afb40SMaksim Panchenko /// .altinstructions section. 267143afb40SMaksim Panchenko ErrorOr<BinarySection &> AltInstrSection = std::errc::bad_address; 268143afb40SMaksim Panchenko 26902629793SMaksim Panchenko /// Section containing Linux bug table. 27002629793SMaksim Panchenko ErrorOr<BinarySection &> BugTableSection = std::errc::bad_address; 27102629793SMaksim Panchenko 27202629793SMaksim Panchenko /// Size of bug_entry struct. 27302629793SMaksim Panchenko static constexpr size_t BUG_TABLE_ENTRY_SIZE = 12; 27402629793SMaksim Panchenko 27535e7d458SMaksim Panchenko /// List of bug entries per function. 27635e7d458SMaksim Panchenko using FunctionBugListType = 27735e7d458SMaksim Panchenko DenseMap<BinaryFunction *, SmallVector<uint32_t, 2>>; 27835e7d458SMaksim Panchenko FunctionBugListType FunctionBugList; 27935e7d458SMaksim Panchenko 280fd32e744SMaksim Panchenko /// .pci_fixup section. 281fd32e744SMaksim Panchenko ErrorOr<BinarySection &> PCIFixupSection = std::errc::bad_address; 282fd32e744SMaksim Panchenko static constexpr size_t PCI_FIXUP_ENTRY_SIZE = 16; 283fd32e744SMaksim Panchenko 284*6e8a1a45SFranklin Error detectLinuxKernelVersion(); 285*6e8a1a45SFranklin 28638639a81SMaksim Panchenko /// Process linux kernel special sections and their relocations. 28738639a81SMaksim Panchenko void processLKSections(); 28838639a81SMaksim Panchenko 28938639a81SMaksim Panchenko /// Process __ksymtab and __ksymtab_gpl. 29038639a81SMaksim Panchenko void processLKKSymtab(bool IsGPL = false); 29138639a81SMaksim Panchenko 29299b4532bSMaksim Panchenko // Create relocations in sections requiring fixups. 29399b4532bSMaksim Panchenko // 29499b4532bSMaksim Panchenko // Make sure functions that will not be emitted are marked as such before this 29599b4532bSMaksim Panchenko // function is executed. 29699b4532bSMaksim Panchenko void processInstructionFixups(); 29738639a81SMaksim Panchenko 29899b4532bSMaksim Panchenko /// Process .smp_locks section. 29999b4532bSMaksim Panchenko Error processSMPLocks(); 30038639a81SMaksim Panchenko 301e6724cbdSMaksim Panchenko /// Read ORC unwind information and annotate instructions. 302e6724cbdSMaksim Panchenko Error readORCTables(); 303e6724cbdSMaksim Panchenko 304138e2abfSMaksim Panchenko /// Update ORC for functions once CFG is constructed. 305138e2abfSMaksim Panchenko Error processORCPostCFG(); 306138e2abfSMaksim Panchenko 307e6724cbdSMaksim Panchenko /// Update ORC data in the binary. 308e6724cbdSMaksim Panchenko Error rewriteORCTables(); 309e6724cbdSMaksim Panchenko 310c665e499SMaksim Panchenko /// Validate written ORC tables after binary emission. 311c665e499SMaksim Panchenko Error validateORCTables(); 312c665e499SMaksim Panchenko 3132646dccaSMaksim Panchenko /// Static call table handling. 3142646dccaSMaksim Panchenko Error readStaticCalls(); 3152646dccaSMaksim Panchenko Error rewriteStaticCalls(); 3162646dccaSMaksim Panchenko 317ccf0c8daSMaksim Panchenko Error readExceptionTable(); 318ccf0c8daSMaksim Panchenko Error rewriteExceptionTable(); 319ccf0c8daSMaksim Panchenko 320f51ade25SMaksim Panchenko /// Paravirtual instruction patch sites. 321f51ade25SMaksim Panchenko Error readParaInstructions(); 32256197d73SMaksim Panchenko Error rewriteParaInstructions(); 323f51ade25SMaksim Panchenko 32435e7d458SMaksim Panchenko /// __bug_table section handling. 32502629793SMaksim Panchenko Error readBugTable(); 32635e7d458SMaksim Panchenko Error rewriteBugTable(); 32702629793SMaksim Panchenko 32856197d73SMaksim Panchenko /// Do no process functions containing instruction annotated with 32956197d73SMaksim Panchenko /// \p Annotation. 33056197d73SMaksim Panchenko void skipFunctionsWithAnnotation(StringRef Annotation) const; 33156197d73SMaksim Panchenko 33256197d73SMaksim Panchenko /// Handle alternative instruction info from .altinstructions. 333143afb40SMaksim Panchenko Error readAltInstructions(); 334ad2905e5SMaksim Panchenko void processAltInstructionsPostCFG(); 335540893e4SMaksim Panchenko Error tryReadAltInstructions(uint32_t AltInstFeatureSize, 336540893e4SMaksim Panchenko bool AltInstHasPadLen, bool ParseOnly); 337143afb40SMaksim Panchenko 338fd32e744SMaksim Panchenko /// Read .pci_fixup 339fd32e744SMaksim Panchenko Error readPCIFixupTable(); 340fd32e744SMaksim Panchenko 3416b1cf004SMaksim Panchenko /// Handle static keys jump table. 3426b1cf004SMaksim Panchenko Error readStaticKeysJumpTable(); 3436b1cf004SMaksim Panchenko Error rewriteStaticKeysJumpTable(); 3446b1cf004SMaksim Panchenko Error updateStaticKeysJumpTablePostEmit(); 3456b1cf004SMaksim Panchenko 34638639a81SMaksim Panchenko public: 34738639a81SMaksim Panchenko LinuxKernelRewriter(BinaryContext &BC) 34838639a81SMaksim Panchenko : MetadataRewriter("linux-kernel-rewriter", BC) {} 34938639a81SMaksim Panchenko 35038639a81SMaksim Panchenko Error preCFGInitializer() override { 351*6e8a1a45SFranklin if (Error E = detectLinuxKernelVersion()) 352*6e8a1a45SFranklin return E; 353*6e8a1a45SFranklin 35438639a81SMaksim Panchenko processLKSections(); 35599b4532bSMaksim Panchenko 35699b4532bSMaksim Panchenko if (Error E = processSMPLocks()) 35738639a81SMaksim Panchenko return E; 358e6724cbdSMaksim Panchenko 3592646dccaSMaksim Panchenko if (Error E = readStaticCalls()) 3602646dccaSMaksim Panchenko return E; 3612646dccaSMaksim Panchenko 362ccf0c8daSMaksim Panchenko if (Error E = readExceptionTable()) 363ccf0c8daSMaksim Panchenko return E; 364ccf0c8daSMaksim Panchenko 365f51ade25SMaksim Panchenko if (Error E = readParaInstructions()) 366f51ade25SMaksim Panchenko return E; 367f51ade25SMaksim Panchenko 36802629793SMaksim Panchenko if (Error E = readBugTable()) 36902629793SMaksim Panchenko return E; 37002629793SMaksim Panchenko 371143afb40SMaksim Panchenko if (Error E = readAltInstructions()) 372143afb40SMaksim Panchenko return E; 373143afb40SMaksim Panchenko 374d16b21b1SMaksim Panchenko // Some ORC entries could be linked to alternative instruction 375d16b21b1SMaksim Panchenko // sequences. Hence, we read ORC after .altinstructions. 376d16b21b1SMaksim Panchenko if (Error E = readORCTables()) 377d16b21b1SMaksim Panchenko return E; 378d16b21b1SMaksim Panchenko 379fd32e744SMaksim Panchenko if (Error E = readPCIFixupTable()) 380fd32e744SMaksim Panchenko return E; 381fd32e744SMaksim Panchenko 3826b1cf004SMaksim Panchenko if (Error E = readStaticKeysJumpTable()) 3836b1cf004SMaksim Panchenko return E; 3846b1cf004SMaksim Panchenko 38538639a81SMaksim Panchenko return Error::success(); 38638639a81SMaksim Panchenko } 38738639a81SMaksim Panchenko 388138e2abfSMaksim Panchenko Error postCFGInitializer() override { 389138e2abfSMaksim Panchenko if (Error E = processORCPostCFG()) 390138e2abfSMaksim Panchenko return E; 391138e2abfSMaksim Panchenko 392ad2905e5SMaksim Panchenko processAltInstructionsPostCFG(); 393ad2905e5SMaksim Panchenko 394138e2abfSMaksim Panchenko return Error::success(); 395138e2abfSMaksim Panchenko } 396138e2abfSMaksim Panchenko 397aa1968c2SMaksim Panchenko Error preEmitFinalizer() override { 398ccf0c8daSMaksim Panchenko // Since rewriteExceptionTable() can mark functions as non-simple, run it 399ccf0c8daSMaksim Panchenko // before other rewriters that depend on simple/emit status. 400ccf0c8daSMaksim Panchenko if (Error E = rewriteExceptionTable()) 401ccf0c8daSMaksim Panchenko return E; 402ccf0c8daSMaksim Panchenko 40356197d73SMaksim Panchenko if (Error E = rewriteParaInstructions()) 40456197d73SMaksim Panchenko return E; 40556197d73SMaksim Panchenko 406e6724cbdSMaksim Panchenko if (Error E = rewriteORCTables()) 407e6724cbdSMaksim Panchenko return E; 408e6724cbdSMaksim Panchenko 4092646dccaSMaksim Panchenko if (Error E = rewriteStaticCalls()) 4102646dccaSMaksim Panchenko return E; 4112646dccaSMaksim Panchenko 4126b1cf004SMaksim Panchenko if (Error E = rewriteStaticKeysJumpTable()) 4136b1cf004SMaksim Panchenko return E; 4146b1cf004SMaksim Panchenko 41535e7d458SMaksim Panchenko if (Error E = rewriteBugTable()) 41635e7d458SMaksim Panchenko return E; 41735e7d458SMaksim Panchenko 41899b4532bSMaksim Panchenko processInstructionFixups(); 41999b4532bSMaksim Panchenko 42038639a81SMaksim Panchenko return Error::success(); 42138639a81SMaksim Panchenko } 422aa1968c2SMaksim Panchenko 423aa1968c2SMaksim Panchenko Error postEmitFinalizer() override { 4246b1cf004SMaksim Panchenko if (Error E = updateStaticKeysJumpTablePostEmit()) 4256b1cf004SMaksim Panchenko return E; 4266b1cf004SMaksim Panchenko 427c665e499SMaksim Panchenko if (Error E = validateORCTables()) 428c665e499SMaksim Panchenko return E; 429c665e499SMaksim Panchenko 430aa1968c2SMaksim Panchenko return Error::success(); 431aa1968c2SMaksim Panchenko } 43238639a81SMaksim Panchenko }; 43338639a81SMaksim Panchenko 434*6e8a1a45SFranklin Error LinuxKernelRewriter::detectLinuxKernelVersion() { 435*6e8a1a45SFranklin if (BinaryData *BD = BC.getBinaryDataByName("linux_banner")) { 436*6e8a1a45SFranklin const BinarySection &Section = BD->getSection(); 437*6e8a1a45SFranklin const std::string S = 438*6e8a1a45SFranklin Section.getContents().substr(BD->getOffset(), BD->getSize()).str(); 439*6e8a1a45SFranklin 440*6e8a1a45SFranklin const std::regex Re(R"---(Linux version ((\d+)\.(\d+)(\.(\d+))?))---"); 441*6e8a1a45SFranklin std::smatch Match; 442*6e8a1a45SFranklin if (std::regex_search(S, Match, Re)) { 443*6e8a1a45SFranklin const unsigned Major = std::stoi(Match[2].str()); 444*6e8a1a45SFranklin const unsigned Minor = std::stoi(Match[3].str()); 445*6e8a1a45SFranklin const unsigned Rev = Match[5].matched ? std::stoi(Match[5].str()) : 0; 446*6e8a1a45SFranklin LinuxKernelVersion = LKVersion(Major, Minor, Rev); 447*6e8a1a45SFranklin BC.outs() << "BOLT-INFO: Linux kernel version is " << Match[1].str() 448*6e8a1a45SFranklin << "\n"; 449*6e8a1a45SFranklin return Error::success(); 450*6e8a1a45SFranklin } 451*6e8a1a45SFranklin } 452*6e8a1a45SFranklin return createStringError(errc::executable_format_error, 453*6e8a1a45SFranklin "Linux kernel version is unknown"); 454*6e8a1a45SFranklin } 455*6e8a1a45SFranklin 45638639a81SMaksim Panchenko void LinuxKernelRewriter::processLKSections() { 45738639a81SMaksim Panchenko processLKKSymtab(); 45838639a81SMaksim Panchenko processLKKSymtab(true); 45938639a81SMaksim Panchenko } 46038639a81SMaksim Panchenko 46138639a81SMaksim Panchenko /// Process __ksymtab[_gpl] sections of Linux Kernel. 46238639a81SMaksim Panchenko /// This section lists all the vmlinux symbols that kernel modules can access. 46338639a81SMaksim Panchenko /// 46438639a81SMaksim Panchenko /// All the entries are 4 bytes each and hence we can read them by one by one 46538639a81SMaksim Panchenko /// and ignore the ones that are not pointing to the .text section. All pointers 46638639a81SMaksim Panchenko /// are PC relative offsets. Always, points to the beginning of the function. 46738639a81SMaksim Panchenko void LinuxKernelRewriter::processLKKSymtab(bool IsGPL) { 46838639a81SMaksim Panchenko StringRef SectionName = "__ksymtab"; 46938639a81SMaksim Panchenko if (IsGPL) 47038639a81SMaksim Panchenko SectionName = "__ksymtab_gpl"; 47138639a81SMaksim Panchenko ErrorOr<BinarySection &> SectionOrError = 47238639a81SMaksim Panchenko BC.getUniqueSectionByName(SectionName); 47338639a81SMaksim Panchenko assert(SectionOrError && 47438639a81SMaksim Panchenko "__ksymtab[_gpl] section not found in Linux Kernel binary"); 47538639a81SMaksim Panchenko const uint64_t SectionSize = SectionOrError->getSize(); 47638639a81SMaksim Panchenko const uint64_t SectionAddress = SectionOrError->getAddress(); 47738639a81SMaksim Panchenko assert((SectionSize % 4) == 0 && 47838639a81SMaksim Panchenko "The size of the __ksymtab[_gpl] section should be a multiple of 4"); 47938639a81SMaksim Panchenko 48038639a81SMaksim Panchenko for (uint64_t I = 0; I < SectionSize; I += 4) { 48138639a81SMaksim Panchenko const uint64_t EntryAddress = SectionAddress + I; 482c460e454SAmir Ayupov ErrorOr<int64_t> Offset = BC.getSignedValueAtAddress(EntryAddress, 4); 48338639a81SMaksim Panchenko assert(Offset && "Reading valid PC-relative offset for a ksymtab entry"); 48438639a81SMaksim Panchenko const int32_t SignedOffset = *Offset; 48538639a81SMaksim Panchenko const uint64_t RefAddress = EntryAddress + SignedOffset; 48638639a81SMaksim Panchenko BinaryFunction *BF = BC.getBinaryFunctionAtAddress(RefAddress); 48738639a81SMaksim Panchenko if (!BF) 48838639a81SMaksim Panchenko continue; 48938639a81SMaksim Panchenko 49038639a81SMaksim Panchenko BC.addRelocation(EntryAddress, BF->getSymbol(), Relocation::getPC32(), 0, 49138639a81SMaksim Panchenko *Offset); 49238639a81SMaksim Panchenko } 49338639a81SMaksim Panchenko } 49438639a81SMaksim Panchenko 49538639a81SMaksim Panchenko /// .smp_locks section contains PC-relative references to instructions with LOCK 49638639a81SMaksim Panchenko /// prefix. The prefix can be converted to NOP at boot time on non-SMP systems. 49799b4532bSMaksim Panchenko Error LinuxKernelRewriter::processSMPLocks() { 49899b4532bSMaksim Panchenko ErrorOr<BinarySection &> SMPLocksSection = 49938639a81SMaksim Panchenko BC.getUniqueSectionByName(".smp_locks"); 50099b4532bSMaksim Panchenko if (!SMPLocksSection) 50199b4532bSMaksim Panchenko return Error::success(); 50238639a81SMaksim Panchenko 50399b4532bSMaksim Panchenko const uint64_t SectionSize = SMPLocksSection->getSize(); 50499b4532bSMaksim Panchenko const uint64_t SectionAddress = SMPLocksSection->getAddress(); 50599b4532bSMaksim Panchenko if (SectionSize % SMP_LOCKS_ENTRY_SIZE) 50699b4532bSMaksim Panchenko return createStringError(errc::executable_format_error, 50799b4532bSMaksim Panchenko "bad size of .smp_locks section"); 50838639a81SMaksim Panchenko 50921684e38SMaksim Panchenko AddressExtractor AE(SMPLocksSection->getContents(), SectionAddress, 51099b4532bSMaksim Panchenko BC.AsmInfo->isLittleEndian(), 51199b4532bSMaksim Panchenko BC.AsmInfo->getCodePointerSize()); 51221684e38SMaksim Panchenko AddressExtractor::Cursor Cursor(0); 51399b4532bSMaksim Panchenko while (Cursor && Cursor.tell() < SectionSize) { 51499b4532bSMaksim Panchenko const uint64_t Offset = Cursor.tell(); 51521684e38SMaksim Panchenko const uint64_t IP = AE.getPCRelAddress32(Cursor); 51638639a81SMaksim Panchenko 51799b4532bSMaksim Panchenko // Consume the status of the cursor. 51899b4532bSMaksim Panchenko if (!Cursor) 51999b4532bSMaksim Panchenko return createStringError(errc::executable_format_error, 52099b4532bSMaksim Panchenko "error while reading .smp_locks: %s", 52199b4532bSMaksim Panchenko toString(Cursor.takeError()).c_str()); 52299b4532bSMaksim Panchenko 52399b4532bSMaksim Panchenko if (opts::DumpSMPLocks) 52499b4532bSMaksim Panchenko BC.outs() << "SMP lock at 0x: " << Twine::utohexstr(IP) << '\n'; 52599b4532bSMaksim Panchenko 52699b4532bSMaksim Panchenko BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(IP); 52799b4532bSMaksim Panchenko if (!BF || !BC.shouldEmit(*BF)) 52838639a81SMaksim Panchenko continue; 52938639a81SMaksim Panchenko 53099b4532bSMaksim Panchenko MCInst *Inst = BF->getInstructionAtOffset(IP - BF->getAddress()); 53199b4532bSMaksim Panchenko if (!Inst) 53299b4532bSMaksim Panchenko return createStringError(errc::executable_format_error, 53399b4532bSMaksim Panchenko "no instruction matches lock at 0x%" PRIx64, IP); 53499b4532bSMaksim Panchenko 53599b4532bSMaksim Panchenko // Check for duplicate entries. 53699b4532bSMaksim Panchenko if (BC.MIB->hasAnnotation(*Inst, "SMPLock")) 53799b4532bSMaksim Panchenko return createStringError(errc::executable_format_error, 53899b4532bSMaksim Panchenko "duplicate SMP lock at 0x%" PRIx64, IP); 53999b4532bSMaksim Panchenko 54099b4532bSMaksim Panchenko BC.MIB->addAnnotation(*Inst, "SMPLock", true); 54199b4532bSMaksim Panchenko MCSymbol *Label = 54299b4532bSMaksim Panchenko BC.MIB->getOrCreateInstLabel(*Inst, "__SMPLock_", BC.Ctx.get()); 54399b4532bSMaksim Panchenko 54499b4532bSMaksim Panchenko Fixups.push_back({*SMPLocksSection, Offset, *BF, *Label, 54599b4532bSMaksim Panchenko /*IsPCRelative*/ true}); 54638639a81SMaksim Panchenko } 54738639a81SMaksim Panchenko 54899b4532bSMaksim Panchenko const uint64_t NumEntries = SectionSize / SMP_LOCKS_ENTRY_SIZE; 54999b4532bSMaksim Panchenko BC.outs() << "BOLT-INFO: parsed " << NumEntries << " SMP lock entries\n"; 55038639a81SMaksim Panchenko 55199b4532bSMaksim Panchenko return Error::success(); 55299b4532bSMaksim Panchenko } 55399b4532bSMaksim Panchenko 55499b4532bSMaksim Panchenko void LinuxKernelRewriter::processInstructionFixups() { 55599b4532bSMaksim Panchenko for (InstructionFixup &Fixup : Fixups) { 55699b4532bSMaksim Panchenko if (!BC.shouldEmit(Fixup.BF)) 55738639a81SMaksim Panchenko continue; 55838639a81SMaksim Panchenko 55999b4532bSMaksim Panchenko Fixup.Section.addRelocation(Fixup.Offset, &Fixup.Label, 56099b4532bSMaksim Panchenko Fixup.IsPCRelative ? ELF::R_X86_64_PC32 56199b4532bSMaksim Panchenko : ELF::R_X86_64_64, 56299b4532bSMaksim Panchenko /*Addend*/ 0); 56338639a81SMaksim Panchenko } 56438639a81SMaksim Panchenko } 565e6724cbdSMaksim Panchenko 566e6724cbdSMaksim Panchenko Error LinuxKernelRewriter::readORCTables() { 567e6724cbdSMaksim Panchenko // NOTE: we should ignore relocations for orc tables as the tables are sorted 568e6724cbdSMaksim Panchenko // post-link time and relocations are not updated. 569e6724cbdSMaksim Panchenko ORCUnwindSection = BC.getUniqueSectionByName(".orc_unwind"); 570e6724cbdSMaksim Panchenko ORCUnwindIPSection = BC.getUniqueSectionByName(".orc_unwind_ip"); 571e6724cbdSMaksim Panchenko 572e6724cbdSMaksim Panchenko if (!ORCUnwindSection && !ORCUnwindIPSection) 573e6724cbdSMaksim Panchenko return Error::success(); 574e6724cbdSMaksim Panchenko 575e6724cbdSMaksim Panchenko if (!ORCUnwindSection || !ORCUnwindIPSection) 576e6724cbdSMaksim Panchenko return createStringError(errc::executable_format_error, 577e6724cbdSMaksim Panchenko "missing ORC section"); 578e6724cbdSMaksim Panchenko 5795a298871SMaksim Panchenko NumORCEntries = ORCUnwindIPSection->getSize() / ORC_UNWIND_IP_ENTRY_SIZE; 5805a298871SMaksim Panchenko if (ORCUnwindSection->getSize() != NumORCEntries * ORC_UNWIND_ENTRY_SIZE || 5815a298871SMaksim Panchenko ORCUnwindIPSection->getSize() != NumORCEntries * ORC_UNWIND_IP_ENTRY_SIZE) 582e6724cbdSMaksim Panchenko return createStringError(errc::executable_format_error, 583e6724cbdSMaksim Panchenko "ORC entries number mismatch detected"); 584e6724cbdSMaksim Panchenko 58521684e38SMaksim Panchenko DataExtractor OrcDE(ORCUnwindSection->getContents(), 586e6724cbdSMaksim Panchenko BC.AsmInfo->isLittleEndian(), 587e6724cbdSMaksim Panchenko BC.AsmInfo->getCodePointerSize()); 58821684e38SMaksim Panchenko AddressExtractor IPAE( 58921684e38SMaksim Panchenko ORCUnwindIPSection->getContents(), ORCUnwindIPSection->getAddress(), 59021684e38SMaksim Panchenko BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); 591e6724cbdSMaksim Panchenko DataExtractor::Cursor ORCCursor(0); 592e6724cbdSMaksim Panchenko DataExtractor::Cursor IPCursor(0); 593ec4ddc28SMaksim Panchenko uint64_t PrevIP = 0; 5945a298871SMaksim Panchenko for (uint32_t Index = 0; Index < NumORCEntries; ++Index) { 59521684e38SMaksim Panchenko const uint64_t IP = IPAE.getPCRelAddress32(IPCursor); 596ec4ddc28SMaksim Panchenko // Consume the status of the cursor. 597ec4ddc28SMaksim Panchenko if (!IPCursor) 598ec4ddc28SMaksim Panchenko return createStringError(errc::executable_format_error, 599a9b0d759SMaksim Panchenko "out of bounds while reading ORC IP table: %s", 600a9b0d759SMaksim Panchenko toString(IPCursor.takeError()).c_str()); 601ec4ddc28SMaksim Panchenko 602ec4ddc28SMaksim Panchenko if (IP < PrevIP && opts::Verbosity) 6030ce01712SMaksim Panchenko BC.errs() << "BOLT-WARNING: out of order IP 0x" << Twine::utohexstr(IP) 604ec4ddc28SMaksim Panchenko << " detected while reading ORC\n"; 605ec4ddc28SMaksim Panchenko 606ec4ddc28SMaksim Panchenko PrevIP = IP; 607ec4ddc28SMaksim Panchenko 608e6724cbdSMaksim Panchenko // Store all entries, includes those we are not going to update as the 609e6724cbdSMaksim Panchenko // tables need to be sorted globally before being written out. 610e6724cbdSMaksim Panchenko ORCEntries.push_back(ORCListEntry()); 611e6724cbdSMaksim Panchenko ORCListEntry &Entry = ORCEntries.back(); 612e6724cbdSMaksim Panchenko 613e6724cbdSMaksim Panchenko Entry.IP = IP; 614e6724cbdSMaksim Panchenko Entry.ORC.SPOffset = (int16_t)OrcDE.getU16(ORCCursor); 615e6724cbdSMaksim Panchenko Entry.ORC.BPOffset = (int16_t)OrcDE.getU16(ORCCursor); 616e6724cbdSMaksim Panchenko Entry.ORC.Info = (int16_t)OrcDE.getU16(ORCCursor); 6175a298871SMaksim Panchenko Entry.BF = nullptr; 618e6724cbdSMaksim Panchenko 619ec4ddc28SMaksim Panchenko // Consume the status of the cursor. 620ec4ddc28SMaksim Panchenko if (!ORCCursor) 621e6724cbdSMaksim Panchenko return createStringError(errc::executable_format_error, 622a9b0d759SMaksim Panchenko "out of bounds while reading ORC: %s", 623a9b0d759SMaksim Panchenko toString(ORCCursor.takeError()).c_str()); 624e6724cbdSMaksim Panchenko 6255a298871SMaksim Panchenko if (Entry.ORC == NullORC) 6265a298871SMaksim Panchenko continue; 6275a298871SMaksim Panchenko 628e6724cbdSMaksim Panchenko BinaryFunction *&BF = Entry.BF; 629e6724cbdSMaksim Panchenko BF = BC.getBinaryFunctionContainingAddress(IP, /*CheckPastEnd*/ true); 630e6724cbdSMaksim Panchenko 631e6724cbdSMaksim Panchenko // If the entry immediately pointing past the end of the function is not 632e6724cbdSMaksim Panchenko // the terminator entry, then it does not belong to this function. 6335a298871SMaksim Panchenko if (BF && BF->getAddress() + BF->getSize() == IP) 634e6724cbdSMaksim Panchenko BF = 0; 635e6724cbdSMaksim Panchenko 636e6724cbdSMaksim Panchenko if (!BF) { 637e6724cbdSMaksim Panchenko if (opts::Verbosity) 6380ce01712SMaksim Panchenko BC.errs() << "BOLT-WARNING: no binary function found matching ORC 0x" 639e6724cbdSMaksim Panchenko << Twine::utohexstr(IP) << ": " << Entry.ORC << '\n'; 640e6724cbdSMaksim Panchenko continue; 641e6724cbdSMaksim Panchenko } 642e6724cbdSMaksim Panchenko 643ec4ddc28SMaksim Panchenko BF->setHasORC(true); 644ec4ddc28SMaksim Panchenko 645ec4ddc28SMaksim Panchenko if (!BF->hasInstructions()) 646e6724cbdSMaksim Panchenko continue; 647e6724cbdSMaksim Panchenko 648d16b21b1SMaksim Panchenko const uint64_t Offset = IP - BF->getAddress(); 649d16b21b1SMaksim Panchenko MCInst *Inst = BF->getInstructionAtOffset(Offset); 650d16b21b1SMaksim Panchenko if (!Inst) { 651d16b21b1SMaksim Panchenko // Check if there is an alternative instruction(s) at this IP. Multiple 652d16b21b1SMaksim Panchenko // alternative instructions can take a place of a single original 653d16b21b1SMaksim Panchenko // instruction and each alternative can have a separate ORC entry. 654d16b21b1SMaksim Panchenko // Since ORC table is shared between all alternative sequences, there's 655d16b21b1SMaksim Panchenko // a requirement that only one (out of many) sequences can have an 656d16b21b1SMaksim Panchenko // instruction from the ORC table to avoid ambiguities/conflicts. 657d16b21b1SMaksim Panchenko // 658d16b21b1SMaksim Panchenko // For now, we have limited support for alternatives. I.e. we still print 659d16b21b1SMaksim Panchenko // functions with them, but will not change the code in the output binary. 660d16b21b1SMaksim Panchenko // As such, we can ignore alternative ORC entries. They will be preserved 661d16b21b1SMaksim Panchenko // in the binary, but will not get printed in the instruction stream. 662d16b21b1SMaksim Panchenko Inst = BF->getInstructionContainingOffset(Offset); 663d16b21b1SMaksim Panchenko if (Inst || BC.MIB->hasAnnotation(*Inst, "AltInst")) 664d16b21b1SMaksim Panchenko continue; 665d16b21b1SMaksim Panchenko 666e6724cbdSMaksim Panchenko return createStringError( 667e6724cbdSMaksim Panchenko errc::executable_format_error, 668e6724cbdSMaksim Panchenko "no instruction at address 0x%" PRIx64 " in .orc_unwind_ip", IP); 669d16b21b1SMaksim Panchenko } 670e6724cbdSMaksim Panchenko 671e6724cbdSMaksim Panchenko // Some addresses will have two entries associated with them. The first 672e6724cbdSMaksim Panchenko // one being a "weak" section terminator. Since we ignore the terminator, 673e6724cbdSMaksim Panchenko // we should only assign one entry per instruction. 674e6724cbdSMaksim Panchenko if (BC.MIB->hasAnnotation(*Inst, "ORC")) 675e6724cbdSMaksim Panchenko return createStringError( 676e6724cbdSMaksim Panchenko errc::executable_format_error, 677e6724cbdSMaksim Panchenko "duplicate non-terminal ORC IP 0x%" PRIx64 " in .orc_unwind_ip", IP); 678e6724cbdSMaksim Panchenko 679e6724cbdSMaksim Panchenko BC.MIB->addAnnotation(*Inst, "ORC", Entry.ORC); 680ec4ddc28SMaksim Panchenko } 681e6724cbdSMaksim Panchenko 6820ce01712SMaksim Panchenko BC.outs() << "BOLT-INFO: parsed " << NumORCEntries << " ORC entries\n"; 683ec4ddc28SMaksim Panchenko 684ec4ddc28SMaksim Panchenko if (opts::DumpORC) { 6850ce01712SMaksim Panchenko BC.outs() << "BOLT-INFO: ORC unwind information:\n"; 686ec4ddc28SMaksim Panchenko for (const ORCListEntry &E : ORCEntries) { 6870ce01712SMaksim Panchenko BC.outs() << "0x" << Twine::utohexstr(E.IP) << ": " << E.ORC; 688ec4ddc28SMaksim Panchenko if (E.BF) 6890ce01712SMaksim Panchenko BC.outs() << ": " << *E.BF; 6900ce01712SMaksim Panchenko BC.outs() << '\n'; 691ec4ddc28SMaksim Panchenko } 692e6724cbdSMaksim Panchenko } 693e6724cbdSMaksim Panchenko 6945a298871SMaksim Panchenko // Add entries for functions that don't have explicit ORC info at the start. 6955a298871SMaksim Panchenko // We'll have the correct info for them even if ORC for the preceding function 6965a298871SMaksim Panchenko // changes. 6975a298871SMaksim Panchenko ORCListType NewEntries; 6985a298871SMaksim Panchenko for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { 6995a298871SMaksim Panchenko auto It = llvm::partition_point(ORCEntries, [&](const ORCListEntry &E) { 7005a298871SMaksim Panchenko return E.IP <= BF.getAddress(); 7015a298871SMaksim Panchenko }); 7025a298871SMaksim Panchenko if (It != ORCEntries.begin()) 7035a298871SMaksim Panchenko --It; 7045a298871SMaksim Panchenko 7055a298871SMaksim Panchenko if (It->BF == &BF) 7065a298871SMaksim Panchenko continue; 7075a298871SMaksim Panchenko 7085a298871SMaksim Panchenko if (It->ORC == NullORC && It->IP == BF.getAddress()) { 7095a298871SMaksim Panchenko assert(!It->BF); 7105a298871SMaksim Panchenko It->BF = &BF; 7115a298871SMaksim Panchenko continue; 7125a298871SMaksim Panchenko } 7135a298871SMaksim Panchenko 7145a298871SMaksim Panchenko NewEntries.push_back({BF.getAddress(), &BF, It->ORC}); 7155a298871SMaksim Panchenko if (It->ORC != NullORC) 7165a298871SMaksim Panchenko BF.setHasORC(true); 7175a298871SMaksim Panchenko } 7185a298871SMaksim Panchenko 7195a298871SMaksim Panchenko llvm::copy(NewEntries, std::back_inserter(ORCEntries)); 7205a298871SMaksim Panchenko llvm::sort(ORCEntries); 7215a298871SMaksim Panchenko 7225a298871SMaksim Panchenko if (opts::DumpORC) { 7230ce01712SMaksim Panchenko BC.outs() << "BOLT-INFO: amended ORC unwind information:\n"; 7245a298871SMaksim Panchenko for (const ORCListEntry &E : ORCEntries) { 7250ce01712SMaksim Panchenko BC.outs() << "0x" << Twine::utohexstr(E.IP) << ": " << E.ORC; 7265a298871SMaksim Panchenko if (E.BF) 7270ce01712SMaksim Panchenko BC.outs() << ": " << *E.BF; 7280ce01712SMaksim Panchenko BC.outs() << '\n'; 7295a298871SMaksim Panchenko } 7305a298871SMaksim Panchenko } 7315a298871SMaksim Panchenko 732e6724cbdSMaksim Panchenko return Error::success(); 733e6724cbdSMaksim Panchenko } 734e6724cbdSMaksim Panchenko 735138e2abfSMaksim Panchenko Error LinuxKernelRewriter::processORCPostCFG() { 7365a298871SMaksim Panchenko if (!NumORCEntries) 7375a298871SMaksim Panchenko return Error::success(); 7385a298871SMaksim Panchenko 739138e2abfSMaksim Panchenko // Propagate ORC to the rest of the function. We can annotate every 740138e2abfSMaksim Panchenko // instruction in every function, but to minimize the overhead, we annotate 741138e2abfSMaksim Panchenko // the first instruction in every basic block to reflect the state at the 742138e2abfSMaksim Panchenko // entry. This way, the ORC state can be calculated based on annotations 743138e2abfSMaksim Panchenko // regardless of the basic block layout. Note that if we insert/delete 744138e2abfSMaksim Panchenko // instructions, we must take care to attach ORC info to the new/deleted ones. 745138e2abfSMaksim Panchenko for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { 746138e2abfSMaksim Panchenko 747138e2abfSMaksim Panchenko std::optional<ORCState> CurrentState; 748138e2abfSMaksim Panchenko for (BinaryBasicBlock &BB : BF) { 749138e2abfSMaksim Panchenko for (MCInst &Inst : BB) { 750138e2abfSMaksim Panchenko ErrorOr<ORCState> State = 751138e2abfSMaksim Panchenko BC.MIB->tryGetAnnotationAs<ORCState>(Inst, "ORC"); 752138e2abfSMaksim Panchenko 753138e2abfSMaksim Panchenko if (State) { 754138e2abfSMaksim Panchenko CurrentState = *State; 755138e2abfSMaksim Panchenko continue; 756138e2abfSMaksim Panchenko } 757138e2abfSMaksim Panchenko 7585a298871SMaksim Panchenko // Get state for the start of the function. 759ec4ddc28SMaksim Panchenko if (!CurrentState) { 7605a298871SMaksim Panchenko // A terminator entry (NullORC) can match the function address. If 7615a298871SMaksim Panchenko // there's also a non-terminator entry, it will be placed after the 7625a298871SMaksim Panchenko // terminator. Hence, we are looking for the last ORC entry that 7635a298871SMaksim Panchenko // matches the address. 764ec4ddc28SMaksim Panchenko auto It = 765ec4ddc28SMaksim Panchenko llvm::partition_point(ORCEntries, [&](const ORCListEntry &E) { 7665a298871SMaksim Panchenko return E.IP <= BF.getAddress(); 767ec4ddc28SMaksim Panchenko }); 768ec4ddc28SMaksim Panchenko if (It != ORCEntries.begin()) 7695a298871SMaksim Panchenko --It; 770ec4ddc28SMaksim Panchenko 7715a298871SMaksim Panchenko assert(It->IP == BF.getAddress() && (!It->BF || It->BF == &BF) && 7725a298871SMaksim Panchenko "ORC info at function entry expected."); 7735a298871SMaksim Panchenko 7745a298871SMaksim Panchenko if (It->ORC == NullORC && BF.hasORC()) { 7750ce01712SMaksim Panchenko BC.errs() << "BOLT-WARNING: ORC unwind info excludes prologue for " 776ec4ddc28SMaksim Panchenko << BF << '\n'; 7775a298871SMaksim Panchenko } 7785a298871SMaksim Panchenko 7795a298871SMaksim Panchenko It->BF = &BF; 780ec4ddc28SMaksim Panchenko 781ec4ddc28SMaksim Panchenko CurrentState = It->ORC; 782ec4ddc28SMaksim Panchenko if (It->ORC != NullORC) 783ec4ddc28SMaksim Panchenko BF.setHasORC(true); 784ec4ddc28SMaksim Panchenko } 785138e2abfSMaksim Panchenko 786138e2abfSMaksim Panchenko // While printing ORC, attach info to every instruction for convenience. 787138e2abfSMaksim Panchenko if (opts::PrintORC || &Inst == &BB.front()) 788138e2abfSMaksim Panchenko BC.MIB->addAnnotation(Inst, "ORC", *CurrentState); 789138e2abfSMaksim Panchenko } 790138e2abfSMaksim Panchenko } 791138e2abfSMaksim Panchenko } 792138e2abfSMaksim Panchenko 793138e2abfSMaksim Panchenko return Error::success(); 794138e2abfSMaksim Panchenko } 795138e2abfSMaksim Panchenko 796e6724cbdSMaksim Panchenko Error LinuxKernelRewriter::rewriteORCTables() { 7975a298871SMaksim Panchenko if (!NumORCEntries) 7985a298871SMaksim Panchenko return Error::success(); 7995a298871SMaksim Panchenko 8005a298871SMaksim Panchenko // Update ORC sections in-place. As we change the code, the number of ORC 8015a298871SMaksim Panchenko // entries may increase for some functions. However, as we remove terminator 8025a298871SMaksim Panchenko // redundancy (see below), more space is freed up and we should always be able 8035a298871SMaksim Panchenko // to fit new ORC tables in the reserved space. 8045a298871SMaksim Panchenko auto createInPlaceWriter = [&](BinarySection &Section) -> BinaryStreamWriter { 8055a298871SMaksim Panchenko const size_t Size = Section.getSize(); 8065a298871SMaksim Panchenko uint8_t *NewContents = new uint8_t[Size]; 8075a298871SMaksim Panchenko Section.updateContents(NewContents, Size); 8085a298871SMaksim Panchenko Section.setOutputFileOffset(Section.getInputFileOffset()); 8095a298871SMaksim Panchenko return BinaryStreamWriter({NewContents, Size}, BC.AsmInfo->isLittleEndian() 8105a298871SMaksim Panchenko ? endianness::little 8115a298871SMaksim Panchenko : endianness::big); 8125a298871SMaksim Panchenko }; 8135a298871SMaksim Panchenko BinaryStreamWriter UnwindWriter = createInPlaceWriter(*ORCUnwindSection); 8145a298871SMaksim Panchenko BinaryStreamWriter UnwindIPWriter = createInPlaceWriter(*ORCUnwindIPSection); 8155a298871SMaksim Panchenko 8165a298871SMaksim Panchenko uint64_t NumEmitted = 0; 8175a298871SMaksim Panchenko std::optional<ORCState> LastEmittedORC; 8185a298871SMaksim Panchenko auto emitORCEntry = [&](const uint64_t IP, const ORCState &ORC, 8195a298871SMaksim Panchenko MCSymbol *Label = 0, bool Force = false) -> Error { 8205a298871SMaksim Panchenko if (LastEmittedORC && ORC == *LastEmittedORC && !Force) 8215a298871SMaksim Panchenko return Error::success(); 8225a298871SMaksim Panchenko 8235a298871SMaksim Panchenko LastEmittedORC = ORC; 8245a298871SMaksim Panchenko 8255a298871SMaksim Panchenko if (++NumEmitted > NumORCEntries) 8265a298871SMaksim Panchenko return createStringError(errc::executable_format_error, 8275a298871SMaksim Panchenko "exceeded the number of allocated ORC entries"); 8285a298871SMaksim Panchenko 8295a298871SMaksim Panchenko if (Label) 8305a298871SMaksim Panchenko ORCUnwindIPSection->addRelocation(UnwindIPWriter.getOffset(), Label, 8315a298871SMaksim Panchenko Relocation::getPC32(), /*Addend*/ 0); 8325a298871SMaksim Panchenko 8335a298871SMaksim Panchenko const int32_t IPValue = 8345a298871SMaksim Panchenko IP - ORCUnwindIPSection->getAddress() - UnwindIPWriter.getOffset(); 8355a298871SMaksim Panchenko if (Error E = UnwindIPWriter.writeInteger(IPValue)) 8365a298871SMaksim Panchenko return E; 8375a298871SMaksim Panchenko 8385a298871SMaksim Panchenko if (Error E = UnwindWriter.writeInteger(ORC.SPOffset)) 8395a298871SMaksim Panchenko return E; 8405a298871SMaksim Panchenko if (Error E = UnwindWriter.writeInteger(ORC.BPOffset)) 8415a298871SMaksim Panchenko return E; 8425a298871SMaksim Panchenko if (Error E = UnwindWriter.writeInteger(ORC.Info)) 8435a298871SMaksim Panchenko return E; 8445a298871SMaksim Panchenko 8455a298871SMaksim Panchenko return Error::success(); 8465a298871SMaksim Panchenko }; 8475a298871SMaksim Panchenko 8485a298871SMaksim Panchenko // Emit new ORC entries for the emitted function. 849dd09a7dbSMaksim Panchenko auto emitORC = [&](const FunctionFragment &FF) -> Error { 8505a298871SMaksim Panchenko ORCState CurrentState = NullORC; 851dd09a7dbSMaksim Panchenko for (BinaryBasicBlock *BB : FF) { 8525a298871SMaksim Panchenko for (MCInst &Inst : *BB) { 8535a298871SMaksim Panchenko ErrorOr<ORCState> ErrorOrState = 8545a298871SMaksim Panchenko BC.MIB->tryGetAnnotationAs<ORCState>(Inst, "ORC"); 8555a298871SMaksim Panchenko if (!ErrorOrState || *ErrorOrState == CurrentState) 8565a298871SMaksim Panchenko continue; 8575a298871SMaksim Panchenko 8585a298871SMaksim Panchenko // Issue label for the instruction. 8597c206c78SMaksim Panchenko MCSymbol *Label = 8607c206c78SMaksim Panchenko BC.MIB->getOrCreateInstLabel(Inst, "__ORC_", BC.Ctx.get()); 8615a298871SMaksim Panchenko 8625a298871SMaksim Panchenko if (Error E = emitORCEntry(0, *ErrorOrState, Label)) 8635a298871SMaksim Panchenko return E; 8645a298871SMaksim Panchenko 8655a298871SMaksim Panchenko CurrentState = *ErrorOrState; 8665a298871SMaksim Panchenko } 8675a298871SMaksim Panchenko } 8685a298871SMaksim Panchenko 8695a298871SMaksim Panchenko return Error::success(); 8705a298871SMaksim Panchenko }; 8715a298871SMaksim Panchenko 872dd09a7dbSMaksim Panchenko // Emit ORC entries for cold fragments. We assume that these fragments are 873dd09a7dbSMaksim Panchenko // emitted contiguously in memory using reserved space in the kernel. This 874dd09a7dbSMaksim Panchenko // assumption is validated in post-emit pass validateORCTables() where we 875dd09a7dbSMaksim Panchenko // check that ORC entries are sorted by their addresses. 876dd09a7dbSMaksim Panchenko auto emitColdORC = [&]() -> Error { 877dd09a7dbSMaksim Panchenko for (BinaryFunction &BF : 878dd09a7dbSMaksim Panchenko llvm::make_second_range(BC.getBinaryFunctions())) { 879dd09a7dbSMaksim Panchenko if (!BC.shouldEmit(BF)) 880dd09a7dbSMaksim Panchenko continue; 881dd09a7dbSMaksim Panchenko for (FunctionFragment &FF : BF.getLayout().getSplitFragments()) 882dd09a7dbSMaksim Panchenko if (Error E = emitORC(FF)) 883dd09a7dbSMaksim Panchenko return E; 884dd09a7dbSMaksim Panchenko } 885dd09a7dbSMaksim Panchenko 886dd09a7dbSMaksim Panchenko return Error::success(); 887dd09a7dbSMaksim Panchenko }; 888dd09a7dbSMaksim Panchenko 889dd09a7dbSMaksim Panchenko bool ShouldEmitCold = !BC.BOLTReserved.empty(); 8905a298871SMaksim Panchenko for (ORCListEntry &Entry : ORCEntries) { 891dd09a7dbSMaksim Panchenko if (ShouldEmitCold && Entry.IP > BC.BOLTReserved.start()) { 892dd09a7dbSMaksim Panchenko if (Error E = emitColdORC()) 893dd09a7dbSMaksim Panchenko return E; 894dd09a7dbSMaksim Panchenko 895dd09a7dbSMaksim Panchenko // Emit terminator entry at the end of the reserved region. 896dd09a7dbSMaksim Panchenko if (Error E = emitORCEntry(BC.BOLTReserved.end(), NullORC)) 897dd09a7dbSMaksim Panchenko return E; 898dd09a7dbSMaksim Panchenko 899dd09a7dbSMaksim Panchenko ShouldEmitCold = false; 900dd09a7dbSMaksim Panchenko } 901dd09a7dbSMaksim Panchenko 9025a298871SMaksim Panchenko // Emit original entries for functions that we haven't modified. 9035a298871SMaksim Panchenko if (!Entry.BF || !BC.shouldEmit(*Entry.BF)) { 9045a298871SMaksim Panchenko // Emit terminator only if it marks the start of a function. 9055a298871SMaksim Panchenko if (Entry.ORC == NullORC && !Entry.BF) 9065a298871SMaksim Panchenko continue; 9075a298871SMaksim Panchenko if (Error E = emitORCEntry(Entry.IP, Entry.ORC)) 9085a298871SMaksim Panchenko return E; 9095a298871SMaksim Panchenko continue; 9105a298871SMaksim Panchenko } 9115a298871SMaksim Panchenko 9125a298871SMaksim Panchenko // Emit all ORC entries for a function referenced by an entry and skip over 9135a298871SMaksim Panchenko // the rest of entries for this function by resetting its ORC attribute. 9145a298871SMaksim Panchenko if (Entry.BF->hasORC()) { 915dd09a7dbSMaksim Panchenko if (Error E = emitORC(Entry.BF->getLayout().getMainFragment())) 9165a298871SMaksim Panchenko return E; 9175a298871SMaksim Panchenko Entry.BF->setHasORC(false); 9185a298871SMaksim Panchenko } 9195a298871SMaksim Panchenko } 9205a298871SMaksim Panchenko 9215a298871SMaksim Panchenko LLVM_DEBUG(dbgs() << "BOLT-DEBUG: emitted " << NumEmitted 9225a298871SMaksim Panchenko << " ORC entries\n"); 9235a298871SMaksim Panchenko 924dd09a7dbSMaksim Panchenko // Populate ORC tables with a terminator entry with max address to match the 925dd09a7dbSMaksim Panchenko // original table sizes. 926dd09a7dbSMaksim Panchenko const uint64_t LastIP = std::numeric_limits<uint64_t>::max(); 9275a298871SMaksim Panchenko while (UnwindWriter.bytesRemaining()) { 9285a298871SMaksim Panchenko if (Error E = emitORCEntry(LastIP, NullORC, nullptr, /*Force*/ true)) 9295a298871SMaksim Panchenko return E; 9305a298871SMaksim Panchenko } 9315a298871SMaksim Panchenko 932e6724cbdSMaksim Panchenko return Error::success(); 933e6724cbdSMaksim Panchenko } 9345a298871SMaksim Panchenko 935c665e499SMaksim Panchenko Error LinuxKernelRewriter::validateORCTables() { 936c665e499SMaksim Panchenko if (!ORCUnwindIPSection) 937c665e499SMaksim Panchenko return Error::success(); 938c665e499SMaksim Panchenko 93921684e38SMaksim Panchenko AddressExtractor IPAE( 94021684e38SMaksim Panchenko ORCUnwindIPSection->getOutputContents(), ORCUnwindIPSection->getAddress(), 94121684e38SMaksim Panchenko BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); 94221684e38SMaksim Panchenko AddressExtractor::Cursor IPCursor(0); 943c665e499SMaksim Panchenko uint64_t PrevIP = 0; 944c665e499SMaksim Panchenko for (uint32_t Index = 0; Index < NumORCEntries; ++Index) { 94521684e38SMaksim Panchenko const uint64_t IP = IPAE.getPCRelAddress32(IPCursor); 946c665e499SMaksim Panchenko if (!IPCursor) 947c665e499SMaksim Panchenko return createStringError(errc::executable_format_error, 948c665e499SMaksim Panchenko "out of bounds while reading ORC IP table: %s", 949c665e499SMaksim Panchenko toString(IPCursor.takeError()).c_str()); 950c665e499SMaksim Panchenko 951c665e499SMaksim Panchenko assert(IP >= PrevIP && "Unsorted ORC table detected"); 952805e08efSKazu Hirata (void)PrevIP; 953c665e499SMaksim Panchenko PrevIP = IP; 954c665e499SMaksim Panchenko } 955c665e499SMaksim Panchenko 956c665e499SMaksim Panchenko return Error::success(); 957c665e499SMaksim Panchenko } 958c665e499SMaksim Panchenko 9592646dccaSMaksim Panchenko /// The static call site table is created by objtool and contains entries in the 9602646dccaSMaksim Panchenko /// following format: 9612646dccaSMaksim Panchenko /// 9622646dccaSMaksim Panchenko /// struct static_call_site { 9632646dccaSMaksim Panchenko /// s32 addr; 9642646dccaSMaksim Panchenko /// s32 key; 9652646dccaSMaksim Panchenko /// }; 9662646dccaSMaksim Panchenko /// 9672646dccaSMaksim Panchenko Error LinuxKernelRewriter::readStaticCalls() { 9682646dccaSMaksim Panchenko const BinaryData *StaticCallTable = 9692646dccaSMaksim Panchenko BC.getBinaryDataByName("__start_static_call_sites"); 9702646dccaSMaksim Panchenko if (!StaticCallTable) 9712646dccaSMaksim Panchenko return Error::success(); 9722646dccaSMaksim Panchenko 9732646dccaSMaksim Panchenko StaticCallTableAddress = StaticCallTable->getAddress(); 9742646dccaSMaksim Panchenko 9752646dccaSMaksim Panchenko const BinaryData *Stop = BC.getBinaryDataByName("__stop_static_call_sites"); 9762646dccaSMaksim Panchenko if (!Stop) 9772646dccaSMaksim Panchenko return createStringError(errc::executable_format_error, 9782646dccaSMaksim Panchenko "missing __stop_static_call_sites symbol"); 9792646dccaSMaksim Panchenko 9802646dccaSMaksim Panchenko ErrorOr<BinarySection &> ErrorOrSection = 9812646dccaSMaksim Panchenko BC.getSectionForAddress(StaticCallTableAddress); 9822646dccaSMaksim Panchenko if (!ErrorOrSection) 9832646dccaSMaksim Panchenko return createStringError(errc::executable_format_error, 9842646dccaSMaksim Panchenko "no section matching __start_static_call_sites"); 9852646dccaSMaksim Panchenko 9862646dccaSMaksim Panchenko StaticCallSection = *ErrorOrSection; 9872646dccaSMaksim Panchenko if (!StaticCallSection->containsAddress(Stop->getAddress() - 1)) 9882646dccaSMaksim Panchenko return createStringError(errc::executable_format_error, 9892646dccaSMaksim Panchenko "__stop_static_call_sites not in the same section " 9902646dccaSMaksim Panchenko "as __start_static_call_sites"); 9912646dccaSMaksim Panchenko 9922646dccaSMaksim Panchenko if ((Stop->getAddress() - StaticCallTableAddress) % STATIC_CALL_ENTRY_SIZE) 9932646dccaSMaksim Panchenko return createStringError(errc::executable_format_error, 9942646dccaSMaksim Panchenko "static call table size error"); 9952646dccaSMaksim Panchenko 9962646dccaSMaksim Panchenko const uint64_t SectionAddress = StaticCallSection->getAddress(); 99721684e38SMaksim Panchenko AddressExtractor AE(StaticCallSection->getContents(), SectionAddress, 9982646dccaSMaksim Panchenko BC.AsmInfo->isLittleEndian(), 9992646dccaSMaksim Panchenko BC.AsmInfo->getCodePointerSize()); 100021684e38SMaksim Panchenko AddressExtractor::Cursor Cursor(StaticCallTableAddress - SectionAddress); 10012646dccaSMaksim Panchenko uint32_t EntryID = 0; 10022646dccaSMaksim Panchenko while (Cursor && Cursor.tell() < Stop->getAddress() - SectionAddress) { 100321684e38SMaksim Panchenko const uint64_t CallAddress = AE.getPCRelAddress32(Cursor); 100421684e38SMaksim Panchenko const uint64_t KeyAddress = AE.getPCRelAddress32(Cursor); 10052646dccaSMaksim Panchenko 10062646dccaSMaksim Panchenko // Consume the status of the cursor. 10072646dccaSMaksim Panchenko if (!Cursor) 10082646dccaSMaksim Panchenko return createStringError(errc::executable_format_error, 1009a9b0d759SMaksim Panchenko "out of bounds while reading static calls: %s", 1010a9b0d759SMaksim Panchenko toString(Cursor.takeError()).c_str()); 10112646dccaSMaksim Panchenko 10122646dccaSMaksim Panchenko ++EntryID; 10132646dccaSMaksim Panchenko 10142646dccaSMaksim Panchenko if (opts::DumpStaticCalls) { 10150ce01712SMaksim Panchenko BC.outs() << "Static Call Site: " << EntryID << '\n'; 10160ce01712SMaksim Panchenko BC.outs() << "\tCallAddress: 0x" << Twine::utohexstr(CallAddress) 10170ce01712SMaksim Panchenko << "\n\tKeyAddress: 0x" << Twine::utohexstr(KeyAddress) 10180ce01712SMaksim Panchenko << '\n'; 10192646dccaSMaksim Panchenko } 10202646dccaSMaksim Panchenko 10212646dccaSMaksim Panchenko BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(CallAddress); 10222646dccaSMaksim Panchenko if (!BF) 10232646dccaSMaksim Panchenko continue; 10242646dccaSMaksim Panchenko 10252646dccaSMaksim Panchenko if (!BC.shouldEmit(*BF)) 10262646dccaSMaksim Panchenko continue; 10272646dccaSMaksim Panchenko 10282646dccaSMaksim Panchenko if (!BF->hasInstructions()) 10292646dccaSMaksim Panchenko continue; 10302646dccaSMaksim Panchenko 10312646dccaSMaksim Panchenko MCInst *Inst = BF->getInstructionAtOffset(CallAddress - BF->getAddress()); 10322646dccaSMaksim Panchenko if (!Inst) 10332646dccaSMaksim Panchenko return createStringError(errc::executable_format_error, 10342646dccaSMaksim Panchenko "no instruction at call site address 0x%" PRIx64, 10352646dccaSMaksim Panchenko CallAddress); 10362646dccaSMaksim Panchenko 10372646dccaSMaksim Panchenko // Check for duplicate entries. 10382646dccaSMaksim Panchenko if (BC.MIB->hasAnnotation(*Inst, "StaticCall")) 10392646dccaSMaksim Panchenko return createStringError(errc::executable_format_error, 10402646dccaSMaksim Panchenko "duplicate static call site at 0x%" PRIx64, 10412646dccaSMaksim Panchenko CallAddress); 10422646dccaSMaksim Panchenko 10432646dccaSMaksim Panchenko BC.MIB->addAnnotation(*Inst, "StaticCall", EntryID); 10442646dccaSMaksim Panchenko 10457c206c78SMaksim Panchenko MCSymbol *Label = 10467c206c78SMaksim Panchenko BC.MIB->getOrCreateInstLabel(*Inst, "__SC_", BC.Ctx.get()); 10472646dccaSMaksim Panchenko 10482646dccaSMaksim Panchenko StaticCallEntries.push_back({EntryID, BF, Label}); 10492646dccaSMaksim Panchenko } 10502646dccaSMaksim Panchenko 10510ce01712SMaksim Panchenko BC.outs() << "BOLT-INFO: parsed " << StaticCallEntries.size() 10522646dccaSMaksim Panchenko << " static call entries\n"; 10532646dccaSMaksim Panchenko 10542646dccaSMaksim Panchenko return Error::success(); 10552646dccaSMaksim Panchenko } 10562646dccaSMaksim Panchenko 10572646dccaSMaksim Panchenko /// The static call table is sorted during boot time in 10582646dccaSMaksim Panchenko /// static_call_sort_entries(). This makes it possible to update existing 10592646dccaSMaksim Panchenko /// entries in-place ignoring their relative order. 10602646dccaSMaksim Panchenko Error LinuxKernelRewriter::rewriteStaticCalls() { 10612646dccaSMaksim Panchenko if (!StaticCallTableAddress || !StaticCallSection) 10622646dccaSMaksim Panchenko return Error::success(); 10632646dccaSMaksim Panchenko 10642646dccaSMaksim Panchenko for (auto &Entry : StaticCallEntries) { 10652646dccaSMaksim Panchenko if (!Entry.Function) 10662646dccaSMaksim Panchenko continue; 10672646dccaSMaksim Panchenko 10682646dccaSMaksim Panchenko BinaryFunction &BF = *Entry.Function; 10692646dccaSMaksim Panchenko if (!BC.shouldEmit(BF)) 10702646dccaSMaksim Panchenko continue; 10712646dccaSMaksim Panchenko 10722646dccaSMaksim Panchenko // Create a relocation against the label. 10732646dccaSMaksim Panchenko const uint64_t EntryOffset = StaticCallTableAddress - 10742646dccaSMaksim Panchenko StaticCallSection->getAddress() + 10752646dccaSMaksim Panchenko (Entry.ID - 1) * STATIC_CALL_ENTRY_SIZE; 10762646dccaSMaksim Panchenko StaticCallSection->addRelocation(EntryOffset, Entry.Label, 10772646dccaSMaksim Panchenko ELF::R_X86_64_PC32, /*Addend*/ 0); 10782646dccaSMaksim Panchenko } 10792646dccaSMaksim Panchenko 10802646dccaSMaksim Panchenko return Error::success(); 10812646dccaSMaksim Panchenko } 10822646dccaSMaksim Panchenko 1083ccf0c8daSMaksim Panchenko /// Instructions that access user-space memory can cause page faults. These 1084ccf0c8daSMaksim Panchenko /// faults will be handled by the kernel and execution will resume at the fixup 1085ccf0c8daSMaksim Panchenko /// code location if the address was invalid. The kernel uses the exception 1086ccf0c8daSMaksim Panchenko /// table to match the faulting instruction to its fixup. The table consists of 1087ccf0c8daSMaksim Panchenko /// the following entries: 1088ccf0c8daSMaksim Panchenko /// 1089ccf0c8daSMaksim Panchenko /// struct exception_table_entry { 1090ccf0c8daSMaksim Panchenko /// int insn; 1091ccf0c8daSMaksim Panchenko /// int fixup; 1092ccf0c8daSMaksim Panchenko /// int data; 1093ccf0c8daSMaksim Panchenko /// }; 1094ccf0c8daSMaksim Panchenko /// 1095ccf0c8daSMaksim Panchenko /// More info at: 1096ccf0c8daSMaksim Panchenko /// https://www.kernel.org/doc/Documentation/x86/exception-tables.txt 1097ccf0c8daSMaksim Panchenko Error LinuxKernelRewriter::readExceptionTable() { 1098ccf0c8daSMaksim Panchenko ExceptionsSection = BC.getUniqueSectionByName("__ex_table"); 1099ccf0c8daSMaksim Panchenko if (!ExceptionsSection) 1100ccf0c8daSMaksim Panchenko return Error::success(); 1101ccf0c8daSMaksim Panchenko 1102ccf0c8daSMaksim Panchenko if (ExceptionsSection->getSize() % EXCEPTION_TABLE_ENTRY_SIZE) 1103ccf0c8daSMaksim Panchenko return createStringError(errc::executable_format_error, 1104ccf0c8daSMaksim Panchenko "exception table size error"); 1105ccf0c8daSMaksim Panchenko 110621684e38SMaksim Panchenko AddressExtractor AE( 110721684e38SMaksim Panchenko ExceptionsSection->getContents(), ExceptionsSection->getAddress(), 110821684e38SMaksim Panchenko BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); 110921684e38SMaksim Panchenko AddressExtractor::Cursor Cursor(0); 1110ccf0c8daSMaksim Panchenko uint32_t EntryID = 0; 1111ccf0c8daSMaksim Panchenko while (Cursor && Cursor.tell() < ExceptionsSection->getSize()) { 111221684e38SMaksim Panchenko const uint64_t InstAddress = AE.getPCRelAddress32(Cursor); 111321684e38SMaksim Panchenko const uint64_t FixupAddress = AE.getPCRelAddress32(Cursor); 111421684e38SMaksim Panchenko const uint64_t Data = AE.getU32(Cursor); 1115ccf0c8daSMaksim Panchenko 1116ccf0c8daSMaksim Panchenko // Consume the status of the cursor. 1117ccf0c8daSMaksim Panchenko if (!Cursor) 1118a9b0d759SMaksim Panchenko return createStringError( 1119a9b0d759SMaksim Panchenko errc::executable_format_error, 1120a9b0d759SMaksim Panchenko "out of bounds while reading exception table: %s", 1121a9b0d759SMaksim Panchenko toString(Cursor.takeError()).c_str()); 1122ccf0c8daSMaksim Panchenko 1123ccf0c8daSMaksim Panchenko ++EntryID; 1124ccf0c8daSMaksim Panchenko 1125ccf0c8daSMaksim Panchenko if (opts::DumpExceptions) { 1126ccf0c8daSMaksim Panchenko BC.outs() << "Exception Entry: " << EntryID << '\n'; 1127ccf0c8daSMaksim Panchenko BC.outs() << "\tInsn: 0x" << Twine::utohexstr(InstAddress) << '\n' 1128ccf0c8daSMaksim Panchenko << "\tFixup: 0x" << Twine::utohexstr(FixupAddress) << '\n' 1129ccf0c8daSMaksim Panchenko << "\tData: 0x" << Twine::utohexstr(Data) << '\n'; 1130ccf0c8daSMaksim Panchenko } 1131ccf0c8daSMaksim Panchenko 1132ccf0c8daSMaksim Panchenko MCInst *Inst = nullptr; 1133ccf0c8daSMaksim Panchenko MCSymbol *FixupLabel = nullptr; 1134ccf0c8daSMaksim Panchenko 1135ccf0c8daSMaksim Panchenko BinaryFunction *InstBF = BC.getBinaryFunctionContainingAddress(InstAddress); 1136ccf0c8daSMaksim Panchenko if (InstBF && BC.shouldEmit(*InstBF)) { 1137ccf0c8daSMaksim Panchenko Inst = InstBF->getInstructionAtOffset(InstAddress - InstBF->getAddress()); 1138ccf0c8daSMaksim Panchenko if (!Inst) 1139ccf0c8daSMaksim Panchenko return createStringError(errc::executable_format_error, 1140ccf0c8daSMaksim Panchenko "no instruction at address 0x%" PRIx64 1141ccf0c8daSMaksim Panchenko " in exception table", 1142ccf0c8daSMaksim Panchenko InstAddress); 1143ccf0c8daSMaksim Panchenko BC.MIB->addAnnotation(*Inst, "ExceptionEntry", EntryID); 1144ccf0c8daSMaksim Panchenko FunctionsWithExceptions.insert(InstBF); 1145ccf0c8daSMaksim Panchenko } 1146ccf0c8daSMaksim Panchenko 1147ccf0c8daSMaksim Panchenko if (!InstBF && opts::Verbosity) { 1148ccf0c8daSMaksim Panchenko BC.outs() << "BOLT-INFO: no function matches instruction at 0x" 1149ccf0c8daSMaksim Panchenko << Twine::utohexstr(InstAddress) 1150ccf0c8daSMaksim Panchenko << " referenced by Linux exception table\n"; 1151ccf0c8daSMaksim Panchenko } 1152ccf0c8daSMaksim Panchenko 1153ccf0c8daSMaksim Panchenko BinaryFunction *FixupBF = 1154ccf0c8daSMaksim Panchenko BC.getBinaryFunctionContainingAddress(FixupAddress); 1155ccf0c8daSMaksim Panchenko if (FixupBF && BC.shouldEmit(*FixupBF)) { 1156ccf0c8daSMaksim Panchenko const uint64_t Offset = FixupAddress - FixupBF->getAddress(); 1157ccf0c8daSMaksim Panchenko if (!FixupBF->getInstructionAtOffset(Offset)) 1158ccf0c8daSMaksim Panchenko return createStringError(errc::executable_format_error, 1159ccf0c8daSMaksim Panchenko "no instruction at fixup address 0x%" PRIx64 1160ccf0c8daSMaksim Panchenko " in exception table", 1161ccf0c8daSMaksim Panchenko FixupAddress); 1162ccf0c8daSMaksim Panchenko FixupLabel = Offset ? FixupBF->addEntryPointAtOffset(Offset) 1163ccf0c8daSMaksim Panchenko : FixupBF->getSymbol(); 1164ccf0c8daSMaksim Panchenko if (Inst) 1165ccf0c8daSMaksim Panchenko BC.MIB->addAnnotation(*Inst, "Fixup", FixupLabel->getName()); 1166ccf0c8daSMaksim Panchenko FunctionsWithExceptions.insert(FixupBF); 1167ccf0c8daSMaksim Panchenko } 1168ccf0c8daSMaksim Panchenko 1169ccf0c8daSMaksim Panchenko if (!FixupBF && opts::Verbosity) { 1170ccf0c8daSMaksim Panchenko BC.outs() << "BOLT-INFO: no function matches fixup code at 0x" 1171ccf0c8daSMaksim Panchenko << Twine::utohexstr(FixupAddress) 1172ccf0c8daSMaksim Panchenko << " referenced by Linux exception table\n"; 1173ccf0c8daSMaksim Panchenko } 1174ccf0c8daSMaksim Panchenko } 1175ccf0c8daSMaksim Panchenko 1176ccf0c8daSMaksim Panchenko BC.outs() << "BOLT-INFO: parsed " 1177ccf0c8daSMaksim Panchenko << ExceptionsSection->getSize() / EXCEPTION_TABLE_ENTRY_SIZE 1178ccf0c8daSMaksim Panchenko << " exception table entries\n"; 1179ccf0c8daSMaksim Panchenko 1180ccf0c8daSMaksim Panchenko return Error::success(); 1181ccf0c8daSMaksim Panchenko } 1182ccf0c8daSMaksim Panchenko 1183ccf0c8daSMaksim Panchenko /// Depending on the value of CONFIG_BUILDTIME_TABLE_SORT, the kernel expects 1184ccf0c8daSMaksim Panchenko /// the exception table to be sorted. Hence we have to sort it after code 1185ccf0c8daSMaksim Panchenko /// reordering. 1186ccf0c8daSMaksim Panchenko Error LinuxKernelRewriter::rewriteExceptionTable() { 1187ccf0c8daSMaksim Panchenko // Disable output of functions with exceptions before rewrite support is 1188ccf0c8daSMaksim Panchenko // added. 1189ccf0c8daSMaksim Panchenko for (BinaryFunction *BF : FunctionsWithExceptions) 1190ccf0c8daSMaksim Panchenko BF->setSimple(false); 1191ccf0c8daSMaksim Panchenko 1192ccf0c8daSMaksim Panchenko return Error::success(); 1193ccf0c8daSMaksim Panchenko } 1194ccf0c8daSMaksim Panchenko 1195f51ade25SMaksim Panchenko /// .parainsrtuctions section contains information for patching parvirtual call 1196f51ade25SMaksim Panchenko /// instructions during runtime. The entries in the section are in the form: 1197f51ade25SMaksim Panchenko /// 1198f51ade25SMaksim Panchenko /// struct paravirt_patch_site { 1199f51ade25SMaksim Panchenko /// u8 *instr; /* original instructions */ 1200f51ade25SMaksim Panchenko /// u8 type; /* type of this instruction */ 1201f51ade25SMaksim Panchenko /// u8 len; /* length of original instruction */ 1202f51ade25SMaksim Panchenko /// }; 1203f51ade25SMaksim Panchenko /// 1204f51ade25SMaksim Panchenko /// Note that the structures are aligned at 8-byte boundary. 1205f51ade25SMaksim Panchenko Error LinuxKernelRewriter::readParaInstructions() { 1206f51ade25SMaksim Panchenko ParavirtualPatchSection = BC.getUniqueSectionByName(".parainstructions"); 1207f51ade25SMaksim Panchenko if (!ParavirtualPatchSection) 1208f51ade25SMaksim Panchenko return Error::success(); 1209f51ade25SMaksim Panchenko 121021684e38SMaksim Panchenko DataExtractor DE(ParavirtualPatchSection->getContents(), 1211f51ade25SMaksim Panchenko BC.AsmInfo->isLittleEndian(), 1212f51ade25SMaksim Panchenko BC.AsmInfo->getCodePointerSize()); 1213f51ade25SMaksim Panchenko uint32_t EntryID = 0; 1214f51ade25SMaksim Panchenko DataExtractor::Cursor Cursor(0); 1215f51ade25SMaksim Panchenko while (Cursor && !DE.eof(Cursor)) { 1216f51ade25SMaksim Panchenko const uint64_t NextOffset = alignTo(Cursor.tell(), Align(PARA_PATCH_ALIGN)); 1217f51ade25SMaksim Panchenko if (!DE.isValidOffset(NextOffset)) 1218f51ade25SMaksim Panchenko break; 1219f51ade25SMaksim Panchenko 1220f51ade25SMaksim Panchenko Cursor.seek(NextOffset); 1221f51ade25SMaksim Panchenko 1222f51ade25SMaksim Panchenko const uint64_t InstrLocation = DE.getU64(Cursor); 1223f51ade25SMaksim Panchenko const uint8_t Type = DE.getU8(Cursor); 1224f51ade25SMaksim Panchenko const uint8_t Len = DE.getU8(Cursor); 1225f51ade25SMaksim Panchenko 1226f51ade25SMaksim Panchenko if (!Cursor) 1227a9b0d759SMaksim Panchenko return createStringError( 1228a9b0d759SMaksim Panchenko errc::executable_format_error, 1229a9b0d759SMaksim Panchenko "out of bounds while reading .parainstructions: %s", 1230a9b0d759SMaksim Panchenko toString(Cursor.takeError()).c_str()); 1231f51ade25SMaksim Panchenko 1232f51ade25SMaksim Panchenko ++EntryID; 1233f51ade25SMaksim Panchenko 1234f51ade25SMaksim Panchenko if (opts::DumpParavirtualPatchSites) { 1235f51ade25SMaksim Panchenko BC.outs() << "Paravirtual patch site: " << EntryID << '\n'; 1236f51ade25SMaksim Panchenko BC.outs() << "\tInstr: 0x" << Twine::utohexstr(InstrLocation) 1237f51ade25SMaksim Panchenko << "\n\tType: 0x" << Twine::utohexstr(Type) << "\n\tLen: 0x" 1238f51ade25SMaksim Panchenko << Twine::utohexstr(Len) << '\n'; 1239f51ade25SMaksim Panchenko } 1240f51ade25SMaksim Panchenko 1241f51ade25SMaksim Panchenko BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(InstrLocation); 1242f51ade25SMaksim Panchenko if (!BF && opts::Verbosity) { 1243f51ade25SMaksim Panchenko BC.outs() << "BOLT-INFO: no function matches address 0x" 1244f51ade25SMaksim Panchenko << Twine::utohexstr(InstrLocation) 1245f51ade25SMaksim Panchenko << " referenced by paravirutal patch site\n"; 1246f51ade25SMaksim Panchenko } 1247f51ade25SMaksim Panchenko 1248f51ade25SMaksim Panchenko if (BF && BC.shouldEmit(*BF)) { 1249f51ade25SMaksim Panchenko MCInst *Inst = 1250f51ade25SMaksim Panchenko BF->getInstructionAtOffset(InstrLocation - BF->getAddress()); 1251f51ade25SMaksim Panchenko if (!Inst) 1252f51ade25SMaksim Panchenko return createStringError(errc::executable_format_error, 1253f51ade25SMaksim Panchenko "no instruction at address 0x%" PRIx64 1254f51ade25SMaksim Panchenko " in paravirtual call site %d", 1255f51ade25SMaksim Panchenko InstrLocation, EntryID); 1256f51ade25SMaksim Panchenko BC.MIB->addAnnotation(*Inst, "ParaSite", EntryID); 1257f51ade25SMaksim Panchenko } 1258f51ade25SMaksim Panchenko } 1259f51ade25SMaksim Panchenko 1260f51ade25SMaksim Panchenko BC.outs() << "BOLT-INFO: parsed " << EntryID << " paravirtual patch sites\n"; 1261f51ade25SMaksim Panchenko 1262f51ade25SMaksim Panchenko return Error::success(); 1263f51ade25SMaksim Panchenko } 1264f51ade25SMaksim Panchenko 126556197d73SMaksim Panchenko void LinuxKernelRewriter::skipFunctionsWithAnnotation( 126656197d73SMaksim Panchenko StringRef Annotation) const { 126756197d73SMaksim Panchenko for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { 126856197d73SMaksim Panchenko if (!BC.shouldEmit(BF)) 126956197d73SMaksim Panchenko continue; 127056197d73SMaksim Panchenko for (const BinaryBasicBlock &BB : BF) { 127156197d73SMaksim Panchenko const bool HasAnnotation = llvm::any_of(BB, [&](const MCInst &Inst) { 127256197d73SMaksim Panchenko return BC.MIB->hasAnnotation(Inst, Annotation); 127356197d73SMaksim Panchenko }); 127456197d73SMaksim Panchenko if (HasAnnotation) { 127556197d73SMaksim Panchenko BF.setSimple(false); 127656197d73SMaksim Panchenko break; 127756197d73SMaksim Panchenko } 127856197d73SMaksim Panchenko } 127956197d73SMaksim Panchenko } 128056197d73SMaksim Panchenko } 128156197d73SMaksim Panchenko 128256197d73SMaksim Panchenko Error LinuxKernelRewriter::rewriteParaInstructions() { 128356197d73SMaksim Panchenko // Disable output of functions with paravirtual instructions before the 128456197d73SMaksim Panchenko // rewrite support is complete. 128556197d73SMaksim Panchenko skipFunctionsWithAnnotation("ParaSite"); 128656197d73SMaksim Panchenko 128756197d73SMaksim Panchenko return Error::success(); 128856197d73SMaksim Panchenko } 128956197d73SMaksim Panchenko 129002629793SMaksim Panchenko /// Process __bug_table section. 129135e7d458SMaksim Panchenko /// This section contains information useful for kernel debugging, mostly 129235e7d458SMaksim Panchenko /// utilized by WARN()/WARN_ON() macros and deprecated BUG()/BUG_ON(). 129335e7d458SMaksim Panchenko /// 129402629793SMaksim Panchenko /// Each entry in the section is a struct bug_entry that contains a pointer to 129502629793SMaksim Panchenko /// the ud2 instruction corresponding to the bug, corresponding file name (both 129602629793SMaksim Panchenko /// pointers use PC relative offset addressing), line number, and flags. 129702629793SMaksim Panchenko /// The definition of the struct bug_entry can be found in 129835e7d458SMaksim Panchenko /// `include/asm-generic/bug.h`. The first entry in the struct is an instruction 129935e7d458SMaksim Panchenko /// address encoded as a PC-relative offset. In theory, it could be an absolute 130035e7d458SMaksim Panchenko /// address if CONFIG_GENERIC_BUG_RELATIVE_POINTERS is not set, but in practice 130135e7d458SMaksim Panchenko /// the kernel code relies on it being a relative offset on x86-64. 130202629793SMaksim Panchenko Error LinuxKernelRewriter::readBugTable() { 130302629793SMaksim Panchenko BugTableSection = BC.getUniqueSectionByName("__bug_table"); 130402629793SMaksim Panchenko if (!BugTableSection) 130502629793SMaksim Panchenko return Error::success(); 130602629793SMaksim Panchenko 130702629793SMaksim Panchenko if (BugTableSection->getSize() % BUG_TABLE_ENTRY_SIZE) 130802629793SMaksim Panchenko return createStringError(errc::executable_format_error, 130902629793SMaksim Panchenko "bug table size error"); 131002629793SMaksim Panchenko 131121684e38SMaksim Panchenko AddressExtractor AE( 131221684e38SMaksim Panchenko BugTableSection->getContents(), BugTableSection->getAddress(), 131321684e38SMaksim Panchenko BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); 131421684e38SMaksim Panchenko AddressExtractor::Cursor Cursor(0); 131502629793SMaksim Panchenko uint32_t EntryID = 0; 131602629793SMaksim Panchenko while (Cursor && Cursor.tell() < BugTableSection->getSize()) { 131702629793SMaksim Panchenko const uint64_t Pos = Cursor.tell(); 131821684e38SMaksim Panchenko const uint64_t InstAddress = AE.getPCRelAddress32(Cursor); 131902629793SMaksim Panchenko Cursor.seek(Pos + BUG_TABLE_ENTRY_SIZE); 132002629793SMaksim Panchenko 132102629793SMaksim Panchenko if (!Cursor) 132202629793SMaksim Panchenko return createStringError(errc::executable_format_error, 1323a9b0d759SMaksim Panchenko "out of bounds while reading __bug_table: %s", 1324a9b0d759SMaksim Panchenko toString(Cursor.takeError()).c_str()); 132502629793SMaksim Panchenko 132602629793SMaksim Panchenko ++EntryID; 132702629793SMaksim Panchenko 132802629793SMaksim Panchenko BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(InstAddress); 132902629793SMaksim Panchenko if (!BF && opts::Verbosity) { 133002629793SMaksim Panchenko BC.outs() << "BOLT-INFO: no function matches address 0x" 133102629793SMaksim Panchenko << Twine::utohexstr(InstAddress) 133202629793SMaksim Panchenko << " referenced by bug table\n"; 133302629793SMaksim Panchenko } 133402629793SMaksim Panchenko 133502629793SMaksim Panchenko if (BF && BC.shouldEmit(*BF)) { 133602629793SMaksim Panchenko MCInst *Inst = BF->getInstructionAtOffset(InstAddress - BF->getAddress()); 133702629793SMaksim Panchenko if (!Inst) 133802629793SMaksim Panchenko return createStringError(errc::executable_format_error, 133902629793SMaksim Panchenko "no instruction at address 0x%" PRIx64 134002629793SMaksim Panchenko " referenced by bug table entry %d", 134102629793SMaksim Panchenko InstAddress, EntryID); 134202629793SMaksim Panchenko BC.MIB->addAnnotation(*Inst, "BugEntry", EntryID); 134335e7d458SMaksim Panchenko 134435e7d458SMaksim Panchenko FunctionBugList[BF].push_back(EntryID); 134502629793SMaksim Panchenko } 134602629793SMaksim Panchenko } 134702629793SMaksim Panchenko 134802629793SMaksim Panchenko BC.outs() << "BOLT-INFO: parsed " << EntryID << " bug table entries\n"; 134902629793SMaksim Panchenko 135002629793SMaksim Panchenko return Error::success(); 135102629793SMaksim Panchenko } 135202629793SMaksim Panchenko 135335e7d458SMaksim Panchenko /// find_bug() uses linear search to match an address to an entry in the bug 135435e7d458SMaksim Panchenko /// table. Hence, there is no need to sort entries when rewriting the table. 135535e7d458SMaksim Panchenko /// When we need to erase an entry, we set its instruction address to zero. 135635e7d458SMaksim Panchenko Error LinuxKernelRewriter::rewriteBugTable() { 135735e7d458SMaksim Panchenko if (!BugTableSection) 135835e7d458SMaksim Panchenko return Error::success(); 135935e7d458SMaksim Panchenko 136035e7d458SMaksim Panchenko for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { 136135e7d458SMaksim Panchenko if (!BC.shouldEmit(BF)) 136235e7d458SMaksim Panchenko continue; 136335e7d458SMaksim Panchenko 136435e7d458SMaksim Panchenko if (!FunctionBugList.count(&BF)) 136535e7d458SMaksim Panchenko continue; 136635e7d458SMaksim Panchenko 136735e7d458SMaksim Panchenko // Bugs that will be emitted for this function. 136835e7d458SMaksim Panchenko DenseSet<uint32_t> EmittedIDs; 136935e7d458SMaksim Panchenko for (BinaryBasicBlock &BB : BF) { 137035e7d458SMaksim Panchenko for (MCInst &Inst : BB) { 137135e7d458SMaksim Panchenko if (!BC.MIB->hasAnnotation(Inst, "BugEntry")) 137235e7d458SMaksim Panchenko continue; 137335e7d458SMaksim Panchenko const uint32_t ID = BC.MIB->getAnnotationAs<uint32_t>(Inst, "BugEntry"); 137435e7d458SMaksim Panchenko EmittedIDs.insert(ID); 137535e7d458SMaksim Panchenko 137635e7d458SMaksim Panchenko // Create a relocation entry for this bug entry. 137735e7d458SMaksim Panchenko MCSymbol *Label = 137835e7d458SMaksim Panchenko BC.MIB->getOrCreateInstLabel(Inst, "__BUG_", BC.Ctx.get()); 137935e7d458SMaksim Panchenko const uint64_t EntryOffset = (ID - 1) * BUG_TABLE_ENTRY_SIZE; 138035e7d458SMaksim Panchenko BugTableSection->addRelocation(EntryOffset, Label, ELF::R_X86_64_PC32, 138135e7d458SMaksim Panchenko /*Addend*/ 0); 138235e7d458SMaksim Panchenko } 138335e7d458SMaksim Panchenko } 138435e7d458SMaksim Panchenko 138535e7d458SMaksim Panchenko // Clear bug entries that were not emitted for this function, e.g. as a 138635e7d458SMaksim Panchenko // result of DCE, but setting their instruction address to zero. 138735e7d458SMaksim Panchenko for (const uint32_t ID : FunctionBugList[&BF]) { 138835e7d458SMaksim Panchenko if (!EmittedIDs.count(ID)) { 138935e7d458SMaksim Panchenko const uint64_t EntryOffset = (ID - 1) * BUG_TABLE_ENTRY_SIZE; 139035e7d458SMaksim Panchenko BugTableSection->addRelocation(EntryOffset, nullptr, ELF::R_X86_64_PC32, 139135e7d458SMaksim Panchenko /*Addend*/ 0); 139235e7d458SMaksim Panchenko } 139335e7d458SMaksim Panchenko } 139435e7d458SMaksim Panchenko } 139535e7d458SMaksim Panchenko 139635e7d458SMaksim Panchenko return Error::success(); 139735e7d458SMaksim Panchenko } 139835e7d458SMaksim Panchenko 1399143afb40SMaksim Panchenko /// The kernel can replace certain instruction sequences depending on hardware 1400143afb40SMaksim Panchenko /// it is running on and features specified during boot time. The information 1401143afb40SMaksim Panchenko /// about alternative instruction sequences is stored in .altinstructions 1402143afb40SMaksim Panchenko /// section. The format of entries in this section is defined in 1403143afb40SMaksim Panchenko /// arch/x86/include/asm/alternative.h: 1404143afb40SMaksim Panchenko /// 1405143afb40SMaksim Panchenko /// struct alt_instr { 1406143afb40SMaksim Panchenko /// s32 instr_offset; 1407143afb40SMaksim Panchenko /// s32 repl_offset; 1408143afb40SMaksim Panchenko /// uXX feature; 1409143afb40SMaksim Panchenko /// u8 instrlen; 1410143afb40SMaksim Panchenko /// u8 replacementlen; 1411143afb40SMaksim Panchenko /// u8 padlen; // present in older kernels 1412143afb40SMaksim Panchenko /// } __packed; 1413143afb40SMaksim Panchenko /// 1414540893e4SMaksim Panchenko /// Note that the structure is packed. 1415540893e4SMaksim Panchenko /// 1416540893e4SMaksim Panchenko /// Since the size of the "feature" field could be either u16 or u32, and 1417540893e4SMaksim Panchenko /// "padlen" presence is unknown, we attempt to parse .altinstructions section 1418540893e4SMaksim Panchenko /// using all possible combinations (four at this time). Since we validate the 1419540893e4SMaksim Panchenko /// contents of the section and its size, the detection works quite well. 1420540893e4SMaksim Panchenko /// Still, we leave the user the opportunity to specify these features on the 1421540893e4SMaksim Panchenko /// command line and skip the guesswork. 1422143afb40SMaksim Panchenko Error LinuxKernelRewriter::readAltInstructions() { 1423143afb40SMaksim Panchenko AltInstrSection = BC.getUniqueSectionByName(".altinstructions"); 1424143afb40SMaksim Panchenko if (!AltInstrSection) 1425143afb40SMaksim Panchenko return Error::success(); 1426143afb40SMaksim Panchenko 1427540893e4SMaksim Panchenko // Presence of "padlen" field. 1428540893e4SMaksim Panchenko std::vector<bool> PadLenVariants; 1429540893e4SMaksim Panchenko if (opts::AltInstHasPadLen.getNumOccurrences()) 1430540893e4SMaksim Panchenko PadLenVariants.push_back(opts::AltInstHasPadLen); 1431540893e4SMaksim Panchenko else 1432540893e4SMaksim Panchenko PadLenVariants = {false, true}; 1433540893e4SMaksim Panchenko 1434540893e4SMaksim Panchenko // Size (in bytes) variants of "feature" field. 1435540893e4SMaksim Panchenko std::vector<uint32_t> FeatureSizeVariants; 1436540893e4SMaksim Panchenko if (opts::AltInstFeatureSize.getNumOccurrences()) 1437540893e4SMaksim Panchenko FeatureSizeVariants.push_back(opts::AltInstFeatureSize); 1438540893e4SMaksim Panchenko else 1439540893e4SMaksim Panchenko FeatureSizeVariants = {2, 4}; 1440540893e4SMaksim Panchenko 1441540893e4SMaksim Panchenko for (bool AltInstHasPadLen : PadLenVariants) { 1442540893e4SMaksim Panchenko for (uint32_t AltInstFeatureSize : FeatureSizeVariants) { 1443540893e4SMaksim Panchenko LLVM_DEBUG({ 1444540893e4SMaksim Panchenko dbgs() << "BOLT-DEBUG: trying AltInstHasPadLen = " << AltInstHasPadLen 1445540893e4SMaksim Panchenko << "; AltInstFeatureSize = " << AltInstFeatureSize << ";\n"; 1446540893e4SMaksim Panchenko }); 1447540893e4SMaksim Panchenko if (Error E = tryReadAltInstructions(AltInstFeatureSize, AltInstHasPadLen, 1448540893e4SMaksim Panchenko /*ParseOnly*/ true)) { 1449540893e4SMaksim Panchenko consumeError(std::move(E)); 1450540893e4SMaksim Panchenko continue; 1451540893e4SMaksim Panchenko } 1452540893e4SMaksim Panchenko 1453540893e4SMaksim Panchenko LLVM_DEBUG(dbgs() << "Matched .altinstructions format\n"); 1454540893e4SMaksim Panchenko 1455540893e4SMaksim Panchenko if (!opts::AltInstHasPadLen.getNumOccurrences()) 1456540893e4SMaksim Panchenko BC.outs() << "BOLT-INFO: setting --" << opts::AltInstHasPadLen.ArgStr 1457540893e4SMaksim Panchenko << '=' << AltInstHasPadLen << '\n'; 1458540893e4SMaksim Panchenko 1459540893e4SMaksim Panchenko if (!opts::AltInstFeatureSize.getNumOccurrences()) 1460540893e4SMaksim Panchenko BC.outs() << "BOLT-INFO: setting --" << opts::AltInstFeatureSize.ArgStr 1461540893e4SMaksim Panchenko << '=' << AltInstFeatureSize << '\n'; 1462540893e4SMaksim Panchenko 1463540893e4SMaksim Panchenko return tryReadAltInstructions(AltInstFeatureSize, AltInstHasPadLen, 1464540893e4SMaksim Panchenko /*ParseOnly*/ false); 1465540893e4SMaksim Panchenko } 1466540893e4SMaksim Panchenko } 1467540893e4SMaksim Panchenko 1468540893e4SMaksim Panchenko // We couldn't match the format. Read again to properly propagate the error 1469540893e4SMaksim Panchenko // to the user. 1470540893e4SMaksim Panchenko return tryReadAltInstructions(opts::AltInstFeatureSize, 1471540893e4SMaksim Panchenko opts::AltInstHasPadLen, /*ParseOnly*/ false); 1472540893e4SMaksim Panchenko } 1473540893e4SMaksim Panchenko 1474540893e4SMaksim Panchenko Error LinuxKernelRewriter::tryReadAltInstructions(uint32_t AltInstFeatureSize, 1475540893e4SMaksim Panchenko bool AltInstHasPadLen, 1476540893e4SMaksim Panchenko bool ParseOnly) { 147721684e38SMaksim Panchenko AddressExtractor AE( 147821684e38SMaksim Panchenko AltInstrSection->getContents(), AltInstrSection->getAddress(), 147921684e38SMaksim Panchenko BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); 148021684e38SMaksim Panchenko AddressExtractor::Cursor Cursor(0); 1481143afb40SMaksim Panchenko uint64_t EntryID = 0; 148221684e38SMaksim Panchenko while (Cursor && !AE.eof(Cursor)) { 148321684e38SMaksim Panchenko const uint64_t OrgInstAddress = AE.getPCRelAddress32(Cursor); 148421684e38SMaksim Panchenko const uint64_t AltInstAddress = AE.getPCRelAddress32(Cursor); 148521684e38SMaksim Panchenko const uint64_t Feature = AE.getUnsigned(Cursor, AltInstFeatureSize); 148621684e38SMaksim Panchenko const uint8_t OrgSize = AE.getU8(Cursor); 148721684e38SMaksim Panchenko const uint8_t AltSize = AE.getU8(Cursor); 1488143afb40SMaksim Panchenko 1489143afb40SMaksim Panchenko // Older kernels may have the padlen field. 149021684e38SMaksim Panchenko const uint8_t PadLen = AltInstHasPadLen ? AE.getU8(Cursor) : 0; 1491143afb40SMaksim Panchenko 1492143afb40SMaksim Panchenko if (!Cursor) 1493a9b0d759SMaksim Panchenko return createStringError( 1494a9b0d759SMaksim Panchenko errc::executable_format_error, 1495a9b0d759SMaksim Panchenko "out of bounds while reading .altinstructions: %s", 1496a9b0d759SMaksim Panchenko toString(Cursor.takeError()).c_str()); 1497143afb40SMaksim Panchenko 1498143afb40SMaksim Panchenko ++EntryID; 1499143afb40SMaksim Panchenko 1500143afb40SMaksim Panchenko if (opts::DumpAltInstructions) { 1501143afb40SMaksim Panchenko BC.outs() << "Alternative instruction entry: " << EntryID 1502143afb40SMaksim Panchenko << "\n\tOrg: 0x" << Twine::utohexstr(OrgInstAddress) 1503143afb40SMaksim Panchenko << "\n\tAlt: 0x" << Twine::utohexstr(AltInstAddress) 1504143afb40SMaksim Panchenko << "\n\tFeature: 0x" << Twine::utohexstr(Feature) 1505143afb40SMaksim Panchenko << "\n\tOrgSize: " << (int)OrgSize 1506143afb40SMaksim Panchenko << "\n\tAltSize: " << (int)AltSize << '\n'; 1507540893e4SMaksim Panchenko if (AltInstHasPadLen) 1508143afb40SMaksim Panchenko BC.outs() << "\tPadLen: " << (int)PadLen << '\n'; 1509143afb40SMaksim Panchenko } 1510143afb40SMaksim Panchenko 1511143afb40SMaksim Panchenko if (AltSize > OrgSize) 1512143afb40SMaksim Panchenko return createStringError(errc::executable_format_error, 1513143afb40SMaksim Panchenko "error reading .altinstructions"); 1514143afb40SMaksim Panchenko 1515143afb40SMaksim Panchenko BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(OrgInstAddress); 1516143afb40SMaksim Panchenko if (!BF && opts::Verbosity) { 1517143afb40SMaksim Panchenko BC.outs() << "BOLT-INFO: no function matches address 0x" 1518143afb40SMaksim Panchenko << Twine::utohexstr(OrgInstAddress) 1519143afb40SMaksim Panchenko << " of instruction from .altinstructions\n"; 1520143afb40SMaksim Panchenko } 1521143afb40SMaksim Panchenko 1522143afb40SMaksim Panchenko BinaryFunction *AltBF = 1523143afb40SMaksim Panchenko BC.getBinaryFunctionContainingAddress(AltInstAddress); 1524540893e4SMaksim Panchenko if (!ParseOnly && AltBF && BC.shouldEmit(*AltBF)) { 1525143afb40SMaksim Panchenko BC.errs() 1526143afb40SMaksim Panchenko << "BOLT-WARNING: alternative instruction sequence found in function " 1527143afb40SMaksim Panchenko << *AltBF << '\n'; 1528143afb40SMaksim Panchenko AltBF->setIgnored(); 1529143afb40SMaksim Panchenko } 1530143afb40SMaksim Panchenko 1531d16b21b1SMaksim Panchenko if (!BF || !BF->hasInstructions()) 1532143afb40SMaksim Panchenko continue; 1533143afb40SMaksim Panchenko 1534143afb40SMaksim Panchenko if (OrgInstAddress + OrgSize > BF->getAddress() + BF->getSize()) 1535143afb40SMaksim Panchenko return createStringError(errc::executable_format_error, 1536143afb40SMaksim Panchenko "error reading .altinstructions"); 1537143afb40SMaksim Panchenko 1538143afb40SMaksim Panchenko MCInst *Inst = 1539143afb40SMaksim Panchenko BF->getInstructionAtOffset(OrgInstAddress - BF->getAddress()); 1540143afb40SMaksim Panchenko if (!Inst) 1541143afb40SMaksim Panchenko return createStringError(errc::executable_format_error, 1542143afb40SMaksim Panchenko "no instruction at address 0x%" PRIx64 1543143afb40SMaksim Panchenko " referenced by .altinstructions entry %d", 1544143afb40SMaksim Panchenko OrgInstAddress, EntryID); 1545143afb40SMaksim Panchenko 1546540893e4SMaksim Panchenko if (ParseOnly) 1547540893e4SMaksim Panchenko continue; 1548540893e4SMaksim Panchenko 1549143afb40SMaksim Panchenko // There could be more than one alternative instruction sequences for the 1550143afb40SMaksim Panchenko // same original instruction. Annotate each alternative separately. 1551143afb40SMaksim Panchenko std::string AnnotationName = "AltInst"; 1552143afb40SMaksim Panchenko unsigned N = 2; 1553143afb40SMaksim Panchenko while (BC.MIB->hasAnnotation(*Inst, AnnotationName)) 1554143afb40SMaksim Panchenko AnnotationName = "AltInst" + std::to_string(N++); 1555143afb40SMaksim Panchenko 1556143afb40SMaksim Panchenko BC.MIB->addAnnotation(*Inst, AnnotationName, EntryID); 1557143afb40SMaksim Panchenko 1558143afb40SMaksim Panchenko // Annotate all instructions from the original sequence. Note that it's not 1559143afb40SMaksim Panchenko // the most efficient way to look for instructions in the address range, 1560143afb40SMaksim Panchenko // but since alternative instructions are uncommon, it will do for now. 1561143afb40SMaksim Panchenko for (uint32_t Offset = 1; Offset < OrgSize; ++Offset) { 1562143afb40SMaksim Panchenko Inst = BF->getInstructionAtOffset(OrgInstAddress + Offset - 1563143afb40SMaksim Panchenko BF->getAddress()); 1564143afb40SMaksim Panchenko if (Inst) 1565143afb40SMaksim Panchenko BC.MIB->addAnnotation(*Inst, AnnotationName, EntryID); 1566143afb40SMaksim Panchenko } 1567143afb40SMaksim Panchenko } 1568143afb40SMaksim Panchenko 15691ebda117SMaksim Panchenko if (!ParseOnly) 1570143afb40SMaksim Panchenko BC.outs() << "BOLT-INFO: parsed " << EntryID 1571143afb40SMaksim Panchenko << " alternative instruction entries\n"; 1572143afb40SMaksim Panchenko 1573143afb40SMaksim Panchenko return Error::success(); 1574143afb40SMaksim Panchenko } 1575143afb40SMaksim Panchenko 1576ad2905e5SMaksim Panchenko void LinuxKernelRewriter::processAltInstructionsPostCFG() { 1577ad2905e5SMaksim Panchenko // Disable optimization and output of functions with alt instructions before 1578ad2905e5SMaksim Panchenko // the rewrite support is complete. Alt instructions can modify the control 1579ad2905e5SMaksim Panchenko // flow, hence we may end up deleting seemingly unreachable code. 158056197d73SMaksim Panchenko skipFunctionsWithAnnotation("AltInst"); 158156197d73SMaksim Panchenko } 158256197d73SMaksim Panchenko 1583fd32e744SMaksim Panchenko /// When the Linux kernel needs to handle an error associated with a given PCI 1584fd32e744SMaksim Panchenko /// device, it uses a table stored in .pci_fixup section to locate a fixup code 1585fd32e744SMaksim Panchenko /// specific to the vendor and the problematic device. The section contains a 1586fd32e744SMaksim Panchenko /// list of the following structures defined in include/linux/pci.h: 1587fd32e744SMaksim Panchenko /// 1588fd32e744SMaksim Panchenko /// struct pci_fixup { 1589fd32e744SMaksim Panchenko /// u16 vendor; /* Or PCI_ANY_ID */ 1590fd32e744SMaksim Panchenko /// u16 device; /* Or PCI_ANY_ID */ 1591fd32e744SMaksim Panchenko /// u32 class; /* Or PCI_ANY_ID */ 1592fd32e744SMaksim Panchenko /// unsigned int class_shift; /* should be 0, 8, 16 */ 1593fd32e744SMaksim Panchenko /// int hook_offset; 1594fd32e744SMaksim Panchenko /// }; 1595fd32e744SMaksim Panchenko /// 1596fd32e744SMaksim Panchenko /// Normally, the hook will point to a function start and we don't have to 1597fd32e744SMaksim Panchenko /// update the pointer if we are not relocating functions. Hence, while reading 1598fd32e744SMaksim Panchenko /// the table we validate this assumption. If a function has a fixup code in the 1599fd32e744SMaksim Panchenko /// middle of its body, we issue a warning and ignore it. 1600fd32e744SMaksim Panchenko Error LinuxKernelRewriter::readPCIFixupTable() { 1601fd32e744SMaksim Panchenko PCIFixupSection = BC.getUniqueSectionByName(".pci_fixup"); 1602fd32e744SMaksim Panchenko if (!PCIFixupSection) 1603fd32e744SMaksim Panchenko return Error::success(); 1604fd32e744SMaksim Panchenko 1605fd32e744SMaksim Panchenko if (PCIFixupSection->getSize() % PCI_FIXUP_ENTRY_SIZE) 1606fd32e744SMaksim Panchenko return createStringError(errc::executable_format_error, 1607fd32e744SMaksim Panchenko "PCI fixup table size error"); 1608fd32e744SMaksim Panchenko 160921684e38SMaksim Panchenko AddressExtractor AE( 161021684e38SMaksim Panchenko PCIFixupSection->getContents(), PCIFixupSection->getAddress(), 161121684e38SMaksim Panchenko BC.AsmInfo->isLittleEndian(), BC.AsmInfo->getCodePointerSize()); 161221684e38SMaksim Panchenko AddressExtractor::Cursor Cursor(0); 1613fd32e744SMaksim Panchenko uint64_t EntryID = 0; 161421684e38SMaksim Panchenko while (Cursor && !AE.eof(Cursor)) { 161521684e38SMaksim Panchenko const uint16_t Vendor = AE.getU16(Cursor); 161621684e38SMaksim Panchenko const uint16_t Device = AE.getU16(Cursor); 161721684e38SMaksim Panchenko const uint32_t Class = AE.getU32(Cursor); 161821684e38SMaksim Panchenko const uint32_t ClassShift = AE.getU32(Cursor); 161921684e38SMaksim Panchenko const uint64_t HookAddress = AE.getPCRelAddress32(Cursor); 1620fd32e744SMaksim Panchenko 1621fd32e744SMaksim Panchenko if (!Cursor) 1622fd32e744SMaksim Panchenko return createStringError(errc::executable_format_error, 1623fd32e744SMaksim Panchenko "out of bounds while reading .pci_fixup: %s", 1624fd32e744SMaksim Panchenko toString(Cursor.takeError()).c_str()); 1625fd32e744SMaksim Panchenko 1626fd32e744SMaksim Panchenko ++EntryID; 1627fd32e744SMaksim Panchenko 1628fd32e744SMaksim Panchenko if (opts::DumpPCIFixups) { 1629fd32e744SMaksim Panchenko BC.outs() << "PCI fixup entry: " << EntryID << "\n\tVendor 0x" 1630fd32e744SMaksim Panchenko << Twine::utohexstr(Vendor) << "\n\tDevice: 0x" 1631fd32e744SMaksim Panchenko << Twine::utohexstr(Device) << "\n\tClass: 0x" 1632fd32e744SMaksim Panchenko << Twine::utohexstr(Class) << "\n\tClassShift: 0x" 1633fd32e744SMaksim Panchenko << Twine::utohexstr(ClassShift) << "\n\tHookAddress: 0x" 1634fd32e744SMaksim Panchenko << Twine::utohexstr(HookAddress) << '\n'; 1635fd32e744SMaksim Panchenko } 1636fd32e744SMaksim Panchenko 1637fd32e744SMaksim Panchenko BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(HookAddress); 1638fd32e744SMaksim Panchenko if (!BF && opts::Verbosity) { 1639fd32e744SMaksim Panchenko BC.outs() << "BOLT-INFO: no function matches address 0x" 1640fd32e744SMaksim Panchenko << Twine::utohexstr(HookAddress) 1641fd32e744SMaksim Panchenko << " of hook from .pci_fixup\n"; 1642fd32e744SMaksim Panchenko } 1643fd32e744SMaksim Panchenko 1644fd32e744SMaksim Panchenko if (!BF || !BC.shouldEmit(*BF)) 1645fd32e744SMaksim Panchenko continue; 1646fd32e744SMaksim Panchenko 1647fd32e744SMaksim Panchenko if (const uint64_t Offset = HookAddress - BF->getAddress()) { 1648fd32e744SMaksim Panchenko BC.errs() << "BOLT-WARNING: PCI fixup detected in the middle of function " 1649fd32e744SMaksim Panchenko << *BF << " at offset 0x" << Twine::utohexstr(Offset) << '\n'; 1650fd32e744SMaksim Panchenko BF->setSimple(false); 1651fd32e744SMaksim Panchenko } 1652fd32e744SMaksim Panchenko } 1653fd32e744SMaksim Panchenko 1654fd32e744SMaksim Panchenko BC.outs() << "BOLT-INFO: parsed " << EntryID << " PCI fixup entries\n"; 1655fd32e744SMaksim Panchenko 1656fd32e744SMaksim Panchenko return Error::success(); 1657fd32e744SMaksim Panchenko } 1658fd32e744SMaksim Panchenko 16596b1cf004SMaksim Panchenko /// Runtime code modification used by static keys is the most ubiquitous 16606b1cf004SMaksim Panchenko /// self-modifying feature of the Linux kernel. The idea is to eliminate the 16616b1cf004SMaksim Panchenko /// condition check and associated conditional jump on a hot path if that 16626b1cf004SMaksim Panchenko /// condition (based on a boolean value of a static key) does not change often. 16636b1cf004SMaksim Panchenko /// Whenever the condition changes, the kernel runtime modifies all code paths 16646b1cf004SMaksim Panchenko /// associated with that key flipping the code between nop and (unconditional) 16656b1cf004SMaksim Panchenko /// jump. The information about the code is stored in a static key jump table 16666b1cf004SMaksim Panchenko /// and contains the list of entries of the following type from 16676b1cf004SMaksim Panchenko /// include/linux/jump_label.h: 16686b1cf004SMaksim Panchenko // 16696b1cf004SMaksim Panchenko /// struct jump_entry { 16706b1cf004SMaksim Panchenko /// s32 code; 16716b1cf004SMaksim Panchenko /// s32 target; 16726b1cf004SMaksim Panchenko /// long key; // key may be far away from the core kernel under KASLR 16736b1cf004SMaksim Panchenko /// }; 16746b1cf004SMaksim Panchenko /// 16756b1cf004SMaksim Panchenko /// The list does not have to be stored in any sorted way, but it is sorted at 16766b1cf004SMaksim Panchenko /// boot time (or module initialization time) first by "key" and then by "code". 16776b1cf004SMaksim Panchenko /// jump_label_sort_entries() is responsible for sorting the table. 16786b1cf004SMaksim Panchenko /// 16796b1cf004SMaksim Panchenko /// The key in jump_entry structure uses lower two bits of the key address 16806b1cf004SMaksim Panchenko /// (which itself is aligned) to store extra information. We are interested in 16816b1cf004SMaksim Panchenko /// the lower bit which indicates if the key is likely to be set on the code 16826b1cf004SMaksim Panchenko /// path associated with this jump_entry. 16836b1cf004SMaksim Panchenko /// 16846b1cf004SMaksim Panchenko /// static_key_{enable,disable}() functions modify the code based on key and 16856b1cf004SMaksim Panchenko /// jump table entries. 16866b1cf004SMaksim Panchenko /// 16876b1cf004SMaksim Panchenko /// jump_label_update() updates all code entries for a given key. Batch mode is 16886b1cf004SMaksim Panchenko /// used for x86. 16896b1cf004SMaksim Panchenko /// 16906b1cf004SMaksim Panchenko /// The actual patching happens in text_poke_bp_batch() that overrides the first 16916b1cf004SMaksim Panchenko /// byte of the sequence with int3 before proceeding with actual code 16926b1cf004SMaksim Panchenko /// replacement. 16936b1cf004SMaksim Panchenko Error LinuxKernelRewriter::readStaticKeysJumpTable() { 16946b1cf004SMaksim Panchenko const BinaryData *StaticKeysJumpTable = 16956b1cf004SMaksim Panchenko BC.getBinaryDataByName("__start___jump_table"); 16966b1cf004SMaksim Panchenko if (!StaticKeysJumpTable) 16976b1cf004SMaksim Panchenko return Error::success(); 16986b1cf004SMaksim Panchenko 16996b1cf004SMaksim Panchenko StaticKeysJumpTableAddress = StaticKeysJumpTable->getAddress(); 17006b1cf004SMaksim Panchenko 17016b1cf004SMaksim Panchenko const BinaryData *Stop = BC.getBinaryDataByName("__stop___jump_table"); 17026b1cf004SMaksim Panchenko if (!Stop) 17036b1cf004SMaksim Panchenko return createStringError(errc::executable_format_error, 17046b1cf004SMaksim Panchenko "missing __stop___jump_table symbol"); 17056b1cf004SMaksim Panchenko 17066b1cf004SMaksim Panchenko ErrorOr<BinarySection &> ErrorOrSection = 17076b1cf004SMaksim Panchenko BC.getSectionForAddress(StaticKeysJumpTableAddress); 17086b1cf004SMaksim Panchenko if (!ErrorOrSection) 17096b1cf004SMaksim Panchenko return createStringError(errc::executable_format_error, 17106b1cf004SMaksim Panchenko "no section matching __start___jump_table"); 17116b1cf004SMaksim Panchenko 17126b1cf004SMaksim Panchenko StaticKeysJumpSection = *ErrorOrSection; 17136b1cf004SMaksim Panchenko if (!StaticKeysJumpSection->containsAddress(Stop->getAddress() - 1)) 17146b1cf004SMaksim Panchenko return createStringError(errc::executable_format_error, 17156b1cf004SMaksim Panchenko "__stop___jump_table not in the same section " 17166b1cf004SMaksim Panchenko "as __start___jump_table"); 17176b1cf004SMaksim Panchenko 17186b1cf004SMaksim Panchenko if ((Stop->getAddress() - StaticKeysJumpTableAddress) % 17196b1cf004SMaksim Panchenko STATIC_KEYS_JUMP_ENTRY_SIZE) 17206b1cf004SMaksim Panchenko return createStringError(errc::executable_format_error, 17216b1cf004SMaksim Panchenko "static keys jump table size error"); 17226b1cf004SMaksim Panchenko 17236b1cf004SMaksim Panchenko const uint64_t SectionAddress = StaticKeysJumpSection->getAddress(); 172421684e38SMaksim Panchenko AddressExtractor AE(StaticKeysJumpSection->getContents(), SectionAddress, 17256b1cf004SMaksim Panchenko BC.AsmInfo->isLittleEndian(), 17266b1cf004SMaksim Panchenko BC.AsmInfo->getCodePointerSize()); 172721684e38SMaksim Panchenko AddressExtractor::Cursor Cursor(StaticKeysJumpTableAddress - SectionAddress); 17286b1cf004SMaksim Panchenko uint32_t EntryID = 0; 17296b1cf004SMaksim Panchenko while (Cursor && Cursor.tell() < Stop->getAddress() - SectionAddress) { 173021684e38SMaksim Panchenko const uint64_t JumpAddress = AE.getPCRelAddress32(Cursor); 173121684e38SMaksim Panchenko const uint64_t TargetAddress = AE.getPCRelAddress32(Cursor); 173221684e38SMaksim Panchenko const uint64_t KeyAddress = AE.getPCRelAddress64(Cursor); 17336b1cf004SMaksim Panchenko 17346b1cf004SMaksim Panchenko // Consume the status of the cursor. 17356b1cf004SMaksim Panchenko if (!Cursor) 17366b1cf004SMaksim Panchenko return createStringError( 17376b1cf004SMaksim Panchenko errc::executable_format_error, 17386b1cf004SMaksim Panchenko "out of bounds while reading static keys jump table: %s", 17396b1cf004SMaksim Panchenko toString(Cursor.takeError()).c_str()); 17406b1cf004SMaksim Panchenko 17416b1cf004SMaksim Panchenko ++EntryID; 17426b1cf004SMaksim Panchenko 17436b1cf004SMaksim Panchenko JumpInfo.push_back(JumpInfoEntry()); 17446b1cf004SMaksim Panchenko JumpInfoEntry &Info = JumpInfo.back(); 17456b1cf004SMaksim Panchenko Info.Likely = KeyAddress & 1; 17466b1cf004SMaksim Panchenko 17476b1cf004SMaksim Panchenko if (opts::DumpStaticKeys) { 17486b1cf004SMaksim Panchenko BC.outs() << "Static key jump entry: " << EntryID 17496b1cf004SMaksim Panchenko << "\n\tJumpAddress: 0x" << Twine::utohexstr(JumpAddress) 17506b1cf004SMaksim Panchenko << "\n\tTargetAddress: 0x" << Twine::utohexstr(TargetAddress) 17516b1cf004SMaksim Panchenko << "\n\tKeyAddress: 0x" << Twine::utohexstr(KeyAddress) 17526b1cf004SMaksim Panchenko << "\n\tIsLikely: " << Info.Likely << '\n'; 17536b1cf004SMaksim Panchenko } 17546b1cf004SMaksim Panchenko 17556b1cf004SMaksim Panchenko BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(JumpAddress); 17566b1cf004SMaksim Panchenko if (!BF && opts::Verbosity) { 17576b1cf004SMaksim Panchenko BC.outs() 17586b1cf004SMaksim Panchenko << "BOLT-INFO: no function matches address 0x" 17596b1cf004SMaksim Panchenko << Twine::utohexstr(JumpAddress) 17606b1cf004SMaksim Panchenko << " of jump instruction referenced from static keys jump table\n"; 17616b1cf004SMaksim Panchenko } 17626b1cf004SMaksim Panchenko 17636b1cf004SMaksim Panchenko if (!BF || !BC.shouldEmit(*BF)) 17646b1cf004SMaksim Panchenko continue; 17656b1cf004SMaksim Panchenko 17666b1cf004SMaksim Panchenko MCInst *Inst = BF->getInstructionAtOffset(JumpAddress - BF->getAddress()); 17676b1cf004SMaksim Panchenko if (!Inst) 17686b1cf004SMaksim Panchenko return createStringError( 17696b1cf004SMaksim Panchenko errc::executable_format_error, 17706b1cf004SMaksim Panchenko "no instruction at static keys jump site address 0x%" PRIx64, 17716b1cf004SMaksim Panchenko JumpAddress); 17726b1cf004SMaksim Panchenko 17736b1cf004SMaksim Panchenko if (!BF->containsAddress(TargetAddress)) 17746b1cf004SMaksim Panchenko return createStringError( 17756b1cf004SMaksim Panchenko errc::executable_format_error, 17766b1cf004SMaksim Panchenko "invalid target of static keys jump at 0x%" PRIx64 " : 0x%" PRIx64, 17776b1cf004SMaksim Panchenko JumpAddress, TargetAddress); 17786b1cf004SMaksim Panchenko 17796b1cf004SMaksim Panchenko const bool IsBranch = BC.MIB->isBranch(*Inst); 17806b1cf004SMaksim Panchenko if (!IsBranch && !BC.MIB->isNoop(*Inst)) 17816b1cf004SMaksim Panchenko return createStringError(errc::executable_format_error, 17826b1cf004SMaksim Panchenko "jump or nop expected at address 0x%" PRIx64, 17836b1cf004SMaksim Panchenko JumpAddress); 17846b1cf004SMaksim Panchenko 17856b1cf004SMaksim Panchenko const uint64_t Size = BC.computeInstructionSize(*Inst); 17866b1cf004SMaksim Panchenko if (Size != 2 && Size != 5) { 17876b1cf004SMaksim Panchenko return createStringError( 17886b1cf004SMaksim Panchenko errc::executable_format_error, 17896b1cf004SMaksim Panchenko "unexpected static keys jump size at address 0x%" PRIx64, 17906b1cf004SMaksim Panchenko JumpAddress); 17916b1cf004SMaksim Panchenko } 17926b1cf004SMaksim Panchenko 17936b1cf004SMaksim Panchenko MCSymbol *Target = BF->registerBranch(JumpAddress, TargetAddress); 17946b1cf004SMaksim Panchenko MCInst StaticKeyBranch; 17956b1cf004SMaksim Panchenko 17966b1cf004SMaksim Panchenko // Create a conditional branch instruction. The actual conditional code type 17976b1cf004SMaksim Panchenko // should not matter as long as it's a valid code. The instruction should be 17986b1cf004SMaksim Panchenko // treated as a conditional branch for control-flow purposes. Before we emit 17996b1cf004SMaksim Panchenko // the code, it will be converted to a different instruction in 18006b1cf004SMaksim Panchenko // rewriteStaticKeysJumpTable(). 18016b1cf004SMaksim Panchenko // 18026b1cf004SMaksim Panchenko // NB: for older kernels, under LongJumpLabels option, we create long 18036b1cf004SMaksim Panchenko // conditional branch to guarantee that code size estimation takes 18046b1cf004SMaksim Panchenko // into account the extra bytes needed for long branch that will be used 18056b1cf004SMaksim Panchenko // by the kernel patching code. Newer kernels can work with both short 18066b1cf004SMaksim Panchenko // and long branches. The code for long conditional branch is larger 18076b1cf004SMaksim Panchenko // than unconditional one, so we are pessimistic in our estimations. 18086b1cf004SMaksim Panchenko if (opts::LongJumpLabels) 18096b1cf004SMaksim Panchenko BC.MIB->createLongCondBranch(StaticKeyBranch, Target, 0, BC.Ctx.get()); 18106b1cf004SMaksim Panchenko else 18116b1cf004SMaksim Panchenko BC.MIB->createCondBranch(StaticKeyBranch, Target, 0, BC.Ctx.get()); 18126b1cf004SMaksim Panchenko BC.MIB->moveAnnotations(std::move(*Inst), StaticKeyBranch); 18136b1cf004SMaksim Panchenko BC.MIB->setDynamicBranch(StaticKeyBranch, EntryID); 18146b1cf004SMaksim Panchenko *Inst = StaticKeyBranch; 18156b1cf004SMaksim Panchenko 18166b1cf004SMaksim Panchenko // IsBranch = InitialValue ^ LIKELY 18176b1cf004SMaksim Panchenko // 18186b1cf004SMaksim Panchenko // 0 0 0 18196b1cf004SMaksim Panchenko // 1 0 1 18206b1cf004SMaksim Panchenko // 1 1 0 18216b1cf004SMaksim Panchenko // 0 1 1 18226b1cf004SMaksim Panchenko // 18236b1cf004SMaksim Panchenko // => InitialValue = IsBranch ^ LIKELY 18246b1cf004SMaksim Panchenko Info.InitValue = IsBranch ^ Info.Likely; 18256b1cf004SMaksim Panchenko 18266b1cf004SMaksim Panchenko // Add annotations to facilitate manual code analysis. 18276b1cf004SMaksim Panchenko BC.MIB->addAnnotation(*Inst, "Likely", Info.Likely); 18286b1cf004SMaksim Panchenko BC.MIB->addAnnotation(*Inst, "InitValue", Info.InitValue); 18296b1cf004SMaksim Panchenko if (!BC.MIB->getSize(*Inst)) 18306b1cf004SMaksim Panchenko BC.MIB->setSize(*Inst, Size); 18316b1cf004SMaksim Panchenko 183259ab2921SMaksim Panchenko if (!BC.MIB->getOffset(*Inst)) 183359ab2921SMaksim Panchenko BC.MIB->setOffset(*Inst, JumpAddress - BF->getAddress()); 183459ab2921SMaksim Panchenko 18356b1cf004SMaksim Panchenko if (opts::LongJumpLabels) 18366b1cf004SMaksim Panchenko BC.MIB->setSize(*Inst, 5); 18376b1cf004SMaksim Panchenko } 18386b1cf004SMaksim Panchenko 18396b1cf004SMaksim Panchenko BC.outs() << "BOLT-INFO: parsed " << EntryID << " static keys jump entries\n"; 18406b1cf004SMaksim Panchenko 18416b1cf004SMaksim Panchenko return Error::success(); 18426b1cf004SMaksim Panchenko } 18436b1cf004SMaksim Panchenko 18446b1cf004SMaksim Panchenko // Pre-emit pass. Convert dynamic branch instructions into jumps that could be 18456b1cf004SMaksim Panchenko // relaxed. In post-emit pass we will convert those jumps into nops when 18466b1cf004SMaksim Panchenko // necessary. We do the unconditional conversion into jumps so that the jumps 18476b1cf004SMaksim Panchenko // can be relaxed and the optimal size of jump/nop instruction is selected. 18486b1cf004SMaksim Panchenko Error LinuxKernelRewriter::rewriteStaticKeysJumpTable() { 18496b1cf004SMaksim Panchenko if (!StaticKeysJumpSection) 18506b1cf004SMaksim Panchenko return Error::success(); 18516b1cf004SMaksim Panchenko 18526b1cf004SMaksim Panchenko uint64_t NumShort = 0; 18536b1cf004SMaksim Panchenko uint64_t NumLong = 0; 18546b1cf004SMaksim Panchenko for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { 18556b1cf004SMaksim Panchenko if (!BC.shouldEmit(BF)) 18566b1cf004SMaksim Panchenko continue; 18576b1cf004SMaksim Panchenko 18586b1cf004SMaksim Panchenko for (BinaryBasicBlock &BB : BF) { 18596b1cf004SMaksim Panchenko for (MCInst &Inst : BB) { 18606b1cf004SMaksim Panchenko if (!BC.MIB->isDynamicBranch(Inst)) 18616b1cf004SMaksim Panchenko continue; 18626b1cf004SMaksim Panchenko 18636b1cf004SMaksim Panchenko const uint32_t EntryID = *BC.MIB->getDynamicBranchID(Inst); 18646b1cf004SMaksim Panchenko MCSymbol *Target = 18656b1cf004SMaksim Panchenko const_cast<MCSymbol *>(BC.MIB->getTargetSymbol(Inst)); 18666b1cf004SMaksim Panchenko assert(Target && "Target symbol should be set."); 18676b1cf004SMaksim Panchenko 18686b1cf004SMaksim Panchenko const JumpInfoEntry &Info = JumpInfo[EntryID - 1]; 18696b1cf004SMaksim Panchenko const bool IsBranch = Info.Likely ^ Info.InitValue; 18706b1cf004SMaksim Panchenko 18716b1cf004SMaksim Panchenko uint32_t Size = *BC.MIB->getSize(Inst); 18726b1cf004SMaksim Panchenko if (Size == 2) 18736b1cf004SMaksim Panchenko ++NumShort; 18746b1cf004SMaksim Panchenko else if (Size == 5) 18756b1cf004SMaksim Panchenko ++NumLong; 18766b1cf004SMaksim Panchenko else 18776b1cf004SMaksim Panchenko llvm_unreachable("Wrong size for static keys jump instruction."); 18786b1cf004SMaksim Panchenko 18796b1cf004SMaksim Panchenko MCInst NewInst; 18806b1cf004SMaksim Panchenko // Replace the instruction with unconditional jump even if it needs to 18816b1cf004SMaksim Panchenko // be nop in the binary. 18826b1cf004SMaksim Panchenko if (opts::LongJumpLabels) { 18836b1cf004SMaksim Panchenko BC.MIB->createLongUncondBranch(NewInst, Target, BC.Ctx.get()); 18846b1cf004SMaksim Panchenko } else { 18856b1cf004SMaksim Panchenko // Newer kernels can handle short and long jumps for static keys. 18866b1cf004SMaksim Panchenko // Optimistically, emit short jump and check if it gets relaxed into 18876b1cf004SMaksim Panchenko // a long one during post-emit. Only then convert the jump to a nop. 18886b1cf004SMaksim Panchenko BC.MIB->createUncondBranch(NewInst, Target, BC.Ctx.get()); 18896b1cf004SMaksim Panchenko } 18906b1cf004SMaksim Panchenko 18916b1cf004SMaksim Panchenko BC.MIB->moveAnnotations(std::move(Inst), NewInst); 18926b1cf004SMaksim Panchenko Inst = NewInst; 18936b1cf004SMaksim Panchenko 18946b1cf004SMaksim Panchenko // Mark the instruction for nop conversion. 18956b1cf004SMaksim Panchenko if (!IsBranch) 18966b1cf004SMaksim Panchenko NopIDs.insert(EntryID); 18976b1cf004SMaksim Panchenko 18986b1cf004SMaksim Panchenko MCSymbol *Label = 18996b1cf004SMaksim Panchenko BC.MIB->getOrCreateInstLabel(Inst, "__SK_", BC.Ctx.get()); 19006b1cf004SMaksim Panchenko 19016b1cf004SMaksim Panchenko // Create a relocation against the label. 19026b1cf004SMaksim Panchenko const uint64_t EntryOffset = StaticKeysJumpTableAddress - 19036b1cf004SMaksim Panchenko StaticKeysJumpSection->getAddress() + 19046b1cf004SMaksim Panchenko (EntryID - 1) * 16; 19056b1cf004SMaksim Panchenko StaticKeysJumpSection->addRelocation(EntryOffset, Label, 19066b1cf004SMaksim Panchenko ELF::R_X86_64_PC32, 19076b1cf004SMaksim Panchenko /*Addend*/ 0); 19086b1cf004SMaksim Panchenko StaticKeysJumpSection->addRelocation(EntryOffset + 4, Target, 19096b1cf004SMaksim Panchenko ELF::R_X86_64_PC32, /*Addend*/ 0); 19106b1cf004SMaksim Panchenko } 19116b1cf004SMaksim Panchenko } 19126b1cf004SMaksim Panchenko } 19136b1cf004SMaksim Panchenko 19146b1cf004SMaksim Panchenko BC.outs() << "BOLT-INFO: the input contains " << NumShort << " short and " 19156b1cf004SMaksim Panchenko << NumLong << " long static keys jumps in optimized functions\n"; 19166b1cf004SMaksim Panchenko 19176b1cf004SMaksim Panchenko return Error::success(); 19186b1cf004SMaksim Panchenko } 19196b1cf004SMaksim Panchenko 19206b1cf004SMaksim Panchenko // Post-emit pass of static keys jump section. Convert jumps to nops. 19216b1cf004SMaksim Panchenko Error LinuxKernelRewriter::updateStaticKeysJumpTablePostEmit() { 19226b1cf004SMaksim Panchenko if (!StaticKeysJumpSection || !StaticKeysJumpSection->isFinalized()) 19236b1cf004SMaksim Panchenko return Error::success(); 19246b1cf004SMaksim Panchenko 19256b1cf004SMaksim Panchenko const uint64_t SectionAddress = StaticKeysJumpSection->getAddress(); 192621684e38SMaksim Panchenko AddressExtractor AE(StaticKeysJumpSection->getOutputContents(), 192721684e38SMaksim Panchenko SectionAddress, BC.AsmInfo->isLittleEndian(), 19286b1cf004SMaksim Panchenko BC.AsmInfo->getCodePointerSize()); 192921684e38SMaksim Panchenko AddressExtractor::Cursor Cursor(StaticKeysJumpTableAddress - SectionAddress); 19306b1cf004SMaksim Panchenko const BinaryData *Stop = BC.getBinaryDataByName("__stop___jump_table"); 19316b1cf004SMaksim Panchenko uint32_t EntryID = 0; 19326b1cf004SMaksim Panchenko uint64_t NumShort = 0; 19336b1cf004SMaksim Panchenko uint64_t NumLong = 0; 19346b1cf004SMaksim Panchenko while (Cursor && Cursor.tell() < Stop->getAddress() - SectionAddress) { 193521684e38SMaksim Panchenko const uint64_t JumpAddress = AE.getPCRelAddress32(Cursor); 193621684e38SMaksim Panchenko const uint64_t TargetAddress = AE.getPCRelAddress32(Cursor); 193721684e38SMaksim Panchenko const uint64_t KeyAddress = AE.getPCRelAddress64(Cursor); 19386b1cf004SMaksim Panchenko 19396b1cf004SMaksim Panchenko // Consume the status of the cursor. 19406b1cf004SMaksim Panchenko if (!Cursor) 19416b1cf004SMaksim Panchenko return createStringError(errc::executable_format_error, 19426b1cf004SMaksim Panchenko "out of bounds while updating static keys: %s", 19436b1cf004SMaksim Panchenko toString(Cursor.takeError()).c_str()); 19446b1cf004SMaksim Panchenko 19456b1cf004SMaksim Panchenko ++EntryID; 19466b1cf004SMaksim Panchenko 19476b1cf004SMaksim Panchenko LLVM_DEBUG({ 19486b1cf004SMaksim Panchenko dbgs() << "\n\tJumpAddress: 0x" << Twine::utohexstr(JumpAddress) 19496b1cf004SMaksim Panchenko << "\n\tTargetAddress: 0x" << Twine::utohexstr(TargetAddress) 19506b1cf004SMaksim Panchenko << "\n\tKeyAddress: 0x" << Twine::utohexstr(KeyAddress) << '\n'; 19516b1cf004SMaksim Panchenko }); 19524865dab0SKazu Hirata (void)TargetAddress; 19534865dab0SKazu Hirata (void)KeyAddress; 19546b1cf004SMaksim Panchenko 19556b1cf004SMaksim Panchenko BinaryFunction *BF = 19566b1cf004SMaksim Panchenko BC.getBinaryFunctionContainingAddress(JumpAddress, 19576b1cf004SMaksim Panchenko /*CheckPastEnd*/ false, 19586b1cf004SMaksim Panchenko /*UseMaxSize*/ true); 19596b1cf004SMaksim Panchenko assert(BF && "Cannot get function for modified static key."); 19606b1cf004SMaksim Panchenko 19616b1cf004SMaksim Panchenko if (!BF->isEmitted()) 19626b1cf004SMaksim Panchenko continue; 19636b1cf004SMaksim Panchenko 19646b1cf004SMaksim Panchenko // Disassemble instruction to collect stats even if nop-conversion is 19656b1cf004SMaksim Panchenko // unnecessary. 19666b1cf004SMaksim Panchenko MutableArrayRef<uint8_t> Contents = MutableArrayRef<uint8_t>( 19676b1cf004SMaksim Panchenko reinterpret_cast<uint8_t *>(BF->getImageAddress()), BF->getImageSize()); 19686b1cf004SMaksim Panchenko assert(Contents.size() && "Non-empty function image expected."); 19696b1cf004SMaksim Panchenko 19706b1cf004SMaksim Panchenko MCInst Inst; 19716b1cf004SMaksim Panchenko uint64_t Size; 19726b1cf004SMaksim Panchenko const uint64_t JumpOffset = JumpAddress - BF->getAddress(); 19736b1cf004SMaksim Panchenko if (!BC.DisAsm->getInstruction(Inst, Size, Contents.slice(JumpOffset), 0, 19746b1cf004SMaksim Panchenko nulls())) { 19756b1cf004SMaksim Panchenko llvm_unreachable("Unable to disassemble jump instruction."); 19766b1cf004SMaksim Panchenko } 19776b1cf004SMaksim Panchenko assert(BC.MIB->isBranch(Inst) && "Branch instruction expected."); 19786b1cf004SMaksim Panchenko 19796b1cf004SMaksim Panchenko if (Size == 2) 19806b1cf004SMaksim Panchenko ++NumShort; 19816b1cf004SMaksim Panchenko else if (Size == 5) 19826b1cf004SMaksim Panchenko ++NumLong; 19836b1cf004SMaksim Panchenko else 19846b1cf004SMaksim Panchenko llvm_unreachable("Unexpected size for static keys jump instruction."); 19856b1cf004SMaksim Panchenko 19866b1cf004SMaksim Panchenko // Check if we need to convert jump instruction into a nop. 19876b1cf004SMaksim Panchenko if (!NopIDs.contains(EntryID)) 19886b1cf004SMaksim Panchenko continue; 19896b1cf004SMaksim Panchenko 19906b1cf004SMaksim Panchenko SmallString<15> NopCode; 19916b1cf004SMaksim Panchenko raw_svector_ostream VecOS(NopCode); 19926b1cf004SMaksim Panchenko BC.MAB->writeNopData(VecOS, Size, BC.STI.get()); 19936b1cf004SMaksim Panchenko for (uint64_t I = 0; I < Size; ++I) 19946b1cf004SMaksim Panchenko Contents[JumpOffset + I] = NopCode[I]; 19956b1cf004SMaksim Panchenko } 19966b1cf004SMaksim Panchenko 19976b1cf004SMaksim Panchenko BC.outs() << "BOLT-INFO: written " << NumShort << " short and " << NumLong 19986b1cf004SMaksim Panchenko << " long static keys jumps in optimized functions\n"; 19996b1cf004SMaksim Panchenko 20006b1cf004SMaksim Panchenko return Error::success(); 20016b1cf004SMaksim Panchenko } 20026b1cf004SMaksim Panchenko 200338639a81SMaksim Panchenko } // namespace 200438639a81SMaksim Panchenko 200538639a81SMaksim Panchenko std::unique_ptr<MetadataRewriter> 200638639a81SMaksim Panchenko llvm::bolt::createLinuxKernelRewriter(BinaryContext &BC) { 200738639a81SMaksim Panchenko return std::make_unique<LinuxKernelRewriter>(BC); 200838639a81SMaksim Panchenko } 2009