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 25 namespace header_checker { 26 namespace repr { 27 28 29 template <typename T> UnWrap(llvm::Expected<T> value_or_error)30static inline T UnWrap(llvm::Expected<T> value_or_error) { 31 if (!value_or_error) { 32 llvm::errs() << "\nerror: " << llvm::toString(value_or_error.takeError()) 33 << ".\n"; 34 llvm::errs().flush(); 35 exit(1); 36 } 37 return std::move(value_or_error.get()); 38 } 39 40 41 static ElfSymbolIR::ElfSymbolBinding LLVMToIRSymbolBinding(unsigned char binding)42LLVMToIRSymbolBinding(unsigned char binding) { 43 switch (binding) { 44 case llvm::ELF::STB_GLOBAL: 45 return ElfSymbolIR::ElfSymbolBinding::Global; 46 case llvm::ELF::STB_WEAK: 47 return ElfSymbolIR::ElfSymbolBinding::Weak; 48 } 49 assert(0); 50 } 51 52 53 template <typename T> 54 class ELFSoFileParser : public SoFileParser { 55 private: 56 LLVM_ELF_IMPORT_TYPES_ELFT(T) 57 typedef llvm::object::ELFFile<T> ELFO; 58 typedef typename ELFO::Elf_Sym Elf_Sym; 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 const Elf_Sym *elf_sym = obj->getSymbol(symbol_it.getRawDataRefImpl()); 93 assert (elf_sym != nullptr); 94 if (!IsSymbolExported(elf_sym) || elf_sym->isUndefined()) { 95 continue; 96 } 97 98 ElfSymbolIR::ElfSymbolBinding symbol_binding = 99 LLVMToIRSymbolBinding(elf_sym->getBinding()); 100 std::string symbol_name = UnWrap(symbol_it.getName()); 101 102 llvm::object::SymbolRef::Type type = UnWrap(symbol_it.getType()); 103 if (type == llvm::object::SymbolRef::Type::ST_Function) { 104 exported_symbols_->AddFunction(symbol_name, symbol_binding); 105 } else if (type == llvm::object::SymbolRef::Type::ST_Data) { 106 exported_symbols_->AddVar(symbol_name, symbol_binding); 107 } 108 } 109 } 110 111 112 template <typename T> CreateELFSoFileParser(const llvm::object::ELFObjectFile<T> * elfo)113static std::unique_ptr<SoFileParser> CreateELFSoFileParser( 114 const llvm::object::ELFObjectFile<T> *elfo) { 115 return llvm::make_unique<ELFSoFileParser<T>>(elfo); 116 } 117 118 Create(const std::string & so_file_path)119std::unique_ptr<SoFileParser> SoFileParser::Create( 120 const std::string &so_file_path) { 121 auto binary = llvm::object::createBinary(so_file_path); 122 if (!binary) { 123 return nullptr; 124 } 125 126 llvm::object::ObjectFile *obj_file = 127 llvm::dyn_cast<llvm::object::ObjectFile>(binary.get().getBinary()); 128 if (!obj_file) { 129 return nullptr; 130 } 131 132 // Little-endian 32-bit 133 if (auto elf_obj_file = 134 llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj_file)) { 135 return CreateELFSoFileParser(elf_obj_file); 136 } 137 138 // Big-endian 32-bit 139 if (auto elf_obj_file = 140 llvm::dyn_cast<llvm::object::ELF32BEObjectFile>(obj_file)) { 141 return CreateELFSoFileParser(elf_obj_file); 142 } 143 144 // Little-endian 64-bit 145 if (auto elf_obj_file = 146 llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj_file)) { 147 return CreateELFSoFileParser(elf_obj_file); 148 } 149 150 // Big-endian 64-bit 151 if (auto elf_obj_file = 152 llvm::dyn_cast<llvm::object::ELF64BEObjectFile>(obj_file)) { 153 return CreateELFSoFileParser(elf_obj_file); 154 } 155 156 return nullptr; 157 } 158 159 160 } // namespace repr 161 } // namespace header_checker 162