Home | History | Annotate | Download | only in symbol
      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>
     30 static 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
     42 LLVMToIRSymbolBinding(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 
     63   ~ELFSoFileParser() override {}
     64 
     65   std::unique_ptr<ExportedSymbolSet> Parse() override {
     66     return std::move(exported_symbols_);
     67   }
     68 
     69  private:
     70   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>
     86 ELFSoFileParser<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>
    113 static std::unique_ptr<SoFileParser> CreateELFSoFileParser(
    114     const llvm::object::ELFObjectFile<T> *elfo) {
    115   return llvm::make_unique<ELFSoFileParser<T>>(elfo);
    116 }
    117 
    118 
    119 std::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