X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-rtdyld%2Fllvm-rtdyld.cpp;h=b68f2a08d92726d4baf7fd936f2afeb6357cacc9;hb=0a230e0d985625a3909cb78fd867a3abaf434565;hp=a670944235626735c47524498136cf6afa57af81;hpb=5acfa9f0fd641906e520a6caaf644d03def27ae0;p=oota-llvm.git diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index a6709442356..b68f2a08d92 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -11,11 +11,13 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/OwningPtr.h" -#include "llvm/ExecutionEngine/JITMemoryManager.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/ExecutionEngine/ObjectBuffer.h" +#include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" -#include "llvm/Object/MachOObject.h" +#include "llvm/Object/MachO.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Memory.h" @@ -25,11 +27,13 @@ using namespace llvm; using namespace llvm::object; -static cl::opt -InputFile(cl::Positional, cl::desc(""), cl::init("-")); +static cl::list +InputFileList(cl::Positional, cl::ZeroOrMore, + cl::desc("")); enum ActionType { - AC_Execute + AC_Execute, + AC_PrintLineInfo }; static cl::opt @@ -37,10 +41,70 @@ Action(cl::desc("Action to perform:"), cl::init(AC_Execute), cl::values(clEnumValN(AC_Execute, "execute", "Load, link, and execute the inputs."), + clEnumValN(AC_PrintLineInfo, "printline", + "Load, link, and print line information for each function."), clEnumValEnd)); +static cl::opt +EntryPoint("entry", + cl::desc("Function to call as entry point."), + cl::init("_main")); + /* *** */ +// A trivial memory manager that doesn't do anything fancy, just uses the +// support library allocation routines directly. +class TrivialMemoryManager : public RTDyldMemoryManager { +public: + SmallVector FunctionMemory; + SmallVector DataMemory; + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID); + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, bool IsReadOnly); + + virtual void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true) { + return 0; + } + + bool finalizeMemory(std::string *ErrMsg) { return false; } + + // Invalidate instruction cache for sections with execute permissions. + // Some platforms with separate data cache and instruction cache require + // explicit cache flush, otherwise JIT code manipulations (like resolved + // relocations) will get to the data cache but not to the instruction cache. + virtual void invalidateInstructionCache(); +}; + +uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID) { + sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0); + FunctionMemory.push_back(MB); + return (uint8_t*)MB.base(); +} + +uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID, + bool IsReadOnly) { + sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0); + DataMemory.push_back(MB); + return (uint8_t*)MB.base(); +} + +void TrivialMemoryManager::invalidateInstructionCache() { + for (int i = 0, e = FunctionMemory.size(); i != e; ++i) + sys::Memory::InvalidateInstructionCache(FunctionMemory[i].base(), + FunctionMemory[i].size()); + + for (int i = 0, e = DataMemory.size(); i != e; ++i) + sys::Memory::InvalidateInstructionCache(DataMemory[i].base(), + DataMemory[i].size()); +} + static const char *ProgramName; static void Message(const char *Type, const Twine &Msg) { @@ -54,41 +118,119 @@ static int Error(const Twine &Msg) { /* *** */ -static int executeInput() { - // Load the input memory buffer. - OwningPtr InputBuffer; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFile, InputBuffer)) - return Error("unable to read input: '" + ec.message() + "'"); +static int printLineInfoForInput() { + // If we don't have any input files, read from stdin. + if (!InputFileList.size()) + InputFileList.push_back("-"); + for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { + // Instantiate a dynamic linker. + TrivialMemoryManager *MemMgr = new TrivialMemoryManager; + RuntimeDyld Dyld(MemMgr); + + // Load the input memory buffer. + OwningPtr InputBuffer; + OwningPtr LoadedObject; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i], + InputBuffer)) + return Error("unable to read input: '" + ec.message() + "'"); + + // Load the object file + LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.take()))); + if (!LoadedObject) { + return Error(Dyld.getErrorString()); + } + + // Resolve all the relocations we can. + Dyld.resolveRelocations(); + + OwningPtr Context(DIContext::getDWARFContext(LoadedObject->getObjectFile())); + + // Use symbol info to iterate functions in the object. + error_code ec; + for (object::symbol_iterator I = LoadedObject->begin_symbols(), + E = LoadedObject->end_symbols(); + I != E && !ec; + I.increment(ec)) { + object::SymbolRef::Type SymType; + if (I->getType(SymType)) continue; + if (SymType == object::SymbolRef::ST_Function) { + StringRef Name; + uint64_t Addr; + uint64_t Size; + if (I->getName(Name)) continue; + if (I->getAddress(Addr)) continue; + if (I->getSize(Size)) continue; + + outs() << "Function: " << Name << ", Size = " << Size << "\n"; + + DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); + DILineInfoTable::iterator Begin = Lines.begin(); + DILineInfoTable::iterator End = Lines.end(); + for (DILineInfoTable::iterator It = Begin; It != End; ++It) { + outs() << " Line info @ " << It->first - Addr << ": " + << It->second.getFileName() + << ", line:" << It->second.getLine() << "\n"; + } + } + } + } - // Instantiate a dynamic linker. - RuntimeDyld Dyld(JITMemoryManager::CreateDefaultMemManager()); + return 0; +} - // Load the object file into it. - if (Dyld.loadObject(InputBuffer.take())) { - return Error(Dyld.getErrorString()); +static int executeInput() { + // Instantiate a dynamic linker. + TrivialMemoryManager *MemMgr = new TrivialMemoryManager; + RuntimeDyld Dyld(MemMgr); + + // If we don't have any input files, read from stdin. + if (!InputFileList.size()) + InputFileList.push_back("-"); + for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { + // Load the input memory buffer. + OwningPtr InputBuffer; + OwningPtr LoadedObject; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i], + InputBuffer)) + return Error("unable to read input: '" + ec.message() + "'"); + + // Load the object file + LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.take()))); + if (!LoadedObject) { + return Error(Dyld.getErrorString()); + } } - // Get the address of "_main". - void *MainAddress = Dyld.getSymbolAddress("_main"); - if (MainAddress == 0) - return Error("no definition for '_main'"); + // Resolve all the relocations we can. + Dyld.resolveRelocations(); + // Clear instruction cache before code will be executed. + MemMgr->invalidateInstructionCache(); - // Invalidate the instruction cache. - sys::MemoryBlock Data = Dyld.getMemoryBlock(); - sys::Memory::InvalidateInstructionCache(Data.base(), Data.size()); + // FIXME: Error out if there are unresolved relocations. - // Make sure the memory is executable. - std::string ErrorStr; - if (!sys::Memory::setExecutable(Data, &ErrorStr)) - return Error("unable to mark function executable: '" + ErrorStr + "'"); + // Get the address of the entry point (_main by default). + void *MainAddress = Dyld.getSymbolAddress(EntryPoint); + if (MainAddress == 0) + return Error("no definition for '" + EntryPoint + "'"); + + // Invalidate the instruction cache for each loaded function. + for (unsigned i = 0, e = MemMgr->FunctionMemory.size(); i != e; ++i) { + sys::MemoryBlock &Data = MemMgr->FunctionMemory[i]; + // Make sure the memory is executable. + std::string ErrorStr; + sys::Memory::InvalidateInstructionCache(Data.base(), Data.size()); + if (!sys::Memory::setExecutable(Data, &ErrorStr)) + return Error("unable to mark function executable: '" + ErrorStr + "'"); + } // Dispatch to _main(). - errs() << "loaded '_main' at: " << MainAddress << "\n"; + errs() << "loaded '" << EntryPoint << "' at: " << (void*)MainAddress << "\n"; int (*Main)(int, const char**) = (int(*)(int,const char**)) uintptr_t(MainAddress); const char **Argv = new const char*[2]; - Argv[0] = InputFile.c_str(); + // Use the name of the first input object module as argv[0] for the target. + Argv[0] = InputFileList[0].c_str(); Argv[1] = 0; return Main(1, Argv); } @@ -100,10 +242,9 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n"); switch (Action) { - default: case AC_Execute: return executeInput(); + case AC_PrintLineInfo: + return printLineInfoForInput(); } - - return 0; }