1 // Copyright (C) 2017 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "repr/symbol/so_file_parser.h" 16 17 #include "repr/ir_representation.h" 18 19 #include <llvm/Object/Binary.h> 20 #include <llvm/Object/ELFObjectFile.h> 21 #include <llvm/Object/ELFTypes.h> 22 #include <llvm/Object/SymbolSize.h> 23 24 #include <utility> 25 26 27 namespace header_checker { 28 namespace repr { 29 30 31 template <typename T> UnWrap(llvm::Expected<T> value_or_error)32static inline T UnWrap(llvm::Expected<T> value_or_error) { 33 if (!value_or_error) { 34 llvm::errs() << "\nerror: " << llvm::toString(value_or_error.takeError()) 35 << ".\n"; 36 llvm::errs().flush(); 37 exit(1); 38 } 39 return std::move(value_or_error.get()); 40 } 41 42 43 static ElfSymbolIR::ElfSymbolBinding LLVMToIRSymbolBinding(unsigned char binding)44LLVMToIRSymbolBinding(unsigned char binding) { 45 switch (binding) { 46 case llvm::ELF::STB_GLOBAL: 47 return ElfSymbolIR::ElfSymbolBinding::Global; 48 case llvm::ELF::STB_WEAK: 49 return ElfSymbolIR::ElfSymbolBinding::Weak; 50 } 51 assert(0); 52 } 53 54 55 template <typename T> 56 class ELFSoFileParser : public SoFileParser { 57 private: 58 LLVM_ELF_IMPORT_TYPES_ELFT(T) 59 typedef llvm::object::ELFFile<T> ELFO; 60 typedef typename ELFO::Elf_Sym Elf_Sym; 61 62 public: 63 ELFSoFileParser(const llvm::object::ELFObjectFile<T> *obj); 64 ~ELFSoFileParser()65 ~ELFSoFileParser() override {} 66 Parse()67 std::unique_ptr<ExportedSymbolSet> Parse() override { 68 return std::move(exported_symbols_); 69 } 70 71 private: IsSymbolExported(const Elf_Sym * elf_sym) const72 bool IsSymbolExported(const Elf_Sym *elf_sym) const { 73 unsigned char visibility = elf_sym->getVisibility(); 74 unsigned char binding = elf_sym->getBinding(); 75 return ((binding == llvm::ELF::STB_GLOBAL || 76 binding == llvm::ELF::STB_WEAK) && 77 (visibility == llvm::ELF::STV_DEFAULT || 78 visibility == llvm::ELF::STV_PROTECTED)); 79 } 80 81 private: 82 const llvm::object::ELFObjectFile<T> *obj_; 83 std::unique_ptr<ExportedSymbolSet> exported_symbols_; 84 }; 85 86 87 template <typename T> ELFSoFileParser(const llvm::object::ELFObjectFile<T> * obj)88ELFSoFileParser<T>::ELFSoFileParser(const llvm::object::ELFObjectFile<T> *obj) { 89 assert(obj != nullptr); 90 91 exported_symbols_.reset(new ExportedSymbolSet()); 92 93 for (auto symbol_it : obj->getDynamicSymbolIterators()) { 94 const Elf_Sym *elf_sym = obj->getSymbol(symbol_it.getRawDataRefImpl()); 95 assert (elf_sym != nullptr); 96 if (!IsSymbolExported(elf_sym) || elf_sym->isUndefined()) { 97 continue; 98 } 99 100 ElfSymbolIR::ElfSymbolBinding symbol_binding = 101 LLVMToIRSymbolBinding(elf_sym->getBinding()); 102 std::string symbol_name(UnWrap(symbol_it.getName())); 103 104 switch (symbol_it.getELFType()) { 105 case llvm::ELF::STT_OBJECT: 106 case llvm::ELF::STT_COMMON: 107 case llvm::ELF::STT_TLS: 108 exported_symbols_->AddVar(symbol_name, symbol_binding); 109 break; 110 case llvm::ELF::STT_FUNC: 111 case llvm::ELF::STT_GNU_IFUNC: 112 exported_symbols_->AddFunction(symbol_name, symbol_binding); 113 break; 114 default: 115 break; 116 } 117 } 118 } 119 120 121 template <typename T> CreateELFSoFileParser(const llvm::object::ELFObjectFile<T> * elfo)122static std::unique_ptr<SoFileParser> CreateELFSoFileParser( 123 const llvm::object::ELFObjectFile<T> *elfo) { 124 return std::make_unique<ELFSoFileParser<T>>(elfo); 125 } 126 127 Create(const std::string & so_file_path)128std::unique_ptr<SoFileParser> SoFileParser::Create( 129 const std::string &so_file_path) { 130 auto binary = llvm::object::createBinary(so_file_path); 131 if (!binary) { 132 return nullptr; 133 } 134 135 llvm::object::ObjectFile *obj_file = 136 llvm::dyn_cast<llvm::object::ObjectFile>(binary.get().getBinary()); 137 if (!obj_file) { 138 return nullptr; 139 } 140 141 // Little-endian 32-bit 142 if (auto elf_obj_file = 143 llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj_file)) { 144 return CreateELFSoFileParser(elf_obj_file); 145 } 146 147 // Big-endian 32-bit 148 if (auto elf_obj_file = 149 llvm::dyn_cast<llvm::object::ELF32BEObjectFile>(obj_file)) { 150 return CreateELFSoFileParser(elf_obj_file); 151 } 152 153 // Little-endian 64-bit 154 if (auto elf_obj_file = 155 llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj_file)) { 156 return CreateELFSoFileParser(elf_obj_file); 157 } 158 159 // Big-endian 64-bit 160 if (auto elf_obj_file = 161 llvm::dyn_cast<llvm::object::ELF64BEObjectFile>(obj_file)) { 162 return CreateELFSoFileParser(elf_obj_file); 163 } 164 165 return nullptr; 166 } 167 168 169 } // namespace repr 170 } // namespace header_checker 171