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 60 public: 61 ELFSoFileParser(const llvm::object::ELFObjectFile<T> *obj); 62 ~ELFSoFileParser()63 ~ELFSoFileParser() override {} 64 Parse()65 std::unique_ptr<ExportedSymbolSet> Parse() override { 66 return std::move(exported_symbols_); 67 } 68 69 private: IsSymbolExported(const Elf_Sym * elf_sym) const70 bool IsSymbolExported(const Elf_Sym *elf_sym) const { 71 unsigned char visibility = elf_sym->getVisibility(); 72 unsigned char binding = elf_sym->getBinding(); 73 return ((binding == llvm::ELF::STB_GLOBAL || 74 binding == llvm::ELF::STB_WEAK) && 75 (visibility == llvm::ELF::STV_DEFAULT || 76 visibility == llvm::ELF::STV_PROTECTED)); 77 } 78 79 private: 80 const llvm::object::ELFObjectFile<T> *obj_; 81 std::unique_ptr<ExportedSymbolSet> exported_symbols_; 82 }; 83 84 85 template <typename T> ELFSoFileParser(const llvm::object::ELFObjectFile<T> * obj)86ELFSoFileParser<T>::ELFSoFileParser(const llvm::object::ELFObjectFile<T> *obj) { 87 assert(obj != nullptr); 88 89 exported_symbols_.reset(new ExportedSymbolSet()); 90 91 for (auto symbol_it : obj->getDynamicSymbolIterators()) { 92 auto elf_sym_or_error = obj->getSymbol(symbol_it.getRawDataRefImpl()); 93 assert (elf_sym_or_error); 94 const Elf_Sym *elf_sym = elf_sym_or_error.get(); 95 if (!IsSymbolExported(elf_sym) || elf_sym->isUndefined()) { 96 continue; 97 } 98 99 ElfSymbolIR::ElfSymbolBinding symbol_binding = 100 LLVMToIRSymbolBinding(elf_sym->getBinding()); 101 std::string symbol_name(UnWrap(symbol_it.getName())); 102 103 switch (symbol_it.getELFType()) { 104 case llvm::ELF::STT_OBJECT: 105 case llvm::ELF::STT_COMMON: 106 case llvm::ELF::STT_TLS: 107 exported_symbols_->AddVar(symbol_name, symbol_binding); 108 break; 109 case llvm::ELF::STT_FUNC: 110 case llvm::ELF::STT_GNU_IFUNC: 111 exported_symbols_->AddFunction(symbol_name, symbol_binding); 112 break; 113 default: 114 break; 115 } 116 } 117 } 118 119 120 template <typename T> CreateELFSoFileParser(const llvm::object::ELFObjectFile<T> * elfo)121static std::unique_ptr<SoFileParser> CreateELFSoFileParser( 122 const llvm::object::ELFObjectFile<T> *elfo) { 123 return std::make_unique<ELFSoFileParser<T>>(elfo); 124 } 125 126 Create(const std::string & so_file_path)127std::unique_ptr<SoFileParser> SoFileParser::Create( 128 const std::string &so_file_path) { 129 auto binary = llvm::object::createBinary(so_file_path); 130 if (!binary) { 131 return nullptr; 132 } 133 134 llvm::object::ObjectFile *obj_file = 135 llvm::dyn_cast<llvm::object::ObjectFile>(binary.get().getBinary()); 136 if (!obj_file) { 137 return nullptr; 138 } 139 140 // Little-endian 32-bit 141 if (auto elf_obj_file = 142 llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj_file)) { 143 return CreateELFSoFileParser(elf_obj_file); 144 } 145 146 // Big-endian 32-bit 147 if (auto elf_obj_file = 148 llvm::dyn_cast<llvm::object::ELF32BEObjectFile>(obj_file)) { 149 return CreateELFSoFileParser(elf_obj_file); 150 } 151 152 // Little-endian 64-bit 153 if (auto elf_obj_file = 154 llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj_file)) { 155 return CreateELFSoFileParser(elf_obj_file); 156 } 157 158 // Big-endian 64-bit 159 if (auto elf_obj_file = 160 llvm::dyn_cast<llvm::object::ELF64BEObjectFile>(obj_file)) { 161 return CreateELFSoFileParser(elf_obj_file); 162 } 163 164 return nullptr; 165 } 166 167 168 } // namespace repr 169 } // namespace header_checker 170