blob: e86d93bd490dabde9cbf90dee5e23a1d79b6bde6 [file] [log] [blame]
Jim Grosbach0072cdb2011-03-18 17:11:39 +00001//===-- llvm-rtdyld.cpp - MCJIT Testing Tool ------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This is a testing tool for use with the MC-JIT LLVM components.
11//
12//===----------------------------------------------------------------------===//
13
Chandler Carruth4d88a1c2012-12-04 10:44:52 +000014#include "llvm/ADT/StringMap.h"
Andrew Kaylord55d7012013-01-25 22:50:58 +000015#include "llvm/DebugInfo/DIContext.h"
Andrew Kayloradc70562012-10-02 21:18:39 +000016#include "llvm/ExecutionEngine/ObjectBuffer.h"
Chandler Carruth4d88a1c2012-12-04 10:44:52 +000017#include "llvm/ExecutionEngine/ObjectImage.h"
18#include "llvm/ExecutionEngine/RuntimeDyld.h"
Rafael Espindola6e040c02013-04-26 20:07:33 +000019#include "llvm/Object/MachO.h"
Jim Grosbach0072cdb2011-03-18 17:11:39 +000020#include "llvm/Support/CommandLine.h"
Lang Hamesd311c0e2014-05-13 22:37:41 +000021#include "llvm/Support/DynamicLibrary.h"
Jim Grosbach0072cdb2011-03-18 17:11:39 +000022#include "llvm/Support/ManagedStatic.h"
23#include "llvm/Support/Memory.h"
24#include "llvm/Support/MemoryBuffer.h"
Alp Toker9f679322013-11-05 09:33:43 +000025#include "llvm/Support/PrettyStackTrace.h"
26#include "llvm/Support/Signals.h"
Jim Grosbach0072cdb2011-03-18 17:11:39 +000027#include "llvm/Support/raw_ostream.h"
Rafael Espindolaa6e9c3e2014-06-12 17:38:55 +000028#include <system_error>
Jim Grosbach0072cdb2011-03-18 17:11:39 +000029using namespace llvm;
30using namespace llvm::object;
Rafael Espindola3acea392014-06-12 21:46:39 +000031using std::error_code;
Jim Grosbach0072cdb2011-03-18 17:11:39 +000032
Jim Grosbach7cb41d72011-04-13 15:49:40 +000033static cl::list<std::string>
34InputFileList(cl::Positional, cl::ZeroOrMore,
35 cl::desc("<input file>"));
Jim Grosbach0072cdb2011-03-18 17:11:39 +000036
37enum ActionType {
Andrew Kaylord55d7012013-01-25 22:50:58 +000038 AC_Execute,
39 AC_PrintLineInfo
Jim Grosbach0072cdb2011-03-18 17:11:39 +000040};
41
42static cl::opt<ActionType>
43Action(cl::desc("Action to perform:"),
44 cl::init(AC_Execute),
45 cl::values(clEnumValN(AC_Execute, "execute",
46 "Load, link, and execute the inputs."),
Andrew Kaylord55d7012013-01-25 22:50:58 +000047 clEnumValN(AC_PrintLineInfo, "printline",
48 "Load, link, and print line information for each function."),
Jim Grosbach0072cdb2011-03-18 17:11:39 +000049 clEnumValEnd));
50
Jim Grosbachd35159a2011-04-13 15:38:30 +000051static cl::opt<std::string>
52EntryPoint("entry",
53 cl::desc("Function to call as entry point."),
54 cl::init("_main"));
55
Lang Hamesd311c0e2014-05-13 22:37:41 +000056static cl::list<std::string>
57Dylibs("dylib",
58 cl::desc("Add library."),
59 cl::ZeroOrMore);
60
Jim Grosbach0072cdb2011-03-18 17:11:39 +000061/* *** */
62
Jim Grosbach2dcef0502011-04-04 23:04:39 +000063// A trivial memory manager that doesn't do anything fancy, just uses the
64// support library allocation routines directly.
65class TrivialMemoryManager : public RTDyldMemoryManager {
66public:
Jim Grosbach3ed03f12011-04-12 00:23:32 +000067 SmallVector<sys::MemoryBlock, 16> FunctionMemory;
Jim Grosbacheff0a402012-01-16 22:26:39 +000068 SmallVector<sys::MemoryBlock, 16> DataMemory;
69
70 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
Craig Toppere56917c2014-03-08 08:27:28 +000071 unsigned SectionID,
72 StringRef SectionName) override;
Jim Grosbacheff0a402012-01-16 22:26:39 +000073 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
Filip Pizlo7aa695e02013-10-02 00:59:25 +000074 unsigned SectionID, StringRef SectionName,
Craig Toppere56917c2014-03-08 08:27:28 +000075 bool IsReadOnly) override;
Jim Grosbach3ed03f12011-04-12 00:23:32 +000076
Craig Toppere56917c2014-03-08 08:27:28 +000077 void *getPointerToNamedFunction(const std::string &Name,
78 bool AbortOnFailure = true) override {
Craig Toppere6cb63e2014-04-25 04:24:47 +000079 return nullptr;
Danil Malyshevbfee5422012-03-28 21:46:36 +000080 }
81
Craig Toppere56917c2014-03-08 08:27:28 +000082 bool finalizeMemory(std::string *ErrMsg) override { return false; }
Andrew Kaylora342cb92012-11-15 23:50:01 +000083
Danil Malyshev8c17fbd2012-05-16 18:50:11 +000084 // Invalidate instruction cache for sections with execute permissions.
85 // Some platforms with separate data cache and instruction cache require
86 // explicit cache flush, otherwise JIT code manipulations (like resolved
87 // relocations) will get to the data cache but not to the instruction cache.
88 virtual void invalidateInstructionCache();
Jim Grosbach2dcef0502011-04-04 23:04:39 +000089};
90
Jim Grosbacheff0a402012-01-16 22:26:39 +000091uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
92 unsigned Alignment,
Filip Pizlo7aa695e02013-10-02 00:59:25 +000093 unsigned SectionID,
94 StringRef SectionName) {
Craig Toppere6cb63e2014-04-25 04:24:47 +000095 sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, nullptr);
Danil Malyshev8c17fbd2012-05-16 18:50:11 +000096 FunctionMemory.push_back(MB);
97 return (uint8_t*)MB.base();
Jim Grosbacheff0a402012-01-16 22:26:39 +000098}
99
100uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
101 unsigned Alignment,
Andrew Kaylora342cb92012-11-15 23:50:01 +0000102 unsigned SectionID,
Filip Pizlo7aa695e02013-10-02 00:59:25 +0000103 StringRef SectionName,
Andrew Kaylora342cb92012-11-15 23:50:01 +0000104 bool IsReadOnly) {
Craig Toppere6cb63e2014-04-25 04:24:47 +0000105 sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, nullptr, nullptr);
Danil Malyshev8c17fbd2012-05-16 18:50:11 +0000106 DataMemory.push_back(MB);
107 return (uint8_t*)MB.base();
108}
109
110void TrivialMemoryManager::invalidateInstructionCache() {
111 for (int i = 0, e = FunctionMemory.size(); i != e; ++i)
112 sys::Memory::InvalidateInstructionCache(FunctionMemory[i].base(),
113 FunctionMemory[i].size());
114
115 for (int i = 0, e = DataMemory.size(); i != e; ++i)
116 sys::Memory::InvalidateInstructionCache(DataMemory[i].base(),
117 DataMemory[i].size());
Jim Grosbacheff0a402012-01-16 22:26:39 +0000118}
119
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000120static const char *ProgramName;
121
122static void Message(const char *Type, const Twine &Msg) {
123 errs() << ProgramName << ": " << Type << ": " << Msg << "\n";
124}
125
126static int Error(const Twine &Msg) {
127 Message("error", Msg);
128 return 1;
129}
130
Lang Hamesd311c0e2014-05-13 22:37:41 +0000131static void loadDylibs() {
132 for (const std::string &Dylib : Dylibs) {
133 if (sys::fs::is_regular_file(Dylib)) {
134 std::string ErrMsg;
135 if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))
136 llvm::errs() << "Error loading '" << Dylib << "': "
137 << ErrMsg << "\n";
138 } else
139 llvm::errs() << "Dylib not found: '" << Dylib << "'.\n";
140 }
141}
142
143
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000144/* *** */
145
Andrew Kaylord55d7012013-01-25 22:50:58 +0000146static int printLineInfoForInput() {
Lang Hamesd311c0e2014-05-13 22:37:41 +0000147 // Load any dylibs requested on the command line.
148 loadDylibs();
149
Andrew Kaylord55d7012013-01-25 22:50:58 +0000150 // If we don't have any input files, read from stdin.
151 if (!InputFileList.size())
152 InputFileList.push_back("-");
153 for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
154 // Instantiate a dynamic linker.
Benjamin Kramer9ce77082013-08-03 22:16:31 +0000155 TrivialMemoryManager MemMgr;
156 RuntimeDyld Dyld(&MemMgr);
Andrew Kaylord55d7012013-01-25 22:50:58 +0000157
158 // Load the input memory buffer.
Ahmed Charles56440fd2014-03-06 05:51:42 +0000159 std::unique_ptr<MemoryBuffer> InputBuffer;
160 std::unique_ptr<ObjectImage> LoadedObject;
Andrew Kaylord55d7012013-01-25 22:50:58 +0000161 if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i],
162 InputBuffer))
163 return Error("unable to read input: '" + ec.message() + "'");
164
165 // Load the object file
Ahmed Charles96c9d952014-03-05 10:19:29 +0000166 LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.release())));
Andrew Kaylord55d7012013-01-25 22:50:58 +0000167 if (!LoadedObject) {
168 return Error(Dyld.getErrorString());
169 }
170
171 // Resolve all the relocations we can.
172 Dyld.resolveRelocations();
173
Ahmed Charles56440fd2014-03-06 05:51:42 +0000174 std::unique_ptr<DIContext> Context(
175 DIContext::getDWARFContext(LoadedObject->getObjectFile()));
Andrew Kaylord55d7012013-01-25 22:50:58 +0000176
177 // Use symbol info to iterate functions in the object.
Andrew Kaylord55d7012013-01-25 22:50:58 +0000178 for (object::symbol_iterator I = LoadedObject->begin_symbols(),
179 E = LoadedObject->end_symbols();
Rafael Espindola5e812af2014-01-30 02:49:50 +0000180 I != E; ++I) {
Andrew Kaylord55d7012013-01-25 22:50:58 +0000181 object::SymbolRef::Type SymType;
182 if (I->getType(SymType)) continue;
183 if (SymType == object::SymbolRef::ST_Function) {
184 StringRef Name;
185 uint64_t Addr;
186 uint64_t Size;
187 if (I->getName(Name)) continue;
188 if (I->getAddress(Addr)) continue;
189 if (I->getSize(Size)) continue;
190
191 outs() << "Function: " << Name << ", Size = " << Size << "\n";
192
Andrew Kaylor9a8ff812013-01-26 00:28:05 +0000193 DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
194 DILineInfoTable::iterator Begin = Lines.begin();
195 DILineInfoTable::iterator End = Lines.end();
196 for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
197 outs() << " Line info @ " << It->first - Addr << ": "
Alexey Samsonovd0109992014-04-18 21:36:39 +0000198 << It->second.FileName << ", line:" << It->second.Line << "\n";
Andrew Kaylor9a8ff812013-01-26 00:28:05 +0000199 }
Andrew Kaylord55d7012013-01-25 22:50:58 +0000200 }
201 }
202 }
203
204 return 0;
205}
206
Jim Grosbach4d5284b2011-03-18 17:24:21 +0000207static int executeInput() {
Lang Hamesd311c0e2014-05-13 22:37:41 +0000208 // Load any dylibs requested on the command line.
209 loadDylibs();
210
Jim Grosbachf016b0a2011-03-21 22:15:52 +0000211 // Instantiate a dynamic linker.
Benjamin Kramer9ce77082013-08-03 22:16:31 +0000212 TrivialMemoryManager MemMgr;
213 RuntimeDyld Dyld(&MemMgr);
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000214
Jim Grosbach7cb41d72011-04-13 15:49:40 +0000215 // If we don't have any input files, read from stdin.
216 if (!InputFileList.size())
217 InputFileList.push_back("-");
218 for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
219 // Load the input memory buffer.
Ahmed Charles56440fd2014-03-06 05:51:42 +0000220 std::unique_ptr<MemoryBuffer> InputBuffer;
221 std::unique_ptr<ObjectImage> LoadedObject;
Jim Grosbach7cb41d72011-04-13 15:49:40 +0000222 if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i],
223 InputBuffer))
224 return Error("unable to read input: '" + ec.message() + "'");
225
Andrew Kayloradc70562012-10-02 21:18:39 +0000226 // Load the object file
Ahmed Charles96c9d952014-03-05 10:19:29 +0000227 LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.release())));
Andrew Kayloradc70562012-10-02 21:18:39 +0000228 if (!LoadedObject) {
Jim Grosbach7cb41d72011-04-13 15:49:40 +0000229 return Error(Dyld.getErrorString());
230 }
Jim Grosbach40411cc2011-03-22 18:19:42 +0000231 }
Jim Grosbach7cb41d72011-04-13 15:49:40 +0000232
Jim Grosbach733d3052011-04-12 21:20:41 +0000233 // Resolve all the relocations we can.
234 Dyld.resolveRelocations();
Danil Malyshev8c17fbd2012-05-16 18:50:11 +0000235 // Clear instruction cache before code will be executed.
Benjamin Kramer5d62ad22013-08-03 22:18:45 +0000236 MemMgr.invalidateInstructionCache();
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000237
Jim Grosbach7cb41d72011-04-13 15:49:40 +0000238 // FIXME: Error out if there are unresolved relocations.
239
Jim Grosbachd35159a2011-04-13 15:38:30 +0000240 // Get the address of the entry point (_main by default).
241 void *MainAddress = Dyld.getSymbolAddress(EntryPoint);
Craig Toppere6cb63e2014-04-25 04:24:47 +0000242 if (!MainAddress)
Jim Grosbachd35159a2011-04-13 15:38:30 +0000243 return Error("no definition for '" + EntryPoint + "'");
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000244
Jim Grosbach3ed03f12011-04-12 00:23:32 +0000245 // Invalidate the instruction cache for each loaded function.
Benjamin Kramer5d62ad22013-08-03 22:18:45 +0000246 for (unsigned i = 0, e = MemMgr.FunctionMemory.size(); i != e; ++i) {
247 sys::MemoryBlock &Data = MemMgr.FunctionMemory[i];
Jim Grosbach3ed03f12011-04-12 00:23:32 +0000248 // Make sure the memory is executable.
249 std::string ErrorStr;
250 sys::Memory::InvalidateInstructionCache(Data.base(), Data.size());
251 if (!sys::Memory::setExecutable(Data, &ErrorStr))
252 return Error("unable to mark function executable: '" + ErrorStr + "'");
253 }
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000254
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000255 // Dispatch to _main().
Jim Grosbach7cb41d72011-04-13 15:49:40 +0000256 errs() << "loaded '" << EntryPoint << "' at: " << (void*)MainAddress << "\n";
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000257
258 int (*Main)(int, const char**) =
259 (int(*)(int,const char**)) uintptr_t(MainAddress);
260 const char **Argv = new const char*[2];
Jim Grosbach7cb41d72011-04-13 15:49:40 +0000261 // Use the name of the first input object module as argv[0] for the target.
262 Argv[0] = InputFileList[0].c_str();
Craig Toppere6cb63e2014-04-25 04:24:47 +0000263 Argv[1] = nullptr;
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000264 return Main(1, Argv);
265}
266
267int main(int argc, char **argv) {
Alp Toker9f679322013-11-05 09:33:43 +0000268 sys::PrintStackTraceOnErrorSignal();
269 PrettyStackTraceProgram X(argc, argv);
270
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000271 ProgramName = argv[0];
272 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
273
274 cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n");
275
276 switch (Action) {
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000277 case AC_Execute:
Jim Grosbach4d5284b2011-03-18 17:24:21 +0000278 return executeInput();
Andrew Kaylord55d7012013-01-25 22:50:58 +0000279 case AC_PrintLineInfo:
280 return printLineInfoForInput();
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000281 }
Jim Grosbach0072cdb2011-03-18 17:11:39 +0000282}