diff options
Diffstat (limited to 'include/llvm/Object')
-rw-r--r-- | include/llvm/Object/Archive.h | 7 | ||||
-rw-r--r-- | include/llvm/Object/Binary.h | 16 | ||||
-rw-r--r-- | include/llvm/Object/COFF.h | 36 | ||||
-rw-r--r-- | include/llvm/Object/ELF.h | 112 | ||||
-rw-r--r-- | include/llvm/Object/ELFObjectFile.h | 31 | ||||
-rw-r--r-- | include/llvm/Object/ELFTypes.h | 6 | ||||
-rw-r--r-- | include/llvm/Object/MachO.h | 1 | ||||
-rw-r--r-- | include/llvm/Object/MachOUniversal.h | 14 | ||||
-rw-r--r-- | include/llvm/Object/Minidump.h | 77 | ||||
-rw-r--r-- | include/llvm/Object/ObjectFile.h | 21 | ||||
-rw-r--r-- | include/llvm/Object/StackMapParser.h | 4 | ||||
-rw-r--r-- | include/llvm/Object/TapiFile.h | 60 | ||||
-rw-r--r-- | include/llvm/Object/TapiUniversal.h | 109 | ||||
-rw-r--r-- | include/llvm/Object/WindowsResource.h | 55 | ||||
-rw-r--r-- | include/llvm/Object/XCOFFObjectFile.h | 132 |
15 files changed, 539 insertions, 142 deletions
diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index c40278a4f923..c3f36bdd9d1a 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -48,8 +48,7 @@ public: /// Get the name looking up long names. Expected<StringRef> getName(uint64_t Size) const; - /// Members are not larger than 4GB. - Expected<uint32_t> getSize() const; + Expected<uint64_t> getSize() const; Expected<sys::fs::perms> getAccessMode() const; Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const; @@ -136,6 +135,7 @@ public: Expected<StringRef> getBuffer() const; uint64_t getChildOffset() const; + uint64_t getDataOffset() const { return getChildOffset() + StartOfFile; } Expected<MemoryBufferRef> getMemoryBufferRef() const; @@ -221,6 +221,9 @@ public: Archive(MemoryBufferRef Source, Error &Err); static Expected<std::unique_ptr<Archive>> create(MemoryBufferRef Source); + /// Size field is 10 decimal digits long + static const uint64_t MaxMemberSize = 9999999999; + enum Kind { K_GNU, K_GNU64, diff --git a/include/llvm/Object/Binary.h b/include/llvm/Object/Binary.h index 3c3e977baff4..aa5e718f5e9b 100644 --- a/include/llvm/Object/Binary.h +++ b/include/llvm/Object/Binary.h @@ -42,7 +42,9 @@ protected: ID_Archive, ID_MachOUniversalBinary, ID_COFFImportFile, - ID_IR, // LLVM IR + ID_IR, // LLVM IR + ID_TapiUniversal, // Text-based Dynamic Library Stub file. + ID_TapiFile, // Text-based Dynamic Library Stub file. ID_Minidump, @@ -101,16 +103,18 @@ public: return TypeID > ID_StartObjects && TypeID < ID_EndObjects; } - bool isSymbolic() const { return isIR() || isObject() || isCOFFImportFile(); } - - bool isArchive() const { - return TypeID == ID_Archive; + bool isSymbolic() const { + return isIR() || isObject() || isCOFFImportFile() || isTapiFile(); } + bool isArchive() const { return TypeID == ID_Archive; } + bool isMachOUniversalBinary() const { return TypeID == ID_MachOUniversalBinary; } + bool isTapiUniversal() const { return TypeID == ID_TapiUniversal; } + bool isELF() const { return TypeID >= ID_ELF32L && TypeID <= ID_ELF64B; } @@ -137,6 +141,8 @@ public: bool isMinidump() const { return TypeID == ID_Minidump; } + bool isTapiFile() const { return TypeID == ID_TapiFile; } + bool isLittleEndian() const { return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B || TypeID == ID_MachO32B || TypeID == ID_MachO64B); diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index c53cbc46c747..b91ee5887fec 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -314,7 +314,10 @@ public: return CS16 ? CS16->Name.Offset : CS32->Name.Offset; } - uint32_t getValue() const { return CS16 ? CS16->Value : CS32->Value; } + uint32_t getValue() const { + assert(isSet() && "COFFSymbolRef points to nothing!"); + return CS16 ? CS16->Value : CS32->Value; + } int32_t getSectionNumber() const { assert(isSet() && "COFFSymbolRef points to nothing!"); @@ -969,11 +972,14 @@ public: return nullptr; return reinterpret_cast<const dos_header *>(base()); } - std::error_code getCOFFHeader(const coff_file_header *&Res) const; - std::error_code - getCOFFBigObjHeader(const coff_bigobj_file_header *&Res) const; - std::error_code getPE32Header(const pe32_header *&Res) const; - std::error_code getPE32PlusHeader(const pe32plus_header *&Res) const; + + const coff_file_header *getCOFFHeader() const { return COFFHeader; } + const coff_bigobj_file_header *getCOFFBigObjHeader() const { + return COFFBigObjHeader; + } + const pe32_header *getPE32Header() const { return PE32Header; } + const pe32plus_header *getPE32PlusHeader() const { return PE32PlusHeader; } + std::error_code getDataDirectory(uint32_t index, const data_directory *&Res) const; std::error_code getSection(int32_t index, const coff_section *&Res) const; @@ -1201,16 +1207,34 @@ public: ResourceSectionRef() = default; explicit ResourceSectionRef(StringRef Ref) : BBS(Ref, support::little) {} + Error load(const COFFObjectFile *O); + Error load(const COFFObjectFile *O, const SectionRef &S); + Expected<ArrayRef<UTF16>> getEntryNameString(const coff_resource_dir_entry &Entry); Expected<const coff_resource_dir_table &> getEntrySubDir(const coff_resource_dir_entry &Entry); + Expected<const coff_resource_data_entry &> + getEntryData(const coff_resource_dir_entry &Entry); Expected<const coff_resource_dir_table &> getBaseTable(); + Expected<const coff_resource_dir_entry &> + getTableEntry(const coff_resource_dir_table &Table, uint32_t Index); + + Expected<StringRef> getContents(const coff_resource_data_entry &Entry); private: BinaryByteStream BBS; + SectionRef Section; + const COFFObjectFile *Obj; + + std::vector<const coff_relocation *> Relocs; + Expected<const coff_resource_dir_table &> getTableAtOffset(uint32_t Offset); + Expected<const coff_resource_dir_entry &> + getTableEntryAtOffset(uint32_t Offset); + Expected<const coff_resource_data_entry &> + getDataEntryAtOffset(uint32_t Offset); Expected<ArrayRef<UTF16>> getDirStringAtOffset(uint32_t Offset); }; diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index cf8e4529bad9..28b00c8413de 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -64,6 +64,10 @@ std::string getSecIndexForError(const ELFFile<ELFT> *Obj, return "[unknown index]"; } +static inline Error defaultWarningHandler(const Twine &Msg) { + return createError(Msg); +} + template <class ELFT> class ELFFile { public: @@ -95,6 +99,13 @@ public: using Elf_Relr_Range = typename ELFT::RelrRange; using Elf_Phdr_Range = typename ELFT::PhdrRange; + // This is a callback that can be passed to a number of functions. + // It can be used to ignore non-critical errors (warnings), which is + // useful for dumpers, like llvm-readobj. + // It accepts a warning message string and returns a success + // when the warning should be ignored or an error otherwise. + using WarningHandler = llvm::function_ref<Error(const Twine &Msg)>; + const uint8_t *base() const { return Buf.bytes_begin(); } size_t getBufSize() const { return Buf.size(); } @@ -114,7 +125,9 @@ public: template <typename T> Expected<const T *> getEntry(const Elf_Shdr *Section, uint32_t Entry) const; - Expected<StringRef> getStringTable(const Elf_Shdr *Section) const; + Expected<StringRef> + getStringTable(const Elf_Shdr *Section, + WarningHandler WarnHandler = &defaultWarningHandler) const; Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section) const; Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section, Elf_Shdr_Range Sections) const; @@ -137,15 +150,16 @@ public: static Expected<ELFFile> create(StringRef Object); + bool isLE() const { + return getHeader()->getDataEncoding() == ELF::ELFDATA2LSB; + } + bool isMipsELF64() const { return getHeader()->e_machine == ELF::EM_MIPS && getHeader()->getFileClass() == ELF::ELFCLASS64; } - bool isMips64EL() const { - return isMipsELF64() && - getHeader()->getDataEncoding() == ELF::ELFDATA2LSB; - } + bool isMips64EL() const { return isMipsELF64() && isLE(); } Expected<Elf_Shdr_Range> sections() const; @@ -261,7 +275,9 @@ public: return make_range(notes_begin(Shdr, Err), notes_end()); } - Expected<StringRef> getSectionStringTable(Elf_Shdr_Range Sections) const; + Expected<StringRef> getSectionStringTable( + Elf_Shdr_Range Sections, + WarningHandler WarnHandler = &defaultWarningHandler) const; Expected<uint32_t> getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms, ArrayRef<Elf_Word> ShndxTable) const; Expected<const Elf_Shdr *> getSection(const Elf_Sym *Sym, @@ -271,12 +287,13 @@ public: Elf_Sym_Range Symtab, ArrayRef<Elf_Word> ShndxTable) const; Expected<const Elf_Shdr *> getSection(uint32_t Index) const; - Expected<const Elf_Shdr *> getSection(const StringRef SectionName) const; Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec, uint32_t Index) const; - Expected<StringRef> getSectionName(const Elf_Shdr *Section) const; + Expected<StringRef> + getSectionName(const Elf_Shdr *Section, + WarningHandler WarnHandler = &defaultWarningHandler) const; Expected<StringRef> getSectionName(const Elf_Shdr *Section, StringRef DotShstrtab) const; template <typename T> @@ -459,18 +476,18 @@ ELFFile<ELFT>::getRelocationSymbol(const Elf_Rel *Rel, template <class ELFT> Expected<StringRef> -ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections) const { +ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections, + WarningHandler WarnHandler) const { uint32_t Index = getHeader()->e_shstrndx; if (Index == ELF::SHN_XINDEX) Index = Sections[0].sh_link; if (!Index) // no section string table. return ""; - // TODO: Test a case when the sh_link of the section with index 0 is broken. if (Index >= Sections.size()) return createError("section header string table index " + Twine(Index) + " does not exist"); - return getStringTable(&Sections[Index]); + return getStringTable(&Sections[Index], WarnHandler); } template <class ELFT> ELFFile<ELFT>::ELFFile(StringRef Object) : Buf(Object) {} @@ -495,7 +512,8 @@ Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const { Twine(getHeader()->e_shentsize)); const uint64_t FileSize = Buf.size(); - if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize) + if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize || + SectionTableOffset + (uintX_t)sizeof(Elf_Shdr) < SectionTableOffset) return createError( "section header table goes past the end of the file: e_shoff = 0x" + Twine::utohexstr(SectionTableOffset)); @@ -513,15 +531,22 @@ Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const { NumSections = First->sh_size; if (NumSections > UINT64_MAX / sizeof(Elf_Shdr)) - // TODO: this error is untested. - return createError("section table goes past the end of file"); + return createError("invalid number of sections specified in the NULL " + "section's sh_size field (" + + Twine(NumSections) + ")"); const uint64_t SectionTableSize = NumSections * sizeof(Elf_Shdr); + if (SectionTableOffset + SectionTableSize < SectionTableOffset) + return createError( + "invalid section header table offset (e_shoff = 0x" + + Twine::utohexstr(SectionTableOffset) + + ") or invalid number of sections specified in the first section " + "header's sh_size field (0x" + + Twine::utohexstr(NumSections) + ")"); // Section table goes past end of file! if (SectionTableOffset + SectionTableSize > FileSize) return createError("section table goes past the end of file"); - return makeArrayRef(First, NumSections); } @@ -540,8 +565,9 @@ template <typename T> Expected<const T *> ELFFile<ELFT>::getEntry(const Elf_Shdr *Section, uint32_t Entry) const { if (sizeof(T) != Section->sh_entsize) - // TODO: this error is untested. - return createError("invalid sh_entsize"); + return createError("section " + getSecIndexForError(this, Section) + + " has invalid sh_entsize: expected " + Twine(sizeof(T)) + + ", but got " + Twine(Section->sh_entsize)); size_t Pos = Section->sh_offset + Entry * sizeof(T); if (Pos + sizeof(T) > Buf.size()) return createError("unable to access section " + @@ -561,42 +587,26 @@ ELFFile<ELFT>::getSection(uint32_t Index) const { } template <class ELFT> -Expected<const typename ELFT::Shdr *> -ELFFile<ELFT>::getSection(const StringRef SectionName) const { - auto TableOrErr = sections(); - if (!TableOrErr) - return TableOrErr.takeError(); - for (auto &Sec : *TableOrErr) { - auto SecNameOrErr = getSectionName(&Sec); - if (!SecNameOrErr) - return SecNameOrErr.takeError(); - if (*SecNameOrErr == SectionName) - return &Sec; - } - // TODO: this error is untested. - return createError("invalid section name"); -} - -template <class ELFT> Expected<StringRef> -ELFFile<ELFT>::getStringTable(const Elf_Shdr *Section) const { +ELFFile<ELFT>::getStringTable(const Elf_Shdr *Section, + WarningHandler WarnHandler) const { if (Section->sh_type != ELF::SHT_STRTAB) - return createError("invalid sh_type for string table section " + - getSecIndexForError(this, Section) + - ": expected SHT_STRTAB, but got " + - object::getELFSectionTypeName(getHeader()->e_machine, - Section->sh_type)); + if (Error E = WarnHandler("invalid sh_type for string table section " + + getSecIndexForError(this, Section) + + ": expected SHT_STRTAB, but got " + + object::getELFSectionTypeName( + getHeader()->e_machine, Section->sh_type))) + return std::move(E); + auto V = getSectionContentsAsArray<char>(Section); if (!V) return V.takeError(); ArrayRef<char> Data = *V; if (Data.empty()) - // TODO: this error is untested. - return createError("empty string table"); + return createError("SHT_STRTAB string table section " + + getSecIndexForError(this, Section) + " is empty"); if (Data.back() != '\0') - return createError(object::getELFSectionTypeName(getHeader()->e_machine, - Section->sh_type) + - " string table section " + + return createError("SHT_STRTAB string table section " + getSecIndexForError(this, Section) + " is non-null terminated"); return StringRef(Data.begin(), Data.size()); @@ -626,8 +636,11 @@ ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section, const Elf_Shdr &SymTable = **SymTableOrErr; if (SymTable.sh_type != ELF::SHT_SYMTAB && SymTable.sh_type != ELF::SHT_DYNSYM) - // TODO: this error is untested. - return createError("invalid sh_type"); + return createError("SHT_SYMTAB_SHNDX section is linked with " + + object::getELFSectionTypeName(getHeader()->e_machine, + SymTable.sh_type) + + " section (expected SHT_SYMTAB/SHT_DYNSYM)"); + if (V.size() != (SymTable.sh_size / sizeof(Elf_Sym))) return createError("SHT_SYMTAB_SHNDX section has sh_size (" + Twine(SymTable.sh_size) + @@ -662,11 +675,12 @@ ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec, template <class ELFT> Expected<StringRef> -ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section) const { +ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section, + WarningHandler WarnHandler) const { auto SectionsOrErr = sections(); if (!SectionsOrErr) return SectionsOrErr.takeError(); - auto Table = getSectionStringTable(*SectionsOrErr); + auto Table = getSectionStringTable(*SectionsOrErr, WarnHandler); if (!Table) return Table.takeError(); return getSectionName(Section, *Table); diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h index 86c015efd704..424289a9ccaa 100644 --- a/include/llvm/Object/ELFObjectFile.h +++ b/include/llvm/Object/ELFObjectFile.h @@ -41,7 +41,7 @@ namespace llvm { namespace object { -constexpr int NumElfSymbolTypes = 8; +constexpr int NumElfSymbolTypes = 16; extern const llvm::EnumEntry<unsigned> ElfSymbolTypes[NumElfSymbolTypes]; class elf_symbol_iterator; @@ -239,6 +239,10 @@ public: using Elf_Rela = typename ELFT::Rela; using Elf_Dyn = typename ELFT::Dyn; + SectionRef toSectionRef(const Elf_Shdr *Sec) const { + return SectionRef(toDRI(Sec), this); + } + private: ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF, const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec, @@ -284,7 +288,8 @@ protected: relocation_iterator section_rel_begin(DataRefImpl Sec) const override; relocation_iterator section_rel_end(DataRefImpl Sec) const override; std::vector<SectionRef> dynamic_relocation_sections() const override; - section_iterator getRelocatedSection(DataRefImpl Sec) const override; + Expected<section_iterator> + getRelocatedSection(DataRefImpl Sec) const override; void moveRelocationNext(DataRefImpl &Rel) const override; uint64_t getRelocationOffset(DataRefImpl Rel) const override; @@ -461,13 +466,15 @@ Expected<StringRef> ELFObjectFile<ELFT>::getSymbolName(DataRefImpl Sym) const { if (!SymStrTabOrErr) return SymStrTabOrErr.takeError(); Expected<StringRef> Name = ESym->getName(*SymStrTabOrErr); + if (Name && !Name->empty()) + return Name; // If the symbol name is empty use the section name. - if ((!Name || Name->empty()) && ESym->getType() == ELF::STT_SECTION) { - StringRef SecName; - Expected<section_iterator> Sec = getSymbolSection(Sym); - if (Sec && !(*Sec)->getName(SecName)) - return SecName; + if (ESym->getType() == ELF::STT_SECTION) { + if (Expected<section_iterator> SecOrErr = getSymbolSection(Sym)) { + consumeError(Name.takeError()); + return (*SecOrErr)->getName(); + } } return Name; } @@ -835,7 +842,7 @@ ELFObjectFile<ELFT>::section_rel_end(DataRefImpl Sec) const { } template <class ELFT> -section_iterator +Expected<section_iterator> ELFObjectFile<ELFT>::getRelocatedSection(DataRefImpl Sec) const { if (EF.getHeader()->e_type != ELF::ET_REL) return section_end(); @@ -845,10 +852,10 @@ ELFObjectFile<ELFT>::getRelocatedSection(DataRefImpl Sec) const { if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA) return section_end(); - auto R = EF.getSection(EShdr->sh_info); - if (!R) - report_fatal_error(errorToErrorCode(R.takeError()).message()); - return section_iterator(SectionRef(toDRI(*R), this)); + Expected<const Elf_Shdr *> SecOrErr = EF.getSection(EShdr->sh_info); + if (!SecOrErr) + return SecOrErr.takeError(); + return section_iterator(SectionRef(toDRI(*SecOrErr), this)); } // Relocations diff --git a/include/llvm/Object/ELFTypes.h b/include/llvm/Object/ELFTypes.h index 5552208b1f8a..7d1ade4d5437 100644 --- a/include/llvm/Object/ELFTypes.h +++ b/include/llvm/Object/ELFTypes.h @@ -248,7 +248,11 @@ template <class ELFT> Expected<StringRef> Elf_Sym_Impl<ELFT>::getName(StringRef StrTab) const { uint32_t Offset = this->st_name; if (Offset >= StrTab.size()) - return errorCodeToError(object_error::parse_failed); + return createStringError(object_error::parse_failed, + "st_name (0x%" PRIx32 + ") is past the end of the string table" + " of size 0x%zx", + Offset, StrTab.size()); return StringRef(StrTab.data() + Offset); } diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index ca9512f21706..76be8049a7d4 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -297,6 +297,7 @@ public: uint64_t getSectionAddress(DataRefImpl Sec) const override; uint64_t getSectionIndex(DataRefImpl Sec) const override; uint64_t getSectionSize(DataRefImpl Sec) const override; + ArrayRef<uint8_t> getSectionContents(uint32_t Offset, uint64_t Size) const; Expected<ArrayRef<uint8_t>> getSectionContents(DataRefImpl Sec) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; diff --git a/include/llvm/Object/MachOUniversal.h b/include/llvm/Object/MachOUniversal.h index 5bf724f2c8b2..eb45aff4480b 100644 --- a/include/llvm/Object/MachOUniversal.h +++ b/include/llvm/Object/MachOUniversal.h @@ -31,6 +31,8 @@ class MachOUniversalBinary : public Binary { uint32_t Magic; uint32_t NumberOfObjects; public: + static constexpr uint32_t MaxSectionAlignment = 15; /* 2**15 or 0x8000 */ + class ObjectForArch { const MachOUniversalBinary *Parent; /// Index of object in the universal binary. @@ -64,13 +66,13 @@ public: else // Parent->getMagic() == MachO::FAT_MAGIC_64 return Header64.cpusubtype; } - uint32_t getOffset() const { + uint64_t getOffset() const { if (Parent->getMagic() == MachO::FAT_MAGIC) return Header.offset; else // Parent->getMagic() == MachO::FAT_MAGIC_64 return Header64.offset; } - uint32_t getSize() const { + uint64_t getSize() const { if (Parent->getMagic() == MachO::FAT_MAGIC) return Header.size; else // Parent->getMagic() == MachO::FAT_MAGIC_64 @@ -157,8 +159,14 @@ public: return V->isMachOUniversalBinary(); } - Expected<std::unique_ptr<MachOObjectFile>> + Expected<ObjectForArch> getObjectForArch(StringRef ArchName) const; + + Expected<std::unique_ptr<MachOObjectFile>> + getMachOObjectForArch(StringRef ArchName) const; + + Expected<std::unique_ptr<Archive>> + getArchiveForArch(StringRef ArchName) const; }; } diff --git a/include/llvm/Object/Minidump.h b/include/llvm/Object/Minidump.h index 470008d552e7..4429493aff45 100644 --- a/include/llvm/Object/Minidump.h +++ b/include/llvm/Object/Minidump.h @@ -11,6 +11,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/iterator.h" #include "llvm/BinaryFormat/Minidump.h" #include "llvm/Object/Binary.h" #include "llvm/Support/Error.h" @@ -80,16 +81,65 @@ public: return getListStream<minidump::Thread>(minidump::StreamType::ThreadList); } - /// Returns the list of memory ranges embedded in the MemoryList stream. An - /// error is returned if the file does not contain this stream, or if the - /// stream is not large enough to contain the number of memory descriptors - /// declared in the stream header. The consistency of the MemoryDescriptor - /// entries themselves is not checked in any way. + /// Returns the contents of the Exception stream. An error is returned if the + /// file does not contain this stream, or the stream is smaller than the size + /// of the ExceptionStream structure. The internal consistency of the stream + /// is not checked in any way. + Expected<const minidump::ExceptionStream &> getExceptionStream() const { + return getStream<minidump::ExceptionStream>( + minidump::StreamType::Exception); + } + + /// Returns the list of descriptors embedded in the MemoryList stream. The + /// descriptors provide the content of interesting regions of memory at the + /// time the minidump was taken. An error is returned if the file does not + /// contain this stream, or if the stream is not large enough to contain the + /// number of memory descriptors declared in the stream header. The + /// consistency of the MemoryDescriptor entries themselves is not checked in + /// any way. Expected<ArrayRef<minidump::MemoryDescriptor>> getMemoryList() const { return getListStream<minidump::MemoryDescriptor>( minidump::StreamType::MemoryList); } + class MemoryInfoIterator + : public iterator_facade_base<MemoryInfoIterator, + std::forward_iterator_tag, + minidump::MemoryInfo> { + public: + MemoryInfoIterator(ArrayRef<uint8_t> Storage, size_t Stride) + : Storage(Storage), Stride(Stride) { + assert(Storage.size() % Stride == 0); + } + + bool operator==(const MemoryInfoIterator &R) const { + return Storage.size() == R.Storage.size(); + } + + const minidump::MemoryInfo &operator*() const { + assert(Storage.size() >= sizeof(minidump::MemoryInfo)); + return *reinterpret_cast<const minidump::MemoryInfo *>(Storage.data()); + } + + MemoryInfoIterator &operator++() { + Storage = Storage.drop_front(Stride); + return *this; + } + + private: + ArrayRef<uint8_t> Storage; + size_t Stride; + }; + + /// Returns the list of descriptors embedded in the MemoryInfoList stream. The + /// descriptors provide properties (e.g. permissions) of interesting regions + /// of memory at the time the minidump was taken. An error is returned if the + /// file does not contain this stream, or if the stream is not large enough to + /// contain the number of memory descriptors declared in the stream header. + /// The consistency of the MemoryInfoList entries themselves is not checked + /// in any way. + Expected<iterator_range<MemoryInfoIterator>> getMemoryInfoList() const; + private: static Error createError(StringRef Str) { return make_error<GenericBinaryError>(Str, object_error::parse_failed); @@ -137,10 +187,10 @@ private: }; template <typename T> -Expected<const T &> MinidumpFile::getStream(minidump::StreamType Stream) const { - if (auto OptionalStream = getRawStream(Stream)) { - if (OptionalStream->size() >= sizeof(T)) - return *reinterpret_cast<const T *>(OptionalStream->data()); +Expected<const T &> MinidumpFile::getStream(minidump::StreamType Type) const { + if (Optional<ArrayRef<uint8_t>> Stream = getRawStream(Type)) { + if (Stream->size() >= sizeof(T)) + return *reinterpret_cast<const T *>(Stream->data()); return createEOFError(); } return createError("No such stream"); @@ -153,10 +203,11 @@ Expected<ArrayRef<T>> MinidumpFile::getDataSliceAs(ArrayRef<uint8_t> Data, // Check for overflow. if (Count > std::numeric_limits<size_t>::max() / sizeof(T)) return createEOFError(); - auto ExpectedArray = getDataSlice(Data, Offset, sizeof(T) * Count); - if (!ExpectedArray) - return ExpectedArray.takeError(); - return ArrayRef<T>(reinterpret_cast<const T *>(ExpectedArray->data()), Count); + Expected<ArrayRef<uint8_t>> Slice = + getDataSlice(Data, Offset, sizeof(T) * Count); + if (!Slice) + return Slice.takeError(); + return ArrayRef<T>(reinterpret_cast<const T *>(Slice->data()), Count); } } // end namespace object diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 483a3486bd72..adc9dbc189af 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -94,7 +94,7 @@ public: void moveNext(); - std::error_code getName(StringRef &Result) const; + Expected<StringRef> getName() const; uint64_t getAddress() const; uint64_t getIndex() const; uint64_t getSize() const; @@ -130,18 +130,13 @@ public: iterator_range<relocation_iterator> relocations() const { return make_range(relocation_begin(), relocation_end()); } - section_iterator getRelocatedSection() const; + Expected<section_iterator> getRelocatedSection() const; DataRefImpl getRawDataRefImpl() const; const ObjectFile *getObject() const; }; struct SectionedAddress { - // TODO: constructors could be removed when C++14 would be adopted. - SectionedAddress() {} - SectionedAddress(uint64_t Addr, uint64_t SectIdx) - : Address(Addr), SectionIndex(SectIdx) {} - const static uint64_t UndefSection = UINT64_MAX; uint64_t Address = 0; @@ -277,7 +272,7 @@ protected: virtual bool isBerkeleyData(DataRefImpl Sec) const; virtual relocation_iterator section_rel_begin(DataRefImpl Sec) const = 0; virtual relocation_iterator section_rel_end(DataRefImpl Sec) const = 0; - virtual section_iterator getRelocatedSection(DataRefImpl Sec) const; + virtual Expected<section_iterator> getRelocatedSection(DataRefImpl Sec) const; // Same as above for RelocationRef. friend class RelocationRef; @@ -434,12 +429,8 @@ inline void SectionRef::moveNext() { return OwningObject->moveSectionNext(SectionPimpl); } -inline std::error_code SectionRef::getName(StringRef &Result) const { - Expected<StringRef> NameOrErr = OwningObject->getSectionName(SectionPimpl); - if (!NameOrErr) - return errorToErrorCode(NameOrErr.takeError()); - Result = *NameOrErr; - return std::error_code(); +inline Expected<StringRef> SectionRef::getName() const { + return OwningObject->getSectionName(SectionPimpl); } inline uint64_t SectionRef::getAddress() const { @@ -510,7 +501,7 @@ inline relocation_iterator SectionRef::relocation_end() const { return OwningObject->section_rel_end(SectionPimpl); } -inline section_iterator SectionRef::getRelocatedSection() const { +inline Expected<section_iterator> SectionRef::getRelocatedSection() const { return OwningObject->getRelocatedSection(SectionPimpl); } diff --git a/include/llvm/Object/StackMapParser.h b/include/llvm/Object/StackMapParser.h index ed44efbf80b9..b408f4041034 100644 --- a/include/llvm/Object/StackMapParser.h +++ b/include/llvm/Object/StackMapParser.h @@ -19,7 +19,7 @@ namespace llvm { -/// A parser for the latest stackmap format. At the moment, latest=V2. +/// A parser for the latest stackmap format. At the moment, latest=V3. template <support::endianness Endianness> class StackMapParser { public: @@ -299,7 +299,7 @@ public: const uint8_t *P; }; - /// Construct a parser for a version-2 stackmap. StackMap data will be read + /// Construct a parser for a version-3 stackmap. StackMap data will be read /// from the given array. StackMapParser(ArrayRef<uint8_t> StackMapSection) : StackMapSection(StackMapSection) { diff --git a/include/llvm/Object/TapiFile.h b/include/llvm/Object/TapiFile.h new file mode 100644 index 000000000000..bc2e04e1cc96 --- /dev/null +++ b/include/llvm/Object/TapiFile.h @@ -0,0 +1,60 @@ +//===- TapiFile.h - Text-based Dynamic Library Stub -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the TapiFile interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_TAPI_FILE_H +#define LLVM_OBJECT_TAPI_FILE_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/TextAPI/MachO/InterfaceFile.h" + +namespace llvm { +namespace object { + +class TapiFile : public SymbolicFile { +public: + TapiFile(MemoryBufferRef Source, const MachO::InterfaceFile &interface, + MachO::Architecture Arch); + ~TapiFile() override; + + void moveSymbolNext(DataRefImpl &DRI) const override; + + Error printSymbolName(raw_ostream &OS, DataRefImpl DRI) const override; + + uint32_t getSymbolFlags(DataRefImpl DRI) const override; + + basic_symbol_iterator symbol_begin() const override; + + basic_symbol_iterator symbol_end() const override; + + static bool classof(const Binary *v) { return v->isTapiFile(); } + +private: + struct Symbol { + StringRef Prefix; + StringRef Name; + uint32_t Flags; + + constexpr Symbol(StringRef Prefix, StringRef Name, uint32_t Flags) + : Prefix(Prefix), Name(Name), Flags(Flags) {} + }; + + std::vector<Symbol> Symbols; +}; + +} // end namespace object. +} // end namespace llvm. + +#endif // LLVM_OBJECT_TAPI_FILE_H diff --git a/include/llvm/Object/TapiUniversal.h b/include/llvm/Object/TapiUniversal.h new file mode 100644 index 000000000000..4931183852ad --- /dev/null +++ b/include/llvm/Object/TapiUniversal.h @@ -0,0 +1,109 @@ +//===-- TapiUniversal.h - Text-based Dynamic Library Stub -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the TapiUniversal interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_TAPI_UNIVERSAL_H +#define LLVM_OBJECT_TAPI_UNIVERSAL_H + +#include "llvm/Object/Binary.h" +#include "llvm/Object/TapiFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/TextAPI/MachO/Architecture.h" +#include "llvm/TextAPI/MachO/InterfaceFile.h" + +namespace llvm { +namespace object { + +class TapiUniversal : public Binary { +public: + class ObjectForArch { + const TapiUniversal *Parent; + int Index; + + public: + ObjectForArch(const TapiUniversal *Parent, int Index) + : Parent(Parent), Index(Index) {} + + ObjectForArch getNext() const { return ObjectForArch(Parent, Index + 1); } + + bool operator==(const ObjectForArch &Other) const { + return (Parent == Other.Parent) && (Index == Other.Index); + } + + uint32_t getCPUType() const { + auto Result = + MachO::getCPUTypeFromArchitecture(Parent->Architectures[Index]); + return Result.first; + } + + uint32_t getCPUSubType() const { + auto Result = + MachO::getCPUTypeFromArchitecture(Parent->Architectures[Index]); + return Result.second; + } + + std::string getArchFlagName() const { + return MachO::getArchitectureName(Parent->Architectures[Index]); + } + + Expected<std::unique_ptr<TapiFile>> getAsObjectFile() const; + }; + + class object_iterator { + ObjectForArch Obj; + + public: + object_iterator(const ObjectForArch &Obj) : Obj(Obj) {} + const ObjectForArch *operator->() const { return &Obj; } + const ObjectForArch &operator*() const { return Obj; } + + bool operator==(const object_iterator &Other) const { + return Obj == Other.Obj; + } + bool operator!=(const object_iterator &Other) const { + return !(*this == Other); + } + + object_iterator &operator++() { // Preincrement + Obj = Obj.getNext(); + return *this; + } + }; + + TapiUniversal(MemoryBufferRef Source, Error &Err); + static Expected<std::unique_ptr<TapiUniversal>> + create(MemoryBufferRef Source); + ~TapiUniversal() override; + + object_iterator begin_objects() const { return ObjectForArch(this, 0); } + object_iterator end_objects() const { + return ObjectForArch(this, Architectures.size()); + } + + iterator_range<object_iterator> objects() const { + return make_range(begin_objects(), end_objects()); + } + + uint32_t getNumberOfObjects() const { return Architectures.size(); } + + // Cast methods. + static bool classof(const Binary *v) { return v->isTapiUniversal(); } + +private: + std::unique_ptr<MachO::InterfaceFile> ParsedFile; + std::vector<MachO::Architecture> Architectures; +}; + +} // end namespace object. +} // end namespace llvm. + +#endif // LLVM_OBJECT_TAPI_UNIVERSAL_H diff --git a/include/llvm/Object/WindowsResource.h b/include/llvm/Object/WindowsResource.h index 356dcb03abba..a0d658491cb9 100644 --- a/include/llvm/Object/WindowsResource.h +++ b/include/llvm/Object/WindowsResource.h @@ -31,6 +31,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/Binary.h" +#include "llvm/Object/COFF.h" #include "llvm/Object/Error.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/BinaryStreamReader.h" @@ -48,6 +49,7 @@ class ScopedPrinter; namespace object { class WindowsResource; +class ResourceSectionRef; const size_t WIN_RES_MAGIC_SIZE = 16; const size_t WIN_RES_NULL_ENTRY_SIZE = 16; @@ -151,8 +153,11 @@ private: class WindowsResourceParser { public: class TreeNode; - WindowsResourceParser(); + WindowsResourceParser(bool MinGW = false); Error parse(WindowsResource *WR, std::vector<std::string> &Duplicates); + Error parse(ResourceSectionRef &RSR, StringRef Filename, + std::vector<std::string> &Duplicates); + void cleanUpManifests(std::vector<std::string> &Duplicates); void printTree(raw_ostream &OS) const; const TreeNode &getTree() const { return Root; } const ArrayRef<std::vector<uint8_t>> getData() const { return Data; } @@ -181,32 +186,38 @@ public: private: friend class WindowsResourceParser; - static uint32_t StringCount; - static uint32_t DataCount; - - static std::unique_ptr<TreeNode> createStringNode(); + // Index is the StringTable vector index for this node's name. + static std::unique_ptr<TreeNode> createStringNode(uint32_t Index); static std::unique_ptr<TreeNode> createIDNode(); + // DataIndex is the Data vector index that the data node points at. static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion, uint16_t MinorVersion, uint32_t Characteristics, - uint32_t Origin); + uint32_t Origin, + uint32_t DataIndex); - explicit TreeNode(bool IsStringNode); + explicit TreeNode(uint32_t StringIndex); TreeNode(uint16_t MajorVersion, uint16_t MinorVersion, - uint32_t Characteristics, uint32_t Origin); + uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex); bool addEntry(const ResourceEntryRef &Entry, uint32_t Origin, - bool &IsNewTypeString, bool &IsNewNameString, + std::vector<std::vector<uint8_t>> &Data, + std::vector<std::vector<UTF16>> &StringTable, TreeNode *&Result); - TreeNode &addTypeNode(const ResourceEntryRef &Entry, bool &IsNewTypeString); - TreeNode &addNameNode(const ResourceEntryRef &Entry, bool &IsNewNameString); + TreeNode &addTypeNode(const ResourceEntryRef &Entry, + std::vector<std::vector<UTF16>> &StringTable); + TreeNode &addNameNode(const ResourceEntryRef &Entry, + std::vector<std::vector<UTF16>> &StringTable); bool addLanguageNode(const ResourceEntryRef &Entry, uint32_t Origin, + std::vector<std::vector<uint8_t>> &Data, TreeNode *&Result); bool addDataChild(uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion, uint32_t Characteristics, uint32_t Origin, - TreeNode *&Result); + uint32_t DataIndex, TreeNode *&Result); TreeNode &addIDChild(uint32_t ID); - TreeNode &addNameChild(ArrayRef<UTF16> NameRef, bool &IsNewString); + TreeNode &addNameChild(ArrayRef<UTF16> NameRef, + std::vector<std::vector<UTF16>> &StringTable); + void shiftDataIndexDown(uint32_t Index); bool IsDataNode = false; uint32_t StringIndex; @@ -222,12 +233,30 @@ public: uint32_t Origin; }; + struct StringOrID { + bool IsString; + ArrayRef<UTF16> String; + uint32_t ID; + + StringOrID(uint32_t ID) : IsString(false), ID(ID) {} + StringOrID(ArrayRef<UTF16> String) : IsString(true), String(String) {} + }; + private: + Error addChildren(TreeNode &Node, ResourceSectionRef &RSR, + const coff_resource_dir_table &Table, uint32_t Origin, + std::vector<StringOrID> &Context, + std::vector<std::string> &Duplicates); + bool shouldIgnoreDuplicate(const ResourceEntryRef &Entry) const; + bool shouldIgnoreDuplicate(const std::vector<StringOrID> &Context) const; + TreeNode Root; std::vector<std::vector<uint8_t>> Data; std::vector<std::vector<UTF16>> StringTable; std::vector<std::string> InputFilenames; + + bool MinGW; }; Expected<std::unique_ptr<MemoryBuffer>> diff --git a/include/llvm/Object/XCOFFObjectFile.h b/include/llvm/Object/XCOFFObjectFile.h index cdee7129a2ab..84073ce5f6cf 100644 --- a/include/llvm/Object/XCOFFObjectFile.h +++ b/include/llvm/Object/XCOFFObjectFile.h @@ -13,23 +13,8 @@ #ifndef LLVM_OBJECT_XCOFFOBJECTFILE_H #define LLVM_OBJECT_XCOFFOBJECTFILE_H -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/BinaryFormat/Magic.h" #include "llvm/BinaryFormat/XCOFF.h" -#include "llvm/MC/SubtargetFeature.h" -#include "llvm/Object/Binary.h" -#include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Object/SymbolicFile.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include <cassert> -#include <cstdint> -#include <memory> -#include <system_error> namespace llvm { namespace object { @@ -63,7 +48,7 @@ struct XCOFFFileHeader64 { }; struct XCOFFSectionHeader32 { - char Name[XCOFF::SectionNameSize]; + char Name[XCOFF::NameSize]; support::ubig32_t PhysicalAddress; support::ubig32_t VirtualAddress; support::ubig32_t SectionSize; @@ -78,7 +63,7 @@ struct XCOFFSectionHeader32 { }; struct XCOFFSectionHeader64 { - char Name[XCOFF::SectionNameSize]; + char Name[XCOFF::NameSize]; support::ubig64_t PhysicalAddress; support::ubig64_t VirtualAddress; support::ubig64_t SectionSize; @@ -106,7 +91,7 @@ struct XCOFFSymbolEntry { } CFileLanguageIdAndTypeIdType; union { - char SymbolName[XCOFF::SymbolNameSize]; + char SymbolName[XCOFF::NameSize]; NameInStrTblType NameInStrTbl; }; @@ -127,6 +112,75 @@ struct XCOFFStringTable { const char *Data; }; +struct XCOFFCsectAuxEnt32 { + support::ubig32_t + SectionOrLength; // If the symbol type is XTY_SD or XTY_CM, the csect + // length. + // If the symbol type is XTY_LD, the symbol table + // index of the containing csect. + // If the symbol type is XTY_ER, 0. + support::ubig32_t ParameterHashIndex; + support::ubig16_t TypeChkSectNum; + uint8_t SymbolAlignmentAndType; + XCOFF::StorageMappingClass StorageMappingClass; + support::ubig32_t StabInfoIndex; + support::ubig16_t StabSectNum; +}; + +struct XCOFFFileAuxEnt { + typedef struct { + support::big32_t Magic; // Zero indicates name in string table. + support::ubig32_t Offset; + char NamePad[XCOFF::FileNamePadSize]; + } NameInStrTblType; + union { + char Name[XCOFF::NameSize + XCOFF::FileNamePadSize]; + NameInStrTblType NameInStrTbl; + }; + XCOFF::CFileStringType Type; + uint8_t ReservedZeros[2]; + uint8_t AuxType; // 64-bit XCOFF file only. +}; + +struct XCOFFSectAuxEntForStat { + support::ubig32_t SectionLength; + support::ubig16_t NumberOfRelocEnt; + support::ubig16_t NumberOfLineNum; + uint8_t Pad[10]; +}; + +struct XCOFFRelocation32 { + // Masks for packing/unpacking the r_rsize field of relocations. + + // The msb is used to indicate if the bits being relocated are signed or + // unsigned. + static constexpr uint8_t XR_SIGN_INDICATOR_MASK = 0x80; + + // The 2nd msb is used to indicate that the binder has replaced/modified the + // original instruction. + static constexpr uint8_t XR_FIXUP_INDICATOR_MASK = 0x40; + + // The remaining bits specify the bit length of the relocatable reference + // minus one. + static constexpr uint8_t XR_BIASED_LENGTH_MASK = 0x3f; + +public: + support::ubig32_t VirtualAddress; + support::ubig32_t SymbolIndex; + + // Packed field, see XR_* masks for details of packing. + uint8_t Info; + + XCOFF::RelocationType Type; + +public: + bool isRelocationSigned() const; + bool isFixupIndicated() const; + + // Returns the number of bits being relocated. + uint8_t getRelocatedLength() const; +}; + class XCOFFObjectFile : public ObjectFile { private: const void *FileHeader = nullptr; @@ -146,18 +200,18 @@ private: const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; - void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; uintptr_t getSectionHeaderTableAddress() const; + uintptr_t getEndOfSymbolTableAddress() const; // This returns a pointer to the start of the storage for the name field of // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily // null-terminated. const char *getSectionNameInternal(DataRefImpl Sec) const; - int32_t getSectionFlags(DataRefImpl Sec) const; + // This function returns string table entry. + Expected<StringRef> getStringTableEntry(uint32_t Offset) const; static bool isReservedSectionNumber(int16_t SectionNumber); - Expected<DataRefImpl> getSectionByNum(int16_t Num) const; // Constructor and "create" factory function. The constructor is only a thin // wrapper around the base constructor. The "create" function fills out the @@ -175,6 +229,8 @@ private: friend Expected<std::unique_ptr<ObjectFile>> ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType); + void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; + public: // Interface inherited from base classes. void moveSymbolNext(DataRefImpl &Symb) const override; @@ -253,15 +309,49 @@ public: uint32_t getLogicalNumberOfSymbolTableEntries32() const; uint32_t getNumberOfSymbolTableEntries64() const; + uint32_t getSymbolIndex(uintptr_t SymEntPtr) const; + Expected<StringRef> getSymbolNameByIndex(uint32_t SymbolTableIndex) const; + Expected<StringRef> getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const; uint16_t getOptionalHeaderSize() const; uint16_t getFlags() const; // Section header table related interfaces. ArrayRef<XCOFFSectionHeader32> sections32() const; ArrayRef<XCOFFSectionHeader64> sections64() const; + + int32_t getSectionFlags(DataRefImpl Sec) const; + Expected<DataRefImpl> getSectionByNum(int16_t Num) const; + + void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const; + + // Relocation-related interfaces. + Expected<uint32_t> + getLogicalNumberOfRelocationEntries(const XCOFFSectionHeader32 &Sec) const; + + Expected<ArrayRef<XCOFFRelocation32>> + relocations(const XCOFFSectionHeader32 &) const; }; // XCOFFObjectFile +class XCOFFSymbolRef { + const DataRefImpl SymEntDataRef; + const XCOFFObjectFile *const OwningObjectPtr; + +public: + XCOFFSymbolRef(DataRefImpl SymEntDataRef, + const XCOFFObjectFile *OwningObjectPtr) + : SymEntDataRef(SymEntDataRef), OwningObjectPtr(OwningObjectPtr){}; + + XCOFF::StorageClass getStorageClass() const; + uint8_t getNumberOfAuxEntries() const; + const XCOFFCsectAuxEnt32 *getXCOFFCsectAuxEnt32() const; + uint16_t getType() const; + int16_t getSectionNumber() const; + + bool hasCsectAuxEnt() const; + bool isFunction() const; +}; + } // namespace object } // namespace llvm |