Home | History | Annotate | Line # | Download | only in Object
      1 //===- Binary.h - A generic binary file -------------------------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file declares the Binary class.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #ifndef LLVM_OBJECT_BINARY_H
     14 #define LLVM_OBJECT_BINARY_H
     15 
     16 #include "llvm-c/Types.h"
     17 #include "llvm/ADT/Triple.h"
     18 #include "llvm/Object/Error.h"
     19 #include "llvm/Support/Error.h"
     20 #include "llvm/Support/MemoryBuffer.h"
     21 #include <algorithm>
     22 #include <memory>
     23 #include <utility>
     24 
     25 namespace llvm {
     26 
     27 class LLVMContext;
     28 class StringRef;
     29 
     30 namespace object {
     31 
     32 class Binary {
     33 private:
     34   unsigned int TypeID;
     35 
     36 protected:
     37   MemoryBufferRef Data;
     38 
     39   Binary(unsigned int Type, MemoryBufferRef Source);
     40 
     41   enum {
     42     ID_Archive,
     43     ID_MachOUniversalBinary,
     44     ID_COFFImportFile,
     45     ID_IR,            // LLVM IR
     46     ID_TapiUniversal, // Text-based Dynamic Library Stub file.
     47     ID_TapiFile,      // Text-based Dynamic Library Stub file.
     48 
     49     ID_Minidump,
     50 
     51     ID_WinRes, // Windows resource (.res) file.
     52 
     53     // Object and children.
     54     ID_StartObjects,
     55     ID_COFF,
     56 
     57     ID_XCOFF32, // AIX XCOFF 32-bit
     58     ID_XCOFF64, // AIX XCOFF 64-bit
     59 
     60     ID_ELF32L, // ELF 32-bit, little endian
     61     ID_ELF32B, // ELF 32-bit, big endian
     62     ID_ELF64L, // ELF 64-bit, little endian
     63     ID_ELF64B, // ELF 64-bit, big endian
     64 
     65     ID_MachO32L, // MachO 32-bit, little endian
     66     ID_MachO32B, // MachO 32-bit, big endian
     67     ID_MachO64L, // MachO 64-bit, little endian
     68     ID_MachO64B, // MachO 64-bit, big endian
     69 
     70     ID_Wasm,
     71 
     72     ID_EndObjects
     73   };
     74 
     75   static inline unsigned int getELFType(bool isLE, bool is64Bits) {
     76     if (isLE)
     77       return is64Bits ? ID_ELF64L : ID_ELF32L;
     78     else
     79       return is64Bits ? ID_ELF64B : ID_ELF32B;
     80   }
     81 
     82   static unsigned int getMachOType(bool isLE, bool is64Bits) {
     83     if (isLE)
     84       return is64Bits ? ID_MachO64L : ID_MachO32L;
     85     else
     86       return is64Bits ? ID_MachO64B : ID_MachO32B;
     87   }
     88 
     89 public:
     90   Binary() = delete;
     91   Binary(const Binary &other) = delete;
     92   virtual ~Binary();
     93 
     94   virtual Error initContent() { return Error::success(); };
     95 
     96   StringRef getData() const;
     97   StringRef getFileName() const;
     98   MemoryBufferRef getMemoryBufferRef() const;
     99 
    100   // Cast methods.
    101   unsigned int getType() const { return TypeID; }
    102 
    103   // Convenience methods
    104   bool isObject() const {
    105     return TypeID > ID_StartObjects && TypeID < ID_EndObjects;
    106   }
    107 
    108   bool isSymbolic() const {
    109     return isIR() || isObject() || isCOFFImportFile() || isTapiFile();
    110   }
    111 
    112   bool isArchive() const { return TypeID == ID_Archive; }
    113 
    114   bool isMachOUniversalBinary() const {
    115     return TypeID == ID_MachOUniversalBinary;
    116   }
    117 
    118   bool isTapiUniversal() const { return TypeID == ID_TapiUniversal; }
    119 
    120   bool isELF() const {
    121     return TypeID >= ID_ELF32L && TypeID <= ID_ELF64B;
    122   }
    123 
    124   bool isMachO() const {
    125     return TypeID >= ID_MachO32L && TypeID <= ID_MachO64B;
    126   }
    127 
    128   bool isCOFF() const {
    129     return TypeID == ID_COFF;
    130   }
    131 
    132   bool isXCOFF() const { return TypeID == ID_XCOFF32 || TypeID == ID_XCOFF64; }
    133 
    134   bool isWasm() const { return TypeID == ID_Wasm; }
    135 
    136   bool isCOFFImportFile() const {
    137     return TypeID == ID_COFFImportFile;
    138   }
    139 
    140   bool isIR() const {
    141     return TypeID == ID_IR;
    142   }
    143 
    144   bool isMinidump() const { return TypeID == ID_Minidump; }
    145 
    146   bool isTapiFile() const { return TypeID == ID_TapiFile; }
    147 
    148   bool isLittleEndian() const {
    149     return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B ||
    150              TypeID == ID_MachO32B || TypeID == ID_MachO64B ||
    151              TypeID == ID_XCOFF32 || TypeID == ID_XCOFF64);
    152   }
    153 
    154   bool isWinRes() const { return TypeID == ID_WinRes; }
    155 
    156   Triple::ObjectFormatType getTripleObjectFormat() const {
    157     if (isCOFF())
    158       return Triple::COFF;
    159     if (isMachO())
    160       return Triple::MachO;
    161     if (isELF())
    162       return Triple::ELF;
    163     return Triple::UnknownObjectFormat;
    164   }
    165 
    166   static Error checkOffset(MemoryBufferRef M, uintptr_t Addr,
    167                            const uint64_t Size) {
    168     if (Addr + Size < Addr || Addr + Size < Size ||
    169         Addr + Size > reinterpret_cast<uintptr_t>(M.getBufferEnd()) ||
    170         Addr < reinterpret_cast<uintptr_t>(M.getBufferStart())) {
    171       return errorCodeToError(object_error::unexpected_eof);
    172     }
    173     return Error::success();
    174   }
    175 };
    176 
    177 // Create wrappers for C Binding types (see CBindingWrapping.h).
    178 DEFINE_ISA_CONVERSION_FUNCTIONS(Binary, LLVMBinaryRef)
    179 
    180 /// Create a Binary from Source, autodetecting the file type.
    181 ///
    182 /// @param Source The data to create the Binary from.
    183 Expected<std::unique_ptr<Binary>> createBinary(MemoryBufferRef Source,
    184                                                LLVMContext *Context = nullptr,
    185                                                bool InitContent = true);
    186 
    187 template <typename T> class OwningBinary {
    188   std::unique_ptr<T> Bin;
    189   std::unique_ptr<MemoryBuffer> Buf;
    190 
    191 public:
    192   OwningBinary();
    193   OwningBinary(std::unique_ptr<T> Bin, std::unique_ptr<MemoryBuffer> Buf);
    194   OwningBinary(OwningBinary<T>&& Other);
    195   OwningBinary<T> &operator=(OwningBinary<T> &&Other);
    196 
    197   std::pair<std::unique_ptr<T>, std::unique_ptr<MemoryBuffer>> takeBinary();
    198 
    199   T* getBinary();
    200   const T* getBinary() const;
    201 };
    202 
    203 template <typename T>
    204 OwningBinary<T>::OwningBinary(std::unique_ptr<T> Bin,
    205                               std::unique_ptr<MemoryBuffer> Buf)
    206     : Bin(std::move(Bin)), Buf(std::move(Buf)) {}
    207 
    208 template <typename T> OwningBinary<T>::OwningBinary() = default;
    209 
    210 template <typename T>
    211 OwningBinary<T>::OwningBinary(OwningBinary &&Other)
    212     : Bin(std::move(Other.Bin)), Buf(std::move(Other.Buf)) {}
    213 
    214 template <typename T>
    215 OwningBinary<T> &OwningBinary<T>::operator=(OwningBinary &&Other) {
    216   Bin = std::move(Other.Bin);
    217   Buf = std::move(Other.Buf);
    218   return *this;
    219 }
    220 
    221 template <typename T>
    222 std::pair<std::unique_ptr<T>, std::unique_ptr<MemoryBuffer>>
    223 OwningBinary<T>::takeBinary() {
    224   return std::make_pair(std::move(Bin), std::move(Buf));
    225 }
    226 
    227 template <typename T> T* OwningBinary<T>::getBinary() {
    228   return Bin.get();
    229 }
    230 
    231 template <typename T> const T* OwningBinary<T>::getBinary() const {
    232   return Bin.get();
    233 }
    234 
    235 Expected<OwningBinary<Binary>> createBinary(StringRef Path,
    236                                             LLVMContext *Context = nullptr,
    237                                             bool InitContent = true);
    238 
    239 } // end namespace object
    240 
    241 } // end namespace llvm
    242 
    243 #endif // LLVM_OBJECT_BINARY_H
    244