1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ELF_HANDLING_H_
18 #define ELF_HANDLING_H_
19
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <system_error>
24 #include <vector>
25
26 #include <llvm/Object/ELFObjectFile.h>
27 #include <llvm/Object/ELFTypes.h>
28 #include <llvm/Object/SymbolSize.h>
29 #include <llvm/Support/Endian.h>
30 #include <llvm/Support/raw_ostream.h>
31
32 using llvm::object::ObjectFile;
33 using llvm::object::ELFObjectFile;
34 using llvm::object::SectionRef;
35 using llvm::object::RelocationRef;
36 using llvm::object::ELFFile;
37 using llvm::object::ELFType;
38 using llvm::object::ELFDataTypeTypedefHelper;
39 using llvm::object::SymbolRef;
40 using llvm::outs;
41
42 class SharedObject {
43 public:
44 static std::unique_ptr<SharedObject> create(const ObjectFile *);
45 virtual void printVTables() const = 0;
46 virtual ~SharedObject() = 0;
47 private:
48 virtual bool getVTables() = 0;
49 };
50
51 class VFunction {
52 public:
53 VFunction(
54 const std::string &,
55 const std::string &,
56 uint64_t);
57
58 uint64_t getOffset() const;
59 bool operator<(const VFunction &) const;
60 const std::string &getMangledName() const;
61 const std::string &getDemangledName() const;
62 private:
63 std::string mMangledName;
64 std::string mDemangledName;
65 uint64_t mOffset;
66 };
67
68 class VTable {
69 public:
70 using func_iterator = std::vector<VFunction>::const_iterator;
71 VTable(
72 const std::string &,
73 const std::string &,
74 uint64_t,
75 uint64_t);
76
77 uint64_t getStartAddr() const;
78 uint64_t getEndAddr() const;
79 uint64_t getBaseOffset() const;
80 uint64_t getVTableSize() const;
81 func_iterator begin() const;
82 func_iterator end() const;
83 const std::string &getMangledName() const;
84 const std::string &getDemangledName() const;
85 void sortVFunctions();
86 void addVFunction(
87 const std::string &,
88 const std::string &,
89 uint64_t);
90
91 bool operator<(const VTable &) const;
92 bool operator<(const uint64_t) const;
93 private:
94 std::vector<VFunction> mFunctions;
95 std::string mMangledName;
96 std::string mDemangledName;
97 /* This holds the range(st_value, st_value) through which the
98 * VTable spans.
99 */
100 uint64_t mStartAddr;
101 uint64_t mEndAddr;
102 uint64_t mBaseOffset;
103 };
104
105 template<typename ELFT>
106 class ELFSharedObject : public SharedObject {
107 public:
108 void printVTables() const override;
109 bool getVTables() override;
110 ~ELFSharedObject();
111 ELFSharedObject(const ELFObjectFile<ELFT> *);
112
113 private:
114 /* We need a sym value to SymbolRef map in case the relocation provides
115 * us with an addr instead of a sym index into dynsym / symtab.
116 */
117 LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
118 typedef ELFFile<ELFT> ELFO;
119 typedef typename ELFO::Elf_Shdr Elf_Shdr;
120 typedef typename ELFO::Elf_Ehdr Elf_Ehdr;
121 typedef typename ELFO::Elf_Sym Elf_Sym;
122 typedef typename ELFO::Elf_Rela Elf_Rela;
123 typedef typename ELFO::uintX_t uintX_t;
124 std::map<uint64_t, std::vector<SymbolRef>> mAddrToSymbolRef;
125 const ELFObjectFile<ELFT> *mObj;
126 /* We cache the relocation sections, to look through their relocations for
127 * vfunctions. Sections with type SHT_PROGBITS are cached since they contain
128 * vtables. We might need to peek at the contents of a vtable in cases of
129 * relative relocations.
130 */
131 std::vector<SectionRef> mRelSectionRefs;
132 std::vector<SectionRef> mProgBitSectionRefs;
133 std::vector<VTable> mVTables;
134
135 private:
136 bool cacheELFSections();
137 bool initVTableRanges();
138 void getVFunctions();
139 VTable *identifyVTable(uint64_t);
140 void relocateSym(
141 const RelocationRef &,
142 const SectionRef &,
143 VTable *);
144
145 bool absoluteRelocation(const RelocationRef &, VTable *);
146 bool relativeRelocation(
147 const RelocationRef &,
148 const SectionRef &,
149 VTable *);
150
151 uint64_t identifyAddend(uint64_t);
152 uint64_t getAddendFromSection(const SectionRef &, uint64_t);
153 SymbolRef matchValueToSymbol(std::vector<SymbolRef> &, VTable *);
154 };
155
156 template <typename T>
UnWrap(llvm::Expected<T> ValueOrError)157 static inline T UnWrap(llvm::Expected<T> ValueOrError) {
158 if (!ValueOrError) {
159 outs() << "\nError: "
160 << llvm::toString(ValueOrError.takeError())
161 << ".\n";
162 outs().flush();
163 exit(1);
164 }
165 return std::move(ValueOrError.get());
166 }
167
168
169 #endif // ELF_HANDLING_H_
170