1 //===---- ExecutionUtils.cpp - Utilities for executing functions in lli ---===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ExecutionUtils.h" 10 11 #include "llvm/Support/FileSystem.h" 12 #include "llvm/Support/FormatVariadic.h" 13 #include "llvm/Support/raw_ostream.h" 14 15 #include <cstdint> 16 #include <vector> 17 18 // Declarations follow the GDB JIT interface (version 1, 2009) and must match 19 // those of the DYLD used for testing. See: 20 // 21 // llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp 22 // llvm/lib/ExecutionEngine/GDBRegistrationListener.cpp 23 // 24 typedef enum { 25 JIT_NOACTION = 0, 26 JIT_REGISTER_FN, 27 JIT_UNREGISTER_FN 28 } jit_actions_t; 29 30 struct jit_code_entry { 31 struct jit_code_entry *next_entry; 32 struct jit_code_entry *prev_entry; 33 const char *symfile_addr; 34 uint64_t symfile_size; 35 }; 36 37 struct jit_descriptor { 38 uint32_t version; 39 // This should be jit_actions_t, but we want to be specific about the 40 // bit-width. 41 uint32_t action_flag; 42 struct jit_code_entry *relevant_entry; 43 struct jit_code_entry *first_entry; 44 }; 45 46 namespace llvm { 47 48 template <typename... Ts> static void outsv(const char *Fmt, Ts &&...Vals) { 49 outs() << formatv(Fmt, Vals...); 50 } 51 52 static const char *actionFlagToStr(uint32_t ActionFlag) { 53 switch (ActionFlag) { 54 case JIT_NOACTION: 55 return "JIT_NOACTION"; 56 case JIT_REGISTER_FN: 57 return "JIT_REGISTER_FN"; 58 case JIT_UNREGISTER_FN: 59 return "JIT_UNREGISTER_FN"; 60 } 61 return "<invalid action_flag>"; 62 } 63 64 // Sample output: 65 // 66 // Reading __jit_debug_descriptor at 0x0000000000404048 67 // 68 // Version: 0 69 // Action: JIT_REGISTER_FN 70 // 71 // Entry Symbol File Size Previous Entry 72 // [ 0] 0x0000000000451290 0x0000000000002000 200 0x0000000000000000 73 // [ 1] 0x0000000000451260 0x0000000000001000 100 0x0000000000451290 74 // ... 75 // 76 static void dumpDebugDescriptor(void *Addr) { 77 outsv("Reading __jit_debug_descriptor at {0}\n\n", Addr); 78 79 jit_descriptor *Descriptor = reinterpret_cast<jit_descriptor *>(Addr); 80 outsv("Version: {0}\n", Descriptor->version); 81 outsv("Action: {0}\n\n", actionFlagToStr(Descriptor->action_flag)); 82 outsv("{0,11} {1,24} {2,15} {3,14}\n", "Entry", "Symbol File", "Size", 83 "Previous Entry"); 84 85 unsigned Idx = 0; 86 for (auto *Entry = Descriptor->first_entry; Entry; Entry = Entry->next_entry) 87 outsv("[{0,2}] {1:X16} {2:X16} {3,8:D} {4}\n", Idx++, Entry, 88 reinterpret_cast<const void *>(Entry->symfile_addr), 89 Entry->symfile_size, Entry->prev_entry); 90 } 91 92 static LLIBuiltinFunctionGenerator *Generator = nullptr; 93 94 static void dumpDebugObjects(void *Addr) { 95 jit_descriptor *Descriptor = reinterpret_cast<jit_descriptor *>(Addr); 96 for (auto *Entry = Descriptor->first_entry; Entry; Entry = Entry->next_entry) 97 Generator->appendDebugObject(Entry->symfile_addr, Entry->symfile_size); 98 } 99 100 LLIBuiltinFunctionGenerator::LLIBuiltinFunctionGenerator( 101 std::vector<BuiltinFunctionKind> Enabled, orc::MangleAndInterner &Mangle) 102 : TestOut(nullptr) { 103 Generator = this; 104 for (BuiltinFunctionKind F : Enabled) { 105 switch (F) { 106 case BuiltinFunctionKind::DumpDebugDescriptor: 107 expose(Mangle("__dump_jit_debug_descriptor"), &dumpDebugDescriptor); 108 break; 109 case BuiltinFunctionKind::DumpDebugObjects: 110 expose(Mangle("__dump_jit_debug_objects"), &dumpDebugObjects); 111 TestOut = createToolOutput(); 112 break; 113 } 114 } 115 } 116 117 Error LLIBuiltinFunctionGenerator::tryToGenerate( 118 orc::LookupState &LS, orc::LookupKind K, orc::JITDylib &JD, 119 orc::JITDylibLookupFlags JDLookupFlags, 120 const orc::SymbolLookupSet &Symbols) { 121 orc::SymbolMap NewSymbols; 122 for (const auto &NameFlags : Symbols) { 123 auto It = BuiltinFunctions.find(NameFlags.first); 124 if (It != BuiltinFunctions.end()) 125 NewSymbols.insert(*It); 126 } 127 128 if (NewSymbols.empty()) 129 return Error::success(); 130 131 return JD.define(absoluteSymbols(std::move(NewSymbols))); 132 } 133 134 // static 135 std::unique_ptr<ToolOutputFile> 136 LLIBuiltinFunctionGenerator::createToolOutput() { 137 std::error_code EC; 138 auto TestOut = std::make_unique<ToolOutputFile>("-", EC, sys::fs::OF_None); 139 if (EC) { 140 errs() << "Error creating tool output file: " << EC.message() << '\n'; 141 exit(1); 142 } 143 return TestOut; 144 } 145 146 } // namespace llvm 147