1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ELF_HANDLING_H_ 18 #define ELF_HANDLING_H_ 19 20 #include <map> 21 #include <memory> 22 #include <string> 23 #include <system_error> 24 #include <vector> 25 26 #include <llvm/Object/ELFObjectFile.h> 27 #include <llvm/Object/ELFTypes.h> 28 #include <llvm/Object/SymbolSize.h> 29 #include <llvm/Support/Endian.h> 30 #include <llvm/Support/raw_ostream.h> 31 32 using llvm::object::ObjectFile; 33 using llvm::object::ELFObjectFile; 34 using llvm::object::SectionRef; 35 using llvm::object::RelocationRef; 36 using llvm::object::ELFFile; 37 using llvm::object::ELFType; 38 using llvm::object::ELFDataTypeTypedefHelper; 39 using llvm::object::SymbolRef; 40 using llvm::outs; 41 42 class SharedObject { 43 public: 44 static std::unique_ptr<SharedObject> create(const ObjectFile *); 45 /* Print mangled names if the argument is true; demangled if false. 46 */ 47 virtual void printVTables(bool) const = 0; 48 virtual ~SharedObject() = 0; 49 private: 50 virtual bool getVTables() = 0; 51 }; 52 53 class VFunction { 54 public: 55 VFunction( 56 const std::string &, 57 const std::string &, 58 uint64_t); 59 60 uint64_t getOffset() const; 61 bool operator<(const VFunction &) const; 62 const std::string &getMangledName() const; 63 const std::string &getDemangledName() const; 64 private: 65 std::string mMangledName; 66 std::string mDemangledName; 67 uint64_t mOffset; 68 }; 69 70 class VTable { 71 public: 72 using func_iterator = std::vector<VFunction>::const_iterator; 73 VTable( 74 const std::string &, 75 const std::string &, 76 uint64_t, 77 uint64_t); 78 79 uint64_t getStartAddr() const; 80 uint64_t getEndAddr() const; 81 uint64_t getBaseOffset() const; 82 uint64_t getVTableSize() const; 83 func_iterator begin() const; 84 func_iterator end() const; 85 const std::string &getMangledName() const; 86 const std::string &getDemangledName() const; 87 void sortVFunctions(); 88 void addVFunction( 89 const std::string &, 90 const std::string &, 91 uint64_t); 92 93 bool operator<(const VTable &) const; 94 bool operator<(const uint64_t) const; 95 private: 96 std::vector<VFunction> mFunctions; 97 std::string mMangledName; 98 std::string mDemangledName; 99 /* This holds the range(st_value, st_value) through which the 100 * VTable spans. 101 */ 102 uint64_t mStartAddr; 103 uint64_t mEndAddr; 104 uint64_t mBaseOffset; 105 }; 106 107 template<typename ELFT> 108 class ELFSharedObject : public SharedObject { 109 public: 110 void printVTables(bool) const override; 111 bool getVTables() override; 112 ~ELFSharedObject(); 113 ELFSharedObject(const ELFObjectFile<ELFT> *); 114 115 private: 116 /* We need a sym value to SymbolRef map in case the relocation provides 117 * us with an addr instead of a sym index into dynsym / symtab. 118 */ 119 LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) 120 typedef ELFFile<ELFT> ELFO; 121 typedef typename ELFO::Elf_Shdr Elf_Shdr; 122 typedef typename ELFO::Elf_Ehdr Elf_Ehdr; 123 typedef typename ELFO::Elf_Sym Elf_Sym; 124 typedef typename ELFO::Elf_Rela Elf_Rela; 125 typedef typename ELFO::uintX_t uintX_t; 126 std::map<uint64_t, std::vector<SymbolRef>> mAddrToSymbolRef; 127 const ELFObjectFile<ELFT> *mObj; 128 /* We cache the relocation sections, to look through their relocations for 129 * vfunctions. Sections with type SHT_PROGBITS are cached since they contain 130 * vtables. We might need to peek at the contents of a vtable in cases of 131 * relative relocations. 132 */ 133 std::vector<SectionRef> mRelSectionRefs; 134 std::vector<SectionRef> mProgBitSectionRefs; 135 std::vector<VTable> mVTables; 136 137 private: 138 bool cacheELFSections(); 139 bool initVTableRanges(); 140 void getVFunctions(); 141 VTable *identifyVTable(uint64_t); 142 void relocateSym( 143 const RelocationRef &, 144 const SectionRef &, 145 VTable *); 146 147 bool absoluteRelocation(const RelocationRef &, VTable *); 148 bool relativeRelocation( 149 const RelocationRef &, 150 const SectionRef &, 151 VTable *); 152 153 uint64_t identifyAddend(uint64_t); 154 uint64_t getAddendFromSection(const SectionRef &, uint64_t); 155 SymbolRef matchValueToSymbol(std::vector<SymbolRef> &, VTable *); 156 }; 157 158 template <typename T> 159 static inline T UnWrap(llvm::Expected<T> ValueOrError) { 160 if (!ValueOrError) { 161 outs() << "\nError: " 162 << llvm::toString(ValueOrError.takeError()) 163 << ".\n"; 164 outs().flush(); 165 exit(1); 166 } 167 return std::move(ValueOrError.get()); 168 } 169 170 171 #endif // ELF_HANDLING_H_ 172