void SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F, const object::Archive::Symbol Sym) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Sym.getName()); if (WasInserted) { replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType); return; } if (!S->body()->isUndefined()) return; // Weak undefined symbols should not fetch members from archives. If we were // to keep old symbol we would not know that an archive member was available // if a strong undefined symbol shows up afterwards in the link. If a strong // undefined symbol never shows up, this lazy symbol will get to the end of // the link and must be treated as the weak undefined one. We already marked // this symbol as used when we added it to the symbol table, but we also need // to preserve its type. FIXME: Move the Type field to Symbol. if (S->isWeak()) { replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type); return; } MemoryBufferRef MBRef = F->getMember(&Sym); if (!MBRef.getBuffer().empty()) addFile(createObjectFile(MBRef, F->getName())); }
template <class ELFT> static ELFFile<ELFT> createELFObj(MemoryBufferRef MB) { std::error_code EC; ELFFile<ELFT> F(MB.getBuffer(), EC); if (EC) fatal(EC, "failed to read " + MB.getBufferIdentifier()); return F; }
ErrorOr<std::unique_ptr<ObjectFile>> ObjectFile::createELFObjectFile(MemoryBufferRef Obj) { std::pair<unsigned char, unsigned char> Ident = getElfArchType(Obj.getBuffer()); std::size_t MaxAlignment = 1ULL << countTrailingZeros(uintptr_t(Obj.getBufferStart())); if (MaxAlignment < 2) return object_error::parse_failed; std::error_code EC; std::unique_ptr<ObjectFile> R; if (Ident.first == ELF::ELFCLASS32) { if (Ident.second == ELF::ELFDATA2LSB) R.reset(new ELFObjectFile<ELFType<support::little, false>>(Obj, EC)); else if (Ident.second == ELF::ELFDATA2MSB) R.reset(new ELFObjectFile<ELFType<support::big, false>>(Obj, EC)); else return object_error::parse_failed; } else if (Ident.first == ELF::ELFCLASS64) { if (Ident.second == ELF::ELFDATA2LSB) R.reset(new ELFObjectFile<ELFType<support::little, true>>(Obj, EC)); else if (Ident.second == ELF::ELFDATA2MSB) R.reset(new ELFObjectFile<ELFType<support::big, true>>(Obj, EC)); else return object_error::parse_failed; } else { return object_error::parse_failed; } if (EC) return EC; return std::move(R); }
Error PDBFile::parseFileHeaders() { std::error_code EC; MemoryBufferRef BufferRef = *Context->Buffer; // Make sure the file is sufficiently large to hold a super block. // Do this before attempting to read the super block. if (BufferRef.getBufferSize() < sizeof(SuperBlock)) return make_error<RawError>(raw_error_code::corrupt_file, "Does not contain superblock"); Context->SB = reinterpret_cast<const SuperBlock *>(BufferRef.getBufferStart()); const SuperBlock *SB = Context->SB; // Check the magic bytes. if (memcmp(SB->MagicBytes, Magic, sizeof(Magic)) != 0) return make_error<RawError>(raw_error_code::corrupt_file, "MSF magic header doesn't match"); // We don't support blocksizes which aren't a multiple of four bytes. if (SB->BlockSize % sizeof(support::ulittle32_t) != 0) return make_error<RawError>(raw_error_code::corrupt_file, "Block size is not multiple of 4."); switch (SB->BlockSize) { case 512: case 1024: case 2048: case 4096: break; default: // An invalid block size suggests a corrupt PDB file. return make_error<RawError>(raw_error_code::corrupt_file, "Unsupported block size."); } if (BufferRef.getBufferSize() % SB->BlockSize != 0) return make_error<RawError>(raw_error_code::corrupt_file, "File size is not a multiple of block size"); // We don't support directories whose sizes aren't a multiple of four bytes. if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) return make_error<RawError>(raw_error_code::corrupt_file, "Directory size is not multiple of 4."); // The number of blocks which comprise the directory is a simple function of // the number of bytes it contains. uint64_t NumDirectoryBlocks = getNumDirectoryBlocks(); // The block map, as we understand it, is a block which consists of a list of // block numbers. // It is unclear what would happen if the number of blocks couldn't fit on a // single block. if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t)) return make_error<RawError>(raw_error_code::corrupt_file, "Too many directory blocks."); // Make sure the directory block array fits within the file. if (auto EC = checkOffset(BufferRef, getDirectoryBlockArray())) return EC; return Error::success(); }
std::unique_ptr<InputFile> LazyArchive::getFile() { MemoryBufferRef MBRef = File->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBRef.getBuffer().empty()) return std::unique_ptr<InputFile>(nullptr); return createObjectFile(MBRef, File->getName()); }
static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, const uint64_t Size) { if (Addr + Size < Addr || Addr + Size < Size || Addr + Size > uintptr_t(M.getBufferEnd()) || Addr < uintptr_t(M.getBufferStart())) { return std::make_error_code(std::errc::bad_address); } return std::error_code(); }
static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, const uint64_t Size) { if (Addr + Size < Addr || Addr + Size < Size || Addr + Size > uintptr_t(M.getBufferEnd()) || Addr < uintptr_t(M.getBufferStart())) { return object_error::unexpected_eof; } return std::error_code(); }
static Error checkOffset(MemoryBufferRef M, uintptr_t Addr, const uint64_t Size) { if (Addr + Size < Addr || Addr + Size < Size || Addr + Size > uintptr_t(M.getBufferEnd()) || Addr < uintptr_t(M.getBufferStart())) { return make_error<RawError>(raw_error_code::corrupt_file, "Invalid buffer address"); } return Error::success(); }
ErrorOr<std::unique_ptr<SymbolicFile>> SymbolicFile::createSymbolicFile( MemoryBufferRef Object, sys::fs::file_magic Type, LLVMContext *Context) { StringRef Data = Object.getBuffer(); if (Type == sys::fs::file_magic::unknown) Type = sys::fs::identify_magic(Data); switch (Type) { case sys::fs::file_magic::bitcode: if (Context) return IRObjectFile::create(Object, *Context); // Fallthrough case sys::fs::file_magic::unknown: case sys::fs::file_magic::archive: case sys::fs::file_magic::macho_universal_binary: case sys::fs::file_magic::windows_resource: return object_error::invalid_file_type; case sys::fs::file_magic::elf: case sys::fs::file_magic::elf_executable: case sys::fs::file_magic::elf_shared_object: case sys::fs::file_magic::elf_core: case sys::fs::file_magic::macho_executable: case sys::fs::file_magic::macho_fixed_virtual_memory_shared_lib: case sys::fs::file_magic::macho_core: case sys::fs::file_magic::macho_preload_executable: case sys::fs::file_magic::macho_dynamically_linked_shared_lib: case sys::fs::file_magic::macho_dynamic_linker: case sys::fs::file_magic::macho_bundle: case sys::fs::file_magic::macho_dynamically_linked_shared_lib_stub: case sys::fs::file_magic::macho_dsym_companion: case sys::fs::file_magic::macho_kext_bundle: case sys::fs::file_magic::pecoff_executable: return ObjectFile::createObjectFile(Object, Type); case sys::fs::file_magic::coff_import_library: return std::unique_ptr<SymbolicFile>(new COFFImportFile(Object)); case sys::fs::file_magic::elf_relocatable: case sys::fs::file_magic::macho_object: case sys::fs::file_magic::coff_object: { ErrorOr<std::unique_ptr<ObjectFile>> Obj = ObjectFile::createObjectFile(Object, Type); if (!Obj || !Context) return std::move(Obj); ErrorOr<MemoryBufferRef> BCData = IRObjectFile::findBitcodeInObject(*Obj->get()); if (!BCData) return std::move(Obj); return IRObjectFile::create( MemoryBufferRef(BCData->getBuffer(), Object.getBufferIdentifier()), *Context); } } llvm_unreachable("Unexpected Binary File Type"); }
static std::unique_ptr<InputFile> createFile(MemoryBufferRef MB) { // File type is detected by contents, not by file extension. file_magic Magic = identify_magic(MB.getBuffer()); if (Magic == file_magic::archive) return std::unique_ptr<InputFile>(new ArchiveFile(MB)); if (Magic == file_magic::bitcode) return std::unique_ptr<InputFile>(new BitcodeFile(MB)); if (Config->OutputFile == "") Config->OutputFile = getOutputPath(MB.getBufferIdentifier()); return std::unique_ptr<InputFile>(new ObjectFile<llvm::object::ELF64LE>(MB)); }
void notifyObjectCompiled(const Module *M, MemoryBufferRef Obj) override { const std::string &ModuleID = M->getModuleIdentifier(); std::string CacheName; if (!getCacheFilename(ModuleID, CacheName)) return; if (!CacheDir.empty()) { // Create user-defined cache dir. SmallString<128> dir(sys::path::parent_path(CacheName)); sys::fs::create_directories(Twine(dir)); } std::error_code EC; raw_fd_ostream outfile(CacheName, EC, sys::fs::F_None); outfile.write(Obj.getBufferStart(), Obj.getBufferSize()); outfile.close(); }
static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) { Triple T(getBitcodeTargetTriple(MB, Driver->Context)); switch (T.getArch()) { case Triple::aarch64: return EM_AARCH64; case Triple::arm: return EM_ARM; case Triple::mips: case Triple::mipsel: case Triple::mips64: case Triple::mips64el: return EM_MIPS; case Triple::ppc: return EM_PPC; case Triple::ppc64: return EM_PPC64; case Triple::x86: return T.isOSIAMCU() ? EM_IAMCU : EM_386; case Triple::x86_64: return EM_X86_64; default: fatal(MB.getBufferIdentifier() + ": could not infer e_machine from bitcode target triple " + T.str()); } }
Optional<MemoryBufferRef> elf::readFile(StringRef Path) { log(Path); auto MBOrErr = MemoryBuffer::getFile(Path); if (auto EC = MBOrErr.getError()) { error("cannot open " + Path + ": " + EC.message()); return None; } std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership if (Tar) Tar->append(relativeToRoot(Path), MBRef.getBuffer()); return MBRef; }
bool llvm::parseAssemblyInto(MemoryBufferRef F, Module &M, SMDiagnostic &Err) { SourceMgr SM; std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(F, false); SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); return LLParser(F.getBuffer(), SM, Err, &M).Run(); }
// Returns false if size is greater than the buffer size. And sets ec. static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) { if (M.getBufferSize() < Size) { EC = object_error::unexpected_eof; return false; } return true; }
bool llvm::parseAssemblyInto(MemoryBufferRef F, Module &M, SMDiagnostic &Err, SlotMapping *Slots, bool UpgradeDebugInfo) { SourceMgr SM; std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(F); SM.AddNewSourceBuffer(std::move(Buf), SMLoc()); return LLParser(F.getBuffer(), SM, Err, &M, Slots, UpgradeDebugInfo).Run(); }
// Split S into linker script tokens. void ScriptParserBase::tokenize(MemoryBufferRef MB) { std::vector<StringRef> Vec; MBs.push_back(MB); StringRef S = MB.getBuffer(); StringRef Begin = S; for (;;) { S = skipSpace(S); if (S.empty()) break; // Quoted token. Note that double-quote characters are parts of a token // because, in a glob match context, only unquoted tokens are interpreted // as glob patterns. Double-quoted tokens are literal patterns in that // context. if (S.startswith("\"")) { size_t E = S.find("\"", 1); if (E == StringRef::npos) { StringRef Filename = MB.getBufferIdentifier(); size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n'); error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote"); return; } Vec.push_back(S.take_front(E + 1)); S = S.substr(E + 1); continue; } // Unquoted token. This is more relaxed than tokens in C-like language, // so that you can write "file-name.cpp" as one bare token, for example. size_t Pos = S.find_first_not_of( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789_.$/\\~=+[]*?-:!<>^"); // A character that cannot start a word (which is usually a // punctuation) forms a single character token. if (Pos == 0) Pos = 1; Vec.push_back(S.substr(0, Pos)); S = S.substr(Pos); } Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end()); }
// Parse the module summary index out of an IR file and return the summary // index object if found, or nullptr if not. Expected<std::unique_ptr<ModuleSummaryIndex>> llvm::getModuleSummaryIndexForFile(StringRef Path) { ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = MemoryBuffer::getFileOrSTDIN(Path); std::error_code EC = FileOrErr.getError(); if (EC) return errorCodeToError(EC); MemoryBufferRef BufferRef = (FileOrErr.get())->getMemBufferRef(); if (IgnoreEmptyThinLTOIndexFile && !BufferRef.getBufferSize()) return nullptr; Expected<std::unique_ptr<object::ModuleSummaryIndexObjectFile>> ObjOrErr = object::ModuleSummaryIndexObjectFile::create(BufferRef); if (!ObjOrErr) return ObjOrErr.takeError(); object::ModuleSummaryIndexObjectFile &Obj = **ObjOrErr; return Obj.takeIndex(); }
std::unique_ptr<Module> llvm::parseIR(MemoryBufferRef Buffer, SMDiagnostic &Err, LLVMContext &Context) { NamedRegionTimer T(TimeIRParsingName, TimeIRParsingGroupName, TimePassesIsEnabled); if (isBitcode((const unsigned char *)Buffer.getBufferStart(), (const unsigned char *)Buffer.getBufferEnd())) { ErrorOr<std::unique_ptr<Module>> ModuleOrErr = parseBitcodeFile(Buffer, Context); if (std::error_code EC = ModuleOrErr.getError()) { Err = SMDiagnostic(Buffer.getBufferIdentifier(), SourceMgr::DK_Error, EC.message()); return nullptr; } return std::move(ModuleOrErr.get()); } return parseAssembly(Buffer, Err, Context); }
static std::unique_ptr<InputFile> createELFFile(MemoryBufferRef MB) { unsigned char Size; unsigned char Endian; std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) fatal("invalid data encoding: " + MB.getBufferIdentifier()); if (Size == ELFCLASS32) { if (Endian == ELFDATA2LSB) return createELFFileAux<T<ELF32LE>>(MB); return createELFFileAux<T<ELF32BE>>(MB); } if (Size == ELFCLASS64) { if (Endian == ELFDATA2LSB) return createELFFileAux<T<ELF64LE>>(MB); return createELFFileAux<T<ELF64BE>>(MB); } fatal("invalid file class: " + MB.getBufferIdentifier()); }
static ELFKind getELFKind(MemoryBufferRef MB) { unsigned char Size; unsigned char Endian; std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) fatal(MB.getBufferIdentifier() + ": invalid data encoding"); if (Size != ELFCLASS32 && Size != ELFCLASS64) fatal(MB.getBufferIdentifier() + ": invalid file class"); size_t BufSize = MB.getBuffer().size(); if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) || (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr))) fatal(MB.getBufferIdentifier() + ": file is too short"); if (Size == ELFCLASS32) return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; }
void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceBody<LazyObject>(S, Name, Obj, SymbolBody::UnknownType); return; } if (!S->body()->isUndefined()) return; // See comment for addLazyArchive above. if (S->isWeak()) { replaceBody<LazyObject>(S, Name, Obj, S->body()->Type); } else { MemoryBufferRef MBRef = Obj.getBuffer(); if (!MBRef.getBuffer().empty()) addFile(createObjectFile(MBRef)); } }
std::unique_ptr<Module> llvm::parseAssembly(MemoryBufferRef F, SMDiagnostic &Err, LLVMContext &Context, SlotMapping *Slots, bool UpgradeDebugInfo) { std::unique_ptr<Module> M = make_unique<Module>(F.getBufferIdentifier(), Context); if (parseAssemblyInto(F, *M, Err, Slots, UpgradeDebugInfo)) return nullptr; return M; }
std::unique_ptr<Module> llvm::parseAssembly(MemoryBufferRef F, SMDiagnostic &Err, LLVMContext &Context) { std::unique_ptr<Module> M = make_unique<Module>(F.getBufferIdentifier(), Context); if (parseAssemblyInto(F, *M, Err)) return nullptr; return M; }
// Returns a buffer pointing to a member file containing a given symbol. std::pair<MemoryBufferRef, uint64_t> ArchiveFile::getMember(const Archive::Symbol *Sym) { Archive::Child C = check(Sym->getMember(), "could not get the member for symbol " + Sym->getName()); if (!Seen.insert(C.getChildOffset()).second) return {MemoryBufferRef(), 0}; MemoryBufferRef Ret = check(C.getMemoryBufferRef(), "could not get the buffer for the member defining symbol " + Sym->getName()); if (C.getParent()->isThin() && Driver->Cpio) Driver->Cpio->append(relativeToRoot(check(C.getFullName())), Ret.getBuffer()); if (C.getParent()->isThin()) return {Ret, 0}; return {Ret, C.getChildOffset()}; }
std::vector<StringRef> lld::args::getLines(MemoryBufferRef MB) { SmallVector<StringRef, 0> Arr; MB.getBuffer().split(Arr, '\n'); std::vector<StringRef> Ret; for (StringRef S : Arr) { S = S.trim(); if (!S.empty() && S[0] != '#') Ret.push_back(S); } return Ret; }
BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) : InputFile(BitcodeKind, MB) { this->ArchiveName = ArchiveName; // Here we pass a new MemoryBufferRef which is identified by ArchiveName // (the fully resolved path of the archive) + member name + offset of the // member in the archive. // ThinLTO uses the MemoryBufferRef identifier to access its internal // data structures and if two archives define two members with the same name, // this causes a collision which result in only one of the objects being // taken into consideration at LTO time (which very likely causes undefined // symbols later in the link stage). MemoryBufferRef MBRef(MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() + utostr(OffsetInArchive))); Obj = check(lto::InputFile::create(MBRef), toString(this)); Triple T(Obj->getTargetTriple()); EKind = getBitcodeELFKind(T); EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T); }
std::unique_ptr<InputFile> Lazy::getMember() { MemoryBufferRef MBRef = File->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBRef.getBuffer().empty()) return std::unique_ptr<InputFile>(nullptr); file_magic Magic = identify_magic(MBRef.getBuffer()); if (Magic == file_magic::coff_import_library) return std::unique_ptr<InputFile>(new ImportFile(MBRef)); std::unique_ptr<InputFile> Obj; if (Magic == file_magic::coff_object) Obj.reset(new ObjectFile(MBRef)); else if (Magic == file_magic::bitcode) Obj.reset(new BitcodeFile(MBRef)); else error(Twine(File->getName()) + ": unknown file type"); Obj->setParentName(File->getName()); return Obj; }
std::error_code PDBFile::parseFileHeaders() { std::error_code EC; MemoryBufferRef BufferRef = *Context->Buffer; Context->SB = reinterpret_cast<const SuperBlock *>(BufferRef.getBufferStart()); const SuperBlock *SB = Context->SB; // Make sure the file is sufficiently large to hold a super block. if (BufferRef.getBufferSize() < sizeof(SuperBlock)) return std::make_error_code(std::errc::illegal_byte_sequence); // Check the magic bytes. if (memcmp(SB->MagicBytes, Magic, sizeof(Magic)) != 0) return std::make_error_code(std::errc::illegal_byte_sequence); // We don't support blocksizes which aren't a multiple of four bytes. if (SB->BlockSize == 0 || SB->BlockSize % sizeof(support::ulittle32_t) != 0) return std::make_error_code(std::errc::not_supported); // We don't support directories whose sizes aren't a multiple of four bytes. if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) return std::make_error_code(std::errc::not_supported); // The number of blocks which comprise the directory is a simple function of // the number of bytes it contains. uint64_t NumDirectoryBlocks = getNumDirectoryBlocks(); // The block map, as we understand it, is a block which consists of a list of // block numbers. // It is unclear what would happen if the number of blocks couldn't fit on a // single block. if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t)) return std::make_error_code(std::errc::illegal_byte_sequence); return std::error_code(); }
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: { ErrorOr<std::unique_ptr<ObjectFile>> ObjFile = ObjectFile::createObjectFile(Object, Type); if (!ObjFile) return ObjFile.getError(); return findBitcodeInObject(*ObjFile->get()); } default: return object_error::invalid_file_type; } }