static void dumpInput(StringRef File) { // Attempt to open the binary. Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File); if (!BinaryOrErr) { auto EC = errorToErrorCode(BinaryOrErr.takeError()); reportError(File, EC); return; } Binary &Binary = *BinaryOrErr.get().getBinary(); if (Archive *Arc = dyn_cast<Archive>(&Binary)) dumpArchive(Arc); else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) dumpCXXData(Obj); else reportError(File, cxxdump_error::unrecognized_file_format); }
ErrorOr<StringRef> Archive::Child::getBuffer() const { if (!isThinMember()) { Expected<uint32_t> Size = getSize(); if (!Size) return errorToErrorCode(Size.takeError()); return StringRef(Data.data() + StartOfFile, Size.get()); } ErrorOr<std::string> FullNameOrEr = getFullName(); if (std::error_code EC = FullNameOrEr.getError()) return EC; const std::string &FullName = *FullNameOrEr; ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile(FullName); if (std::error_code EC = Buf.getError()) return EC; Parent->ThinBuffers.push_back(std::move(*Buf)); return Parent->ThinBuffers.back()->getBuffer(); }
ErrorOr<ObjectFile *> LLVMSymbolizer::getOrCreateObject(const std::string &Path, const std::string &ArchName) { const auto &I = BinaryForPath.find(Path); Binary *Bin = nullptr; if (I == BinaryForPath.end()) { Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path); if (!BinOrErr) { auto EC = errorToErrorCode(BinOrErr.takeError()); BinaryForPath.insert(std::make_pair(Path, EC)); return EC; } Bin = BinOrErr->getBinary(); BinaryForPath.insert(std::make_pair(Path, std::move(BinOrErr.get()))); } else if (auto EC = I->second.getError()) { return EC; } else { Bin = I->second->getBinary(); } assert(Bin != nullptr); if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) { const auto &I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName)); if (I != ObjectForUBPathAndArch.end()) { if (auto EC = I->second.getError()) return EC; return I->second->get(); } ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = UB->getObjectForArch(ArchName); if (auto EC = ObjOrErr.getError()) { ObjectForUBPathAndArch.insert( std::make_pair(std::make_pair(Path, ArchName), EC)); return EC; } ObjectFile *Res = ObjOrErr->get(); ObjectForUBPathAndArch.insert(std::make_pair(std::make_pair(Path, ArchName), std::move(ObjOrErr.get()))); return Res; } if (Bin->isObject()) { return cast<ObjectFile>(Bin); } return object_error::arch_not_found; }
ErrorOr<MemoryBufferRef> IRObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Object) { sys::fs::file_magic Type = sys::fs::identify_magic(Object.getBuffer()); switch (Type) { case sys::fs::file_magic::bitcode: return Object; case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::macho_object: case sys::fs::file_magic::coff_object: { Expected<std::unique_ptr<ObjectFile>> ObjFile = ObjectFile::createObjectFile(Object, Type); if (!ObjFile) return errorToErrorCode(ObjFile.takeError()); return findBitcodeInObject(*ObjFile->get()); } default: return object_error::invalid_file_type; } }
static void performReadOperation(ArchiveOperation Operation, object::Archive *OldArchive) { if (Operation == Extract && OldArchive->isThin()) fail("extracting from a thin archive is not supported"); bool Filter = !Members.empty(); { Error Err; for (auto &C : OldArchive->children(Err)) { Expected<StringRef> NameOrErr = C.getName(); failIfError(NameOrErr.takeError()); StringRef Name = NameOrErr.get(); if (Filter) { auto I = find(Members, Name); if (I == Members.end()) continue; Members.erase(I); } switch (Operation) { default: llvm_unreachable("Not a read operation"); case Print: doPrint(Name, C); break; case DisplayTable: doDisplayTable(Name, C); break; case Extract: doExtract(Name, C); break; } } failIfError(std::move(Err)); } if (Members.empty()) return; for (StringRef Name : Members) errs() << Name << " was not found\n"; std::exit(1); }
extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { std::unique_ptr<MemoryBuffer> Buff = MemoryBuffer::getMemBuffer( StringRef((const char *)data, size), "", false); Expected<std::unique_ptr<ObjectFile>> ObjOrErr = ObjectFile::createObjectFile(Buff->getMemBufferRef()); if (auto E = ObjOrErr.takeError()) { consumeError(std::move(E)); return 0; } ObjectFile &Obj = *ObjOrErr.get(); std::unique_ptr<DIContext> DICtx = DWARFContext::create(Obj); DIDumpOptions opts; opts.DumpType = DIDT_All; DICtx->dump(nulls(), opts); return 0; }
std::unique_ptr<Module> TempFile::readBitcode(LLVMContext &Context) const { DEBUG(dbgs() << " - read bitcode\n"); ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOr = MemoryBuffer::getFile(Filename); if (!BufferOr) { errs() << "verify-uselistorder: error: " << BufferOr.getError().message() << "\n"; return nullptr; } MemoryBuffer *Buffer = BufferOr.get().get(); Expected<std::unique_ptr<Module>> ModuleOr = parseBitcodeFile(Buffer->getMemBufferRef(), Context); if (!ModuleOr) { logAllUnhandledErrors(ModuleOr.takeError(), errs(), "verify-uselistorder: error: "); return nullptr; } return std::move(ModuleOr.get()); }
/// @brief Opens \a File and dumps it. static void dumpInput(StringRef File) { // Attempt to open the binary. Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File); if (!BinaryOrErr) reportError(File, errorToErrorCode(BinaryOrErr.takeError())); Binary &Binary = *BinaryOrErr.get().getBinary(); if (Archive *Arc = dyn_cast<Archive>(&Binary)) dumpArchive(Arc); else if (MachOUniversalBinary *UBinary = dyn_cast<MachOUniversalBinary>(&Binary)) dumpMachOUniversalBinary(UBinary); else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) dumpObject(Obj); else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary)) dumpCOFFImportFile(Import); else reportError(File, readobj_error::unrecognized_file_format); }
int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm objcopy utility\n"); ToolName = argv[0]; if (InputFilename.empty()) { cl::PrintHelpMessage(); return 2; } Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFilename); if (!BinaryOrErr) reportError(InputFilename, BinaryOrErr.takeError()); Binary &Binary = *BinaryOrErr.get().getBinary(); if (ELFObjectFile<ELF64LE> *o = dyn_cast<ELFObjectFile<ELF64LE>>(&Binary)) { CopyBinary(*o); return 0; } reportError(InputFilename, object_error::invalid_file_type); }
extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) { ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr = MemoryBuffer::getFile(Path, -1, false); if (!BufOr) { LLVMRustSetLastError(BufOr.getError().message().c_str()); return nullptr; } Expected<std::unique_ptr<Archive>> ArchiveOr = Archive::create(BufOr.get()->getMemBufferRef()); if (!ArchiveOr) { LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str()); return nullptr; } OwningBinary<Archive> *Ret = new OwningBinary<Archive>( std::move(ArchiveOr.get()), std::move(BufOr.get())); return Ret; }
/// @brief Dumps each object file in \a Arc; static void dumpArchive(const Archive *Arc) { for (auto &ErrorOrChild : Arc->children()) { if (std::error_code EC = ErrorOrChild.getError()) reportError(Arc->getFileName(), EC.message()); const auto &Child = *ErrorOrChild; Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); if (!ChildOrErr) { if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) { std::string Buf; raw_string_ostream OS(Buf); logAllUnhandledErrors(ChildOrErr.takeError(), OS, ""); OS.flush(); reportError(Arc->getFileName(), Buf); } continue; } if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get())) dumpObject(Obj); else reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); } }
/// Return an appropriate object file handler. We use the specific object /// handler if we know how to deal with that format, otherwise we use a default /// binary file handler. static FileHandler *CreateObjectFileHandler(MemoryBuffer &FirstInput) { // Check if the input file format is one that we know how to deal with. Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput); // Failed to open the input as a known binary. Use the default binary handler. if (!BinaryOrErr) { // We don't really care about the error (we just consume it), if we could // not get a valid device binary object we use the default binary handler. consumeError(BinaryOrErr.takeError()); return new BinaryFileHandler(); } // We only support regular object files. If this is not an object file, // default to the binary handler. The handler will be owned by the client of // this function. std::unique_ptr<ObjectFile> Obj( dyn_cast<ObjectFile>(BinaryOrErr.get().release())); if (!Obj) return new BinaryFileHandler(); return new ObjectFileHandler(std::move(Obj)); }
Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err) : Parent(Parent), Header(Parent, Start, Parent->getData().size() - (Start - Parent->getData().data()), Err) { if (!Start) return; ErrorAsOutParameter ErrAsOutParam(Err); // If there was an error in the construction of the Header and we were passed // Err that is not nullptr then just return with the error now set. if (Err && *Err) return; uint64_t Size = Header.getSizeOf(); Data = StringRef(Start, Size); if (!isThinMember()) { Expected<uint64_t> MemberSize = getRawSize(); if (!MemberSize) { if (Err) *Err = MemberSize.takeError(); return; } Size += MemberSize.get(); Data = StringRef(Start, Size); } // Setup StartOfFile and PaddingBytes. StartOfFile = Header.getSizeOf(); // Don't include attached name. StringRef Name = getRawName(); if (Name.startswith("#1/")) { uint64_t NameSize; if (Name.substr(3).rtrim(' ').getAsInteger(10, NameSize)) llvm_unreachable("Long name length is not an integer"); StartOfFile += NameSize; } }
//===----------------------------------------------------------------------===// // 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) return runOrcLazyJIT(std::move(Owner), argc, argv); 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) { if (std::error_code EC = Mod->materializeAll()) { errs() << argv[0] << ": bitcode didn't read correctly.\n"; errs() << "Reason: " << EC.message() << "\n"; exit(1); } } 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(); ErrorOr<std::unique_ptr<object::Archive>> ArOrErr = object::Archive::create(ArBuf->getMemBufferRef()); if (std::error_code EC = ArOrErr.getError()) { errs() << EC.message(); 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<FDRPCChannel> 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::remote::RPCChannel> MyRemote; MyRemote 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 RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported); return RuntimeDyld::SymbolInfo(nullptr); } )); // Grab the target address of the JIT'd main function on the remote and call // it. // FIXME: argv and envp handling. orc::TargetAddress 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; }
int main(int argc, char **argv) { InitLLVM X(argc, argv); // Initialize targets and assembly parsers. InitializeAllTargetInfos(); InitializeAllTargetMCs(); InitializeAllAsmParsers(); // Enable printing of available targets when flag --version is specified. cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); cl::HideUnrelatedOptions({&ToolOptions, &ViewOptions}); // Parse flags and initialize target options. cl::ParseCommandLineOptions(argc, argv, "llvm machine code performance analyzer.\n"); // Get the target from the triple. If a triple is not specified, then select // the default triple for the host. If the triple doesn't correspond to any // registered target, then exit with an error message. const char *ProgName = argv[0]; const Target *TheTarget = getTarget(ProgName); if (!TheTarget) return 1; // GetTarget() may replaced TripleName with a default triple. // For safety, reconstruct the Triple object. Triple TheTriple(TripleName); ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr = MemoryBuffer::getFileOrSTDIN(InputFilename); if (std::error_code EC = BufferPtr.getError()) { WithColor::error() << InputFilename << ": " << EC.message() << '\n'; return 1; } // Apply overrides to llvm-mca specific options. processViewOptions(); SourceMgr SrcMgr; // Tell SrcMgr about this buffer, which is what the parser will pick up. SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc()); 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!"); MCObjectFileInfo MOFI; MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr); MOFI.InitMCObjectFileInfo(TheTriple, /* PIC= */ false, Ctx); std::unique_ptr<buffer_ostream> BOS; std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); std::unique_ptr<MCInstrAnalysis> MCIA( TheTarget->createMCInstrAnalysis(MCII.get())); if (!MCPU.compare("native")) MCPU = llvm::sys::getHostCPUName(); std::unique_ptr<MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(TripleName, MCPU, /* FeaturesStr */ "")); if (!STI->isCPUStringValid(MCPU)) return 1; if (!PrintInstructionTables && !STI->getSchedModel().isOutOfOrder()) { WithColor::error() << "please specify an out-of-order cpu. '" << MCPU << "' is an in-order cpu.\n"; return 1; } if (!STI->getSchedModel().hasInstrSchedModel()) { WithColor::error() << "unable to find instruction-level scheduling information for" << " target triple '" << TheTriple.normalize() << "' and cpu '" << MCPU << "'.\n"; if (STI->getSchedModel().InstrItineraries) WithColor::note() << "cpu '" << MCPU << "' provides itineraries. However, " << "instruction itineraries are currently unsupported.\n"; return 1; } // Parse the input and create CodeRegions that llvm-mca can analyze. mca::AsmCodeRegionGenerator CRG(*TheTarget, SrcMgr, Ctx, *MAI, *STI, *MCII); Expected<const mca::CodeRegions &> RegionsOrErr = CRG.parseCodeRegions(); if (!RegionsOrErr) { if (auto Err = handleErrors(RegionsOrErr.takeError(), [](const StringError &E) { WithColor::error() << E.getMessage() << '\n'; })) { // Default case. WithColor::error() << toString(std::move(Err)) << '\n'; } return 1; } const mca::CodeRegions &Regions = *RegionsOrErr; if (Regions.empty()) { WithColor::error() << "no assembly instructions found.\n"; return 1; } // Now initialize the output file. auto OF = getOutputStream(); if (std::error_code EC = OF.getError()) { WithColor::error() << EC.message() << '\n'; return 1; } unsigned AssemblerDialect = CRG.getAssemblerDialect(); if (OutputAsmVariant >= 0) AssemblerDialect = static_cast<unsigned>(OutputAsmVariant); std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( Triple(TripleName), AssemblerDialect, *MAI, *MCII, *MRI)); if (!IP) { WithColor::error() << "unable to create instruction printer for target triple '" << TheTriple.normalize() << "' with assembly variant " << AssemblerDialect << ".\n"; return 1; } std::unique_ptr<ToolOutputFile> TOF = std::move(*OF); const MCSchedModel &SM = STI->getSchedModel(); // Create an instruction builder. mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get()); // Create a context to control ownership of the pipeline hardware. mca::Context MCA(*MRI, *STI); mca::PipelineOptions PO(MicroOpQueue, DecoderThroughput, DispatchWidth, RegisterFileSize, LoadQueueSize, StoreQueueSize, AssumeNoAlias, EnableBottleneckAnalysis); // Number each region in the sequence. unsigned RegionIdx = 0; for (const std::unique_ptr<mca::CodeRegion> &Region : Regions) { // Skip empty code regions. if (Region->empty()) continue; // Don't print the header of this region if it is the default region, and // it doesn't have an end location. if (Region->startLoc().isValid() || Region->endLoc().isValid()) { TOF->os() << "\n[" << RegionIdx++ << "] Code Region"; StringRef Desc = Region->getDescription(); if (!Desc.empty()) TOF->os() << " - " << Desc; TOF->os() << "\n\n"; } // Lower the MCInst sequence into an mca::Instruction sequence. ArrayRef<MCInst> Insts = Region->getInstructions(); std::vector<std::unique_ptr<mca::Instruction>> LoweredSequence; for (const MCInst &MCI : Insts) { Expected<std::unique_ptr<mca::Instruction>> Inst = IB.createInstruction(MCI); if (!Inst) { if (auto NewE = handleErrors( Inst.takeError(), [&IP, &STI](const mca::InstructionError<MCInst> &IE) { std::string InstructionStr; raw_string_ostream SS(InstructionStr); WithColor::error() << IE.Message << '\n'; IP->printInst(&IE.Inst, SS, "", *STI); SS.flush(); WithColor::note() << "instruction: " << InstructionStr << '\n'; })) { // Default case. WithColor::error() << toString(std::move(NewE)); } return 1; } LoweredSequence.emplace_back(std::move(Inst.get())); } mca::SourceMgr S(LoweredSequence, PrintInstructionTables ? 1 : Iterations); if (PrintInstructionTables) { // Create a pipeline, stages, and a printer. auto P = llvm::make_unique<mca::Pipeline>(); P->appendStage(llvm::make_unique<mca::EntryStage>(S)); P->appendStage(llvm::make_unique<mca::InstructionTables>(SM)); mca::PipelinePrinter Printer(*P); // Create the views for this pipeline, execute, and emit a report. if (PrintInstructionInfoView) { Printer.addView(llvm::make_unique<mca::InstructionInfoView>( *STI, *MCII, Insts, *IP)); } Printer.addView( llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts)); if (!runPipeline(*P)) return 1; Printer.printReport(TOF->os()); continue; } // Create a basic pipeline simulating an out-of-order backend. auto P = MCA.createDefaultPipeline(PO, IB, S); mca::PipelinePrinter Printer(*P); if (PrintSummaryView) Printer.addView(llvm::make_unique<mca::SummaryView>( SM, Insts, DispatchWidth)); if (EnableBottleneckAnalysis) Printer.addView(llvm::make_unique<mca::BottleneckAnalysis>(SM)); if (PrintInstructionInfoView) Printer.addView( llvm::make_unique<mca::InstructionInfoView>(*STI, *MCII, Insts, *IP)); if (PrintDispatchStats) Printer.addView(llvm::make_unique<mca::DispatchStatistics>()); if (PrintSchedulerStats) Printer.addView(llvm::make_unique<mca::SchedulerStatistics>(*STI)); if (PrintRetireStats) Printer.addView(llvm::make_unique<mca::RetireControlUnitStatistics>(SM)); if (PrintRegisterFileStats) Printer.addView(llvm::make_unique<mca::RegisterFileStatistics>(*STI)); if (PrintResourcePressureView) Printer.addView( llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts)); if (PrintTimelineView) { unsigned TimelineIterations = TimelineMaxIterations ? TimelineMaxIterations : 10; Printer.addView(llvm::make_unique<mca::TimelineView>( *STI, *IP, Insts, std::min(TimelineIterations, S.getNumIterations()), TimelineMaxCycles)); } if (!runPipeline(*P)) return 1; Printer.printReport(TOF->os()); // Clear the InstrBuilder internal state in preparation for another round. IB.clear(); } TOF->keep(); return 0; }
// Returns the offset of the first reference to a member offset. static ErrorOr<unsigned> writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, ArrayRef<NewArchiveMember> Members, std::vector<unsigned> &MemberOffsetRefs, bool Deterministic) { unsigned HeaderStartOffset = 0; unsigned BodyStartOffset = 0; SmallString<128> NameBuf; raw_svector_ostream NameOS(NameBuf); LLVMContext Context; for (unsigned MemberNum = 0, N = Members.size(); MemberNum < N; ++MemberNum) { MemoryBufferRef MemberBuffer = Members[MemberNum].Buf->getMemBufferRef(); Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = object::SymbolicFile::createSymbolicFile( MemberBuffer, sys::fs::file_magic::unknown, &Context); if (!ObjOrErr) { // FIXME: check only for "not an object file" errors. consumeError(ObjOrErr.takeError()); continue; } object::SymbolicFile &Obj = *ObjOrErr.get(); if (!HeaderStartOffset) { HeaderStartOffset = Out.tell(); if (Kind == object::Archive::K_GNU) printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0); else printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0); BodyStartOffset = Out.tell(); print32(Out, Kind, 0); // number of entries or bytes } for (const object::BasicSymbolRef &S : Obj.symbols()) { uint32_t Symflags = S.getFlags(); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; unsigned NameOffset = NameOS.tell(); if (auto EC = S.printName(NameOS)) return EC; NameOS << '\0'; MemberOffsetRefs.push_back(MemberNum); if (Kind == object::Archive::K_BSD) print32(Out, Kind, NameOffset); print32(Out, Kind, 0); // member offset } } if (HeaderStartOffset == 0) return 0; StringRef StringTable = NameOS.str(); if (Kind == object::Archive::K_BSD) print32(Out, Kind, StringTable.size()); // byte count of the string table Out << StringTable; // ld64 requires the next member header to start at an offset that is // 4 bytes aligned. unsigned Pad = OffsetToAlignment(Out.tell(), 4); while (Pad--) Out.write(uint8_t(0)); // Patch up the size of the symbol table now that we know how big it is. unsigned Pos = Out.tell(); const unsigned MemberHeaderSize = 60; Out.seek(HeaderStartOffset + 48); // offset of the size field. printWithSpacePadding(Out, Pos - MemberHeaderSize - HeaderStartOffset, 10); // Patch up the number of symbols. Out.seek(BodyStartOffset); unsigned NumSyms = MemberOffsetRefs.size(); if (Kind == object::Archive::K_GNU) print32(Out, Kind, NumSyms); else print32(Out, Kind, NumSyms * 8); Out.seek(Pos); return BodyStartOffset + 4; }
int main(int Argc, const char **Argv) { InitLLVM X(Argc, Argv); CvtResOptTable T; unsigned MAI, MAC; ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1); opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC); if (InputArgs.hasArg(OPT_HELP)) { T.PrintHelp(outs(), "llvm-cvtres [options] file...", "Resource Converter"); return 0; } bool Verbose = InputArgs.hasArg(OPT_VERBOSE); COFF::MachineTypes MachineType; if (InputArgs.hasArg(OPT_MACHINE)) { std::string MachineString = InputArgs.getLastArgValue(OPT_MACHINE).upper(); MachineType = StringSwitch<COFF::MachineTypes>(MachineString) .Case("ARM", COFF::IMAGE_FILE_MACHINE_ARMNT) .Case("ARM64", COFF::IMAGE_FILE_MACHINE_ARM64) .Case("X64", COFF::IMAGE_FILE_MACHINE_AMD64) .Case("X86", COFF::IMAGE_FILE_MACHINE_I386) .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN); if (MachineType == COFF::IMAGE_FILE_MACHINE_UNKNOWN) reportError("Unsupported machine architecture"); } else { if (Verbose) outs() << "Machine architecture not specified; assumed X64.\n"; MachineType = COFF::IMAGE_FILE_MACHINE_AMD64; } std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT); if (InputFiles.size() == 0) { reportError("No input file specified.\n"); } SmallString<128> OutputFile; if (InputArgs.hasArg(OPT_OUT)) { OutputFile = InputArgs.getLastArgValue(OPT_OUT); } else { OutputFile = sys::path::filename(StringRef(InputFiles[0])); sys::path::replace_extension(OutputFile, ".obj"); } if (Verbose) { outs() << "Machine: "; switch (MachineType) { case COFF::IMAGE_FILE_MACHINE_ARM64: outs() << "ARM64\n"; break; case COFF::IMAGE_FILE_MACHINE_ARMNT: outs() << "ARM\n"; break; case COFF::IMAGE_FILE_MACHINE_I386: outs() << "X86\n"; break; default: outs() << "X64\n"; } } WindowsResourceParser Parser; for (const auto &File : InputFiles) { Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File); if (!BinaryOrErr) reportError(File, errorToErrorCode(BinaryOrErr.takeError())); Binary &Binary = *BinaryOrErr.get().getBinary(); WindowsResource *RF = dyn_cast<WindowsResource>(&Binary); if (!RF) reportError(File + ": unrecognized file format.\n"); if (Verbose) { int EntryNumber = 0; ResourceEntryRef Entry = error(RF->getHeadEntry()); bool End = false; while (!End) { error(Entry.moveNext(End)); EntryNumber++; } outs() << "Number of resources: " << EntryNumber << "\n"; } error(Parser.parse(RF)); } if (Verbose) { Parser.printTree(outs()); } std::unique_ptr<MemoryBuffer> OutputBuffer = error(llvm::object::writeWindowsResourceCOFF(MachineType, Parser)); auto FileOrErr = FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize()); if (!FileOrErr) reportError(OutputFile, errorToErrorCode(FileOrErr.takeError())); std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr); std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(), FileBuffer->getBufferStart()); error(FileBuffer->commit()); if (Verbose) { Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(OutputFile); if (!BinaryOrErr) reportError(OutputFile, errorToErrorCode(BinaryOrErr.takeError())); Binary &Binary = *BinaryOrErr.get().getBinary(); ScopedPrinter W(errs()); W.printBinaryBlock("Output File Raw Data", Binary.getData()); } return 0; }
template <typename T> T error(Expected<T> EC) { if (!EC) error(EC.takeError()); return std::move(EC.get()); }
// We have to walk this twice and computing it is not trivial, so creating an // explicit std::vector is actually fairly efficient. static std::vector<NewArchiveMember> computeNewArchiveMembers(ArchiveOperation Operation, object::Archive *OldArchive) { std::vector<NewArchiveMember> Ret; std::vector<NewArchiveMember> Moved; int InsertPos = -1; StringRef PosName = sys::path::filename(RelPos); if (OldArchive) { Error Err; for (auto &Child : OldArchive->children(Err)) { int Pos = Ret.size(); Expected<StringRef> NameOrErr = Child.getName(); failIfError(NameOrErr.takeError()); StringRef Name = NameOrErr.get(); if (Name == PosName) { assert(AddAfter || AddBefore); if (AddBefore) InsertPos = Pos; else InsertPos = Pos + 1; } std::vector<StringRef>::iterator MemberI = Members.end(); InsertAction Action = computeInsertAction(Operation, Child, Name, MemberI); switch (Action) { case IA_AddOldMember: addMember(Ret, Child); break; case IA_AddNewMeber: addMember(Ret, *MemberI); break; case IA_Delete: break; case IA_MoveOldMember: addMember(Moved, Child); break; case IA_MoveNewMember: addMember(Moved, *MemberI); break; } if (MemberI != Members.end()) Members.erase(MemberI); } failIfError(std::move(Err)); } if (Operation == Delete) return Ret; if (!RelPos.empty() && InsertPos == -1) fail("Insertion point not found"); if (RelPos.empty()) InsertPos = Ret.size(); assert(unsigned(InsertPos) <= Ret.size()); int Pos = InsertPos; for (auto &M : Moved) { Ret.insert(Ret.begin() + Pos, std::move(M)); ++Pos; } for (unsigned I = 0; I != Members.size(); ++I) Ret.insert(Ret.begin() + InsertPos, NewArchiveMember()); Pos = InsertPos; for (auto &Member : Members) { addMember(Ret, Member, Pos); ++Pos; } return Ret; }
TEST(MinidumpFile, getModuleList) { std::vector<uint8_t> OneModule{ // Header 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version 1, 0, 0, 0, // NumberOfStreams, 32, 0, 0, 0, // StreamDirectoryRVA 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp 0, 0, 0, 0, 0, 0, 0, 0, // Flags // Stream Directory 4, 0, 0, 0, 112, 0, 0, 0, // Type, DataSize, 44, 0, 0, 0, // RVA // ModuleList 1, 0, 0, 0, // NumberOfModules 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags 0, 0, 0, 0, // FileOS 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType 0, 0, 0, 0, 0, 0, 0, 0, // FileDate 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1 }; // Same as before, but with a padded module list. std::vector<uint8_t> PaddedModule{ // Header 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version 1, 0, 0, 0, // NumberOfStreams, 32, 0, 0, 0, // StreamDirectoryRVA 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp 0, 0, 0, 0, 0, 0, 0, 0, // Flags // Stream Directory 4, 0, 0, 0, 116, 0, 0, 0, // Type, DataSize, 44, 0, 0, 0, // RVA // ModuleList 1, 0, 0, 0, // NumberOfModules 0, 0, 0, 0, // Padding 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags 0, 0, 0, 0, // FileOS 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType 0, 0, 0, 0, 0, 0, 0, 0, // FileDate 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1 }; for (const std::vector<uint8_t> &Data : {OneModule, PaddedModule}) { auto ExpectedFile = create(Data); ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); const MinidumpFile &File = **ExpectedFile; Expected<ArrayRef<Module>> ExpectedModule = File.getModuleList(); ASSERT_THAT_EXPECTED(ExpectedModule, Succeeded()); ASSERT_EQ(1u, ExpectedModule->size()); const Module &M = ExpectedModule.get()[0]; EXPECT_EQ(0x0807060504030201u, M.BaseOfImage); EXPECT_EQ(0x02010009u, M.SizeOfImage); EXPECT_EQ(0x06050403u, M.Checksum); EXPECT_EQ(0x00090807u, M.TimeDateStamp); EXPECT_EQ(0x04030201u, M.ModuleNameRVA); EXPECT_EQ(0x04030201u, M.CvRecord.DataSize); EXPECT_EQ(0x08070605u, M.CvRecord.RVA); EXPECT_EQ(0x02010009u, M.MiscRecord.DataSize); EXPECT_EQ(0x06050403u, M.MiscRecord.RVA); EXPECT_EQ(0x0403020100090807u, M.Reserved0); EXPECT_EQ(0x0201000908070605u, M.Reserved1); } std::vector<uint8_t> StreamTooShort{ // Header 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version 1, 0, 0, 0, // NumberOfStreams, 32, 0, 0, 0, // StreamDirectoryRVA 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp 0, 0, 0, 0, 0, 0, 0, 0, // Flags // Stream Directory 4, 0, 0, 0, 111, 0, 0, 0, // Type, DataSize, 44, 0, 0, 0, // RVA // ModuleList 1, 0, 0, 0, // NumberOfModules 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags 0, 0, 0, 0, // FileOS 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType 0, 0, 0, 0, 0, 0, 0, 0, // FileDate 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1 }; auto ExpectedFile = create(StreamTooShort); ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); const MinidumpFile &File = **ExpectedFile; EXPECT_THAT_EXPECTED(File.getModuleList(), Failed<BinaryError>()); }
static void addModule(LTO &Lto, claimed_file &F, const void *View, StringRef Filename) { MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize), Filename); Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(BufferRef); if (!ObjOrErr) message(LDPL_FATAL, "Could not read bitcode from file : %s", toString(ObjOrErr.takeError()).c_str()); unsigned SymNum = 0; std::unique_ptr<InputFile> Input = std::move(ObjOrErr.get()); auto InputFileSyms = Input->symbols(); assert(InputFileSyms.size() == F.syms.size()); std::vector<SymbolResolution> Resols(F.syms.size()); for (ld_plugin_symbol &Sym : F.syms) { const InputFile::Symbol &InpSym = InputFileSyms[SymNum]; SymbolResolution &R = Resols[SymNum++]; ld_plugin_symbol_resolution Resolution = (ld_plugin_symbol_resolution)Sym.resolution; ResolutionInfo &Res = ResInfo[Sym.name]; switch (Resolution) { case LDPR_UNKNOWN: llvm_unreachable("Unexpected resolution"); case LDPR_RESOLVED_IR: case LDPR_RESOLVED_EXEC: case LDPR_RESOLVED_DYN: case LDPR_PREEMPTED_IR: case LDPR_PREEMPTED_REG: case LDPR_UNDEF: break; case LDPR_PREVAILING_DEF_IRONLY: R.Prevailing = true; break; case LDPR_PREVAILING_DEF: R.Prevailing = true; R.VisibleToRegularObj = true; break; case LDPR_PREVAILING_DEF_IRONLY_EXP: R.Prevailing = true; if (!Res.CanOmitFromDynSym) R.VisibleToRegularObj = true; break; } // If the symbol has a C identifier section name, we need to mark // it as visible to a regular object so that LTO will keep it around // to ensure the linker generates special __start_<secname> and // __stop_<secname> symbols which may be used elsewhere. if (isValidCIdentifier(InpSym.getSectionName())) R.VisibleToRegularObj = true; if (Resolution != LDPR_RESOLVED_DYN && Resolution != LDPR_UNDEF && (IsExecutable || !Res.DefaultVisibility)) R.FinalDefinitionInLinkageUnit = true; freeSymName(Sym); } check(Lto.add(std::move(Input), Resols), std::string("Failed to link module ") + F.name); }
int main(int argc_, const char *argv_[]) { sys::PrintStackTraceOnErrorSignal(argv_[0]); PrettyStackTraceProgram X(argc_, argv_); ExitOnErr.setBanner("llvm-cvtres: "); SmallVector<const char *, 256> argv; SpecificBumpPtrAllocator<char> ArgAllocator; ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector( argv, makeArrayRef(argv_, argc_), ArgAllocator))); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. CvtResOptTable T; unsigned MAI, MAC; ArrayRef<const char *> ArgsArr = makeArrayRef(argv_ + 1, argc_); opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC); if (InputArgs.hasArg(OPT_HELP)) { T.PrintHelp(outs(), "cvtres", "Resource Converter", false); return 0; } bool Verbose = InputArgs.hasArg(OPT_VERBOSE); Machine MachineType; if (InputArgs.hasArg(OPT_MACHINE)) { std::string MachineString = InputArgs.getLastArgValue(OPT_MACHINE).upper(); MachineType = StringSwitch<Machine>(MachineString) .Case("ARM", Machine::ARM) .Case("X64", Machine::X64) .Case("X86", Machine::X86) .Default(Machine::UNKNOWN); if (MachineType == Machine::UNKNOWN) reportError("Unsupported machine architecture"); } else { if (Verbose) outs() << "Machine architecture not specified; assumed X64.\n"; MachineType = Machine::X64; } std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT); if (InputFiles.size() == 0) { reportError("No input file specified.\n"); } SmallString<128> OutputFile; if (InputArgs.hasArg(OPT_OUT)) { OutputFile = InputArgs.getLastArgValue(OPT_OUT); } else { OutputFile = llvm::sys::path::filename(StringRef(InputFiles[0])); llvm::sys::path::replace_extension(OutputFile, ".obj"); } if (Verbose) { outs() << "Machine: "; switch (MachineType) { case Machine::ARM: outs() << "ARM\n"; break; case Machine::X86: outs() << "X86\n"; break; default: outs() << "X64\n"; } } WindowsResourceParser Parser; for (const auto &File : InputFiles) { Expected<object::OwningBinary<object::Binary>> BinaryOrErr = object::createBinary(File); if (!BinaryOrErr) reportError(File, errorToErrorCode(BinaryOrErr.takeError())); Binary &Binary = *BinaryOrErr.get().getBinary(); WindowsResource *RF = dyn_cast<WindowsResource>(&Binary); if (!RF) reportError(File + ": unrecognized file format.\n"); if (Verbose) { int EntryNumber = 0; Expected<ResourceEntryRef> EntryOrErr = RF->getHeadEntry(); if (!EntryOrErr) error(EntryOrErr.takeError()); ResourceEntryRef Entry = EntryOrErr.get(); bool End = false; while (!End) { error(Entry.moveNext(End)); EntryNumber++; } outs() << "Number of resources: " << EntryNumber << "\n"; } error(Parser.parse(RF)); } if (Verbose) { Parser.printTree(outs()); Parser.printTree(errs()); } error( llvm::object::writeWindowsResourceCOFF(OutputFile, MachineType, Parser)); if (Verbose) { Expected<object::OwningBinary<object::Binary>> BinaryOrErr = object::createBinary(OutputFile); if (!BinaryOrErr) reportError(OutputFile, errorToErrorCode(BinaryOrErr.takeError())); Binary &Binary = *BinaryOrErr.get().getBinary(); ScopedPrinter W(errs()); W.printBinaryBlock("Output File Raw Data", Binary.getData()); } return 0; }