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 llvm::object::SymbolRef::Type type = UnWrap(symbol_it.getType()); 105 if (type == llvm::object::SymbolRef::Type::ST_Function) { 106 exported_symbols_->AddFunction(symbol_name, symbol_binding); 107 } else if (type == llvm::object::SymbolRef::Type::ST_Data) { 108 exported_symbols_->AddVar(symbol_name, symbol_binding); 109 } 110 } 111 } 112 113 114 template <typename T> CreateELFSoFileParser(const llvm::object::ELFObjectFile<T> * elfo)115static std::unique_ptr<SoFileParser> CreateELFSoFileParser( 116 const llvm::object::ELFObjectFile<T> *elfo) { 117 return std::make_unique<ELFSoFileParser<T>>(elfo); 118 } 119 120 Create(const std::string & so_file_path)121std::unique_ptr<SoFileParser> SoFileParser::Create( 122 const std::string &so_file_path) { 123 auto binary = llvm::object::createBinary(so_file_path); 124 if (!binary) { 125 return nullptr; 126 } 127 128 llvm::object::ObjectFile *obj_file = 129 llvm::dyn_cast<llvm::object::ObjectFile>(binary.get().getBinary()); 130 if (!obj_file) { 131 return nullptr; 132 } 133 134 // Little-endian 32-bit 135 if (auto elf_obj_file = 136 llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj_file)) { 137 return CreateELFSoFileParser(elf_obj_file); 138 } 139 140 // Big-endian 32-bit 141 if (auto elf_obj_file = 142 llvm::dyn_cast<llvm::object::ELF32BEObjectFile>(obj_file)) { 143 return CreateELFSoFileParser(elf_obj_file); 144 } 145 146 // Little-endian 64-bit 147 if (auto elf_obj_file = 148 llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj_file)) { 149 return CreateELFSoFileParser(elf_obj_file); 150 } 151 152 // Big-endian 64-bit 153 if (auto elf_obj_file = 154 llvm::dyn_cast<llvm::object::ELF64BEObjectFile>(obj_file)) { 155 return CreateELFSoFileParser(elf_obj_file); 156 } 157 158 return nullptr; 159 } 160 161 162 } // namespace repr 163 } // namespace header_checker 164