xref: /llvm-project/bolt/lib/Rewrite/LinuxKernelRewriter.cpp (revision 6e8a1a45a783c13e4cd19bfd20b7a56cab6f7d81)
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