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