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