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