//===- SymbolicFile.h - Interface that only provides symbols ----*- 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 SymbolicFile interface. // //===----------------------------------------------------------------------===// #ifndef LLVM_OBJECT_SYMBOLICFILE_H #define LLVM_OBJECT_SYMBOLICFILE_H #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Object/Binary.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" #include "llvm/Support/MemoryBufferRef.h" #include #include #include #include #include namespace llvm { class LLVMContext; class raw_ostream; namespace object { union DataRefImpl { // This entire union should probably be a // char[max(8, sizeof(uintptr_t))] and require the impl to cast. struct { uint32_t a, b; } d; uintptr_t p; DataRefImpl() { std::memset(this, 0, sizeof(DataRefImpl)); } }; template OStream& operator<<(OStream &OS, const DataRefImpl &D) { OS << "(" << format("0x%08" PRIxPTR, D.p) << " (" << format("0x%08x", D.d.a) << ", " << format("0x%08x", D.d.b) << "))"; return OS; } inline bool operator==(const DataRefImpl &a, const DataRefImpl &b) { // Check bitwise identical. This is the only legal way to compare a union w/o // knowing which member is in use. return std::memcmp(&a, &b, sizeof(DataRefImpl)) == 0; } inline bool operator!=(const DataRefImpl &a, const DataRefImpl &b) { return !operator==(a, b); } inline bool operator<(const DataRefImpl &a, const DataRefImpl &b) { // Check bitwise identical. This is the only legal way to compare a union w/o // knowing which member is in use. return std::memcmp(&a, &b, sizeof(DataRefImpl)) < 0; } template class content_iterator { content_type Current; public: using iterator_category = std::forward_iterator_tag; using value_type = content_type; using difference_type = std::ptrdiff_t; using pointer = value_type *; using reference = value_type &; content_iterator(content_type symb) : Current(std::move(symb)) {} const content_type *operator->() const { return &Current; } const content_type &operator*() const { return Current; } bool operator==(const content_iterator &other) const { return Current == other.Current; } bool operator!=(const content_iterator &other) const { return !(*this == other); } content_iterator &operator++() { // preincrement Current.moveNext(); return *this; } }; class SymbolicFile; /// This is a value type class that represents a single symbol in the list of /// symbols in the object file. class BasicSymbolRef { DataRefImpl SymbolPimpl; const SymbolicFile *OwningObject = nullptr; public: enum Flags : unsigned { SF_None = 0, SF_Undefined = 1U << 0, // Symbol is defined in another object file SF_Global = 1U << 1, // Global symbol SF_Weak = 1U << 2, // Weak symbol SF_Absolute = 1U << 3, // Absolute symbol SF_Common = 1U << 4, // Symbol has common linkage SF_Indirect = 1U << 5, // Symbol is an alias to another symbol SF_Exported = 1U << 6, // Symbol is visible to other DSOs SF_FormatSpecific = 1U << 7, // Specific to the object file format // (e.g. section symbols) SF_Thumb = 1U << 8, // Thumb symbol in a 32-bit ARM binary SF_Hidden = 1U << 9, // Symbol has hidden visibility SF_Const = 1U << 10, // Symbol value is constant SF_Executable = 1U << 11, // Symbol points to an executable section // (IR only) }; BasicSymbolRef() = default; BasicSymbolRef(DataRefImpl SymbolP, const SymbolicFile *Owner); bool operator==(const BasicSymbolRef &Other) const; bool operator<(const BasicSymbolRef &Other) const; void moveNext(); Error printName(raw_ostream &OS) const; /// Get symbol flags (bitwise OR of SymbolRef::Flags) Expected getFlags() const; DataRefImpl getRawDataRefImpl() const; const SymbolicFile *getObject() const; }; using basic_symbol_iterator = content_iterator; class SymbolicFile : public Binary { public: SymbolicFile(unsigned int Type, MemoryBufferRef Source); ~SymbolicFile() override; // virtual interface. virtual void moveSymbolNext(DataRefImpl &Symb) const = 0; virtual Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const = 0; virtual Expected getSymbolFlags(DataRefImpl Symb) const = 0; virtual basic_symbol_iterator symbol_begin() const = 0; virtual basic_symbol_iterator symbol_end() const = 0; virtual bool is64Bit() const = 0; // convenience wrappers. using basic_symbol_iterator_range = iterator_range; basic_symbol_iterator_range symbols() const { return basic_symbol_iterator_range(symbol_begin(), symbol_end()); } // construction aux. static Expected> createSymbolicFile(MemoryBufferRef Object, llvm::file_magic Type, LLVMContext *Context, bool InitContent = true); static Expected> createSymbolicFile(MemoryBufferRef Object) { return createSymbolicFile(Object, llvm::file_magic::unknown, nullptr); } static bool classof(const Binary *v) { return v->isSymbolic(); } static bool isSymbolicFile(file_magic Type, const LLVMContext *Context); }; inline BasicSymbolRef::BasicSymbolRef(DataRefImpl SymbolP, const SymbolicFile *Owner) : SymbolPimpl(SymbolP), OwningObject(Owner) {} inline bool BasicSymbolRef::operator==(const BasicSymbolRef &Other) const { return SymbolPimpl == Other.SymbolPimpl; } inline bool BasicSymbolRef::operator<(const BasicSymbolRef &Other) const { return SymbolPimpl < Other.SymbolPimpl; } inline void BasicSymbolRef::moveNext() { return OwningObject->moveSymbolNext(SymbolPimpl); } inline Error BasicSymbolRef::printName(raw_ostream &OS) const { return OwningObject->printSymbolName(OS, SymbolPimpl); } inline Expected BasicSymbolRef::getFlags() const { return OwningObject->getSymbolFlags(SymbolPimpl); } inline DataRefImpl BasicSymbolRef::getRawDataRefImpl() const { return SymbolPimpl; } inline const SymbolicFile *BasicSymbolRef::getObject() const { return OwningObject; } } // end namespace object } // end namespace llvm #endif // LLVM_OBJECT_SYMBOLICFILE_H