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)32 static 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)44 LLVMToIRSymbolBinding(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)88 ELFSoFileParser<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)115 static 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)121 std::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