int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); if (!ValidateCheckPrefixes()) { errs() << "Supplied check-prefix is invalid! Prefixes must be unique and " "start with a letter and contain only alphanumeric characters, " "hyphens and underscores\n"; return 2; } AddCheckPrefixIfNeeded(); SourceMgr SM; // Read the expected strings from the check file. std::vector<CheckString> CheckStrings; if (ReadCheckFile(SM, CheckStrings)) return 2; // Open the file to check and add it to SourceMgr. ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = MemoryBuffer::getFileOrSTDIN(InputFilename); if (std::error_code EC = FileOrErr.getError()) { errs() << "Could not open input file '" << InputFilename << "': " << EC.message() << '\n'; return 2; } std::unique_ptr<MemoryBuffer> File = std::move(FileOrErr.get()); if (File->getBufferSize() == 0) { errs() << "FileCheck error: '" << InputFilename << "' is empty.\n"; return 2; } // Remove duplicate spaces in the input file if requested. // Remove DOS style line endings. MemoryBuffer *F = CanonicalizeInputFile(File.release(), NoCanonicalizeWhiteSpace); SM.AddNewSourceBuffer(F, SMLoc()); /// VariableTable - This holds all the current filecheck variables. StringMap<StringRef> VariableTable; // Check that we have all of the expected strings, in order, in the input // file. StringRef Buffer = F->getBuffer(); bool hasError = false; unsigned i = 0, j = 0, e = CheckStrings.size(); while (true) { StringRef CheckRegion; if (j == e) { CheckRegion = Buffer; } else { const CheckString &CheckLabelStr = CheckStrings[j]; if (CheckLabelStr.CheckTy != Check::CheckLabel) { ++j; continue; } // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG size_t MatchLabelLen = 0; size_t MatchLabelPos = CheckLabelStr.Check(SM, Buffer, true, MatchLabelLen, VariableTable); if (MatchLabelPos == StringRef::npos) { hasError = true; break; } CheckRegion = Buffer.substr(0, MatchLabelPos + MatchLabelLen); Buffer = Buffer.substr(MatchLabelPos + MatchLabelLen); ++j; } for ( ; i != j; ++i) { const CheckString &CheckStr = CheckStrings[i]; // Check each string within the scanned region, including a second check // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) size_t MatchLen = 0; size_t MatchPos = CheckStr.Check(SM, CheckRegion, false, MatchLen, VariableTable); if (MatchPos == StringRef::npos) { hasError = true; i = j; break; } CheckRegion = CheckRegion.substr(MatchPos + MatchLen); } if (j == e) break; } return hasError ? 1 : 0; }
int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. // Initialize targets and assembly printers/parsers. llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmParsers(); llvm::InitializeAllDisassemblers(); // Register the target printer for --version. cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n"); MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); TripleName = Triple::normalize(TripleName); setDwarfDebugFlags(argc, argv); setDwarfDebugProducer(); const char *ProgName = argv[0]; const Target *TheTarget = GetTarget(ProgName); if (!TheTarget) return 1; // Now that GetTarget() has (potentially) replaced TripleName, it's safe to // construct the Triple object. Triple TheTriple(TripleName); ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr = MemoryBuffer::getFileOrSTDIN(InputFilename); if (std::error_code EC = BufferPtr.getError()) { errs() << InputFilename << ": " << EC.message() << '\n'; return 1; } MemoryBuffer *Buffer = BufferPtr->get(); SourceMgr SrcMgr; // Tell SrcMgr about this buffer, which is what the parser will pick up. SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc()); // Record the location of the include directories so that the lexer can find // it later. SrcMgr.setIncludeDirs(IncludeDirs); std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); assert(MAI && "Unable to create target asm info!"); MAI->setRelaxELFRelocations(RelaxELFRel); if (CompressDebugSections != DebugCompressionType::DCT_None) { if (!zlib::isAvailable()) { errs() << ProgName << ": build tools with zlib to enable -compress-debug-sections"; return 1; } MAI->setCompressDebugSections(CompressDebugSections); } // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and // MCObjectFileInfo needs a MCContext reference in order to initialize itself. MCObjectFileInfo MOFI; MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr); MOFI.InitMCObjectFileInfo(TheTriple, PIC, CMModel, Ctx); if (SaveTempLabels) Ctx.setAllowTemporaryLabels(false); Ctx.setGenDwarfForAssembly(GenDwarfForAssembly); // Default to 4 for dwarf version. unsigned DwarfVersion = MCOptions.DwarfVersion ? MCOptions.DwarfVersion : 4; if (DwarfVersion < 2 || DwarfVersion > 4) { errs() << ProgName << ": Dwarf version " << DwarfVersion << " is not supported." << '\n'; return 1; } Ctx.setDwarfVersion(DwarfVersion); if (!DwarfDebugFlags.empty()) Ctx.setDwarfDebugFlags(StringRef(DwarfDebugFlags)); if (!DwarfDebugProducer.empty()) Ctx.setDwarfDebugProducer(StringRef(DwarfDebugProducer)); if (!DebugCompilationDir.empty()) Ctx.setCompilationDir(DebugCompilationDir); else { // If no compilation dir is set, try to use the current directory. SmallString<128> CWD; if (!sys::fs::current_path(CWD)) Ctx.setCompilationDir(CWD); } if (!MainFileName.empty()) Ctx.setMainFileName(MainFileName); // Package up features to be passed to target/subtarget std::string FeaturesStr; if (MAttrs.size()) { SubtargetFeatures Features; for (unsigned i = 0; i != MAttrs.size(); ++i) Features.AddFeature(MAttrs[i]); FeaturesStr = Features.getString(); } std::unique_ptr<tool_output_file> Out = GetOutputStream(); if (!Out) return 1; std::unique_ptr<buffer_ostream> BOS; raw_pwrite_stream *OS = &Out->os(); std::unique_ptr<MCStreamer> Str; std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); std::unique_ptr<MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr)); MCInstPrinter *IP = nullptr; if (FileType == OFT_AssemblyFile) { IP = TheTarget->createMCInstPrinter(Triple(TripleName), OutputAsmVariant, *MAI, *MCII, *MRI); // Set the display preference for hex vs. decimal immediates. IP->setPrintImmHex(PrintImmHex); // Set up the AsmStreamer. MCCodeEmitter *CE = nullptr; MCAsmBackend *MAB = nullptr; if (ShowEncoding) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); } auto FOut = llvm::make_unique<formatted_raw_ostream>(*OS); Str.reset(TheTarget->createAsmStreamer( Ctx, std::move(FOut), /*asmverbose*/ true, /*useDwarfDirectory*/ true, IP, CE, MAB, ShowInst)); } else if (FileType == OFT_Null) { Str.reset(TheTarget->createNullStreamer(Ctx)); } else { assert(FileType == OFT_ObjectFile && "Invalid file type!"); // Don't waste memory on names of temp labels. Ctx.setUseNamesOnTempLabels(false); if (!Out->os().supportsSeeking()) { BOS = make_unique<buffer_ostream>(Out->os()); OS = BOS.get(); } MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); Str.reset(TheTarget->createMCObjectStreamer( TheTriple, Ctx, *MAB, *OS, CE, *STI, MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible, /*DWARFMustBeAtTheEnd*/ false)); if (NoExecStack) Str->InitSections(true); } int Res = 1; bool disassemble = false; switch (Action) { case AC_AsLex: Res = AsLexInput(SrcMgr, *MAI, Out->os()); break; case AC_Assemble: Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI, *MCII, MCOptions); break; case AC_MDisassemble: assert(IP && "Expected assembly output"); IP->setUseMarkup(1); disassemble = true; break; case AC_Disassemble: disassemble = true; break; } if (disassemble) Res = Disassembler::disassemble(*TheTarget, TripleName, *STI, *Str, *Buffer, SrcMgr, Out->os()); // Keep output if no errors. if (Res == 0) Out->keep(); return Res; }
static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName, std::string ArchiveName = std::string(), std::string ArchitectureName = std::string()) { auto Symbols = Obj.symbols(); if (DynamicSyms) { const auto *E = dyn_cast<ELFObjectFileBase>(&Obj); if (!E) { error("File format has no dynamic symbol table", Obj.getFileName()); return; } auto DynSymbols = E->getDynamicSymbolIterators(); Symbols = make_range<basic_symbol_iterator>(DynSymbols.begin(), DynSymbols.end()); } std::string NameBuffer; raw_string_ostream OS(NameBuffer); // If a "-s segname sectname" option was specified and this is a Mach-O // file get the section number for that section in this object file. unsigned int Nsect = 0; MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj); if (SegSect.size() != 0 && MachO) { Nsect = getNsectForSegSect(MachO); // If this section is not in the object file no symbols are printed. if (Nsect == 0) return; } for (BasicSymbolRef Sym : Symbols) { uint32_t SymFlags = Sym.getFlags(); if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific)) continue; if (WithoutAliases) { if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj)) { const GlobalValue *GV = IR->getSymbolGV(Sym.getRawDataRefImpl()); if (GV && isa<GlobalAlias>(GV)) continue; } } // If a "-s segname sectname" option was specified and this is a Mach-O // file and this section appears in this file, Nsect will be non-zero then // see if this symbol is a symbol from that section and if not skip it. if (Nsect && Nsect != getNsectInMachO(*MachO, Sym)) continue; NMSymbol S; S.Size = 0; S.Address = 0; if (PrintSize) { if (isa<ELFObjectFileBase>(&Obj)) S.Size = ELFSymbolRef(Sym).getSize(); } if (PrintAddress && isa<ObjectFile>(Obj)) { SymbolRef SymRef(Sym); ErrorOr<uint64_t> AddressOrErr = SymRef.getAddress(); if (error(AddressOrErr.getError())) break; S.Address = *AddressOrErr; } S.TypeChar = getNMTypeChar(Obj, Sym); if (error(Sym.printName(OS))) break; OS << '\0'; S.Sym = Sym; SymbolList.push_back(S); } OS.flush(); const char *P = NameBuffer.c_str(); for (unsigned I = 0; I < SymbolList.size(); ++I) { SymbolList[I].Name = P; P += strlen(P) + 1; } CurrentFilename = Obj.getFileName(); sortAndPrintSymbolList(Obj, printName, ArchiveName, ArchitectureName); }
// Load and link the objects specified on the command line, but do not execute // anything. Instead, attach a RuntimeDyldChecker instance and call it to // verify the correctness of the linked memory. static int linkAndVerify() { // Check for missing triple. if (TripleName == "") ErrorAndExit("-triple required when running in -verify mode."); // Look up the target and build the disassembler. Triple TheTriple(Triple::normalize(TripleName)); std::string ErrorStr; const Target *TheTarget = TargetRegistry::lookupTarget("", TheTriple, ErrorStr); if (!TheTarget) ErrorAndExit("Error accessing target '" + TripleName + "': " + ErrorStr); TripleName = TheTriple.getTriple(); std::unique_ptr<MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(TripleName, MCPU, "")); if (!STI) ErrorAndExit("Unable to create subtarget info!"); std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); if (!MRI) ErrorAndExit("Unable to create target register info!"); std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); if (!MAI) ErrorAndExit("Unable to create target asm info!"); MCContext Ctx(MAI.get(), MRI.get(), nullptr); std::unique_ptr<MCDisassembler> Disassembler( TheTarget->createMCDisassembler(*STI, Ctx)); if (!Disassembler) ErrorAndExit("Unable to create disassembler!"); std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo()); std::unique_ptr<MCInstPrinter> InstPrinter( TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI)); // Load any dylibs requested on the command line. loadDylibs(); // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; doPreallocation(MemMgr); RuntimeDyld Dyld(MemMgr, MemMgr); Dyld.setProcessAllSections(true); RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(), llvm::dbgs()); // If we don't have any input files, read from stdin. if (!InputFileList.size()) InputFileList.push_back("-"); for (auto &Filename : InputFileList) { // Load the input memory buffer. ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = MemoryBuffer::getFileOrSTDIN(Filename); if (std::error_code EC = InputBuffer.getError()) ErrorAndExit("unable to read input: '" + EC.message() + "'"); Expected<std::unique_ptr<ObjectFile>> MaybeObj( ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); if (!MaybeObj) { std::string Buf; raw_string_ostream OS(Buf); logAllUnhandledErrors(MaybeObj.takeError(), OS, ""); OS.flush(); ErrorAndExit("unable to create object file: '" + Buf + "'"); } ObjectFile &Obj = **MaybeObj; // Load the object file Dyld.loadObject(Obj); if (Dyld.hasError()) { ErrorAndExit(Dyld.getErrorString()); } } // Re-map the section addresses into the phony target address space and add // dummy symbols. remapSectionsAndSymbols(TheTriple, MemMgr, Checker); // Resolve all the relocations we can. Dyld.resolveRelocations(); // Register EH frames. Dyld.registerEHFrames(); int ErrorCode = checkAllExpressions(Checker); if (Dyld.hasError()) ErrorAndExit("RTDyld reported an error applying relocations:\n " + Dyld.getErrorString()); return ErrorCode; }
static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M, std::unique_ptr<raw_pwrite_stream> OS, std::string SampleProfile) { StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>> ModuleToDefinedGVSummaries; CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); // We can simply import the values mentioned in the combined index, since // we should only invoke this using the individual indexes written out // via a WriteIndexesThinBackend. FunctionImporter::ImportMapTy ImportList; for (auto &GlobalList : *CombinedIndex) { auto GUID = GlobalList.first; assert(GlobalList.second.size() == 1 && "Expected individual combined index to have one summary per GUID"); auto &Summary = GlobalList.second[0]; // Skip the summaries for the importing module. These are included to // e.g. record required linkage changes. if (Summary->modulePath() == M->getModuleIdentifier()) continue; // Doesn't matter what value we plug in to the map, just needs an entry // to provoke importing by thinBackend. ImportList[Summary->modulePath()][GUID] = 1; } std::vector<std::unique_ptr<llvm::MemoryBuffer>> OwnedImports; MapVector<llvm::StringRef, llvm::BitcodeModule> ModuleMap; for (auto &I : ImportList) { ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MBOrErr = llvm::MemoryBuffer::getFile(I.first()); if (!MBOrErr) { errs() << "Error loading imported file '" << I.first() << "': " << MBOrErr.getError().message() << "\n"; return; } Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(**MBOrErr); if (!BMsOrErr) { handleAllErrors(BMsOrErr.takeError(), [&](ErrorInfoBase &EIB) { errs() << "Error loading imported file '" << I.first() << "': " << EIB.message() << '\n'; }); return; } // The bitcode file may contain multiple modules, we want the one with a // summary. bool FoundModule = false; for (BitcodeModule &BM : *BMsOrErr) { Expected<bool> HasSummary = BM.hasSummary(); if (HasSummary && *HasSummary) { ModuleMap.insert({I.first(), BM}); FoundModule = true; break; } } if (!FoundModule) { errs() << "Error loading imported file '" << I.first() << "': Could not find module summary\n"; return; } OwnedImports.push_back(std::move(*MBOrErr)); } auto AddStream = [&](size_t Task) { return llvm::make_unique<lto::NativeObjectStream>(std::move(OS)); }; lto::Config Conf; Conf.SampleProfile = SampleProfile; if (Error E = thinBackend( Conf, 0, AddStream, *M, *CombinedIndex, ImportList, ModuleToDefinedGVSummaries[M->getModuleIdentifier()], ModuleMap)) { handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { errs() << "Error running ThinLTO backend: " << EIB.message() << '\n'; }); } }
static void runMRIScript() { enum class MRICommand { AddLib, AddMod, Create, Save, End, Invalid }; ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getSTDIN(); failIfError(Buf.getError()); const MemoryBuffer &Ref = *Buf.get(); bool Saved = false; std::vector<NewArchiveMember> NewMembers; std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers; std::vector<std::unique_ptr<object::Archive>> Archives; for (line_iterator I(Ref, /*SkipBlanks*/ true, ';'), E; I != E; ++I) { StringRef Line = *I; StringRef CommandStr, Rest; std::tie(CommandStr, Rest) = Line.split(' '); Rest = Rest.trim(); if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"') Rest = Rest.drop_front().drop_back(); auto Command = StringSwitch<MRICommand>(CommandStr.lower()) .Case("addlib", MRICommand::AddLib) .Case("addmod", MRICommand::AddMod) .Case("create", MRICommand::Create) .Case("save", MRICommand::Save) .Case("end", MRICommand::End) .Default(MRICommand::Invalid); switch (Command) { case MRICommand::AddLib: { auto BufOrErr = MemoryBuffer::getFile(Rest, -1, false); failIfError(BufOrErr.getError(), "Could not open library"); ArchiveBuffers.push_back(std::move(*BufOrErr)); auto LibOrErr = object::Archive::create(ArchiveBuffers.back()->getMemBufferRef()); failIfError(errorToErrorCode(LibOrErr.takeError()), "Could not parse library"); Archives.push_back(std::move(*LibOrErr)); object::Archive &Lib = *Archives.back(); { Error Err; for (auto &Member : Lib.children(Err)) addMember(NewMembers, Member); failIfError(std::move(Err)); } break; } case MRICommand::AddMod: addMember(NewMembers, Rest); break; case MRICommand::Create: Create = true; if (!ArchiveName.empty()) fail("Editing multiple archives not supported"); if (Saved) fail("File already saved"); ArchiveName = Rest; break; case MRICommand::Save: Saved = true; break; case MRICommand::End: break; case MRICommand::Invalid: fail("Unknown command: " + CommandStr); } } // Nothing to do if not saved. if (Saved) performOperation(ReplaceOrInsert, &NewMembers); exit(0); }
static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { assert(LoadObjects || !UseDebugObj); // Load any dylibs requested on the command line. loadDylibs(); // If we don't have any input files, read from stdin. if (!InputFileList.size()) InputFileList.push_back("-"); for (auto &File : InputFileList) { // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; RuntimeDyld Dyld(MemMgr, MemMgr); // Load the input memory buffer. ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = MemoryBuffer::getFileOrSTDIN(File); if (std::error_code EC = InputBuffer.getError()) ErrorAndExit("unable to read input: '" + EC.message() + "'"); Expected<std::unique_ptr<ObjectFile>> MaybeObj( ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); if (!MaybeObj) { std::string Buf; raw_string_ostream OS(Buf); logAllUnhandledErrors(MaybeObj.takeError(), OS, ""); OS.flush(); ErrorAndExit("unable to create object file: '" + Buf + "'"); } ObjectFile &Obj = **MaybeObj; OwningBinary<ObjectFile> DebugObj; std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = nullptr; ObjectFile *SymbolObj = &Obj; if (LoadObjects) { // Load the object file LoadedObjInfo = Dyld.loadObject(Obj); if (Dyld.hasError()) ErrorAndExit(Dyld.getErrorString()); // Resolve all the relocations we can. Dyld.resolveRelocations(); if (UseDebugObj) { DebugObj = LoadedObjInfo->getObjectForDebug(Obj); SymbolObj = DebugObj.getBinary(); LoadedObjInfo.reset(); } } std::unique_ptr<DIContext> Context( new DWARFContextInMemory(*SymbolObj,LoadedObjInfo.get())); std::vector<std::pair<SymbolRef, uint64_t>> SymAddr = object::computeSymbolSizes(*SymbolObj); // Use symbol info to iterate functions in the object. for (const auto &P : SymAddr) { object::SymbolRef Sym = P.first; Expected<SymbolRef::Type> TypeOrErr = Sym.getType(); if (!TypeOrErr) { // TODO: Actually report errors helpfully. consumeError(TypeOrErr.takeError()); continue; } SymbolRef::Type Type = *TypeOrErr; if (Type == object::SymbolRef::ST_Function) { Expected<StringRef> Name = Sym.getName(); if (!Name) { // TODO: Actually report errors helpfully. consumeError(Name.takeError()); continue; } Expected<uint64_t> AddrOrErr = Sym.getAddress(); if (!AddrOrErr) { // TODO: Actually report errors helpfully. consumeError(AddrOrErr.takeError()); continue; } uint64_t Addr = *AddrOrErr; uint64_t Size = P.second; // If we're not using the debug object, compute the address of the // symbol in memory (rather than that in the unrelocated object file) // and use that to query the DWARFContext. if (!UseDebugObj && LoadObjects) { auto SecOrErr = Sym.getSection(); if (!SecOrErr) { // TODO: Actually report errors helpfully. consumeError(SecOrErr.takeError()); continue; } object::section_iterator Sec = *SecOrErr; StringRef SecName; Sec->getName(SecName); uint64_t SectionLoadAddress = LoadedObjInfo->getSectionLoadAddress(*Sec); if (SectionLoadAddress != 0) Addr += SectionLoadAddress - Sec->getAddress(); } outs() << "Function: " << *Name << ", Size = " << Size << ", Addr = " << Addr << "\n"; DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); for (auto &D : Lines) { outs() << " Line info @ " << D.first - Addr << ": " << D.second.FileName << ", line:" << D.second.Line << "\n"; } } } } return 0; }
DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L) : IsLittleEndian(Obj.isLittleEndian()), AddressSize(Obj.getBytesInAddress()) { for (const SectionRef &Section : Obj.sections()) { StringRef name; Section.getName(name); // Skip BSS and Virtual sections, they aren't interesting. bool IsBSS = Section.isBSS(); if (IsBSS) continue; bool IsVirtual = Section.isVirtual(); if (IsVirtual) continue; StringRef data; section_iterator RelocatedSection = Section.getRelocatedSection(); // Try to obtain an already relocated version of this section. // Else use the unrelocated section from the object file. We'll have to // apply relocations ourselves later. if (!L || !L->getLoadedSectionContents(*RelocatedSection,data)) Section.getContents(data); name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. // Check if debug info section is compressed with zlib. if (name.startswith("zdebug_")) { uint64_t OriginalSize; if (!zlib::isAvailable() || !consumeCompressedDebugSectionHeader(data, OriginalSize)) continue; UncompressedSections.resize(UncompressedSections.size() + 1); if (zlib::uncompress(data, UncompressedSections.back(), OriginalSize) != zlib::StatusOK) { UncompressedSections.pop_back(); continue; } // Make data point to uncompressed section contents and save its contents. name = name.substr(1); data = UncompressedSections.back(); } StringRef *SectionData = StringSwitch<StringRef *>(name) .Case("debug_info", &InfoSection.Data) .Case("debug_abbrev", &AbbrevSection) .Case("debug_loc", &LocSection.Data) .Case("debug_line", &LineSection.Data) .Case("debug_aranges", &ARangeSection) .Case("debug_frame", &DebugFrameSection) .Case("debug_str", &StringSection) .Case("debug_ranges", &RangeSection) .Case("debug_pubnames", &PubNamesSection) .Case("debug_pubtypes", &PubTypesSection) .Case("debug_gnu_pubnames", &GnuPubNamesSection) .Case("debug_gnu_pubtypes", &GnuPubTypesSection) .Case("debug_info.dwo", &InfoDWOSection.Data) .Case("debug_abbrev.dwo", &AbbrevDWOSection) .Case("debug_loc.dwo", &LocDWOSection.Data) .Case("debug_line.dwo", &LineDWOSection.Data) .Case("debug_str.dwo", &StringDWOSection) .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) .Case("debug_addr", &AddrSection) .Case("apple_names", &AppleNamesSection.Data) .Case("apple_types", &AppleTypesSection.Data) .Case("apple_namespaces", &AppleNamespacesSection.Data) .Case("apple_namespac", &AppleNamespacesSection.Data) .Case("apple_objc", &AppleObjCSection.Data) // Any more debug info sections go here. .Default(nullptr); if (SectionData) { *SectionData = data; if (name == "debug_ranges") { // FIXME: Use the other dwo range section when we emit it. RangeDWOSection = data; } } else if (name == "debug_types") { // Find debug_types data by section rather than name as there are // multiple, comdat grouped, debug_types sections. TypesSections[Section].Data = data; } else if (name == "debug_types.dwo") { TypesDWOSections[Section].Data = data; } if (RelocatedSection == Obj.section_end()) continue; StringRef RelSecName; StringRef RelSecData; RelocatedSection->getName(RelSecName); // If the section we're relocating was relocated already by the JIT, // then we used the relocated version above, so we do not need to process // relocations for it now. if (L && L->getLoadedSectionContents(*RelocatedSection,RelSecData)) continue; RelSecName = RelSecName.substr( RelSecName.find_first_not_of("._")); // Skip . and _ prefixes. // TODO: Add support for relocations in other sections as needed. // Record relocations for the debug_info and debug_line sections. RelocAddrMap *Map = StringSwitch<RelocAddrMap*>(RelSecName) .Case("debug_info", &InfoSection.Relocs) .Case("debug_loc", &LocSection.Relocs) .Case("debug_info.dwo", &InfoDWOSection.Relocs) .Case("debug_line", &LineSection.Relocs) .Case("apple_names", &AppleNamesSection.Relocs) .Case("apple_types", &AppleTypesSection.Relocs) .Case("apple_namespaces", &AppleNamespacesSection.Relocs) .Case("apple_namespac", &AppleNamespacesSection.Relocs) .Case("apple_objc", &AppleObjCSection.Relocs) .Default(nullptr); if (!Map) { // Find debug_types relocs by section rather than name as there are // multiple, comdat grouped, debug_types sections. if (RelSecName == "debug_types") Map = &TypesSections[*RelocatedSection].Relocs; else if (RelSecName == "debug_types.dwo") Map = &TypesDWOSections[*RelocatedSection].Relocs; else continue; } if (Section.relocation_begin() != Section.relocation_end()) { uint64_t SectionSize = RelocatedSection->getSize(); for (const RelocationRef &Reloc : Section.relocations()) { uint64_t Address = Reloc.getOffset(); uint64_t Type = Reloc.getType(); uint64_t SymAddr = 0; uint64_t SectionLoadAddress = 0; object::symbol_iterator Sym = Reloc.getSymbol(); object::section_iterator RSec = Obj.section_end(); // First calculate the address of the symbol or section as it appears // in the objct file if (Sym != Obj.symbol_end()) { ErrorOr<uint64_t> SymAddrOrErr = Sym->getAddress(); if (std::error_code EC = SymAddrOrErr.getError()) { errs() << "error: failed to compute symbol address: " << EC.message() << '\n'; continue; } SymAddr = *SymAddrOrErr; // Also remember what section this symbol is in for later Sym->getSection(RSec); } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) { // MachO also has relocations that point to sections and // scattered relocations. auto RelocInfo = MObj->getRelocation(Reloc.getRawDataRefImpl()); if (MObj->isRelocationScattered(RelocInfo)) { // FIXME: it's not clear how to correctly handle scattered // relocations. continue; } else { RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); SymAddr = RSec->getAddress(); } } // If we are given load addresses for the sections, we need to adjust: // SymAddr = (Address of Symbol Or Section in File) - // (Address of Section in File) + // (Load Address of Section) if (L != nullptr && RSec != Obj.section_end()) { // RSec is now either the section being targetted or the section // containing the symbol being targetted. In either case, // we need to perform the same computation. StringRef SecName; RSec->getName(SecName); // llvm::dbgs() << "Name: '" << SecName // << "', RSec: " << RSec->getRawDataRefImpl() // << ", Section: " << Section.getRawDataRefImpl() << "\n"; SectionLoadAddress = L->getSectionLoadAddress(*RSec); if (SectionLoadAddress != 0) SymAddr += SectionLoadAddress - RSec->getAddress(); } object::RelocVisitor V(Obj); object::RelocToApply R(V.visit(Type, Reloc, SymAddr)); if (V.error()) { SmallString<32> Name; Reloc.getTypeName(Name); errs() << "error: failed to compute relocation: " << Name << "\n"; continue; } if (Address + R.Width > SectionSize) { errs() << "error: " << R.Width << "-byte relocation starting " << Address << " bytes into section " << name << " which is " << SectionSize << " bytes long.\n"; continue; } if (R.Width > 8) { errs() << "error: can't handle a relocation of more than 8 bytes at " "a time.\n"; continue; } DEBUG(dbgs() << "Writing " << format("%p", R.Value) << " at " << format("%p", Address) << " with width " << format("%d", R.Width) << "\n"); Map->insert(std::make_pair(Address, std::make_pair(R.Width, R.Value))); } } } }
// Returns true on error. static bool format(StringRef FileName) { ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = MemoryBuffer::getFileOrSTDIN(FileName); if (std::error_code EC = CodeOrErr.getError()) { errs() << EC.message() << "\n"; return true; } std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get()); if (Code->getBufferSize() == 0) return false; // Empty files are formatted correctly. std::vector<tooling::Range> Ranges; if (fillRanges(Code.get(), Ranges)) return true; StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName; FormatStyle FormatStyle = getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer()); if (SortIncludes.getNumOccurrences() != 0) FormatStyle.SortIncludes = SortIncludes; unsigned CursorPosition = Cursor; Replacements Replaces = sortIncludes(FormatStyle, Code->getBuffer(), Ranges, AssumedFileName, &CursorPosition); auto ChangedCode = tooling::applyAllReplacements(Code->getBuffer(), Replaces); if (!ChangedCode) { llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n"; return true; } // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); bool IncompleteFormat = false; Replacements FormatChanges = reformat(FormatStyle, *ChangedCode, Ranges, AssumedFileName, &IncompleteFormat); Replaces = Replaces.merge(FormatChanges); if (OutputXML) { outs() << "<?xml version='1.0'?>\n<replacements " "xml:space='preserve' incomplete_format='" << (IncompleteFormat ? "true" : "false") << "'>\n"; if (Cursor.getNumOccurrences() != 0) outs() << "<cursor>" << FormatChanges.getShiftedCodePosition(CursorPosition) << "</cursor>\n"; outputReplacementsXML(Replaces); outs() << "</replacements>\n"; } else { IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( new vfs::InMemoryFileSystem); FileManager Files(FileSystemOptions(), InMemoryFileSystem); DiagnosticsEngine Diagnostics( IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), new DiagnosticOptions); SourceManager Sources(Diagnostics, Files); FileID ID = createInMemoryFile(AssumedFileName, Code.get(), Sources, Files, InMemoryFileSystem.get()); Rewriter Rewrite(Sources, LangOptions()); tooling::applyAllReplacements(Replaces, Rewrite); if (Inplace) { if (FileName == "-") errs() << "error: cannot use -i when reading from stdin.\n"; else if (Rewrite.overwriteChangedFiles()) return true; } else { if (Cursor.getNumOccurrences() != 0) outs() << "{ \"Cursor\": " << FormatChanges.getShiftedCodePosition(CursorPosition) << ", \"IncompleteFormat\": " << (IncompleteFormat ? "true" : "false") << " }\n"; Rewrite.getEditBuffer(ID).write(outs()); } } return false; }
static std::unique_ptr<Module> getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, StringSet<> &Internalize, StringSet<> &Maybe) { ld_plugin_input_file File; if (get_input_file(F.handle, &File) != LDPS_OK) message(LDPL_FATAL, "Failed to get file information"); if (get_symbols(F.handle, F.syms.size(), &F.syms[0]) != LDPS_OK) message(LDPL_FATAL, "Failed to get symbol information"); const void *View; if (get_view(F.handle, &View) != LDPS_OK) message(LDPL_FATAL, "Failed to get a view of file"); llvm::ErrorOr<MemoryBufferRef> MBOrErr = object::IRObjectFile::findBitcodeInMemBuffer( MemoryBufferRef(StringRef((const char *)View, File.filesize), "")); if (std::error_code EC = MBOrErr.getError()) message(LDPL_FATAL, "Could not read bitcode from file : %s", EC.message().c_str()); std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(MBOrErr->getBuffer(), "", false); if (release_input_file(F.handle) != LDPS_OK) message(LDPL_FATAL, "Failed to release file information"); ErrorOr<Module *> MOrErr = getLazyBitcodeModule(std::move(Buffer), Context); if (std::error_code EC = MOrErr.getError()) message(LDPL_FATAL, "Could not read bitcode from file : %s", EC.message().c_str()); std::unique_ptr<Module> M(MOrErr.get()); SmallPtrSet<GlobalValue *, 8> Used; collectUsedGlobalVariables(*M, Used, /*CompilerUsed*/ false); DenseSet<GlobalValue *> Drop; std::vector<GlobalAlias *> KeptAliases; for (ld_plugin_symbol &Sym : F.syms) { ld_plugin_symbol_resolution Resolution = (ld_plugin_symbol_resolution)Sym.resolution; if (options::generate_api_file) *ApiFile << Sym.name << ' ' << getResolutionName(Resolution) << '\n'; GlobalValue *GV = M->getNamedValue(Sym.name); if (!GV) continue; // Asm symbol. if (Resolution != LDPR_PREVAILING_DEF_IRONLY && GV->hasCommonLinkage()) { // Common linkage is special. There is no single symbol that wins the // resolution. Instead we have to collect the maximum alignment and size. // The IR linker does that for us if we just pass it every common GV. // We still have to keep track of LDPR_PREVAILING_DEF_IRONLY so we // internalize once the IR linker has done its job. continue; } switch (Resolution) { case LDPR_UNKNOWN: llvm_unreachable("Unexpected resolution"); case LDPR_RESOLVED_IR: case LDPR_RESOLVED_EXEC: case LDPR_RESOLVED_DYN: case LDPR_UNDEF: assert(GV->isDeclarationForLinker()); break; case LDPR_PREVAILING_DEF_IRONLY: { keepGlobalValue(*GV, KeptAliases); if (!Used.count(GV)) { // Since we use the regular lib/Linker, we cannot just internalize GV // now or it will not be copied to the merged module. Instead we force // it to be copied and then internalize it. Internalize.insert(Sym.name); } break; } case LDPR_PREVAILING_DEF: keepGlobalValue(*GV, KeptAliases); break; case LDPR_PREEMPTED_IR: // Gold might have selected a linkonce_odr and preempted a weak_odr. // In that case we have to make sure we don't end up internalizing it. if (!GV->isDiscardableIfUnused()) Maybe.erase(Sym.name); // fall-through case LDPR_PREEMPTED_REG: Drop.insert(GV); break; case LDPR_PREVAILING_DEF_IRONLY_EXP: { // We can only check for address uses after we merge the modules. The // reason is that this GV might have a copy in another module // and in that module the address might be significant, but that // copy will be LDPR_PREEMPTED_IR. if (GV->hasLinkOnceODRLinkage()) Maybe.insert(Sym.name); keepGlobalValue(*GV, KeptAliases); break; } } free(Sym.name); free(Sym.comdat_key); Sym.name = nullptr; Sym.comdat_key = nullptr; } ValueToValueMapTy VM; LocalValueMaterializer Materializer(Drop); for (GlobalAlias *GA : KeptAliases) { // Gold told us to keep GA. It is possible that a GV usied in the aliasee // expression is being dropped. If that is the case, that GV must be copied. Constant *Aliasee = GA->getAliasee(); Constant *Replacement = mapConstantToLocalCopy(Aliasee, VM, &Materializer); if (Aliasee != Replacement) GA->setAliasee(Replacement); } for (auto *GV : Drop) drop(*GV); return M; }
/// Import any functions requested via the -import option. static bool importFunctions(const char *argv0, LLVMContext &Context, Linker &L) { if (SummaryIndex.empty()) return true; ErrorOr<std::unique_ptr<ModuleSummaryIndex>> IndexOrErr = llvm::getModuleSummaryIndexForFile(SummaryIndex, diagnosticHandler); std::error_code EC = IndexOrErr.getError(); if (EC) { errs() << EC.message() << '\n'; return false; } auto Index = std::move(IndexOrErr.get()); // Map of Module -> List of globals to import from the Module std::map<StringRef, DenseSet<const GlobalValue *>> ModuleToGlobalsToImportMap; auto ModuleLoader = [&Context](const char *argv0, const std::string &Identifier) { return loadFile(argv0, Identifier, Context, false); }; ModuleLazyLoaderCache ModuleLoaderCache(ModuleLoader); for (const auto &Import : Imports) { // Identify the requested function and its bitcode source file. size_t Idx = Import.find(':'); if (Idx == std::string::npos) { errs() << "Import parameter bad format: " << Import << "\n"; return false; } std::string FunctionName = Import.substr(0, Idx); std::string FileName = Import.substr(Idx + 1, std::string::npos); // Load the specified source module. auto &SrcModule = ModuleLoaderCache(argv0, FileName); if (verifyModule(SrcModule, &errs())) { errs() << argv0 << ": " << FileName << ": error: input module is broken!\n"; return false; } Function *F = SrcModule.getFunction(FunctionName); if (!F) { errs() << "Ignoring import request for non-existent function " << FunctionName << " from " << FileName << "\n"; continue; } // We cannot import weak_any functions without possibly affecting the // order they are seen and selected by the linker, changing program // semantics. if (F->hasWeakAnyLinkage()) { errs() << "Ignoring import request for weak-any function " << FunctionName << " from " << FileName << "\n"; continue; } if (Verbose) errs() << "Importing " << FunctionName << " from " << FileName << "\n"; auto &Entry = ModuleToGlobalsToImportMap[SrcModule.getModuleIdentifier()]; Entry.insert(F); F->materialize(); } // Do the actual import of globals now, one Module at a time for (auto &GlobalsToImportPerModule : ModuleToGlobalsToImportMap) { // Get the module for the import auto &GlobalsToImport = GlobalsToImportPerModule.second; std::unique_ptr<Module> SrcModule = ModuleLoaderCache.takeModule(GlobalsToImportPerModule.first); assert(&Context == &SrcModule->getContext() && "Context mismatch"); // If modules were created with lazy metadata loading, materialize it // now, before linking it (otherwise this will be a noop). SrcModule->materializeMetadata(); UpgradeDebugInfo(*SrcModule); // Linkage Promotion and renaming if (renameModuleForThinLTO(*SrcModule, *Index, &GlobalsToImport)) return true; // Instruct the linker to not automatically import linkonce defintion. unsigned Flags = Linker::Flags::DontForceLinkLinkonceODR; if (L.linkInModule(std::move(SrcModule), Flags, &GlobalsToImport)) return false; } return true; }
/// Called by gold to see whether this file is one that our plugin can handle. /// We'll try to open it and register all the symbols with add_symbol if /// possible. static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, int *claimed) { LLVMContext Context; MemoryBufferRef BufferRef; std::unique_ptr<MemoryBuffer> Buffer; if (get_view) { const void *view; if (get_view(file->handle, &view) != LDPS_OK) { message(LDPL_ERROR, "Failed to get a view of %s", file->name); return LDPS_ERR; } BufferRef = MemoryBufferRef(StringRef((const char *)view, file->filesize), ""); } else { int64_t offset = 0; // Gold has found what might be IR part-way inside of a file, such as // an .a archive. if (file->offset) { offset = file->offset; } ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = MemoryBuffer::getOpenFileSlice(file->fd, file->name, file->filesize, offset); if (std::error_code EC = BufferOrErr.getError()) { message(LDPL_ERROR, EC.message().c_str()); return LDPS_ERR; } Buffer = std::move(BufferOrErr.get()); BufferRef = Buffer->getMemBufferRef(); } ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr = object::IRObjectFile::createIRObjectFile(BufferRef, Context); std::error_code EC = ObjOrErr.getError(); if (EC == BitcodeError::InvalidBitcodeSignature || EC == object::object_error::invalid_file_type || EC == object::object_error::bitcode_section_not_found) return LDPS_OK; *claimed = 1; if (EC) { message(LDPL_ERROR, "LLVM gold plugin has failed to create LTO module: %s", EC.message().c_str()); return LDPS_ERR; } std::unique_ptr<object::IRObjectFile> Obj = std::move(*ObjOrErr); Modules.resize(Modules.size() + 1); claimed_file &cf = Modules.back(); cf.handle = file->handle; for (auto &Sym : Obj->symbols()) { uint32_t Symflags = Sym.getFlags(); if (!(Symflags & object::BasicSymbolRef::SF_Global)) continue; if (Symflags & object::BasicSymbolRef::SF_FormatSpecific) continue; cf.syms.push_back(ld_plugin_symbol()); ld_plugin_symbol &sym = cf.syms.back(); sym.version = nullptr; SmallString<64> Name; { raw_svector_ostream OS(Name); Sym.printName(OS); } sym.name = strdup(Name.c_str()); const GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl()); sym.visibility = LDPV_DEFAULT; if (GV) { switch (GV->getVisibility()) { case GlobalValue::DefaultVisibility: sym.visibility = LDPV_DEFAULT; break; case GlobalValue::HiddenVisibility: sym.visibility = LDPV_HIDDEN; break; case GlobalValue::ProtectedVisibility: sym.visibility = LDPV_PROTECTED; break; } } if (Symflags & object::BasicSymbolRef::SF_Undefined) { sym.def = LDPK_UNDEF; if (GV && GV->hasExternalWeakLinkage()) sym.def = LDPK_WEAKUNDEF; } else { sym.def = LDPK_DEF; if (GV) { assert(!GV->hasExternalWeakLinkage() && !GV->hasAvailableExternallyLinkage() && "Not a declaration!"); if (GV->hasCommonLinkage()) sym.def = LDPK_COMMON; else if (GV->isWeakForLinker()) sym.def = LDPK_WEAKDEF; } } sym.size = 0; sym.comdat_key = nullptr; if (GV) { const GlobalObject *Base = getBaseObject(*GV); if (!Base) message(LDPL_FATAL, "Unable to determine comdat of alias!"); const Comdat *C = Base->getComdat(); if (C) sym.comdat_key = strdup(C->getName().str().c_str()); else if (Base->hasWeakLinkage() || Base->hasLinkOnceLinkage()) sym.comdat_key = strdup(sym.name); } sym.resolution = LDPR_UNKNOWN; } if (!cf.syms.empty()) { if (add_symbols(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) { message(LDPL_ERROR, "Unable to add symbols!"); return LDPS_ERR; } } return LDPS_OK; }
LTOModule *LTOModule::makeLTOModule(MemoryBufferRef Buffer, TargetOptions options, std::string &errMsg, LLVMContext *Context) { std::unique_ptr<LLVMContext> OwnedContext; if (!Context) { OwnedContext = llvm::make_unique<LLVMContext>(); Context = OwnedContext.get(); } ErrorOr<MemoryBufferRef> MBOrErr = IRObjectFile::findBitcodeInMemBuffer(Buffer); if (std::error_code EC = MBOrErr.getError()) { errMsg = EC.message(); return nullptr; } ErrorOr<Module *> MOrErr = parseBitcodeFile(*MBOrErr, *Context); if (std::error_code EC = MOrErr.getError()) { errMsg = EC.message(); return nullptr; } std::unique_ptr<Module> M(MOrErr.get()); std::string TripleStr = M->getTargetTriple(); if (TripleStr.empty()) TripleStr = sys::getDefaultTargetTriple(); llvm::Triple Triple(TripleStr); // find machine architecture for this module const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); if (!march) return nullptr; // construct LTOModule, hand over ownership of module and target SubtargetFeatures Features; Features.getDefaultSubtargetFeatures(Triple); std::string FeatureStr = Features.getString(); // Set a default CPU for Darwin triples. std::string CPU; if (Triple.isOSDarwin()) { if (Triple.getArch() == llvm::Triple::x86_64) CPU = "core2"; else if (Triple.getArch() == llvm::Triple::x86) CPU = "yonah"; else if (Triple.getArch() == llvm::Triple::aarch64) CPU = "cyclone"; } TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr, options); M->setDataLayout(target->getSubtargetImpl()->getDataLayout()); std::unique_ptr<object::IRObjectFile> IRObj( new object::IRObjectFile(Buffer, std::move(M))); LTOModule *Ret; if (OwnedContext) Ret = new LTOModule(std::move(IRObj), target, std::move(OwnedContext)); else Ret = new LTOModule(std::move(IRObj), target); if (Ret->parseSymbols(errMsg)) { delete Ret; return nullptr; } Ret->parseMetadata(); return Ret; }
/// ReadCheckFile - Read the check file, which specifies the sequence of /// expected strings. The strings are added to the CheckStrings vector. /// Returns true in case of an error, false otherwise. static bool ReadCheckFile(SourceMgr &SM, std::vector<CheckString> &CheckStrings) { ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = MemoryBuffer::getFileOrSTDIN(CheckFilename); if (std::error_code EC = FileOrErr.getError()) { errs() << "Could not open check file '" << CheckFilename << "': " << EC.message() << '\n'; return true; } // If we want to canonicalize whitespace, strip excess whitespace from the // buffer containing the CHECK lines. Remove DOS style line endings. MemoryBuffer *F = CanonicalizeInputFile(FileOrErr.get().release(), NoCanonicalizeWhiteSpace); SM.AddNewSourceBuffer(F, SMLoc()); // Find all instances of CheckPrefix followed by : in the file. StringRef Buffer = F->getBuffer(); std::vector<Pattern> DagNotMatches; // LineNumber keeps track of the line on which CheckPrefix instances are // found. unsigned LineNumber = 1; while (1) { Check::CheckType CheckTy; size_t PrefixLoc; // See if a prefix occurs in the memory buffer. StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer, LineNumber, CheckTy, PrefixLoc); if (UsedPrefix.empty()) break; Buffer = Buffer.drop_front(PrefixLoc); // Location to use for error messages. const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); // PrefixLoc is to the start of the prefix. Skip to the end. Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy)); // Okay, we found the prefix, yay. Remember the rest of the line, but ignore // leading and trailing whitespace. Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); // Scan ahead to the end of line. size_t EOL = Buffer.find_first_of("\n\r"); // Remember the location of the start of the pattern, for diagnostics. SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); // Parse the pattern. Pattern P(CheckTy); if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber)) return true; // Verify that CHECK-LABEL lines do not define or use variables if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, "found '" + UsedPrefix + "-LABEL:'" " with variable definition or use"); return true; } Buffer = Buffer.substr(EOL); // Verify that CHECK-NEXT lines have at least one CHECK line before them. if ((CheckTy == Check::CheckNext) && CheckStrings.empty()) { SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, "found '" + UsedPrefix + "-NEXT:' without previous '" + UsedPrefix + ": line"); return true; } // Handle CHECK-DAG/-NOT. if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { DagNotMatches.push_back(P); continue; } // Okay, add the string we captured to the output vector and move on. CheckStrings.push_back(CheckString(P, UsedPrefix, PatternLoc, CheckTy)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first // prefix as a filler for the error message. if (!DagNotMatches.empty()) { CheckStrings.push_back(CheckString(Pattern(Check::CheckEOF), CheckPrefixes[0], SMLoc::getFromPointer(Buffer.data()), Check::CheckEOF)); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } if (CheckStrings.empty()) { errs() << "error: no check strings found with prefix" << (CheckPrefixes.size() > 1 ? "es " : " "); for (size_t I = 0, N = CheckPrefixes.size(); I != N; ++I) { StringRef Prefix(CheckPrefixes[I]); errs() << '\'' << Prefix << ":'"; if (I != N - 1) errs() << ", "; } errs() << '\n'; return true; } return false; }
void ObjectLoadListener::getDebugInfoForObject( const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) { OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); const ObjectFile &DebugObj = *DebugObjOwner.getBinary(); // TODO: This extracts DWARF information from the object file, but we will // want to also be able to eventually extract WinCodeView information as well DWARFContextInMemory DwarfContext(DebugObj); // Use symbol info to find the function size. // If there are funclets, they will each have separate symbols, so we need // to sum the sizes, since the EE wants a single report for the entire // function+funclets. uint64_t Addr = UINT64_MAX; uint64_t Size = 0; std::vector<std::pair<SymbolRef, uint64_t>> SymbolSizes = object::computeSymbolSizes(DebugObj); for (const auto &Pair : SymbolSizes) { object::SymbolRef Symbol = Pair.first; SymbolRef::Type SymType = Symbol.getType(); if (SymType != SymbolRef::ST_Function) continue; // Function info ErrorOr<uint64_t> AddrOrError = Symbol.getAddress(); if (!AddrOrError) { continue; // Error. } uint64_t SingleAddr = AddrOrError.get(); uint64_t SingleSize = Pair.second; if (SingleAddr < Addr) { // The main function is always laid out first Addr = SingleAddr; } Size += SingleSize; } uint32_t LastDebugOffset = (uint32_t)-1; uint32_t NumDebugRanges = 0; ICorDebugInfo::OffsetMapping *OM; DILineInfoTable Lines = DwarfContext.getLineInfoForAddressRange(Addr, Size); DILineInfoTable::iterator Begin = Lines.begin(); DILineInfoTable::iterator End = Lines.end(); // Count offset entries. Will skip an entry if the current IL offset // matches the previous offset. for (DILineInfoTable::iterator It = Begin; It != End; ++It) { uint32_t LineNumber = (It->second).Line; if (LineNumber != LastDebugOffset) { NumDebugRanges++; LastDebugOffset = LineNumber; } } // Reset offset LastDebugOffset = (uint32_t)-1; if (NumDebugRanges > 0) { // Allocate OffsetMapping array unsigned SizeOfArray = (NumDebugRanges) * sizeof(ICorDebugInfo::OffsetMapping); OM = (ICorDebugInfo::OffsetMapping *)Context->JitInfo->allocateArray( SizeOfArray); unsigned CurrentDebugEntry = 0; // Iterate through the debug entries and save IL offset, native // offset, and source reason for (DILineInfoTable::iterator It = Begin; It != End; ++It) { int Offset = It->first; uint32_t LineNumber = (It->second).Line; // We store info about if the instruction is being recorded because // it is a call in the column field bool IsCall = (It->second).Column == 1; if (LineNumber != LastDebugOffset) { LastDebugOffset = LineNumber; OM[CurrentDebugEntry].nativeOffset = Offset; OM[CurrentDebugEntry].ilOffset = LineNumber; OM[CurrentDebugEntry].source = IsCall ? ICorDebugInfo::CALL_INSTRUCTION : ICorDebugInfo::STACK_EMPTY; CurrentDebugEntry++; } } // Send array of OffsetMappings to CLR EE CORINFO_METHOD_INFO *MethodInfo = Context->MethodInfo; CORINFO_METHOD_HANDLE MethodHandle = MethodInfo->ftn; Context->JitInfo->setBoundaries(MethodHandle, NumDebugRanges, OM); getDebugInfoForLocals(DwarfContext, Addr, Size); } }
//===----------------------------------------------------------------------===// // main Driver function // int main(int argc, char **argv, char * const *envp) { sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); atexit(llvm_shutdown); // Call llvm_shutdown() on exit. if (argc > 1) ExitOnErr.setBanner(std::string(argv[0]) + ": "); // If we have a native target, initialize it to ensure it is linked in and // usable by the JIT. InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); InitializeNativeTargetAsmParser(); cl::ParseCommandLineOptions(argc, argv, "llvm interpreter & dynamic compiler\n"); // If the user doesn't want core files, disable them. if (DisableCoreFiles) sys::Process::PreventCoreFiles(); LLVMContext Context; // Load the bitcode... SMDiagnostic Err; std::unique_ptr<Module> Owner = parseIRFile(InputFile, Err, Context); Module *Mod = Owner.get(); if (!Mod) { Err.print(argv[0], errs()); return 1; } if (UseJITKind == JITKind::OrcLazy) { std::vector<std::unique_ptr<Module>> Ms; Ms.push_back(std::move(Owner)); for (auto &ExtraMod : ExtraModules) { Ms.push_back(parseIRFile(ExtraMod, Err, Context)); if (!Ms.back()) { Err.print(argv[0], errs()); return 1; } } std::vector<std::string> Args; Args.push_back(InputFile); for (auto &Arg : InputArgv) Args.push_back(Arg); return runOrcLazyJIT(std::move(Ms), Args); } if (EnableCacheManager) { std::string CacheName("file:"); CacheName.append(InputFile); Mod->setModuleIdentifier(CacheName); } // If not jitting lazily, load the whole bitcode file eagerly too. if (NoLazyCompilation) { // Use *argv instead of argv[0] to work around a wrong GCC warning. ExitOnError ExitOnErr(std::string(*argv) + ": bitcode didn't read correctly: "); ExitOnErr(Mod->materializeAll()); } std::string ErrorMsg; EngineBuilder builder(std::move(Owner)); builder.setMArch(MArch); builder.setMCPU(MCPU); builder.setMAttrs(MAttrs); if (RelocModel.getNumOccurrences()) builder.setRelocationModel(RelocModel); builder.setCodeModel(CMModel); builder.setErrorStr(&ErrorMsg); builder.setEngineKind(ForceInterpreter ? EngineKind::Interpreter : EngineKind::JIT); builder.setUseOrcMCJITReplacement(UseJITKind == JITKind::OrcMCJITReplacement); // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) Mod->setTargetTriple(Triple::normalize(TargetTriple)); // Enable MCJIT if desired. RTDyldMemoryManager *RTDyldMM = nullptr; if (!ForceInterpreter) { if (RemoteMCJIT) RTDyldMM = new ForwardingMemoryManager(); else RTDyldMM = new SectionMemoryManager(); // Deliberately construct a temp std::unique_ptr to pass in. Do not null out // RTDyldMM: We still use it below, even though we don't own it. builder.setMCJITMemoryManager( std::unique_ptr<RTDyldMemoryManager>(RTDyldMM)); } else if (RemoteMCJIT) { errs() << "error: Remote process execution does not work with the " "interpreter.\n"; exit(1); } builder.setOptLevel(getOptLevel()); TargetOptions Options; if (FloatABIForCalls != FloatABI::Default) Options.FloatABIType = FloatABIForCalls; builder.setTargetOptions(Options); std::unique_ptr<ExecutionEngine> EE(builder.create()); if (!EE) { if (!ErrorMsg.empty()) errs() << argv[0] << ": error creating EE: " << ErrorMsg << "\n"; else errs() << argv[0] << ": unknown error creating EE!\n"; exit(1); } std::unique_ptr<LLIObjectCache> CacheManager; if (EnableCacheManager) { CacheManager.reset(new LLIObjectCache(ObjectCacheDir)); EE->setObjectCache(CacheManager.get()); } // Load any additional modules specified on the command line. for (unsigned i = 0, e = ExtraModules.size(); i != e; ++i) { std::unique_ptr<Module> XMod = parseIRFile(ExtraModules[i], Err, Context); if (!XMod) { Err.print(argv[0], errs()); return 1; } if (EnableCacheManager) { std::string CacheName("file:"); CacheName.append(ExtraModules[i]); XMod->setModuleIdentifier(CacheName); } EE->addModule(std::move(XMod)); } for (unsigned i = 0, e = ExtraObjects.size(); i != e; ++i) { Expected<object::OwningBinary<object::ObjectFile>> Obj = object::ObjectFile::createObjectFile(ExtraObjects[i]); if (!Obj) { // TODO: Actually report errors helpfully. consumeError(Obj.takeError()); Err.print(argv[0], errs()); return 1; } object::OwningBinary<object::ObjectFile> &O = Obj.get(); EE->addObjectFile(std::move(O)); } for (unsigned i = 0, e = ExtraArchives.size(); i != e; ++i) { ErrorOr<std::unique_ptr<MemoryBuffer>> ArBufOrErr = MemoryBuffer::getFileOrSTDIN(ExtraArchives[i]); if (!ArBufOrErr) { Err.print(argv[0], errs()); return 1; } std::unique_ptr<MemoryBuffer> &ArBuf = ArBufOrErr.get(); Expected<std::unique_ptr<object::Archive>> ArOrErr = object::Archive::create(ArBuf->getMemBufferRef()); if (!ArOrErr) { std::string Buf; raw_string_ostream OS(Buf); logAllUnhandledErrors(ArOrErr.takeError(), OS, ""); OS.flush(); errs() << Buf; return 1; } std::unique_ptr<object::Archive> &Ar = ArOrErr.get(); object::OwningBinary<object::Archive> OB(std::move(Ar), std::move(ArBuf)); EE->addArchive(std::move(OB)); } // If the target is Cygwin/MingW and we are generating remote code, we // need an extra module to help out with linking. if (RemoteMCJIT && Triple(Mod->getTargetTriple()).isOSCygMing()) { addCygMingExtraModule(*EE, Context, Mod->getTargetTriple()); } // The following functions have no effect if their respective profiling // support wasn't enabled in the build configuration. EE->RegisterJITEventListener( JITEventListener::createOProfileJITEventListener()); EE->RegisterJITEventListener( JITEventListener::createIntelJITEventListener()); if (!NoLazyCompilation && RemoteMCJIT) { errs() << "warning: remote mcjit does not support lazy compilation\n"; NoLazyCompilation = true; } EE->DisableLazyCompilation(NoLazyCompilation); // If the user specifically requested an argv[0] to pass into the program, // do it now. if (!FakeArgv0.empty()) { InputFile = static_cast<std::string>(FakeArgv0); } else { // Otherwise, if there is a .bc suffix on the executable strip it off, it // might confuse the program. if (StringRef(InputFile).endswith(".bc")) InputFile.erase(InputFile.length() - 3); } // Add the module's name to the start of the vector of arguments to main(). InputArgv.insert(InputArgv.begin(), InputFile); // Call the main function from M as if its signature were: // int main (int argc, char **argv, const char **envp) // using the contents of Args to determine argc & argv, and the contents of // EnvVars to determine envp. // Function *EntryFn = Mod->getFunction(EntryFunc); if (!EntryFn) { errs() << '\'' << EntryFunc << "\' function not found in module.\n"; return -1; } // Reset errno to zero on entry to main. errno = 0; int Result = -1; // Sanity check use of remote-jit: LLI currently only supports use of the // remote JIT on Unix platforms. if (RemoteMCJIT) { #ifndef LLVM_ON_UNIX errs() << "Warning: host does not support external remote targets.\n" << " Defaulting to local execution\n"; return -1; #else if (ChildExecPath.empty()) { errs() << "-remote-mcjit requires -mcjit-remote-process.\n"; exit(1); } else if (!sys::fs::can_execute(ChildExecPath)) { errs() << "Unable to find usable child executable: '" << ChildExecPath << "'\n"; return -1; } #endif } if (!RemoteMCJIT) { // If the program doesn't explicitly call exit, we will need the Exit // function later on to make an explicit call, so get the function now. Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), Type::getInt32Ty(Context), nullptr); // Run static constructors. if (!ForceInterpreter) { // Give MCJIT a chance to apply relocations and set page permissions. EE->finalizeObject(); } EE->runStaticConstructorsDestructors(false); // Trigger compilation separately so code regions that need to be // invalidated will be known. (void)EE->getPointerToFunction(EntryFn); // Clear instruction cache before code will be executed. if (RTDyldMM) static_cast<SectionMemoryManager*>(RTDyldMM)->invalidateInstructionCache(); // Run main. Result = EE->runFunctionAsMain(EntryFn, InputArgv, envp); // Run static destructors. EE->runStaticConstructorsDestructors(true); // If the program didn't call exit explicitly, we should call it now. // This ensures that any atexit handlers get called correctly. if (Function *ExitF = dyn_cast<Function>(Exit)) { std::vector<GenericValue> Args; GenericValue ResultGV; ResultGV.IntVal = APInt(32, Result); Args.push_back(ResultGV); EE->runFunction(ExitF, Args); errs() << "ERROR: exit(" << Result << ") returned!\n"; abort(); } else { errs() << "ERROR: exit defined with wrong prototype!\n"; abort(); } } else { // else == "if (RemoteMCJIT)" // Remote target MCJIT doesn't (yet) support static constructors. No reason // it couldn't. This is a limitation of the LLI implemantation, not the // MCJIT itself. FIXME. // Lanch the remote process and get a channel to it. std::unique_ptr<FDRawChannel> C = launchRemote(); if (!C) { errs() << "Failed to launch remote JIT.\n"; exit(1); } // Create a remote target client running over the channel. typedef orc::remote::OrcRemoteTargetClient<orc::rpc::RawByteChannel> MyRemote; auto R = ExitOnErr(MyRemote::Create(*C)); // Create a remote memory manager. std::unique_ptr<MyRemote::RCMemoryManager> RemoteMM; ExitOnErr(R->createRemoteMemoryManager(RemoteMM)); // Forward MCJIT's memory manager calls to the remote memory manager. static_cast<ForwardingMemoryManager*>(RTDyldMM)->setMemMgr( std::move(RemoteMM)); // Forward MCJIT's symbol resolution calls to the remote. static_cast<ForwardingMemoryManager*>(RTDyldMM)->setResolver( orc::createLambdaResolver( [](const std::string &Name) { return nullptr; }, [&](const std::string &Name) { if (auto Addr = ExitOnErr(R->getSymbolAddress(Name))) return JITSymbol(Addr, JITSymbolFlags::Exported); return JITSymbol(nullptr); } )); // Grab the target address of the JIT'd main function on the remote and call // it. // FIXME: argv and envp handling. JITTargetAddress Entry = EE->getFunctionAddress(EntryFn->getName().str()); EE->finalizeObject(); DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x" << format("%llx", Entry) << "\n"); Result = ExitOnErr(R->callIntVoid(Entry)); // Like static constructors, the remote target MCJIT support doesn't handle // this yet. It could. FIXME. // Delete the EE - we need to tear it down *before* we terminate the session // with the remote, otherwise it'll crash when it tries to release resources // on a remote that has already been disconnected. EE.reset(); // Signal the remote target that we're done JITing. ExitOnErr(R->terminateSession()); } return Result; }
void ObjectLoadListener::recordRelocations( const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) { for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); SI != SE; ++SI) { section_iterator Section = SI->getRelocatedSection(); if (Section == SE) { continue; } StringRef SectionName; std::error_code ErrorCode = Section->getName(SectionName); if (ErrorCode) { assert(false && ErrorCode.message().c_str()); } if (SectionName.startswith(".debug") || SectionName.startswith(".rela.debug") || !SectionName.compare(".pdata") || SectionName.startswith(".eh_frame") || SectionName.startswith(".rela.eh_frame")) { // Skip sections whose contents are not directly reported to the EE continue; } relocation_iterator I = SI->relocation_begin(); relocation_iterator E = SI->relocation_end(); for (; I != E; ++I) { symbol_iterator Symbol = I->getSymbol(); assert(Symbol != Obj.symbol_end()); ErrorOr<section_iterator> SymbolSectionOrErr = Symbol->getSection(); assert(!SymbolSectionOrErr.getError()); object::section_iterator SymbolSection = *SymbolSectionOrErr; const bool IsExtern = SymbolSection == Obj.section_end(); uint64_t RelType = I->getType(); uint64_t Offset = I->getOffset(); uint8_t *RelocationTarget; if (IsExtern) { // This is an external symbol. Verify that it's one we created for // a global variable and report the relocation via Jit interface. ErrorOr<StringRef> NameOrError = Symbol->getName(); assert(NameOrError); StringRef TargetName = NameOrError.get(); auto MapIter = Context->NameToHandleMap.find(TargetName); if (MapIter == Context->NameToHandleMap.end()) { // The xdata gets a pointer to our personality routine, which we // dummied up. We can safely skip it since the EE isn't actually // going to use the value (it inserts the correct one before handing // the xdata off to the OS). assert(!TargetName.compare("ProcessCLRException")); assert(SectionName.startswith(".xdata")); continue; } else { assert(MapIter->second == Context->NameToHandleMap[TargetName]); RelocationTarget = (uint8_t *)MapIter->second; } } else { RelocationTarget = (uint8_t *)(L.getSectionLoadAddress(*SymbolSection) + Symbol->getValue()); } uint64_t Addend = 0; uint64_t EERelType = getRelocationType(RelType); uint64_t SectionAddress = L.getSectionLoadAddress(*Section); assert(SectionAddress != 0); uint8_t *FixupAddress = (uint8_t *)(SectionAddress + Offset); if (Obj.isELF()) { // Addend is part of the relocation ELFRelocationRef ElfReloc(*I); ErrorOr<uint64_t> ElfAddend = ElfReloc.getAddend(); assert(!ElfAddend.getError()); Addend = ElfAddend.get(); } else { // Addend is read from the location to be fixed up Addend = getRelocationAddend(RelType, FixupAddress); } Context->JitInfo->recordRelocation(FixupAddress, RelocationTarget + Addend, EERelType); } } }
// Load single header list and dependencies. std::error_code ModularizeUtilities::loadSingleHeaderListsAndDependencies( llvm::StringRef InputPath) { // By default, use the path component of the list file name. SmallString<256> HeaderDirectory(InputPath); llvm::sys::path::remove_filename(HeaderDirectory); SmallString<256> CurrentDirectory; llvm::sys::fs::current_path(CurrentDirectory); // Get the prefix if we have one. if (HeaderPrefix.size() != 0) HeaderDirectory = HeaderPrefix; // Read the header list file into a buffer. ErrorOr<std::unique_ptr<MemoryBuffer>> listBuffer = MemoryBuffer::getFile(InputPath); if (std::error_code EC = listBuffer.getError()) return EC; // Parse the header list into strings. SmallVector<StringRef, 32> Strings; listBuffer.get()->getBuffer().split(Strings, "\n", -1, false); // Collect the header file names from the string list. for (SmallVectorImpl<StringRef>::iterator I = Strings.begin(), E = Strings.end(); I != E; ++I) { StringRef Line = I->trim(); // Ignore comments and empty lines. if (Line.empty() || (Line[0] == '#')) continue; std::pair<StringRef, StringRef> TargetAndDependents = Line.split(':'); SmallString<256> HeaderFileName; // Prepend header file name prefix if it's not absolute. if (llvm::sys::path::is_absolute(TargetAndDependents.first)) llvm::sys::path::native(TargetAndDependents.first, HeaderFileName); else { if (HeaderDirectory.size() != 0) HeaderFileName = HeaderDirectory; else HeaderFileName = CurrentDirectory; llvm::sys::path::append(HeaderFileName, TargetAndDependents.first); llvm::sys::path::native(HeaderFileName); } // Handle optional dependencies. DependentsVector Dependents; SmallVector<StringRef, 4> DependentsList; TargetAndDependents.second.split(DependentsList, " ", -1, false); int Count = DependentsList.size(); for (int Index = 0; Index < Count; ++Index) { SmallString<256> Dependent; if (llvm::sys::path::is_absolute(DependentsList[Index])) Dependent = DependentsList[Index]; else { if (HeaderDirectory.size() != 0) Dependent = HeaderDirectory; else Dependent = CurrentDirectory; llvm::sys::path::append(Dependent, DependentsList[Index]); } llvm::sys::path::native(Dependent); Dependents.push_back(getCanonicalPath(Dependent.str())); } // Get canonical form. HeaderFileName = getCanonicalPath(HeaderFileName); // Save the resulting header file path and dependencies. HeaderFileNames.push_back(HeaderFileName.str()); Dependencies[HeaderFileName.str()] = Dependents; } return std::error_code(); }
static void dumpCXXData(const ObjectFile *Obj) { struct CompleteObjectLocator { StringRef Symbols[2]; ArrayRef<little32_t> Data; }; struct ClassHierarchyDescriptor { StringRef Symbols[1]; ArrayRef<little32_t> Data; }; struct BaseClassDescriptor { StringRef Symbols[2]; ArrayRef<little32_t> Data; }; struct TypeDescriptor { StringRef Symbols[1]; uint64_t AlwaysZero; StringRef MangledName; }; struct ThrowInfo { uint32_t Flags; }; struct CatchableTypeArray { uint32_t NumEntries; }; struct CatchableType { uint32_t Flags; uint32_t NonVirtualBaseAdjustmentOffset; int32_t VirtualBasePointerOffset; uint32_t VirtualBaseAdjustmentOffset; uint32_t Size; StringRef Symbols[2]; }; std::map<std::pair<StringRef, uint64_t>, StringRef> VFTableEntries; std::map<std::pair<StringRef, uint64_t>, StringRef> TIEntries; std::map<std::pair<StringRef, uint64_t>, StringRef> CTAEntries; std::map<StringRef, ArrayRef<little32_t>> VBTables; std::map<StringRef, CompleteObjectLocator> COLs; std::map<StringRef, ClassHierarchyDescriptor> CHDs; std::map<std::pair<StringRef, uint64_t>, StringRef> BCAEntries; std::map<StringRef, BaseClassDescriptor> BCDs; std::map<StringRef, TypeDescriptor> TDs; std::map<StringRef, ThrowInfo> TIs; std::map<StringRef, CatchableTypeArray> CTAs; std::map<StringRef, CatchableType> CTs; std::map<std::pair<StringRef, uint64_t>, StringRef> VTableSymEntries; std::map<std::pair<StringRef, uint64_t>, int64_t> VTableDataEntries; std::map<std::pair<StringRef, uint64_t>, StringRef> VTTEntries; std::map<StringRef, StringRef> TINames; SectionRelocMap.clear(); for (const SectionRef &Section : Obj->sections()) { section_iterator Sec2 = Section.getRelocatedSection(); if (Sec2 != Obj->section_end()) SectionRelocMap[*Sec2].push_back(Section); } uint8_t BytesInAddress = Obj->getBytesInAddress(); std::vector<std::pair<SymbolRef, uint64_t>> SymAddr = object::computeSymbolSizes(*Obj); for (auto &P : SymAddr) { object::SymbolRef Sym = P.first; uint64_t SymSize = P.second; ErrorOr<StringRef> SymNameOrErr = Sym.getName(); error(SymNameOrErr.getError()); StringRef SymName = *SymNameOrErr; ErrorOr<object::section_iterator> SecIOrErr = Sym.getSection(); error(SecIOrErr.getError()); object::section_iterator SecI = *SecIOrErr; // Skip external symbols. if (SecI == Obj->section_end()) continue; const SectionRef &Sec = *SecI; // Skip virtual or BSS sections. if (Sec.isBSS() || Sec.isVirtual()) continue; StringRef SecContents; error(Sec.getContents(SecContents)); ErrorOr<uint64_t> SymAddressOrErr = Sym.getAddress(); error(SymAddressOrErr.getError()); uint64_t SymAddress = *SymAddressOrErr; uint64_t SecAddress = Sec.getAddress(); uint64_t SecSize = Sec.getSize(); uint64_t SymOffset = SymAddress - SecAddress; StringRef SymContents = SecContents.substr(SymOffset, SymSize); // VFTables in the MS-ABI start with '??_7' and are contained within their // own COMDAT section. We then determine the contents of the VFTable by // looking at each relocation in the section. if (SymName.startswith("??_7")) { // Each relocation either names a virtual method or a thunk. We note the // offset into the section and the symbol used for the relocation. collectRelocationOffsets(Obj, Sec, SecAddress, SecAddress, SecSize, SymName, VFTableEntries); } // VBTables in the MS-ABI start with '??_8' and are filled with 32-bit // offsets of virtual bases. else if (SymName.startswith("??_8")) { ArrayRef<little32_t> VBTableData( reinterpret_cast<const little32_t *>(SymContents.data()), SymContents.size() / sizeof(little32_t)); VBTables[SymName] = VBTableData; } // Complete object locators in the MS-ABI start with '??_R4' else if (SymName.startswith("??_R4")) { CompleteObjectLocator COL; COL.Data = makeArrayRef( reinterpret_cast<const little32_t *>(SymContents.data()), 3); StringRef *I = std::begin(COL.Symbols), *E = std::end(COL.Symbols); collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); COLs[SymName] = COL; } // Class hierarchy descriptors in the MS-ABI start with '??_R3' else if (SymName.startswith("??_R3")) { ClassHierarchyDescriptor CHD; CHD.Data = makeArrayRef( reinterpret_cast<const little32_t *>(SymContents.data()), 3); StringRef *I = std::begin(CHD.Symbols), *E = std::end(CHD.Symbols); collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); CHDs[SymName] = CHD; } // Class hierarchy descriptors in the MS-ABI start with '??_R2' else if (SymName.startswith("??_R2")) { // Each relocation names a base class descriptor. We note the offset into // the section and the symbol used for the relocation. collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, SymName, BCAEntries); } // Base class descriptors in the MS-ABI start with '??_R1' else if (SymName.startswith("??_R1")) { BaseClassDescriptor BCD; BCD.Data = makeArrayRef( reinterpret_cast<const little32_t *>(SymContents.data()) + 1, 5); StringRef *I = std::begin(BCD.Symbols), *E = std::end(BCD.Symbols); collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); BCDs[SymName] = BCD; } // Type descriptors in the MS-ABI start with '??_R0' else if (SymName.startswith("??_R0")) { const char *DataPtr = SymContents.drop_front(BytesInAddress).data(); TypeDescriptor TD; if (BytesInAddress == 8) TD.AlwaysZero = *reinterpret_cast<const little64_t *>(DataPtr); else TD.AlwaysZero = *reinterpret_cast<const little32_t *>(DataPtr); TD.MangledName = SymContents.drop_front(BytesInAddress * 2); StringRef *I = std::begin(TD.Symbols), *E = std::end(TD.Symbols); collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); TDs[SymName] = TD; } // Throw descriptors in the MS-ABI start with '_TI' else if (SymName.startswith("_TI") || SymName.startswith("__TI")) { ThrowInfo TI; TI.Flags = *reinterpret_cast<const little32_t *>(SymContents.data()); collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, SymName, TIEntries); TIs[SymName] = TI; } // Catchable type arrays in the MS-ABI start with _CTA or __CTA. else if (SymName.startswith("_CTA") || SymName.startswith("__CTA")) { CatchableTypeArray CTA; CTA.NumEntries = *reinterpret_cast<const little32_t *>(SymContents.data()); collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, SymName, CTAEntries); CTAs[SymName] = CTA; } // Catchable types in the MS-ABI start with _CT or __CT. else if (SymName.startswith("_CT") || SymName.startswith("__CT")) { const little32_t *DataPtr = reinterpret_cast<const little32_t *>(SymContents.data()); CatchableType CT; CT.Flags = DataPtr[0]; CT.NonVirtualBaseAdjustmentOffset = DataPtr[2]; CT.VirtualBasePointerOffset = DataPtr[3]; CT.VirtualBaseAdjustmentOffset = DataPtr[4]; CT.Size = DataPtr[5]; StringRef *I = std::begin(CT.Symbols), *E = std::end(CT.Symbols); collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, E); CTs[SymName] = CT; } // Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'. else if (SymName.startswith("_ZTT") || SymName.startswith("__ZTT")) { collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, SymName, VTTEntries); } // Typeinfo names in the Itanium ABI start with '_ZTS' or '__ZTS'. else if (SymName.startswith("_ZTS") || SymName.startswith("__ZTS")) { TINames[SymName] = SymContents.slice(0, SymContents.find('\0')); } // Vtables in the Itanium ABI start with '_ZTV' or '__ZTV'. else if (SymName.startswith("_ZTV") || SymName.startswith("__ZTV")) { collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, SymName, VTableSymEntries); for (uint64_t SymOffI = 0; SymOffI < SymSize; SymOffI += BytesInAddress) { auto Key = std::make_pair(SymName, SymOffI); if (VTableSymEntries.count(Key)) continue; const char *DataPtr = SymContents.substr(SymOffI, BytesInAddress).data(); int64_t VData; if (BytesInAddress == 8) VData = *reinterpret_cast<const little64_t *>(DataPtr); else VData = *reinterpret_cast<const little32_t *>(DataPtr); VTableDataEntries[Key] = VData; } } // Typeinfo structures in the Itanium ABI start with '_ZTI' or '__ZTI'. else if (SymName.startswith("_ZTI") || SymName.startswith("__ZTI")) { // FIXME: Do something with these! } } for (const auto &VFTableEntry : VFTableEntries) { StringRef VFTableName = VFTableEntry.first.first; uint64_t Offset = VFTableEntry.first.second; StringRef SymName = VFTableEntry.second; outs() << VFTableName << '[' << Offset << "]: " << SymName << '\n'; } for (const auto &VBTable : VBTables) { StringRef VBTableName = VBTable.first; uint32_t Idx = 0; for (little32_t Offset : VBTable.second) { outs() << VBTableName << '[' << Idx << "]: " << Offset << '\n'; Idx += sizeof(Offset); } } for (const auto &COLPair : COLs) { StringRef COLName = COLPair.first; const CompleteObjectLocator &COL = COLPair.second; outs() << COLName << "[IsImageRelative]: " << COL.Data[0] << '\n'; outs() << COLName << "[OffsetToTop]: " << COL.Data[1] << '\n'; outs() << COLName << "[VFPtrOffset]: " << COL.Data[2] << '\n'; outs() << COLName << "[TypeDescriptor]: " << COL.Symbols[0] << '\n'; outs() << COLName << "[ClassHierarchyDescriptor]: " << COL.Symbols[1] << '\n'; } for (const auto &CHDPair : CHDs) { StringRef CHDName = CHDPair.first; const ClassHierarchyDescriptor &CHD = CHDPair.second; outs() << CHDName << "[AlwaysZero]: " << CHD.Data[0] << '\n'; outs() << CHDName << "[Flags]: " << CHD.Data[1] << '\n'; outs() << CHDName << "[NumClasses]: " << CHD.Data[2] << '\n'; outs() << CHDName << "[BaseClassArray]: " << CHD.Symbols[0] << '\n'; } for (const auto &BCAEntry : BCAEntries) { StringRef BCAName = BCAEntry.first.first; uint64_t Offset = BCAEntry.first.second; StringRef SymName = BCAEntry.second; outs() << BCAName << '[' << Offset << "]: " << SymName << '\n'; } for (const auto &BCDPair : BCDs) { StringRef BCDName = BCDPair.first; const BaseClassDescriptor &BCD = BCDPair.second; outs() << BCDName << "[TypeDescriptor]: " << BCD.Symbols[0] << '\n'; outs() << BCDName << "[NumBases]: " << BCD.Data[0] << '\n'; outs() << BCDName << "[OffsetInVBase]: " << BCD.Data[1] << '\n'; outs() << BCDName << "[VBPtrOffset]: " << BCD.Data[2] << '\n'; outs() << BCDName << "[OffsetInVBTable]: " << BCD.Data[3] << '\n'; outs() << BCDName << "[Flags]: " << BCD.Data[4] << '\n'; outs() << BCDName << "[ClassHierarchyDescriptor]: " << BCD.Symbols[1] << '\n'; } for (const auto &TDPair : TDs) { StringRef TDName = TDPair.first; const TypeDescriptor &TD = TDPair.second; outs() << TDName << "[VFPtr]: " << TD.Symbols[0] << '\n'; outs() << TDName << "[AlwaysZero]: " << TD.AlwaysZero << '\n'; outs() << TDName << "[MangledName]: "; outs().write_escaped(TD.MangledName.rtrim(StringRef("\0", 1)), /*UseHexEscapes=*/true) << '\n'; } for (const auto &TIPair : TIs) { StringRef TIName = TIPair.first; const ThrowInfo &TI = TIPair.second; auto dumpThrowInfoFlag = [&](const char *Name, uint32_t Flag) { outs() << TIName << "[Flags." << Name << "]: " << (TI.Flags & Flag ? "true" : "false") << '\n'; }; auto dumpThrowInfoSymbol = [&](const char *Name, int Offset) { outs() << TIName << '[' << Name << "]: "; auto Entry = TIEntries.find(std::make_pair(TIName, Offset)); outs() << (Entry == TIEntries.end() ? "null" : Entry->second) << '\n'; }; outs() << TIName << "[Flags]: " << TI.Flags << '\n'; dumpThrowInfoFlag("Const", 1); dumpThrowInfoFlag("Volatile", 2); dumpThrowInfoSymbol("CleanupFn", 4); dumpThrowInfoSymbol("ForwardCompat", 8); dumpThrowInfoSymbol("CatchableTypeArray", 12); } for (const auto &CTAPair : CTAs) { StringRef CTAName = CTAPair.first; const CatchableTypeArray &CTA = CTAPair.second; outs() << CTAName << "[NumEntries]: " << CTA.NumEntries << '\n'; unsigned Idx = 0; for (auto I = CTAEntries.lower_bound(std::make_pair(CTAName, 0)), E = CTAEntries.upper_bound(std::make_pair(CTAName, UINT64_MAX)); I != E; ++I) outs() << CTAName << '[' << Idx++ << "]: " << I->second << '\n'; } for (const auto &CTPair : CTs) { StringRef CTName = CTPair.first; const CatchableType &CT = CTPair.second; auto dumpCatchableTypeFlag = [&](const char *Name, uint32_t Flag) { outs() << CTName << "[Flags." << Name << "]: " << (CT.Flags & Flag ? "true" : "false") << '\n'; }; outs() << CTName << "[Flags]: " << CT.Flags << '\n'; dumpCatchableTypeFlag("ScalarType", 1); dumpCatchableTypeFlag("VirtualInheritance", 4); outs() << CTName << "[TypeDescriptor]: " << CT.Symbols[0] << '\n'; outs() << CTName << "[NonVirtualBaseAdjustmentOffset]: " << CT.NonVirtualBaseAdjustmentOffset << '\n'; outs() << CTName << "[VirtualBasePointerOffset]: " << CT.VirtualBasePointerOffset << '\n'; outs() << CTName << "[VirtualBaseAdjustmentOffset]: " << CT.VirtualBaseAdjustmentOffset << '\n'; outs() << CTName << "[Size]: " << CT.Size << '\n'; outs() << CTName << "[CopyCtor]: " << (CT.Symbols[1].empty() ? "null" : CT.Symbols[1]) << '\n'; } for (const auto &VTTPair : VTTEntries) { StringRef VTTName = VTTPair.first.first; uint64_t VTTOffset = VTTPair.first.second; StringRef VTTEntry = VTTPair.second; outs() << VTTName << '[' << VTTOffset << "]: " << VTTEntry << '\n'; } for (const auto &TIPair : TINames) { StringRef TIName = TIPair.first; outs() << TIName << ": " << TIPair.second << '\n'; } auto VTableSymI = VTableSymEntries.begin(); auto VTableSymE = VTableSymEntries.end(); auto VTableDataI = VTableDataEntries.begin(); auto VTableDataE = VTableDataEntries.end(); for (;;) { bool SymDone = VTableSymI == VTableSymE; bool DataDone = VTableDataI == VTableDataE; if (SymDone && DataDone) break; if (!SymDone && (DataDone || VTableSymI->first < VTableDataI->first)) { StringRef VTableName = VTableSymI->first.first; uint64_t Offset = VTableSymI->first.second; StringRef VTableEntry = VTableSymI->second; outs() << VTableName << '[' << Offset << "]: "; outs() << VTableEntry; outs() << '\n'; ++VTableSymI; continue; } if (!DataDone && (SymDone || VTableDataI->first < VTableSymI->first)) { StringRef VTableName = VTableDataI->first.first; uint64_t Offset = VTableDataI->first.second; int64_t VTableEntry = VTableDataI->second; outs() << VTableName << '[' << Offset << "]: "; outs() << VTableEntry; outs() << '\n'; ++VTableDataI; continue; } } }
void COFFDumper::printSymbol(const SymbolRef &Sym) { DictScope D(W, "Symbol"); COFFSymbolRef Symbol = Obj->getCOFFSymbol(Sym); const coff_section *Section; if (std::error_code EC = Obj->getSection(Symbol.getSectionNumber(), Section)) { W.startLine() << "Invalid section number: " << EC.message() << "\n"; W.flush(); return; } StringRef SymbolName; if (Obj->getSymbolName(Symbol, SymbolName)) SymbolName = ""; StringRef SectionName = ""; ErrorOr<StringRef> Res = getSectionName(Obj, Symbol.getSectionNumber(), Section); if (Res) SectionName = *Res; W.printString("Name", SymbolName); W.printNumber("Value", Symbol.getValue()); W.printNumber("Section", SectionName, Symbol.getSectionNumber()); W.printEnum ("BaseType", Symbol.getBaseType(), makeArrayRef(ImageSymType)); W.printEnum ("ComplexType", Symbol.getComplexType(), makeArrayRef(ImageSymDType)); W.printEnum ("StorageClass", Symbol.getStorageClass(), makeArrayRef(ImageSymClass)); W.printNumber("AuxSymbolCount", Symbol.getNumberOfAuxSymbols()); for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) { if (Symbol.isFunctionDefinition()) { const coff_aux_function_definition *Aux; if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) break; DictScope AS(W, "AuxFunctionDef"); W.printNumber("TagIndex", Aux->TagIndex); W.printNumber("TotalSize", Aux->TotalSize); W.printHex("PointerToLineNumber", Aux->PointerToLinenumber); W.printHex("PointerToNextFunction", Aux->PointerToNextFunction); } else if (Symbol.isAnyUndefined()) { const coff_aux_weak_external *Aux; if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) break; ErrorOr<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex); StringRef LinkedName; std::error_code EC = Linked.getError(); if (EC || (EC = Obj->getSymbolName(*Linked, LinkedName))) { LinkedName = ""; error(EC); } DictScope AS(W, "AuxWeakExternal"); W.printNumber("Linked", LinkedName, Aux->TagIndex); W.printEnum ("Search", Aux->Characteristics, makeArrayRef(WeakExternalCharacteristics)); } else if (Symbol.isFileRecord()) { const char *FileName; if (error(getSymbolAuxData(Obj, Symbol, I, FileName))) break; DictScope AS(W, "AuxFileRecord"); StringRef Name(FileName, Symbol.getNumberOfAuxSymbols() * Obj->getSymbolTableEntrySize()); W.printString("FileName", Name.rtrim(StringRef("\0", 1))); break; } else if (Symbol.isSectionDefinition()) { const coff_aux_section_definition *Aux; if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) break; int32_t AuxNumber = Aux->getNumber(Symbol.isBigObj()); DictScope AS(W, "AuxSectionDef"); W.printNumber("Length", Aux->Length); W.printNumber("RelocationCount", Aux->NumberOfRelocations); W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers); W.printHex("Checksum", Aux->CheckSum); W.printNumber("Number", AuxNumber); W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect)); if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { const coff_section *Assoc; StringRef AssocName = ""; std::error_code EC = Obj->getSection(AuxNumber, Assoc); ErrorOr<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc); if (Res) AssocName = *Res; if (!EC) EC = Res.getError(); if (EC) { AssocName = ""; error(EC); } W.printNumber("AssocSection", AssocName, AuxNumber); } } else if (Symbol.isCLRToken()) { const coff_aux_clr_token *Aux; if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) break; ErrorOr<COFFSymbolRef> ReferredSym = Obj->getSymbol(Aux->SymbolTableIndex); StringRef ReferredName; std::error_code EC = ReferredSym.getError(); if (EC || (EC = Obj->getSymbolName(*ReferredSym, ReferredName))) { ReferredName = ""; error(EC); } DictScope AS(W, "AuxCLRToken"); W.printNumber("AuxType", Aux->AuxType); W.printNumber("Reserved", Aux->Reserved); W.printNumber("SymbolTableIndex", ReferredName, Aux->SymbolTableIndex); } else { W.startLine() << "<unhandled auxiliary record>\n"; } } }
static int executeInput() { // Load any dylibs requested on the command line. loadDylibs(); // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; doPreallocation(MemMgr); RuntimeDyld Dyld(MemMgr, MemMgr); // If we don't have any input files, read from stdin. if (!InputFileList.size()) InputFileList.push_back("-"); for (auto &File : InputFileList) { // Load the input memory buffer. ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = MemoryBuffer::getFileOrSTDIN(File); if (std::error_code EC = InputBuffer.getError()) ErrorAndExit("unable to read input: '" + EC.message() + "'"); Expected<std::unique_ptr<ObjectFile>> MaybeObj( ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); if (!MaybeObj) { std::string Buf; raw_string_ostream OS(Buf); logAllUnhandledErrors(MaybeObj.takeError(), OS, ""); OS.flush(); ErrorAndExit("unable to create object file: '" + Buf + "'"); } ObjectFile &Obj = **MaybeObj; // Load the object file Dyld.loadObject(Obj); if (Dyld.hasError()) { ErrorAndExit(Dyld.getErrorString()); } } // Resove all the relocations we can. // FIXME: Error out if there are unresolved relocations. Dyld.resolveRelocations(); // Get the address of the entry point (_main by default). void *MainAddress = Dyld.getSymbolLocalAddress(EntryPoint); if (!MainAddress) ErrorAndExit("no definition for '" + EntryPoint + "'"); // Invalidate the instruction cache for each loaded function. for (auto &FM : MemMgr.FunctionMemory) { // Make sure the memory is executable. // setExecutable will call InvalidateInstructionCache. std::string ErrorStr; if (!sys::Memory::setExecutable(FM, &ErrorStr)) ErrorAndExit("unable to mark function executable: '" + ErrorStr + "'"); } // Dispatch to _main(). 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]; // Use the name of the first input object module as argv[0] for the target. Argv[0] = InputFileList[0].c_str(); Argv[1] = nullptr; return Main(1, Argv); }
Archive::Archive(MemoryBufferRef Source, Error &Err) : Binary(Binary::ID_Archive, Source) { ErrorAsOutParameter ErrAsOutParam(&Err); StringRef Buffer = Data.getBuffer(); // Check for sufficient magic. if (Buffer.startswith(ThinMagic)) { IsThin = true; } else if (Buffer.startswith(Magic)) { IsThin = false; } else { Err = make_error<GenericBinaryError>("File too small to be an archive", object_error::invalid_file_type); return; } // Get the special members. child_iterator I = child_begin(Err, false); if (Err) return; child_iterator E = child_end(); // This is at least a valid empty archive. Since an empty archive is the // same in all formats, just claim it to be gnu to make sure Format is // initialized. Format = K_GNU; if (I == E) { Err = Error::success(); return; } const Child *C = &*I; auto Increment = [&]() { ++I; if (Err) return true; C = &*I; return false; }; StringRef Name = C->getRawName(); // Below is the pattern that is used to figure out the archive format // GNU archive format // First member : / (may exist, if it exists, points to the symbol table ) // Second member : // (may exist, if it exists, points to the string table) // Note : The string table is used if the filename exceeds 15 characters // BSD archive format // First member : __.SYMDEF or "__.SYMDEF SORTED" (the symbol table) // There is no string table, if the filename exceeds 15 characters or has a // embedded space, the filename has #1/<size>, The size represents the size // of the filename that needs to be read after the archive header // COFF archive format // First member : / // Second member : / (provides a directory of symbols) // Third member : // (may exist, if it exists, contains the string table) // Note: Microsoft PE/COFF Spec 8.3 says that the third member is present // even if the string table is empty. However, lib.exe does not in fact // seem to create the third member if there's no member whose filename // exceeds 15 characters. So the third member is optional. if (Name == "__.SYMDEF" || Name == "__.SYMDEF_64") { if (Name == "__.SYMDEF") Format = K_BSD; else // Name == "__.SYMDEF_64" Format = K_DARWIN64; // We know that the symbol table is not an external file, so we just assert // there is no error. SymbolTable = *C->getBuffer(); if (Increment()) return; setFirstRegular(*C); Err = Error::success(); return; } if (Name.startswith("#1/")) { Format = K_BSD; // We know this is BSD, so getName will work since there is no string table. ErrorOr<StringRef> NameOrErr = C->getName(); if (auto ec = NameOrErr.getError()) { Err = errorCodeToError(ec); return; } Name = NameOrErr.get(); if (Name == "__.SYMDEF SORTED" || Name == "__.SYMDEF") { // We know that the symbol table is not an external file, so we just // assert there is no error. SymbolTable = *C->getBuffer(); if (Increment()) return; } else if (Name == "__.SYMDEF_64 SORTED" || Name == "__.SYMDEF_64") { Format = K_DARWIN64; // We know that the symbol table is not an external file, so we just // assert there is no error. SymbolTable = *C->getBuffer(); if (Increment()) return; } setFirstRegular(*C); return; } // MIPS 64-bit ELF archives use a special format of a symbol table. // This format is marked by `ar_name` field equals to "/SYM64/". // For detailed description see page 96 in the following document: // http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf bool has64SymTable = false; if (Name == "/" || Name == "/SYM64/") { // We know that the symbol table is not an external file, so we just assert // there is no error. SymbolTable = *C->getBuffer(); if (Name == "/SYM64/") has64SymTable = true; if (Increment()) return; if (I == E) { Err = Error::success(); return; } Name = C->getRawName(); } if (Name == "//") { Format = has64SymTable ? K_MIPS64 : K_GNU; // The string table is never an external member, so we just assert on the // ErrorOr. StringTable = *C->getBuffer(); if (Increment()) return; setFirstRegular(*C); Err = Error::success(); return; } if (Name[0] != '/') { Format = has64SymTable ? K_MIPS64 : K_GNU; setFirstRegular(*C); Err = Error::success(); return; } if (Name != "/") { Err = errorCodeToError(object_error::parse_failed); return; } Format = K_COFF; // We know that the symbol table is not an external file, so we just assert // there is no error. SymbolTable = *C->getBuffer(); if (Increment()) return; if (I == E) { setFirstRegular(*C); Err = Error::success(); return; } Name = C->getRawName(); if (Name == "//") { // The string table is never an external member, so we just assert on the // ErrorOr. StringTable = *C->getBuffer(); if (Increment()) return; } setFirstRegular(*C); Err = Error::success(); }
std::error_code MipsAbiInfoHandler<ELFT>::mergeFlags(uint32_t newFlags, const Elf_Mips_ABIFlags *newSec) { std::lock_guard<std::mutex> lock(_mutex); ErrorOr<MipsAbiFlags> abiFlags = createAbiFlags(newFlags, newSec); if (auto ec = abiFlags.getError()) return ec; // We support two ABI: O32 and N64. The last one does not have // the corresponding ELF flag. uint32_t supportedAbi = ELFT::Is64Bits ? 0 : uint32_t(EF_MIPS_ABI_O32); if (abiFlags->_abi != supportedAbi) return make_dynamic_error_code("Unsupported ABI"); // ... and still do not support MIPS-16 extension. if (abiFlags->_ases & AFL_ASE_MIPS16) return make_dynamic_error_code("Unsupported extension: MIPS16"); // PIC code is inherently CPIC and may not set CPIC flag explicitly. // Ensure that this flag will exist in the linked file. if (abiFlags->_isPic) abiFlags->_isCPic = true; // If the old set of flags is empty, use the new one as a result. if (!_abiFlags.hasValue()) { _abiFlags = *abiFlags; return std::error_code(); } // Check PIC / CPIC flags compatibility. if (abiFlags->_isCPic != _abiFlags->_isCPic) llvm::errs() << "lld warning: linking abicalls and non-abicalls files\n"; if (!abiFlags->_isPic) _abiFlags->_isPic = false; if (abiFlags->_isCPic) _abiFlags->_isCPic = true; // Check mixing -mnan=2008 / -mnan=legacy modules. if (abiFlags->_isNan2008 != _abiFlags->_isNan2008) return make_dynamic_error_code( "Linking -mnan=2008 and -mnan=legacy modules"); // Check ISA compatibility and update the extension flag. if (!matchMipsISA(MipsISAs(abiFlags->_isa), MipsISAs(_abiFlags->_isa))) { if (!matchMipsISA(MipsISAs(_abiFlags->_isa), MipsISAs(abiFlags->_isa))) return make_dynamic_error_code("Linking modules with incompatible ISA"); _abiFlags->_isa = abiFlags->_isa; } _abiFlags->_ases |= abiFlags->_ases; _abiFlags->_isNoReorder = _abiFlags->_isNoReorder || abiFlags->_isNoReorder; _abiFlags->_is32BitMode = _abiFlags->_is32BitMode || abiFlags->_is32BitMode; _abiFlags->_fpAbi = selectFpAbiFlag(_abiFlags->_fpAbi, abiFlags->_fpAbi); _abiFlags->_gprSize = std::max(_abiFlags->_gprSize, abiFlags->_gprSize); _abiFlags->_cpr1Size = std::max(_abiFlags->_cpr1Size, abiFlags->_cpr1Size); _abiFlags->_cpr2Size = std::max(_abiFlags->_cpr2Size, abiFlags->_cpr2Size); _abiFlags->_flags1 |= abiFlags->_flags1; return std::error_code(); }
static bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) { // Get the target specific parser. std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error); if (!TheTarget) return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = MemoryBuffer::getFileOrSTDIN(Opts.InputFile); if (std::error_code EC = Buffer.getError()) { Error = EC.message(); return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile; } SourceMgr SrcMgr; // Tell SrcMgr about this buffer, which is what the parser will pick up. SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc()); // Record the location of the include directories so that the lexer can find // it later. SrcMgr.setIncludeDirs(Opts.IncludePaths); std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple)); assert(MRI && "Unable to create target register info!"); std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, Opts.Triple)); assert(MAI && "Unable to create target asm info!"); // Ensure MCAsmInfo initialization occurs before any use, otherwise sections // may be created with a combination of default and explicit settings. if (Opts.CompressDebugSections) MAI->setCompressDebugSections(true); bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj; std::unique_ptr<raw_fd_ostream> FDOS = getOutputStream(Opts, Diags, IsBinary); if (!FDOS) return true; // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and // MCObjectFileInfo needs a MCContext reference in order to initialize itself. std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); // FIXME: Assembler behavior can change with -static. MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), Reloc::Default, CodeModel::Default, Ctx); if (Opts.SaveTemporaryLabels) Ctx.setAllowTemporaryLabels(false); if (Opts.GenDwarfForAssembly) Ctx.setGenDwarfForAssembly(true); if (!Opts.DwarfDebugFlags.empty()) Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags)); if (!Opts.DwarfDebugProducer.empty()) Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer)); if (!Opts.DebugCompilationDir.empty()) Ctx.setCompilationDir(Opts.DebugCompilationDir); if (!Opts.MainFileName.empty()) Ctx.setMainFileName(StringRef(Opts.MainFileName)); Ctx.setDwarfVersion(Opts.DwarfVersion); // Build up the feature string from the target feature list. std::string FS; if (!Opts.Features.empty()) { FS = Opts.Features[0]; for (unsigned i = 1, e = Opts.Features.size(); i != e; ++i) FS += "," + Opts.Features[i]; } std::unique_ptr<MCStreamer> Str; std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); std::unique_ptr<MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS)); raw_pwrite_stream *Out = FDOS.get(); std::unique_ptr<buffer_ostream> BOS; // FIXME: There is a bit of code duplication with addPassesToEmitFile. if (Opts.OutputType == AssemblerInvocation::FT_Asm) { MCInstPrinter *IP = TheTarget->createMCInstPrinter( llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI); MCCodeEmitter *CE = nullptr; MCAsmBackend *MAB = nullptr; if (Opts.ShowEncoding) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple, Opts.CPU); } auto FOut = llvm::make_unique<formatted_raw_ostream>(*Out); Str.reset(TheTarget->createAsmStreamer( Ctx, std::move(FOut), /*asmverbose*/ true, /*useDwarfDirectory*/ true, IP, CE, MAB, Opts.ShowInst)); } else if (Opts.OutputType == AssemblerInvocation::FT_Null) { Str.reset(createNullStreamer(Ctx)); } else { assert(Opts.OutputType == AssemblerInvocation::FT_Obj && "Invalid file type!"); if (!FDOS->supportsSeeking()) { BOS = make_unique<buffer_ostream>(*FDOS); Out = BOS.get(); } MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple, Opts.CPU); Triple T(Opts.Triple); Str.reset(TheTarget->createMCObjectStreamer(T, Ctx, *MAB, *Out, CE, *STI, Opts.RelaxAll, /*DWARFMustBeAtTheEnd*/ true)); Str.get()->InitSections(Opts.NoExecStack); } bool Failed = false; std::unique_ptr<MCAsmParser> Parser( createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); // FIXME: init MCTargetOptions from sanitizer flags here. MCTargetOptions Options; std::unique_ptr<MCTargetAsmParser> TAP( TheTarget->createMCAsmParser(*STI, *Parser, *MCII, Options)); if (!TAP) Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; if (!Failed) { Parser->setTargetParser(*TAP.get()); Failed = Parser->Run(Opts.NoInitialTextSection); } // Close Streamer first. // It might have a reference to the output stream. Str.reset(); // Close the output stream early. BOS.reset(); FDOS.reset(); // Delete output file if there were errors. if (Failed && Opts.OutputPath != "-") sys::fs::remove(Opts.OutputPath); return Failed; }
void jl_getDylibFunctionInfo(const char **name, int *line, const char **filename, size_t pointer, int skipC) { #ifdef _OS_WINDOWS_ DWORD fbase = SymGetModuleBase64(GetCurrentProcess(),(DWORD)pointer); if (fbase != 0) { #else Dl_info dlinfo; if ((dladdr((void*)pointer, &dlinfo) != 0) && dlinfo.dli_fname) { if (skipC && !jl_is_sysimg(dlinfo.dli_fname)) return; uint64_t fbase = (uint64_t)dlinfo.dli_fbase; #endif obfiletype::iterator it = objfilemap.find(fbase); llvm::object::ObjectFile *obj = NULL; DIContext *context = NULL; int64_t slide = 0; if (it == objfilemap.end()) { #ifdef _OS_DARWIN_ // First find the uuid of the object file (we'll use this to make sure we find the // correct debug symbol file). uint8_t uuid[16], uuid2[16]; #ifdef LLVM35 ErrorOr<llvm::object::ObjectFile*> origerrorobj = llvm::object::ObjectFile::createObjectFile( #else llvm::object::ObjectFile *origerrorobj = llvm::object::ObjectFile::createObjectFile( #endif MemoryBuffer::getMemBuffer( StringRef((const char *)fbase, (size_t)(((uint64_t)-1)-fbase)),"",false) #ifdef LLVM35 ,false, sys::fs::file_magic::unknown #endif ); if (!origerrorobj) { objfileentry_t entry = {obj,context,slide}; objfilemap[fbase] = entry; return; } #ifdef LLVM35 llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj.get(); #else llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)origerrorobj; #endif if (!getObjUUID(morigobj,uuid)) { objfileentry_t entry = {obj,context,slide}; objfilemap[fbase] = entry; return; } // On OS X debug symbols are not contained in the dynamic library and that's why // we can't have nice things (easily). For now we only support .dSYM files in the same directory // as the shared library. In the future we may use DBGCopyFullDSYMURLForUUID from CoreFoundation to make // use of spotlight to find the .dSYM file. char dsympath[PATH_MAX]; strlcpy(dsympath, dlinfo.dli_fname, sizeof(dsympath)); strlcat(dsympath, ".dSYM/Contents/Resources/DWARF/", sizeof(dsympath)); strlcat(dsympath, strrchr(dlinfo.dli_fname,'/')+1, sizeof(dsympath)); #ifdef LLVM35 ErrorOr<llvm::object::ObjectFile*> errorobj = llvm::object::ObjectFile::createObjectFile(dsympath); #else llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(dsympath); #endif #else #ifndef _OS_WINDOWS_ const char *fname = dlinfo.dli_fname; #else IMAGEHLP_MODULE64 ModuleInfo; ModuleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)pointer, &ModuleInfo); char *fname = ModuleInfo.LoadedImageName; JL_PRINTF(JL_STDOUT,fname); #endif // On non OS X systems we need to mmap another copy because of the permissions on the mmaped // shared library. #ifdef LLVM35 ErrorOr<llvm::object::ObjectFile*> errorobj = llvm::object::ObjectFile::createObjectFile(fname); #else llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(fname); #endif #endif #ifdef LLVM35 if (errorobj) { obj = errorobj.get(); #else if (errorobj != NULL) { obj = errorobj; #endif #ifdef _OS_DARWIN_ if (getObjUUID(morigobj,uuid2) && memcmp(uuid,uuid2,sizeof(uuid)) == 0) { #endif context = DIContext::getDWARFContext(obj); slide = -(uint64_t)fbase; #ifdef _OS_DARWIN_ } #endif #ifdef _OS_WINDOWS_ assert(obj->isCOFF()); llvm::object::COFFObjectFile *coffobj = (llvm::object::COFFObjectFile *)obj; const llvm::object::pe32plus_header *pe32plus; coffobj->getPE32PlusHeader(pe32plus); if (pe32plus != NULL) { slide = pe32plus->ImageBase-fbase; } else { const llvm::object::pe32_header *pe32; coffobj->getPE32Header(pe32); if (pe32 == NULL) { obj = NULL; context = NULL; } else { slide = pe32->ImageBase-fbase; } } #endif } objfileentry_t entry = {obj,context,slide}; objfilemap[fbase] = entry; } else { obj = it->second.obj; context = it->second.ctx; slide = it->second.slide; } lookup_pointer(context, name, line, filename, pointer+slide, jl_is_sysimg(dlinfo.dli_fname)); } return; }
/*! A helper function for klee::linkWithLibrary() that links in an archive of bitcode * modules into a composite bitcode module * * \param[in] archive Archive of bitcode modules * \param[in,out] composite The bitcode module to link against the archive * \param[out] errorMessage Set to an error message if linking fails * * \return True if linking succeeds otherwise false */ static bool linkBCA(object::Archive* archive, Module* composite, std::string& errorMessage) { llvm::raw_string_ostream SS(errorMessage); std::vector<Module*> archiveModules; // Is this efficient? Could we use StringRef instead? std::set<std::string> undefinedSymbols; GetAllUndefinedSymbols(composite, undefinedSymbols); if (undefinedSymbols.size() == 0) { // Nothing to do KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "No undefined symbols. Not linking anything in!\n"); return true; } KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Loading modules\n"); // Load all bitcode files in to memory so we can examine their symbols #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) for (object::Archive::child_iterator AI = archive->child_begin(), AE = archive->child_end(); AI != AE; ++AI) #else for (object::Archive::child_iterator AI = archive->begin_children(), AE = archive->end_children(); AI != AE; ++AI) #endif { StringRef memberName; #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) std::error_code ec; ErrorOr<StringRef> errorOr_memberName = AI->getName(); // as per // http://llvm.org/docs/doxygen/html/classllvm_1_1ErrorOr.html#details bool memname_success = true; // maybe a better way but this works to // recreate functionality of llvm<3.6 if ((ec = errorOr_memberName.getError())) memname_success = false; memberName = errorOr_memberName.get(); #else error_code ec = AI->getName(memberName); bool memname_success = (ec == errc::success); #endif if (memname_success) { KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Loading archive member " << memberName << "\n"); } else { errorMessage="Archive member does not have a name!\n"; return false; } #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) ErrorOr<std::unique_ptr<llvm::object::Binary>> child = AI->getAsBinary(); bool getAsBin_success = true; if ((ec = child.getError())) getAsBin_success = false; #else OwningPtr<object::Binary> child; ec = AI->getAsBinary(child); bool getAsBin_success = (ec == object::object_error::success); #endif if (!getAsBin_success) { // If we can't open as a binary object file its hopefully a bitcode file Module *Result = 0; #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) ErrorOr<MemoryBufferRef> buff = AI->getMemoryBufferRef(); bool getMemBuff_success = true; if ((ec = buff.getError())) getMemBuff_success = false; #else OwningPtr<MemoryBuffer> buff; // Once this is destroyed will Module still be valid?? bool getMemBuff_success = !(ec = AI->getMemoryBuffer(buff)); #endif if (!getMemBuff_success) { SS << "Failed to get MemoryBuffer: " << ec.message(); SS.flush(); return false; } if (buff) { // FIXME: Maybe load bitcode file lazily? Then if we need to link, materialise // the module #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) bool parseFile_success = true; ErrorOr<Module *> Result_error = parseBitcodeFile(buff.get(), getGlobalContext()); if ((ec = Result_error.getError())) parseFile_success = false; Result = Result_error.get(); #else Result = ParseBitcodeFile(buff.get(), getGlobalContext(), &errorMessage); bool parseFile_success = (Result); #endif if (!parseFile_success) { SS << "Loading module failed : " << errorMessage << "\n"; SS.flush(); return false; } archiveModules.push_back(Result); } else { errorMessage = "Buffer was NULL!"; return false; } } else if (child.get()->isObject()) { SS << "Object file " << child.get()->getFileName().data() << " in archive is not supported"; SS.flush(); return false; } else { SS << "Loading archive child with error " << ec.message(); SS.flush(); return false; } } KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Loaded " << archiveModules.size() << " modules\n"); std::set<std::string> previouslyUndefinedSymbols; // Walk through the modules looking for definitions of undefined symbols // if we find a match we should link that module in. unsigned int passCounter=0; do { unsigned int modulesLoadedOnPass=0; previouslyUndefinedSymbols = undefinedSymbols; for (size_t i = 0, j = archiveModules.size(); i < j; ++i) { // skip empty archives if (archiveModules[i] == 0) continue; Module * M = archiveModules[i]; // Look for the undefined symbols in the composite module for (std::set<std::string>::iterator S = undefinedSymbols.begin(), SE = undefinedSymbols.end(); S != SE; ++S) { // FIXME: We aren't handling weak symbols here! // However the algorithm used in LLVM3.2 didn't seem to either // so maybe it doesn't matter? if ( GlobalValue* GV = dyn_cast_or_null<GlobalValue>(M->getValueSymbolTable().lookup(*S))) { if (GV->isDeclaration()) continue; // Not a definition KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Found " << GV->getName() << " in " << M->getModuleIdentifier() << "\n"); #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) if (Linker::LinkModules(composite, M)) #else if (Linker::LinkModules(composite, M, Linker::DestroySource, &errorMessage)) #endif { // Linking failed SS << "Linking archive module with composite failed:" << errorMessage; SS.flush(); CleanUpLinkBCA(archiveModules); return false; } else { // Link succeed, now clean up modulesLoadedOnPass++; KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Linking succeeded.\n"); delete M; archiveModules[i] = 0; // We need to recompute the undefined symbols in the composite module // after linking GetAllUndefinedSymbols(composite, undefinedSymbols); break; // Look for symbols in next module } } } } passCounter++; KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Completed " << passCounter << " linker passes.\n" << modulesLoadedOnPass << " modules loaded on the last pass\n"); } while (undefinedSymbols != previouslyUndefinedSymbols); // Iterate until we reach a fixed point // What's left in archiveModules we don't want to link in so free it CleanUpLinkBCA(archiveModules); return true; }
static void dumpSymbolNamesFromFile(std::string &Filename) { ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = MemoryBuffer::getFileOrSTDIN(Filename); if (error(BufferOrErr.getError(), Filename)) return; LLVMContext &Context = getGlobalContext(); ErrorOr<std::unique_ptr<Binary>> BinaryOrErr = createBinary( BufferOrErr.get()->getMemBufferRef(), NoLLVMBitcode ? nullptr : &Context); if (error(BinaryOrErr.getError(), Filename)) return; Binary &Bin = *BinaryOrErr.get(); if (Archive *A = dyn_cast<Archive>(&Bin)) { if (ArchiveMap) { Archive::symbol_iterator I = A->symbol_begin(); Archive::symbol_iterator E = A->symbol_end(); if (I != E) { outs() << "Archive map\n"; for (; I != E; ++I) { ErrorOr<Archive::Child> C = I->getMember(); if (error(C.getError())) return; ErrorOr<StringRef> FileNameOrErr = C->getName(); if (error(FileNameOrErr.getError())) return; StringRef SymName = I->getName(); outs() << SymName << " in " << FileNameOrErr.get() << "\n"; } outs() << "\n"; } } for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); I != E; ++I) { if (error(I->getError())) return; auto &C = I->get(); ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(&Context); if (ChildOrErr.getError()) continue; if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { if (!checkMachOAndArchFlags(O, Filename)) return; if (!PrintFileName) { outs() << "\n"; if (isa<MachOObjectFile>(O)) { outs() << Filename << "(" << O->getFileName() << ")"; } else outs() << O->getFileName(); outs() << ":\n"; } dumpSymbolNamesFromObject(*O, false, Filename); } } return; } if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) { // If we have a list of architecture flags specified dump only those. if (!ArchAll && ArchFlags.size() != 0) { // Look for a slice in the universal binary that matches each ArchFlag. bool ArchFound; for (unsigned i = 0; i < ArchFlags.size(); ++i) { ArchFound = false; for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), E = UB->end_objects(); I != E; ++I) { if (ArchFlags[i] == I->getArchTypeName()) { ArchFound = true; ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); std::string ArchiveName; std::string ArchitectureName; ArchiveName.clear(); ArchitectureName.clear(); if (ObjOrErr) { ObjectFile &Obj = *ObjOrErr.get(); if (ArchFlags.size() > 1) { if (PrintFileName) ArchitectureName = I->getArchTypeName(); else outs() << "\n" << Obj.getFileName() << " (for architecture " << I->getArchTypeName() << ")" << ":\n"; } dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName); } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) { std::unique_ptr<Archive> &A = *AOrErr; for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { if (error(AI->getError())) return; auto &C = AI->get(); ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(&Context); if (ChildOrErr.getError()) continue; if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { if (PrintFileName) { ArchiveName = A->getFileName(); if (ArchFlags.size() > 1) ArchitectureName = I->getArchTypeName(); } else { outs() << "\n" << A->getFileName(); outs() << "(" << O->getFileName() << ")"; if (ArchFlags.size() > 1) { outs() << " (for architecture " << I->getArchTypeName() << ")"; } outs() << ":\n"; } dumpSymbolNamesFromObject(*O, false, ArchiveName, ArchitectureName); } } } } } if (!ArchFound) { error(ArchFlags[i], "file: " + Filename + " does not contain architecture"); return; } } return; } // No architecture flags were specified so if this contains a slice that // matches the host architecture dump only that. if (!ArchAll) { StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), E = UB->end_objects(); I != E; ++I) { if (HostArchName == I->getArchTypeName()) { ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); std::string ArchiveName; ArchiveName.clear(); if (ObjOrErr) { ObjectFile &Obj = *ObjOrErr.get(); dumpSymbolNamesFromObject(Obj, false); } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) { std::unique_ptr<Archive> &A = *AOrErr; for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { if (error(AI->getError())) return; auto &C = AI->get(); ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(&Context); if (ChildOrErr.getError()) continue; if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { if (PrintFileName) ArchiveName = A->getFileName(); else outs() << "\n" << A->getFileName() << "(" << O->getFileName() << ")" << ":\n"; dumpSymbolNamesFromObject(*O, false, ArchiveName); } } } return; } } } // Either all architectures have been specified or none have been specified // and this does not contain the host architecture so dump all the slices. bool moreThanOneArch = UB->getNumberOfObjects() > 1; for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), E = UB->end_objects(); I != E; ++I) { ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); std::string ArchiveName; std::string ArchitectureName; ArchiveName.clear(); ArchitectureName.clear(); if (ObjOrErr) { ObjectFile &Obj = *ObjOrErr.get(); if (PrintFileName) { if (isa<MachOObjectFile>(Obj) && moreThanOneArch) ArchitectureName = I->getArchTypeName(); } else { if (moreThanOneArch) outs() << "\n"; outs() << Obj.getFileName(); if (isa<MachOObjectFile>(Obj) && moreThanOneArch) outs() << " (for architecture " << I->getArchTypeName() << ")"; outs() << ":\n"; } dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName); } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) { std::unique_ptr<Archive> &A = *AOrErr; for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { if (error(AI->getError())) return; auto &C = AI->get(); ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary(&Context); if (ChildOrErr.getError()) continue; if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { if (PrintFileName) { ArchiveName = A->getFileName(); if (isa<MachOObjectFile>(O) && moreThanOneArch) ArchitectureName = I->getArchTypeName(); } else { outs() << "\n" << A->getFileName(); if (isa<MachOObjectFile>(O)) { outs() << "(" << O->getFileName() << ")"; if (moreThanOneArch) outs() << " (for architecture " << I->getArchTypeName() << ")"; } else outs() << ":" << O->getFileName(); outs() << ":\n"; } dumpSymbolNamesFromObject(*O, false, ArchiveName, ArchitectureName); } } } } return; } if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin)) { if (!checkMachOAndArchFlags(O, Filename)) return; dumpSymbolNamesFromObject(*O, true); return; } error("unrecognizable file type", Filename); }
Module *klee::linkWithLibrary(Module *module, const std::string &libraryName) { KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Linking file " << libraryName << "\n"); #if LLVM_VERSION_CODE >= LLVM_VERSION(3, 6) if (!sys::fs::exists(libraryName)) { klee_error("Link with library %s failed. No such file.", libraryName.c_str()); } ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = MemoryBuffer::getFile(libraryName); std::error_code ec; if ((ec = Buffer.getError())) { klee_error("Link with library %s failed: %s", libraryName.c_str(), ec.message().c_str()); } sys::fs::file_magic magic = sys::fs::identify_magic(Buffer.get()->getBuffer()); MemoryBufferRef BufferRef = Buffer.get()->getMemBufferRef(); LLVMContext &Context = getGlobalContext(); std::string ErrorMessage; if (magic == sys::fs::file_magic::bitcode) { ErrorOr<Module *> Result = parseBitcodeFile(BufferRef, Context); if ((ec = Buffer.getError()) || Linker::LinkModules(module, Result.get())) klee_error("Link with library %s failed: %s", libraryName.c_str(), ErrorMessage.c_str()); delete Result.get(); } else if (magic == sys::fs::file_magic::archive) { ErrorOr<std::unique_ptr<object::Binary>> arch = object::createBinary(BufferRef, &Context); if ((ec = arch.getError())) klee_error("Link with library %s failed: %s", libraryName.c_str(), arch.getError().message().c_str()); if (object::Archive *a = dyn_cast<object::Archive>(arch.get().get())) { // Handle in helper if (!linkBCA(a, module, ErrorMessage)) klee_error("Link with library %s failed: %s", libraryName.c_str(), ErrorMessage.c_str()); } else { klee_error("Link with library %s failed: Cast to archive failed", libraryName.c_str()); } } else if (magic.is_object()) { std::unique_ptr<object::Binary> obj; if (object::ObjectFile *o = dyn_cast<object::ObjectFile>(obj.get())) { klee_warning("Link with library: Object file %s in archive %s found. " "Currently not supported.", o->getFileName().data(), libraryName.c_str()); } } else { klee_error("Link with library %s failed: Unrecognized file type.", libraryName.c_str()); } return module; #elif LLVM_VERSION_CODE >= LLVM_VERSION(3, 3) if (!sys::fs::exists(libraryName)) { klee_error("Link with library %s failed. No such file.", libraryName.c_str()); } OwningPtr<MemoryBuffer> Buffer; if (error_code ec = MemoryBuffer::getFile(libraryName, Buffer)) { klee_error("Link with library %s failed: %s", libraryName.c_str(), ec.message().c_str()); } sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer()); LLVMContext &Context = getGlobalContext(); std::string ErrorMessage; if (magic == sys::fs::file_magic::bitcode) { Module *Result = 0; Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); if (!Result || Linker::LinkModules(module, Result, Linker::DestroySource, &ErrorMessage)) klee_error("Link with library %s failed: %s", libraryName.c_str(), ErrorMessage.c_str()); delete Result; } else if (magic == sys::fs::file_magic::archive) { OwningPtr<object::Binary> arch; if (error_code ec = object::createBinary(Buffer.take(), arch)) klee_error("Link with library %s failed: %s", libraryName.c_str(), ec.message().c_str()); if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) { // Handle in helper if (!linkBCA(a, module, ErrorMessage)) klee_error("Link with library %s failed: %s", libraryName.c_str(), ErrorMessage.c_str()); } else { klee_error("Link with library %s failed: Cast to archive failed", libraryName.c_str()); } } else if (magic.is_object()) { OwningPtr<object::Binary> obj; if (object::ObjectFile *o = dyn_cast<object::ObjectFile>(obj.get())) { klee_warning("Link with library: Object file %s in archive %s found. " "Currently not supported.", o->getFileName().data(), libraryName.c_str()); } } else { klee_error("Link with library %s failed: Unrecognized file type.", libraryName.c_str()); } return module; #else Linker linker("klee", module, false); llvm::sys::Path libraryPath(libraryName); bool native = false; if (linker.LinkInFile(libraryPath, native)) { klee_error("Linking library %s failed", libraryName.c_str()); } return linker.releaseModule(); #endif }
bool JSONImporter::runOnScop(Scop &S) { Region &R = S.getRegion(); const Dependences &D = getAnalysis<DependenceInfo>().getDependences(); const DataLayout &DL = S.getRegion().getEntry()->getParent()->getParent()->getDataLayout(); std::string FileName = ImportDir + "/" + getFileName(S); std::string FunctionName = R.getEntry()->getParent()->getName(); errs() << "Reading JScop '" << R.getNameStr() << "' in function '" << FunctionName << "' from '" << FileName << "'.\n"; ErrorOr<std::unique_ptr<MemoryBuffer>> result = MemoryBuffer::getFile(FileName); std::error_code ec = result.getError(); if (ec) { errs() << "File could not be read: " << ec.message() << "\n"; return false; } Json::Reader reader; Json::Value jscop; bool parsingSuccessful = reader.parse(result.get()->getBufferStart(), jscop); if (!parsingSuccessful) { errs() << "JSCoP file could not be parsed\n"; return false; } isl_set *OldContext = S.getContext(); isl_set *NewContext = isl_set_read_from_str(S.getIslCtx(), jscop["context"].asCString()); for (unsigned i = 0; i < isl_set_dim(OldContext, isl_dim_param); i++) { isl_id *id = isl_set_get_dim_id(OldContext, isl_dim_param, i); NewContext = isl_set_set_dim_id(NewContext, isl_dim_param, i, id); } isl_set_free(OldContext); S.setContext(NewContext); StatementToIslMapTy NewSchedule; int index = 0; for (ScopStmt &Stmt : S) { Json::Value schedule = jscop["statements"][index]["schedule"]; isl_map *m = isl_map_read_from_str(S.getIslCtx(), schedule.asCString()); isl_space *Space = Stmt.getDomainSpace(); // Copy the old tuple id. This is necessary to retain the user pointer, // that stores the reference to the ScopStmt this schedule belongs to. m = isl_map_set_tuple_id(m, isl_dim_in, isl_space_get_tuple_id(Space, isl_dim_set)); for (unsigned i = 0; i < isl_space_dim(Space, isl_dim_param); i++) { isl_id *id = isl_space_get_dim_id(Space, isl_dim_param, i); m = isl_map_set_dim_id(m, isl_dim_param, i, id); } isl_space_free(Space); NewSchedule[&Stmt] = m; index++; } if (!D.isValidSchedule(S, &NewSchedule)) { errs() << "JScop file contains a schedule that changes the " << "dependences. Use -disable-polly-legality to continue anyways\n"; for (StatementToIslMapTy::iterator SI = NewSchedule.begin(), SE = NewSchedule.end(); SI != SE; ++SI) isl_map_free(SI->second); return false; } auto ScheduleMap = isl_union_map_empty(S.getParamSpace()); for (ScopStmt &Stmt : S) { if (NewSchedule.find(&Stmt) != NewSchedule.end()) ScheduleMap = isl_union_map_add_map(ScheduleMap, NewSchedule[&Stmt]); else ScheduleMap = isl_union_map_add_map(ScheduleMap, Stmt.getSchedule()); } S.setSchedule(ScheduleMap); int statementIdx = 0; for (ScopStmt &Stmt : S) { int memoryAccessIdx = 0; for (MemoryAccess *MA : Stmt) { Json::Value accesses = jscop["statements"][statementIdx]["accesses"] [memoryAccessIdx]["relation"]; isl_map *newAccessMap = isl_map_read_from_str(S.getIslCtx(), accesses.asCString()); isl_map *currentAccessMap = MA->getAccessRelation(); if (isl_map_dim(newAccessMap, isl_dim_param) != isl_map_dim(currentAccessMap, isl_dim_param)) { errs() << "JScop file changes the number of parameter dimensions\n"; isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } isl_id *OutId = isl_map_get_tuple_id(currentAccessMap, isl_dim_out); newAccessMap = isl_map_set_tuple_id(newAccessMap, isl_dim_out, OutId); if (MA->isArrayKind()) { // We keep the old alignment, thus we cannot allow accesses to memory // locations that were not accessed before if the alignment of the // access is not the default alignment. bool SpecialAlignment = true; if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) { SpecialAlignment = DL.getABITypeAlignment(LoadI->getType()) != LoadI->getAlignment(); } else if (StoreInst *StoreI = dyn_cast<StoreInst>(MA->getAccessInstruction())) { SpecialAlignment = DL.getABITypeAlignment(StoreI->getValueOperand()->getType()) != StoreI->getAlignment(); } if (SpecialAlignment) { isl_set *newAccessSet = isl_map_range(isl_map_copy(newAccessMap)); isl_set *currentAccessSet = isl_map_range(isl_map_copy(currentAccessMap)); bool isSubset = isl_set_is_subset(newAccessSet, currentAccessSet); isl_set_free(newAccessSet); isl_set_free(currentAccessSet); if (!isSubset) { errs() << "JScop file changes the accessed memory\n"; isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } } } // We need to copy the isl_ids for the parameter dimensions to the new // map. Without doing this the current map would have different // ids then the new one, even though both are named identically. for (unsigned i = 0; i < isl_map_dim(currentAccessMap, isl_dim_param); i++) { isl_id *id = isl_map_get_dim_id(currentAccessMap, isl_dim_param, i); newAccessMap = isl_map_set_dim_id(newAccessMap, isl_dim_param, i, id); } // Copy the old tuple id. This is necessary to retain the user pointer, // that stores the reference to the ScopStmt this access belongs to. isl_id *Id = isl_map_get_tuple_id(currentAccessMap, isl_dim_in); newAccessMap = isl_map_set_tuple_id(newAccessMap, isl_dim_in, Id); if (!isl_map_has_equal_space(currentAccessMap, newAccessMap)) { errs() << "JScop file contains access function with incompatible " << "dimensions\n"; isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } auto NewAccessDomain = isl_map_domain(isl_map_copy(newAccessMap)); auto CurrentAccessDomain = isl_map_domain(isl_map_copy(currentAccessMap)); NewAccessDomain = isl_set_intersect_params(NewAccessDomain, S.getContext()); CurrentAccessDomain = isl_set_intersect_params(CurrentAccessDomain, S.getContext()); if (isl_set_is_subset(CurrentAccessDomain, NewAccessDomain) == isl_bool_false) { errs() << "Mapping not defined for all iteration domain elements\n"; isl_set_free(CurrentAccessDomain); isl_set_free(NewAccessDomain); isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } isl_set_free(CurrentAccessDomain); isl_set_free(NewAccessDomain); if (!isl_map_is_equal(newAccessMap, currentAccessMap)) { // Statistics. ++NewAccessMapFound; newAccessStrings.push_back(accesses.asCString()); MA->setNewAccessRelation(newAccessMap); } else { isl_map_free(newAccessMap); } isl_map_free(currentAccessMap); memoryAccessIdx++; } statementIdx++; } return false; }
static void DumpSymbolNamesFromFile(std::string &Filename) { if (Filename != "-" && !sys::fs::exists(Filename)) { errs() << ToolName << ": '" << Filename << "': " << "No such file\n"; return; } OwningPtr<MemoryBuffer> Buffer; if (error(MemoryBuffer::getFileOrSTDIN(Filename, Buffer), Filename)) return; sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer()); LLVMContext &Context = getGlobalContext(); if (magic == sys::fs::file_magic::bitcode) { ErrorOr<Module *> ModuleOrErr = parseBitcodeFile(Buffer.get(), Context); if (error(ModuleOrErr.getError(), Filename)) { return; } else { Module *Result = ModuleOrErr.get(); DumpSymbolNamesFromModule(Result); delete Result; } } else if (magic == sys::fs::file_magic::archive) { ErrorOr<Binary *> BinaryOrErr = object::createBinary(Buffer.take(), magic); if (error(BinaryOrErr.getError(), Filename)) return; OwningPtr<Binary> arch(BinaryOrErr.get()); if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) { if (ArchiveMap) { object::Archive::symbol_iterator I = a->symbol_begin(); object::Archive::symbol_iterator E = a->symbol_end(); if (I !=E) { outs() << "Archive map" << "\n"; for (; I != E; ++I) { object::Archive::child_iterator c; StringRef symname; StringRef filename; if (error(I->getMember(c))) return; if (error(I->getName(symname))) return; if (error(c->getName(filename))) return; outs() << symname << " in " << filename << "\n"; } outs() << "\n"; } } for (object::Archive::child_iterator i = a->child_begin(), e = a->child_end(); i != e; ++i) { OwningPtr<Binary> child; if (i->getAsBinary(child)) { // Try opening it as a bitcode file. OwningPtr<MemoryBuffer> buff; if (error(i->getMemoryBuffer(buff))) return; ErrorOr<Module *> ModuleOrErr = parseBitcodeFile(buff.get(), Context); if (ModuleOrErr) { Module *Result = ModuleOrErr.get(); DumpSymbolNamesFromModule(Result); delete Result; } continue; } if (object::ObjectFile *o = dyn_cast<ObjectFile>(child.get())) { outs() << o->getFileName() << ":\n"; DumpSymbolNamesFromObject(o); } } } } else if (magic == sys::fs::file_magic::macho_universal_binary) { ErrorOr<Binary *> BinaryOrErr = object::createBinary(Buffer.take(), magic); if (error(BinaryOrErr.getError(), Filename)) return; OwningPtr<Binary> Bin(BinaryOrErr.get()); object::MachOUniversalBinary *UB = cast<object::MachOUniversalBinary>(Bin.get()); for (object::MachOUniversalBinary::object_iterator I = UB->begin_objects(), E = UB->end_objects(); I != E; ++I) { OwningPtr<ObjectFile> Obj; if (!I->getAsObjectFile(Obj)) { outs() << Obj->getFileName() << ":\n"; DumpSymbolNamesFromObject(Obj.get()); } } } else if (magic.is_object()) { ErrorOr<Binary *> BinaryOrErr = object::createBinary(Buffer.take(), magic); if (error(BinaryOrErr.getError(), Filename)) return; OwningPtr<Binary> obj(BinaryOrErr.get()); if (object::ObjectFile *o = dyn_cast<ObjectFile>(obj.get())) DumpSymbolNamesFromObject(o); } else { errs() << ToolName << ": " << Filename << ": " << "unrecognizable file type\n"; HadError = true; return; } }