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