• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
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 
16 #ifndef ELF_PARSER_H_
17 #define ELF_PARSER_H_
18 #include <cassert>
19 #include <cstring>
20 #include <functional>
21 #include <unordered_map>
22 #if !is_ohos
23 // this is not good enough
24 #include <../musl/include/elf.h>
25 #else
26 #include <elf.h>
27 #endif
28 #include <fcntl.h>
29 #include <stdint.h>
30 #include <strings.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include "utilities.h"
34 
35 #if !is_mingw
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38 #endif
39 
40 namespace OHOS {
41 namespace Developtools {
42 namespace HiPerf {
43 namespace ELF {
44 using namespace std::string_literals;
45 
46 constexpr std::size_t ehdr32Size {52};
47 constexpr std::size_t ehdr64Size {64};
48 constexpr std::size_t shdr32Size {40};
49 constexpr std::size_t shdr64Size {64};
50 constexpr std::size_t phdr32Size {32};
51 constexpr std::size_t phdr64Size {56};
52 constexpr std::size_t symEnt32Size {16};
53 constexpr std::size_t symEnt64Size {24};
54 
55 class ElfHeader {
56 public:
57     static std::unique_ptr<ElfHeader> MakeUnique(unsigned char * const ehdrBuf,
58                                                  const std::size_t bufSize);
59     bool Init(unsigned char * const ehdrBuf, const std::size_t bufSize);
60 
61     unsigned char ehdrIdent_[EI_NIDENT];
62     uint16_t type_;
63     uint16_t machine_;
64     uint16_t ehdrSize_;
65     uint16_t phdrEntSize_;
66     uint16_t phdrNumEnts_;
67     uint16_t shdrEntSize_;
68     uint16_t shdrNumEnts_;
69     uint16_t shdrStrTabIdx_;
70     uint32_t elfVersion_;
71     uint32_t ehdrFlags_;
72     uint64_t prgEntryVaddr_;
73     uint64_t phdrOffset_;
74     uint64_t shdrOffset_;
75 
76 private:
77     explicit ElfHeader() = default;
78     bool ParseElf32Header(unsigned char * const ehdrBuf, const std::size_t bufSize);
79     bool ParseElf64Header(unsigned char * const ehdrBuf, const std::size_t bufSize);
DumpEhdrBuf(const char * const ehdrBuf,const std::size_t bufSize)80     static inline void DumpEhdrBuf(const char * const ehdrBuf, const std::size_t bufSize)
81     {
82         const std::string fileName {"ehdr_buffer_dump"};
83         std::ofstream ofs {fileName, std::ios::binary};
84         if (ofs.is_open()) {
85             ofs.write(ehdrBuf, bufSize);
86         }
87     }
88 };
89 
90 class ProgramHeader {
91 public:
92     static std::unique_ptr<ProgramHeader> MakeUnique(char * const phdrBuf, const size_t bufSize);
Init(char * const phdrBuf,const size_t bufSize)93     inline bool Init(char * const phdrBuf, const size_t bufSize)
94     {
95         if (bufSize == phdr32Size and ParsePrgHeader32(phdrBuf)) {
96             return true;
97         }
98         if (bufSize == phdr64Size and ParsePrgHeader64(phdrBuf)) {
99             return true;
100         }
101         HLOGE("parse program header failed, program header buffer dumped");
102         return false;
103     }
104 
105     uint32_t type_;
106     uint32_t flags_;
107     uint64_t offset_;
108     uint64_t vaddr_;
109     uint64_t paddr_;
110     uint64_t fileSize_;
111     uint64_t memSize_;
112     uint64_t secAlign_;
113 
114 private:
115     explicit ProgramHeader() = default;
116     bool ParsePrgHeader32(char * const phdrBuf);
117     bool ParsePrgHeader64(char * const phdrBuf);
DumpPhdrBuf(const char * const phdrBuf,const std::size_t bufSize)118     static inline void DumpPhdrBuf(const char * const phdrBuf, const std::size_t bufSize)
119     {
120         const std::string fileName {"phdr_buffer_dump"};
121         std::ofstream ofs {fileName, std::ios::binary};
122         if (ofs.is_open()) {
123             ofs.write(phdrBuf, bufSize);
124         }
125     }
126 };
127 
128 class SectionHeader {
129 public:
130     static std::unique_ptr<SectionHeader> MakeUnique(char * const shdrBuf, const size_t bufSize,
131                                                      const size_t index);
132 
Init(char * const shdrBuf,const size_t bufSize,const size_t index)133     inline bool Init(char * const shdrBuf, const size_t bufSize, const size_t index)
134     {
135         secIndex_ = index;
136         if (bufSize == shdr32Size and ParseSecHeader32(shdrBuf)) {
137             return true;
138         }
139         if (bufSize == shdr64Size and ParseSecHeader64(shdrBuf)) {
140             return true;
141         }
142         HLOGE("parse section header failed, section header buffer dumped");
143         return false;
144     }
145 
146     uint32_t nameIndex_;
147     uint32_t link_;
148     uint32_t info_;
149     uint64_t secFlags_;
150     uint64_t secVaddr_;
151     uint64_t fileOffset_;
152     uint64_t secSize_;
153     uint64_t secAddrAlign_;
154     uint64_t secEntrySize_;
155     uint64_t secType_;
156     uint32_t secIndex_;
157     std::string secTypeName_;
158 
159 private:
160     explicit SectionHeader() = default;
161     bool ParseSecHeader32(char * const shdrBuf);
162     bool ParseSecHeader64(char * const shdrBuf);
DumpShdrBuf(const char * const shdrBuf,const std::size_t bufSize)163     static inline void DumpShdrBuf(const char * const shdrBuf, const std::size_t bufSize)
164     {
165         const std::string fileName {"shdr_buffer_dump"};
166         std::ofstream ofs {fileName, std::ios::binary};
167         if (ofs.is_open()) {
168             ofs.write(shdrBuf, bufSize);
169         }
170     }
171 };
172 
173 class ElfSymbol {
174 public:
175     static std::unique_ptr<ElfSymbol> MakeUnique(char * const symBuf, const std::size_t bufSize);
Init(char * const symBuf,const std::size_t bufSize)176     inline bool Init(char * const symBuf, const std::size_t bufSize)
177     {
178         if (bufSize == symEnt32Size and ParseElf32Symbol(symBuf)) {
179             return true;
180         }
181         if (bufSize == symEnt64Size and ParseElf64Symbol(symBuf)) {
182             return true;
183         }
184         HLOGE("parse elf symbol failed, symbol buffer dumped");
185         return false;
186     }
187 
188     uint16_t secIndex_;
189     uint32_t nameIndex_;
190     uint64_t symValue_;
191     uint64_t symSize_;
192     unsigned char symInfo_;
193     unsigned char symOtherInfo_;
194 
195 private:
196     explicit ElfSymbol() = default;
197     bool ParseElf32Symbol(char * const symBuf);
198     bool ParseElf64Symbol(char * const symBuf);
DumpSymBuf(const char * const symBuf,const std::size_t bufSize)199     static inline void DumpSymBuf(const char * const symBuf, const std::size_t bufSize)
200     {
201         const std::string fileName {"shdr_buffer_dump"};
202         std::ofstream ofs {fileName, std::ios::binary};
203         if (ofs.is_open()) {
204             ofs.write(symBuf, bufSize);
205         }
206     }
207 };
208 
209 class SymbolTable {
210 public:
211     static std::unique_ptr<SymbolTable> MakeUnique(const std::string &symNamesStr,
212                                                    const char * const secBuf,
213                                                    const uint64_t secSize,
214                                                    const uint64_t entrySize);
215 
216     std::vector<std::unique_ptr<ElfSymbol>> symbols_;
217 
218 private:
SymbolTable(const std::string & symNamesStr)219     explicit SymbolTable(const std::string &symNamesStr) : symNamesStr_ {symNamesStr} {}
220 
221     const std::string symNamesStr_ {};
222 };
223 
224 class ElfFile : public Noncopyable {
225 public:
226     virtual ~ElfFile();
227     static std::unique_ptr<ElfFile> MakeUnique(const std::string &filename);
228     bool ParseFile();
229     bool ParseSymTable(const SectionHeader *shdr);
230     std::string GetSectionName(const uint32_t startIndex);
231 
IsOpened()232     inline bool IsOpened() const
233     {
234         return fd_ != -1;
235     }
236 
GetStrPtr(uint32_t sh_link,uint32_t st_name)237     inline const char *GetStrPtr(uint32_t sh_link, uint32_t st_name)
238     {
239         for (const auto &shdrsItem : shdrs_) {
240             if (shdrsItem.second->secIndex_ == sh_link) {
241                 if (mmap_ != MMAP_FAILED) {
242                     char *elfFileBegin = (char *)mmap_;
243                     return elfFileBegin + shdrsItem.second->fileOffset_ + st_name;
244                 }
245             }
246         }
247         HLOGE("string not found sh_link %u st_name %d", sh_link, st_name);
248         return nullptr;
249     }
250 
GetSectionData(uint32_t shIndex)251     inline const unsigned char *GetSectionData(uint32_t shIndex)
252     {
253         for (const auto &shdrsItem : shdrs_) {
254             if (shdrsItem.second->secIndex_ == shIndex) {
255                 if (mmap_ != MMAP_FAILED) {
256                     const unsigned char *elfFileBegin = (const unsigned char *)mmap_;
257                     return elfFileBegin + shdrsItem.second->fileOffset_;
258                 }
259             }
260         }
261         HLOGE("string not found shIndex %u ", shIndex);
262         return nullptr;
263     }
264 
265     using SecHeaderTableType = std::unordered_map<std::string, std::unique_ptr<SectionHeader>>;
266     using PrgHeaderTableType = std::vector<std::unique_ptr<ProgramHeader>>;
267     int fd_ {-1};
268     std::unique_ptr<ElfHeader> ehdr_ {nullptr};
269     SecHeaderTableType shdrs_ {};
270     PrgHeaderTableType phdrs_ {};
271     std::string secNamesStr_ {};
272     std::string symNamesStr_ {};
273     std::unique_ptr<SymbolTable> symTable_ {nullptr};
274     std::unique_ptr<SymbolTable> dynSymTable_ {nullptr};
275 
276 protected:
277     // for fuzz test we make a virtual function
ReadFile(void * buf,size_t count)278     virtual ssize_t ReadFile(void *buf, size_t count)
279     {
280         return read(fd_, buf, count);
281     };
282     explicit ElfFile(const std::string &filename);
283 
284 private:
285     bool ParseElfHeader();
286     bool ParsePrgHeaders();
287     bool ParseSecNamesStr();
288     bool ParseSecHeaders();
289     bool ParseSymNamesStr();
290     bool ParseSymTable(const std::string = ".symtab");
291     bool ParseDynSymTable();
292 
293     void *mmap_ = MMAP_FAILED;
294     uint64_t mmapSize_ = 0;
295 };
296 } // namespace ELF
297 } // namespace HiPerf
298 } // namespace Developtools
299 } // namespace OHOS
300 #endif // ELF_PARSER_H_
301