• 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 #include <elf_parser.h>
17 
18 using namespace OHOS::Developtools::NativeDaemon::ELF;
19 namespace OHOS {
20 namespace Developtools {
21 namespace NativeDaemon {
ElfFile(const std::string & filename)22 ElfFile::ElfFile(const std::string &filename)
23 {
24 #if is_mingw
25     fd_ = open(filename.c_str(), O_RDONLY | O_BINARY);
26 #else
27     fd_ = open(filename.c_str(), O_RDONLY);
28 #endif
29     if (fd_ != -1) {
30         struct stat sb;
31         if (fstat(fd_, &sb) == -1) {
32             HLOGE("unable to check the file size");
33         } else {
34             HLOGD("file stat size %" PRIu64 "", sb.st_size);
35 
36             mmap_ = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd_, 0);
37             if (mmap_ == MMAP_FAILED) {
38                 HLOGE("unable to map the file size %" PRIu64 " ", sb.st_size);
39                 mmapSize_ = 0;
40             } else {
41                 mmapSize_ = sb.st_size;
42                 HLOGD("mmap build with size %" PRIu64 " ", mmapSize_);
43             }
44         }
45     }
46 }
47 
~ElfFile()48 ElfFile::~ElfFile()
49 {
50     if (mmap_ != MMAP_FAILED) {
51         munmap(mmap_, mmapSize_);
52     }
53 
54     if (fd_ != -1) {
55         close(fd_);
56         fd_ = -1;
57     }
58 }
59 
MakeUnique(const std::string & filename)60 std::unique_ptr<ElfFile> ElfFile::MakeUnique(const std::string &filename)
61 {
62     std::unique_ptr<ElfFile> file {new (std::nothrow) ElfFile(filename)};
63     if (file == nullptr) {
64         HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ElfFile() failed");
65         return nullptr;
66     }
67     if (!file->IsOpened()) {
68         HLOGE("Error in ElfFile::MakeUnique(): elf file not opended");
69         return nullptr;
70     }
71     if (!file->ParseFile()) {
72         HLOGE("parse elf file failed");
73         return nullptr;
74     }
75     return file;
76 }
77 
ParseFile()78 bool ElfFile::ParseFile()
79 {
80     if (!ParseElfHeader()) {
81         HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParseElfHeader() failed");
82         return false;
83     }
84     if (!ParsePrgHeaders()) {
85         HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParsePrgHeaders() failed");
86         return false;
87     }
88     if (!ParseSecNamesStr()) {
89         HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParseSecNamesStr() failed");
90         return false;
91     }
92     if (!ParseSecHeaders()) {
93         HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParseSecHeaders() failed");
94         return false;
95     }
96     return true;
97 }
98 
ParseElfHeader()99 bool ElfFile::ParseElfHeader()
100 {
101     size_t ret = lseek(fd_, 0, SEEK_SET);
102     if (ret != 0) {
103         HLOGW("lseek ret %zu", ret);
104         return false;
105     }
106     HLOG_ASSERT(ret == 0);
107     unsigned char ehdrBuf[ehdr64Size] {0};
108     ret = ReadFile(ehdrBuf, ehdr64Size);
109     if (ret < ehdr64Size) {
110         HLOGW("file size not enough, try read %zu, only have %zu", ehdr64Size, ret);
111     }
112     HLOG_ASSERT(ret > 0);
113     ehdr_ = ElfHeader::MakeUnique(ehdrBuf, ret);
114     return !(ehdr_ == nullptr);
115 }
116 
ParsePrgHeaders()117 bool ElfFile::ParsePrgHeaders()
118 {
119     size_t phdrSize = ehdr_->phdrEntSize_;
120     size_t numPhdrs = ehdr_->phdrNumEnts_;
121     uint64_t phdrOffset = ehdr_->phdrOffset_;
122     int64_t ret = lseek(fd_, phdrOffset, SEEK_SET);
123     HLOG_ASSERT(ret == static_cast<int64_t>(phdrOffset));
124     char *phdrsBuf = new (std::nothrow) char[phdrSize * numPhdrs];
125     if (phdrsBuf == nullptr) {
126         HLOGE("Error in ELF::ElfFile::ParsePrgHeaders(): new failed");
127         return false;
128     }
129     if (memset_s(phdrsBuf, phdrSize * numPhdrs, 0, phdrSize * numPhdrs) != EOK) {
130         HLOGE("memset_s failed");
131     }
132     ret = ReadFile(phdrsBuf, phdrSize * numPhdrs);
133     if (ret != static_cast<int64_t>(phdrSize * numPhdrs)) {
134         delete[] phdrsBuf;
135         phdrsBuf = nullptr;
136         return false;
137     }
138     char *phdrBuf = phdrsBuf;
139     for (size_t count = 0; count < numPhdrs; ++count) {
140         std::unique_ptr<ProgramHeader> phdr = ProgramHeader::MakeUnique(phdrBuf, phdrSize);
141         if (phdr == nullptr) {
142             delete[] phdrsBuf;
143             phdrsBuf = nullptr;
144             HLOGE("Error in Elf::ParsePrgHeaders(): ProgramHeader::MakeUnique() failed");
145             return false;
146         }
147         phdrs_.push_back(std::move(phdr));
148         phdrBuf += phdrSize;
149     }
150     delete[] phdrsBuf;
151     phdrsBuf = nullptr;
152     return true;
153 }
154 
ParseSecNamesStr()155 bool ElfFile::ParseSecNamesStr()
156 {
157     // get string table section header
158     size_t shdrSize = ehdr_->shdrEntSize_;
159     size_t shdrIndex = ehdr_->shdrStrTabIdx_;
160     uint64_t shdrOffset = ehdr_->shdrOffset_ + shdrIndex * shdrSize;
161     int64_t ret = lseek(fd_, shdrOffset, SEEK_SET);
162     HLOG_ASSERT(ret == static_cast<int64_t>(shdrOffset));
163     char *shdrBuf = new (std::nothrow) char[shdrSize];
164     if (shdrBuf == nullptr) {
165         HLOGE("Error in ElfFile::ParseSecNamesStr(): new failed");
166         return false;
167     }
168     if (memset_s(shdrBuf, shdrSize, 0, shdrSize) != EOK) {
169         HLOGE("memset_s failed");
170     }
171     ret = ReadFile(shdrBuf, shdrSize);
172     HLOG_ASSERT(ret == static_cast<int64_t>(shdrSize));
173     const std::string secName {".shstrtab"};
174     shdrs_[secName] = SectionHeader::MakeUnique(shdrBuf, shdrSize, shdrIndex);
175     if (shdrs_[secName] == nullptr) {
176         HLOGE("Error in ElfFile::ParseSecNamesStr(): SectionHeader::MakeUnique() failed");
177         delete[] shdrBuf;
178         shdrBuf = nullptr;
179         return false;
180     }
181     delete[] shdrBuf;
182     shdrBuf = nullptr;
183 
184     // get content of string section table
185     uint64_t secOffset = shdrs_[secName]->fileOffset_;
186     size_t secSize = shdrs_[secName]->secSize_;
187     ret = lseek(fd_, secOffset, SEEK_SET);
188     HLOG_ASSERT(ret == static_cast<int64_t>(secOffset));
189     char *secNamesBuf = new (std::nothrow) char[secSize];
190     if (secNamesBuf == nullptr) {
191         return false;
192     }
193     if (memset_s(secNamesBuf, secSize, '\0', secSize) != EOK) {
194         delete[] secNamesBuf;
195         secNamesBuf = nullptr;
196         HLOGE("memset_s failed");
197         return false;
198     }
199     ret = ReadFile(secNamesBuf, secSize);
200     if (ret != static_cast<int64_t>(secSize)) {
201         delete[] secNamesBuf;
202         secNamesBuf = nullptr;
203         return false;
204     }
205     secNamesStr_ = std::string(secNamesBuf, secNamesBuf + secSize);
206     delete[] secNamesBuf;
207     secNamesBuf = nullptr;
208     return true;
209 }
210 
ParseSecHeaders()211 bool ElfFile::ParseSecHeaders()
212 {
213     size_t shdrSize = ehdr_->shdrEntSize_;
214     size_t numShdrs = ehdr_->shdrNumEnts_;
215     uint64_t shdrOffset = ehdr_->shdrOffset_;
216     int64_t ret = lseek(fd_, shdrOffset, SEEK_SET);
217     HLOG_ASSERT(ret == static_cast<int64_t>(shdrOffset));
218     char *shdrsBuf = new (std::nothrow) char[shdrSize * numShdrs];
219     if (shdrsBuf == nullptr) {
220         HLOGE("Error in ELF::ElfFile::ParseSecHeaders(): new failed");
221         return false;
222     }
223     if (memset_s(shdrsBuf, shdrSize * numShdrs, '\0', shdrSize * numShdrs) != EOK) {
224         HLOGE("memset_s failed");
225     }
226     ret = ReadFile(shdrsBuf, shdrSize * numShdrs);
227     HLOG_ASSERT(ret == static_cast<int64_t>(shdrSize * numShdrs));
228     char *shdrBuf = shdrsBuf;
229     for (size_t count = 0; count < numShdrs; ++count) {
230         if (count == ehdr_->shdrStrTabIdx_) {
231             shdrBuf += shdrSize;
232             continue;
233         }
234         std::unique_ptr<SectionHeader> shdr = SectionHeader::MakeUnique(shdrBuf, shdrSize, count);
235         if (shdr == nullptr) {
236             delete[] shdrsBuf;
237             shdrsBuf = nullptr;
238             return false;
239         }
240         std::string secName = GetSectionName(shdr->nameIndex_);
241         shdrs_[secName] = std::move(shdr);
242         shdr.reset(nullptr);
243         shdrBuf += shdrSize;
244     }
245     delete[] shdrsBuf;
246     shdrsBuf = nullptr;
247     return true;
248 }
249 
ParseSymTable(const std::string secName)250 bool ElfFile::ParseSymTable(const std::string secName)
251 {
252     if (shdrs_.find(secName) == shdrs_.end()) {
253         HLOGE("Error in ELF::ElfFile::ParseSymTable(): section %s does not exist", secName.c_str());
254         return false;
255     } else {
256         return ParseSymTable(shdrs_[secName].get());
257     }
258 }
259 
ParseSymTable(const SectionHeader * shdr)260 bool ElfFile::ParseSymTable(const SectionHeader *shdr)
261 {
262     if (shdr == nullptr) {
263         return false;
264     }
265     uint64_t secOffset = shdr->fileOffset_;
266     int64_t ret = lseek(fd_, secOffset, SEEK_SET);
267     HLOG_ASSERT(ret == static_cast<int64_t>(secOffset));
268     uint64_t secSize = shdr->secSize_;
269     uint64_t entrySize = shdr->secEntrySize_;
270     char *secBuf = new (std::nothrow) char[secSize];
271     if (secBuf == nullptr) {
272         HLOGE("Error in EFL::ElfFile::ParseSymTable(): new failed");
273         return false;
274     }
275     ret = ReadFile(secBuf, secSize);
276     HLOG_ASSERT(ret == static_cast<int64_t>(secSize));
277     symTable_ = SymbolTable::MakeUnique(symNamesStr_, secBuf, secSize, entrySize);
278     if (symTable_ == nullptr) {
279         delete[] secBuf;
280         secBuf = nullptr;
281         return false;
282     }
283     delete[] secBuf;
284     secBuf = nullptr;
285     return true;
286 }
287 
ParseSymNamesStr()288 bool ElfFile::ParseSymNamesStr()
289 {
290     const std::string secName {".strtab"};
291     if (shdrs_.find(secName) == shdrs_.end()) {
292         HLOGE("Error in ElfFile::ParseSymNamesStr(): section %s  does not exist", secName.c_str());
293         return false;
294     }
295     const auto &shdr = shdrs_[secName];
296     uint64_t secOffset = shdr->fileOffset_;
297     uint64_t secSize = shdr->secSize_;
298     int64_t ret = lseek(fd_, secOffset, SEEK_SET);
299     char *secBuf = new (std::nothrow) char[secSize];
300     if (secBuf == nullptr) {
301         HLOGE("Error in ElfFile::ParsesymNamesStr(): new failed");
302         return false;
303     }
304     if (memset_s(secBuf, secSize, '\0', secSize) != EOK) {
305         HLOGE("memset failed");
306     }
307     ret = ReadFile(secBuf, secSize);
308     HLOG_ASSERT(ret == static_cast<int64_t>(secSize));
309     symNamesStr_ = std::string(secBuf, secSize);
310     if (symNamesStr_ == "") {
311         delete[] secBuf;
312         secBuf = nullptr;
313         return false;
314     }
315     delete[] secBuf;
316     secBuf = nullptr;
317     return true;
318 }
319 
ParseDynSymTable()320 bool ElfFile::ParseDynSymTable()
321 {
322     const std::string secName {".dynsym"};
323     if (shdrs_.find(secName) == shdrs_.end()) {
324         HLOGE("Error in ELF::ElfFile::ParseSymTable(): section %s does not exist", secName.c_str());
325         return false;
326     }
327     const auto &shdr = shdrs_[secName];
328     uint64_t secOffset = shdr->fileOffset_;
329     int64_t ret = lseek(fd_, secOffset, SEEK_SET);
330     HLOG_ASSERT(ret == static_cast<int64_t>(secOffset));
331     uint64_t secSize = shdr->secSize_;
332     uint64_t entrySize = shdr->secEntrySize_;
333     char *secBuf = new (std::nothrow) char[secSize];
334     if (secBuf == nullptr) {
335         HLOGE("Error in EFL::ElfFile::ParseDynSymTable(): new failed");
336         return false;
337     }
338     ret = ReadFile(secBuf, secSize);
339     HLOG_ASSERT(ret == static_cast<int64_t>(secSize));
340     dynSymTable_ = SymbolTable::MakeUnique(symNamesStr_, secBuf, secSize, entrySize);
341     if (dynSymTable_ == nullptr) {
342         delete[] secBuf;
343         secBuf = nullptr;
344         return false;
345     }
346     delete[] secBuf;
347     secBuf = nullptr;
348     return true;
349 }
350 
GetSectionName(const uint32_t startIndex)351 std::string ElfFile::GetSectionName(const uint32_t startIndex)
352 {
353     if (startIndex >= secNamesStr_.size()) {
354         HLOGF("out_of_range %s ,endIndex %d ", secNamesStr_.c_str(), startIndex);
355         return "";
356     }
357     size_t endIndex {startIndex};
358     for (; endIndex < secNamesStr_.size(); ++endIndex) {
359         if (secNamesStr_[endIndex] == '\0') {
360             break;
361         }
362     }
363     return secNamesStr_.substr(startIndex, endIndex - startIndex);
364 }
365 } // namespace NativeDaemon
366 } // namespace Developtools
367 } // namespace OHOS