• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)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
LLVMToIRSymbolBinding(unsigned char binding)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 
~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)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>
CreateELFSoFileParser(const llvm::object::ELFObjectFile<T> * elfo)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 
Create(const std::string & so_file_path)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