1//===-- 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
14#include "llvm/ADT/OwningPtr.h"
15#include "llvm/ADT/StringMap.h"
16#include "llvm/DebugInfo/DIContext.h"
17#include "llvm/ExecutionEngine/ObjectBuffer.h"
18#include "llvm/ExecutionEngine/ObjectImage.h"
19#include "llvm/ExecutionEngine/RuntimeDyld.h"
20#include "llvm/Object/MachOObject.h"
21#include "llvm/Support/CommandLine.h"
22#include "llvm/Support/ManagedStatic.h"
23#include "llvm/Support/Memory.h"
24#include "llvm/Support/MemoryBuffer.h"
25#include "llvm/Support/raw_ostream.h"
26#include "llvm/Support/system_error.h"
27using namespace llvm;
28using namespace llvm::object;
29
30static cl::list<std::string>
31InputFileList(cl::Positional, cl::ZeroOrMore,
32              cl::desc("<input file>"));
33
34enum ActionType {
35  AC_Execute,
36  AC_PrintLineInfo
37};
38
39static cl::opt<ActionType>
40Action(cl::desc("Action to perform:"),
41       cl::init(AC_Execute),
42       cl::values(clEnumValN(AC_Execute, "execute",
43                             "Load, link, and execute the inputs."),
44                  clEnumValN(AC_PrintLineInfo, "printline",
45                             "Load, link, and print line information for each function."),
46                  clEnumValEnd));
47
48static cl::opt<std::string>
49EntryPoint("entry",
50           cl::desc("Function to call as entry point."),
51           cl::init("_main"));
52
53/* *** */
54
55// A trivial memory manager that doesn't do anything fancy, just uses the
56// support library allocation routines directly.
57class TrivialMemoryManager : public RTDyldMemoryManager {
58public:
59  SmallVector<sys::MemoryBlock, 16> FunctionMemory;
60  SmallVector<sys::MemoryBlock, 16> DataMemory;
61
62  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
63                               unsigned SectionID);
64  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
65                               unsigned SectionID, bool IsReadOnly);
66
67  virtual void *getPointerToNamedFunction(const std::string &Name,
68                                          bool AbortOnFailure = true) {
69    return 0;
70  }
71
72  bool applyPermissions(std::string *ErrMsg) { return false; }
73
74  // Invalidate instruction cache for sections with execute permissions.
75  // Some platforms with separate data cache and instruction cache require
76  // explicit cache flush, otherwise JIT code manipulations (like resolved
77  // relocations) will get to the data cache but not to the instruction cache.
78  virtual void invalidateInstructionCache();
79};
80
81uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
82                                                   unsigned Alignment,
83                                                   unsigned SectionID) {
84  sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0);
85  FunctionMemory.push_back(MB);
86  return (uint8_t*)MB.base();
87}
88
89uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
90                                                   unsigned Alignment,
91                                                   unsigned SectionID,
92                                                   bool IsReadOnly) {
93  sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0);
94  DataMemory.push_back(MB);
95  return (uint8_t*)MB.base();
96}
97
98void TrivialMemoryManager::invalidateInstructionCache() {
99  for (int i = 0, e = FunctionMemory.size(); i != e; ++i)
100    sys::Memory::InvalidateInstructionCache(FunctionMemory[i].base(),
101                                            FunctionMemory[i].size());
102
103  for (int i = 0, e = DataMemory.size(); i != e; ++i)
104    sys::Memory::InvalidateInstructionCache(DataMemory[i].base(),
105                                            DataMemory[i].size());
106}
107
108static const char *ProgramName;
109
110static void Message(const char *Type, const Twine &Msg) {
111  errs() << ProgramName << ": " << Type << ": " << Msg << "\n";
112}
113
114static int Error(const Twine &Msg) {
115  Message("error", Msg);
116  return 1;
117}
118
119/* *** */
120
121static int printLineInfoForInput() {
122  // If we don't have any input files, read from stdin.
123  if (!InputFileList.size())
124    InputFileList.push_back("-");
125  for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
126    // Instantiate a dynamic linker.
127    TrivialMemoryManager *MemMgr = new TrivialMemoryManager;
128    RuntimeDyld Dyld(MemMgr);
129
130    // Load the input memory buffer.
131    OwningPtr<MemoryBuffer> InputBuffer;
132    OwningPtr<ObjectImage>  LoadedObject;
133    if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i],
134                                                     InputBuffer))
135      return Error("unable to read input: '" + ec.message() + "'");
136
137    // Load the object file
138    LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.take())));
139    if (!LoadedObject) {
140      return Error(Dyld.getErrorString());
141    }
142
143    // Resolve all the relocations we can.
144    Dyld.resolveRelocations();
145
146    OwningPtr<DIContext> Context(DIContext::getDWARFContext(LoadedObject->getObjectFile()));
147
148    // Use symbol info to iterate functions in the object.
149    error_code ec;
150    for (object::symbol_iterator I = LoadedObject->begin_symbols(),
151                                 E = LoadedObject->end_symbols();
152                          I != E && !ec;
153                          I.increment(ec)) {
154      object::SymbolRef::Type SymType;
155      if (I->getType(SymType)) continue;
156      if (SymType == object::SymbolRef::ST_Function) {
157        StringRef  Name;
158        uint64_t   Addr;
159        uint64_t   Size;
160        if (I->getName(Name)) continue;
161        if (I->getAddress(Addr)) continue;
162        if (I->getSize(Size)) continue;
163
164        outs() << "Function: " << Name << ", Size = " << Size << "\n";
165
166        DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
167        DILineInfoTable::iterator  Begin = Lines.begin();
168        DILineInfoTable::iterator  End = Lines.end();
169        for (DILineInfoTable::iterator It = Begin; It != End; ++It) {
170          outs() << "  Line info @ " << It->first - Addr << ": "
171                 << It->second.getFileName()
172                 << ", line:" << It->second.getLine() << "\n";
173        }
174      }
175    }
176  }
177
178  return 0;
179}
180
181static int executeInput() {
182  // Instantiate a dynamic linker.
183  TrivialMemoryManager *MemMgr = new TrivialMemoryManager;
184  RuntimeDyld Dyld(MemMgr);
185
186  // If we don't have any input files, read from stdin.
187  if (!InputFileList.size())
188    InputFileList.push_back("-");
189  for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
190    // Load the input memory buffer.
191    OwningPtr<MemoryBuffer> InputBuffer;
192    OwningPtr<ObjectImage>  LoadedObject;
193    if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i],
194                                                     InputBuffer))
195      return Error("unable to read input: '" + ec.message() + "'");
196
197    // Load the object file
198    LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.take())));
199    if (!LoadedObject) {
200      return Error(Dyld.getErrorString());
201    }
202  }
203
204  // Resolve all the relocations we can.
205  Dyld.resolveRelocations();
206  // Clear instruction cache before code will be executed.
207  MemMgr->invalidateInstructionCache();
208
209  // FIXME: Error out if there are unresolved relocations.
210
211  // Get the address of the entry point (_main by default).
212  void *MainAddress = Dyld.getSymbolAddress(EntryPoint);
213  if (MainAddress == 0)
214    return Error("no definition for '" + EntryPoint + "'");
215
216  // Invalidate the instruction cache for each loaded function.
217  for (unsigned i = 0, e = MemMgr->FunctionMemory.size(); i != e; ++i) {
218    sys::MemoryBlock &Data = MemMgr->FunctionMemory[i];
219    // Make sure the memory is executable.
220    std::string ErrorStr;
221    sys::Memory::InvalidateInstructionCache(Data.base(), Data.size());
222    if (!sys::Memory::setExecutable(Data, &ErrorStr))
223      return Error("unable to mark function executable: '" + ErrorStr + "'");
224  }
225
226  // Dispatch to _main().
227  errs() << "loaded '" << EntryPoint << "' at: " << (void*)MainAddress << "\n";
228
229  int (*Main)(int, const char**) =
230    (int(*)(int,const char**)) uintptr_t(MainAddress);
231  const char **Argv = new const char*[2];
232  // Use the name of the first input object module as argv[0] for the target.
233  Argv[0] = InputFileList[0].c_str();
234  Argv[1] = 0;
235  return Main(1, Argv);
236}
237
238int main(int argc, char **argv) {
239  ProgramName = argv[0];
240  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
241
242  cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n");
243
244  switch (Action) {
245  case AC_Execute:
246    return executeInput();
247  case AC_PrintLineInfo:
248    return printLineInfoForInput();
249  }
250}
251