X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-rtdyld%2Fllvm-rtdyld.cpp;h=65c0ab72553895fd5ddf7c198a3520ee229d05c7;hb=3bd3f426a517f8a8f05e20ebc0c1a56e2a6365ac;hp=6de5742a6a3831681e67e658ebd82461a324f16c;hpb=35fdeb7b373e416ff00c54abef12e786963af725;p=oota-llvm.git diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index 6de5742a6a3..65c0ab72553 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -11,23 +11,31 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/OwningPtr.h" -#include "llvm/Object/MachOObject.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/MachO.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Memory.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" 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 @@ -35,289 +43,214 @@ 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 const char *ProgramName; - -static void Message(const char *Type, const Twine &Msg) { - errs() << ProgramName << ": " << Type << ": " << Msg << "\n"; -} - -static int Error(const Twine &Msg) { - Message("error", Msg); - return 1; -} +static cl::opt +EntryPoint("entry", + cl::desc("Function to call as entry point."), + cl::init("_main")); /* *** */ -static bool -loadSegment32(const MachOObject *Obj, - sys::MemoryBlock &Data, - const MachOObject::LoadCommandInfo *SegmentLCI, - const InMemoryStruct &SymtabLC, - StringMap &SymbolTable) { - InMemoryStruct Segment32LC; - Obj->ReadSegmentLoadCommand(*SegmentLCI, Segment32LC); - if (!Segment32LC) - return Error("unable to load segment load command"); - - // Map the segment into memory. - std::string ErrorStr; - Data = sys::Memory::AllocateRWX(Segment32LC->VMSize, 0, &ErrorStr); - if (!Data.base()) - return Error("unable to allocate memory block: '" + ErrorStr + "'"); - memcpy(Data.base(), Obj->getData(Segment32LC->FileOffset, - Segment32LC->FileSize).data(), - Segment32LC->FileSize); - memset((char*)Data.base() + Segment32LC->FileSize, 0, - Segment32LC->VMSize - Segment32LC->FileSize); - - // Bind the section indices to address. - void **SectionBases = new void*[Segment32LC->NumSections]; - for (unsigned i = 0; i != Segment32LC->NumSections; ++i) { - InMemoryStruct Sect; - Obj->ReadSection(*SegmentLCI, i, Sect); - if (!Sect) - return Error("unable to load section: '" + Twine(i) + "'"); - - // FIXME: We don't support relocations yet. - if (Sect->NumRelocationTableEntries != 0) - return Error("not yet implemented: relocations!"); - - // FIXME: Improve check. - if (Sect->Flags != 0x80000400) - return Error("unsupported section type!"); - - SectionBases[i] = (char*) Data.base() + Sect->Address; - } - - // Bind all the symbols to address. - for (unsigned i = 0; i != SymtabLC->NumSymbolTableEntries; ++i) { - InMemoryStruct STE; - Obj->ReadSymbolTableEntry(SymtabLC->SymbolTableOffset, i, STE); - if (!STE) - return Error("unable to read symbol: '" + Twine(i) + "'"); - if (STE->SectionIndex == 0) - return Error("unexpected undefined symbol!"); - unsigned Index = STE->SectionIndex - 1; - if (Index >= Segment32LC->NumSections) - return Error("invalid section index for symbol: '" + Twine() + "'"); - - // Get the symbol name. - StringRef Name = Obj->getStringAtIndex(STE->StringIndex); - - // Get the section base address. - void *SectionBase = SectionBases[Index]; +// 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, StringRef SectionName); + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool IsReadOnly); + + virtual void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true) { + return 0; + } - // Get the symbol address. - void *Address = (char*) SectionBase + STE->Value; + bool finalizeMemory(std::string *ErrMsg) { return false; } - // FIXME: Check the symbol type and flags. - if (STE->Type != 0xF) - return Error("unexpected symbol type!"); - if (STE->Flags != 0x0) - return Error("unexpected symbol type!"); + // 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(); +}; - SymbolTable[Name] = Address; - } +uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID, + StringRef SectionName) { + sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0); + FunctionMemory.push_back(MB); + return (uint8_t*)MB.base(); +} - delete SectionBases; - return false; +uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID, + StringRef SectionName, + bool IsReadOnly) { + sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0); + DataMemory.push_back(MB); + return (uint8_t*)MB.base(); } -static bool -loadSegment64(const MachOObject *Obj, - sys::MemoryBlock &Data, - const MachOObject::LoadCommandInfo *SegmentLCI, - const InMemoryStruct &SymtabLC, - StringMap &SymbolTable) { - InMemoryStruct Segment64LC; - Obj->ReadSegment64LoadCommand(*SegmentLCI, Segment64LC); - if (!Segment64LC) - return Error("unable to load segment load command"); - - // Map the segment into memory. - std::string ErrorStr; - Data = sys::Memory::AllocateRWX(Segment64LC->VMSize, 0, &ErrorStr); - if (!Data.base()) - return Error("unable to allocate memory block: '" + ErrorStr + "'"); - memcpy(Data.base(), Obj->getData(Segment64LC->FileOffset, - Segment64LC->FileSize).data(), - Segment64LC->FileSize); - memset((char*)Data.base() + Segment64LC->FileSize, 0, - Segment64LC->VMSize - Segment64LC->FileSize); - - // Bind the section indices to address. - void **SectionBases = new void*[Segment64LC->NumSections]; - for (unsigned i = 0; i != Segment64LC->NumSections; ++i) { - InMemoryStruct Sect; - Obj->ReadSection64(*SegmentLCI, i, Sect); - if (!Sect) - return Error("unable to load section: '" + Twine(i) + "'"); - - // FIXME: We don't support relocations yet. - if (Sect->NumRelocationTableEntries != 0) - return Error("not yet implemented: relocations!"); - - // FIXME: Improve check. - if (Sect->Flags != 0x80000400) - return Error("unsupported section type!"); - - SectionBases[i] = (char*) Data.base() + Sect->Address; - } +void TrivialMemoryManager::invalidateInstructionCache() { + for (int i = 0, e = FunctionMemory.size(); i != e; ++i) + sys::Memory::InvalidateInstructionCache(FunctionMemory[i].base(), + FunctionMemory[i].size()); - // Bind all the symbols to address. - for (unsigned i = 0; i != SymtabLC->NumSymbolTableEntries; ++i) { - InMemoryStruct STE; - Obj->ReadSymbol64TableEntry(SymtabLC->SymbolTableOffset, i, STE); - if (!STE) - return Error("unable to read symbol: '" + Twine(i) + "'"); - if (STE->SectionIndex == 0) - return Error("unexpected undefined symbol!"); + for (int i = 0, e = DataMemory.size(); i != e; ++i) + sys::Memory::InvalidateInstructionCache(DataMemory[i].base(), + DataMemory[i].size()); +} - unsigned Index = STE->SectionIndex - 1; - if (Index >= Segment64LC->NumSections) - return Error("invalid section index for symbol: '" + Twine() + "'"); +static const char *ProgramName; - // Get the symbol name. - StringRef Name = Obj->getStringAtIndex(STE->StringIndex); +static void Message(const char *Type, const Twine &Msg) { + errs() << ProgramName << ": " << Type << ": " << Msg << "\n"; +} - // Get the section base address. - void *SectionBase = SectionBases[Index]; +static int Error(const Twine &Msg) { + Message("error", Msg); + return 1; +} - // Get the symbol address. - void *Address = (char*) SectionBase + STE->Value; +/* *** */ - // FIXME: Check the symbol type and flags. - if (STE->Type != 0xF) - return Error("unexpected symbol type!"); - if (STE->Flags != 0x0) - return Error("unexpected symbol type!"); +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; + 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()); + } - SymbolTable[Name] = Address; + // Resolve all the relocations we can. + Dyld.resolveRelocations(); + + OwningPtr Context(DIContext::getDWARFContext(LoadedObject->getObjectFile())); + + // Use symbol info to iterate functions in the object. + for (object::symbol_iterator I = LoadedObject->begin_symbols(), + E = LoadedObject->end_symbols(); + I != E; ++I) { + 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"; + } + } + } } - delete SectionBases; - return false; + return 0; } 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() + "'"); - - // Load the Mach-O wrapper object. - std::string ErrorStr; - OwningPtr Obj( - MachOObject::LoadFromBuffer(InputBuffer.take(), &ErrorStr)); - if (!Obj) - return Error("unable to load object: '" + ErrorStr + "'"); - - // Validate that the load commands match what we expect. - const MachOObject::LoadCommandInfo *SegmentLCI = 0, *SymtabLCI = 0, - *DysymtabLCI = 0; - for (unsigned i = 0; i != Obj->getHeader().NumLoadCommands; ++i) { - const MachOObject::LoadCommandInfo &LCI = Obj->getLoadCommandInfo(i); - switch (LCI.Command.Type) { - case macho::LCT_Segment: - case macho::LCT_Segment64: - if (SegmentLCI) - return Error("unexpected input object (multiple segments)"); - SegmentLCI = &LCI; - break; - case macho::LCT_Symtab: - if (SymtabLCI) - return Error("unexpected input object (multiple symbol tables)"); - SymtabLCI = &LCI; - break; - case macho::LCT_Dysymtab: - if (DysymtabLCI) - return Error("unexpected input object (multiple symbol tables)"); - DysymtabLCI = &LCI; - break; - default: - return Error("unexpected input object (unexpected load command"); + // Instantiate a dynamic linker. + TrivialMemoryManager MemMgr; + 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()); } } - if (!SymtabLCI) - return Error("no symbol table found in object"); - if (!SegmentLCI) - return Error("no symbol table found in object"); - - // Read and register the symbol table data. - InMemoryStruct SymtabLC; - Obj->ReadSymtabLoadCommand(*SymtabLCI, SymtabLC); - if (!SymtabLC) - return Error("unable to load symbol table load command"); - Obj->RegisterStringTable(*SymtabLC); - - // Read the dynamic link-edit information, if present (not present in static - // objects). - if (DysymtabLCI) { - InMemoryStruct DysymtabLC; - Obj->ReadDysymtabLoadCommand(*DysymtabLCI, DysymtabLC); - if (!DysymtabLC) - return Error("unable to load dynamic link-exit load command"); - - // FIXME: We don't support anything interesting yet. - if (DysymtabLC->LocalSymbolsIndex != 0) - return Error("NOT YET IMPLEMENTED: local symbol entries"); - if (DysymtabLC->ExternalSymbolsIndex != 0) - return Error("NOT YET IMPLEMENTED: non-external symbol entries"); - if (DysymtabLC->UndefinedSymbolsIndex != SymtabLC->NumSymbolTableEntries) - return Error("NOT YET IMPLEMENTED: undefined symbol entries"); + // Resolve all the relocations we can. + Dyld.resolveRelocations(); + // Clear instruction cache before code will be executed. + MemMgr.invalidateInstructionCache(); + + // FIXME: Error out if there are unresolved relocations. + + // 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 + "'"); } - // Load the segment load command. - sys::MemoryBlock Data; - StringMap SymbolTable; - if (SegmentLCI->Command.Type == macho::LCT_Segment) { - if (loadSegment32(Obj.get(), Data, SegmentLCI, SymtabLC, SymbolTable)) - return true; - } else { - if (loadSegment64(Obj.get(), Data, SegmentLCI, SymtabLC, SymbolTable)) - return true; - } - - // Get the address of "_main". - StringMap::iterator it = SymbolTable.find("_main"); - if (it == SymbolTable.end()) - return Error("no definition for '_main'"); - - // Invalidate the instruction cache. - sys::Memory::InvalidateInstructionCache(Data.base(), Data.size()); - - // Make sure the memory is executable. - if (!sys::Memory::setExecutable(Data, &ErrorStr)) - return Error("unable to mark function executable: '" + ErrorStr + "'"); - // Dispatch to _main(). - void *MainAddress = it->second; - 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); } int main(int argc, char **argv) { + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + ProgramName = argv[0]; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n"); switch (Action) { - default: case AC_Execute: return executeInput(); + case AC_PrintLineInfo: + return printLineInfoForInput(); } - - return 0; }