• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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