• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
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 #include <elf_file.h>
16 
17 #include <cinttypes>
18 
19 namespace OHOS {
20 namespace Developtools {
21 namespace Hiebpf {
ElfFile(const std::string & filename)22 ElfFile::ElfFile(const std::string &filename)
23 {
24     fd_ = open(filename.c_str(), O_RDONLY);
25     if (fd_ != -1) {
26         struct stat sb;
27         if (fstat(fd_, &sb) == -1) {
28             HHLOGE(true, "unable to check the file size");
29         } else {
30             HHLOGD(true, "file stat size %" PRIu64 " ", sb.st_size);
31             mmap_ = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd_, 0);
32             if (mmap_ == MMAP_FAILED) {
33                 HHLOGE(true, "unable to map the file size %" PRIu64 " ", sb.st_size);
34                 mmapSize_ = 0;
35             } else {
36                 mmapSize_ = sb.st_size;
37                 HHLOGD(true, "mmap build with size %" PRIu64 " ", mmapSize_);
38             }
39         }
40     }
41 }
42 
~ElfFile()43 ElfFile::~ElfFile()
44 {
45     if (mmap_ != MMAP_FAILED) {
46         munmap(mmap_, mmapSize_);
47     }
48 
49     if (fd_ != -1) {
50         close(fd_);
51         fd_ = -1;
52     }
53 }
54 
MakeUnique(const std::string & filename)55 std::unique_ptr<ElfFile> ElfFile::MakeUnique(const std::string &filename)
56 {
57     std::unique_ptr<ElfFile> file {new (std::nothrow) ElfFile(filename)};
58     CHECK_NOTNULL(file, nullptr, "Error in ElfFile::MakeUnique(): ElfFile::ElfFile() failed");
59     CHECK_TRUE(file->IsOpened(), nullptr, "Error in ElfFile::MakeUnique(): elf file not opended");
60     CHECK_TRUE(file->ParseFile(), nullptr, "parse elf file failed");
61     return file;
62 }
63 
ParseFile()64 bool ElfFile::ParseFile()
65 {
66     CHECK_TRUE(ParseElfHeader(), false, "Error in ElfFile::MakeUnique(): ElfFile::ParseElfHeader() failed");
67     CHECK_TRUE(ParsePrgHeaders(), false, "Error in ElfFile::MakeUnique(): ElfFile::ParsePrgHeaders() failed");
68     CHECK_TRUE(ParseSecNamesStr(), false, "Error in ElfFile::MakeUnique(): ElfFile::ParseSecNamesStr() failed");
69     CHECK_TRUE(ParseSecHeaders(), false, "Error in ElfFile::MakeUnique(): ElfFile::ParseSecHeaders() failed");
70     return true;
71 }
72 
ParseElfHeader()73 bool ElfFile::ParseElfHeader()
74 {
75     ssize_t ret = lseek(fd_, 0, SEEK_SET);
76     CHECK_TRUE(ret == 0, false, "lseek ret %zu", ret);
77 
78     unsigned char ehdrBuf[ehdr64Size] {0};
79     size_t readsize = ReadFile(ehdrBuf, ehdr64Size);
80     CHECK_TRUE(readsize >= ehdr64Size, false,
81                "file size not enough, try read %zu, only have %zu", ehdr64Size, readsize);
82     ehdr_ = ElfHeader::MakeUnique(ehdrBuf, readsize);
83     return !(ehdr_ == nullptr);
84 }
85 
ParsePrgHeaders()86 bool ElfFile::ParsePrgHeaders()
87 {
88     size_t phdrSize = ehdr_->phdrEntSize_;
89     size_t numPhdrs = ehdr_->phdrNumEnts_;
90     uint64_t phdrOffset = ehdr_->phdrOffset_;
91     int64_t ret = lseek(fd_, phdrOffset, SEEK_SET);
92     if (ret != static_cast<int64_t>(phdrOffset)) {
93         return false;
94     }
95     char *phdrsBuf = new (std::nothrow) char[phdrSize * numPhdrs];
96     CHECK_NOTNULL(phdrsBuf, false, "Error in ELF::ElfFile::ParsePrgHeaders(): new failed");
97 
98     ret = ReadFile(phdrsBuf, phdrSize * numPhdrs);
99     if (ret != static_cast<int64_t>(phdrSize * numPhdrs)) {
100         delete[] phdrsBuf;
101         phdrsBuf = nullptr;
102         return false;
103     }
104     char *phdrBuf = phdrsBuf;
105     for (size_t count = 0; count < numPhdrs; ++count) {
106         std::unique_ptr<ProgramHeader> phdr = ProgramHeader::MakeUnique(phdrBuf, phdrSize);
107         if (phdr == nullptr) {
108             delete[] phdrsBuf;
109             phdrsBuf = nullptr;
110             HHLOGE(true, "Error in Elf::ParsePrgHeaders(): ProgramHeader::MakeUnique() failed");
111             return false;
112         }
113         phdrs_.push_back(std::move(phdr));
114         phdrBuf += phdrSize;
115     }
116     delete[] phdrsBuf;
117     phdrsBuf = nullptr;
118     return true;
119 }
120 
ParseSecNamesStr()121 bool ElfFile::ParseSecNamesStr()
122 {
123     // get string table section header
124     size_t shdrSize = ehdr_->shdrEntSize_;
125     size_t shdrIndex = ehdr_->shdrStrTabIdx_;
126     uint64_t shdrOffset = ehdr_->shdrOffset_ + ((uint64_t)shdrIndex) * shdrSize;
127     int64_t ret = lseek(fd_, shdrOffset, SEEK_SET);
128     if (ret != static_cast<int64_t>(shdrOffset)) {
129         return false;
130     }
131 
132     char *shdrBuf = new (std::nothrow) char[shdrSize];
133     CHECK_NOTNULL(shdrBuf, false, "Error in ElfFile::ParseSecNamesStr(): new failed");
134 
135     ret = ReadFile(shdrBuf, shdrSize);
136     if (ret != static_cast<int64_t>(shdrSize)) {
137         delete[] shdrBuf;
138         shdrBuf = nullptr;
139         return false;
140     }
141     const std::string secName {".shstrtab"};
142     shdrs_[secName] = SectionHeader::MakeUnique(shdrBuf, shdrSize, shdrIndex);
143     if (shdrs_[secName] == nullptr) {
144         HHLOGE(true, "Error in ElfFile::ParseSecNamesStr(): SectionHeader::MakeUnique() failed");
145         delete[] shdrBuf;
146         shdrBuf = nullptr;
147         return false;
148     }
149     delete[] shdrBuf;
150     shdrBuf = nullptr;
151 
152     // get content of string section table
153     uint64_t secOffset = shdrs_[secName]->fileOffset_;
154     size_t secSize = shdrs_[secName]->secSize_;
155     ret = lseek(fd_, secOffset, SEEK_SET);
156     if (ret != static_cast<int64_t>(secOffset)) {
157         return false;
158     }
159     char *secNamesBuf = new (std::nothrow) char[secSize];
160     CHECK_NOTNULL(secNamesBuf, false, "Error in ElfFile::ParseSecNamesStr(): new secNamesBuf failed");
161     ret = ReadFile(secNamesBuf, secSize);
162     if (ret != static_cast<int64_t>(secSize)) {
163         delete[] secNamesBuf;
164         secNamesBuf = nullptr;
165         return false;
166     }
167     secNamesStr_ = std::string(secNamesBuf, secNamesBuf + secSize);
168     delete[] secNamesBuf;
169     secNamesBuf = nullptr;
170     return true;
171 }
172 
ParseSecHeaders()173 bool ElfFile::ParseSecHeaders()
174 {
175     size_t shdrSize = ehdr_->shdrEntSize_;
176     size_t numShdrs = ehdr_->shdrNumEnts_;
177     uint64_t shdrOffset = ehdr_->shdrOffset_;
178     int64_t ret = lseek(fd_, shdrOffset, SEEK_SET);
179     if (ret != static_cast<int64_t>(shdrOffset)) {
180         return false;
181     }
182     char *shdrsBuf = new (std::nothrow) char[shdrSize * numShdrs];
183     CHECK_NOTNULL(shdrsBuf, false, "Error in ELF::ElfFile::ParseSecHeaders(): new failed");
184 
185     ret = ReadFile(shdrsBuf, shdrSize * numShdrs);
186     if (ret != static_cast<int64_t>(shdrSize * numShdrs)) {
187         delete[] shdrsBuf;
188         shdrsBuf = nullptr;
189         return false;
190     }
191 
192     char *shdrBuf = shdrsBuf;
193     for (size_t count = 0; count < numShdrs; ++count) {
194         if (count == ehdr_->shdrStrTabIdx_) {
195             shdrBuf += shdrSize;
196             continue;
197         }
198         std::unique_ptr<SectionHeader> shdr = SectionHeader::MakeUnique(shdrBuf, shdrSize, count);
199         if (shdr == nullptr) {
200             delete[] shdrsBuf;
201             shdrsBuf = nullptr;
202             return false;
203         }
204         std::string secName = GetSectionName(shdr->nameIndex_);
205         shdrs_[secName] = std::move(shdr);
206         shdr.reset(nullptr);
207         shdrBuf += shdrSize;
208     }
209     delete[] shdrsBuf;
210     shdrsBuf = nullptr;
211     return true;
212 }
213 
GetSectionName(const uint32_t startIndex)214 std::string ElfFile::GetSectionName(const uint32_t startIndex)
215 {
216     if (startIndex >= secNamesStr_.size()) {
217         HHLOGF(true, "out_of_range %s ,endIndex %d ", secNamesStr_.c_str(), startIndex);
218         return "";
219     }
220     size_t endIndex {startIndex};
221     for (; endIndex < secNamesStr_.size(); ++endIndex) {
222         if (secNamesStr_[endIndex] == '\0') {
223             break;
224         }
225     }
226     return secNamesStr_.substr(startIndex, endIndex - startIndex);
227 }
228 
229 // ElfHeader
MakeUnique(unsigned char * const ehdrBuf,const std::size_t bufSize)230 std::unique_ptr<ElfHeader> ElfHeader::MakeUnique(unsigned char * const ehdrBuf,
231                                                  const std::size_t bufSize)
232 {
233     std::unique_ptr<ElfHeader> ehdr {new (std::nothrow) ElfHeader()};
234     CHECK_NOTNULL(ehdr, nullptr, "ElfHeader() failed");
235     CHECK_TRUE(ehdr->Init(ehdrBuf, bufSize), nullptr, "ElfHeader::Init(ehdrBuf, bufSize) failed\n");
236     return ehdr;
237 }
238 
Init(unsigned char * const ehdrBuf,const std::size_t bufSize)239 bool ElfHeader::Init(unsigned char * const ehdrBuf, const std::size_t bufSize)
240 {
241     std::string magicStr {ehdrBuf, ehdrBuf + SELFMAG};
242     std::string elfMagic {ELFMAG};
243     CHECK_TRUE(magicStr.compare(elfMagic) == 0, false, "elf magic not found");
244     std::copy(ehdrBuf, ehdrBuf + EI_NIDENT, ehdrIdent_);
245 
246     if (ehdrBuf[EI_CLASS] == ELFCLASS32 and ParseElf32Header(ehdrBuf, bufSize)) {
247         return true;
248     }
249     if (ehdrBuf[EI_CLASS] == ELFCLASS64 and ParseElf64Header(ehdrBuf, bufSize)) {
250         return true;
251     }
252     HHLOGE(true, "init elf header failed, elf header buffer dumped");
253     return false;
254 }
255 
ParseElf32Header(unsigned char * const ehdrBuf,const std::size_t bufSize)256 bool ElfHeader::ParseElf32Header(unsigned char * const ehdrBuf, const std::size_t bufSize)
257 {
258     if (bufSize < ehdr32Size) {
259         HHLOGE(true, "bad elf32 header buffer");
260         return false;
261     }
262     size_t curIndex {EI_NIDENT};
263     uint16_t *u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
264     type_ = u2Buf[0];
265     curIndex += sizeof(uint16_t);
266 
267     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
268     machine_ = u2Buf[0];
269     curIndex += sizeof(uint16_t);
270 
271     uint32_t *u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
272     elfVersion_ = u4Buf[0];
273     curIndex += sizeof(uint32_t);
274 
275     u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
276     prgEntryVaddr_ = u4Buf[0];
277     curIndex += sizeof(uint32_t);
278 
279     u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
280     phdrOffset_ = u4Buf[0];
281     curIndex += sizeof(uint32_t);
282 
283     u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
284     shdrOffset_ = u4Buf[0];
285     curIndex += sizeof(uint32_t);
286 
287     u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
288     ehdrFlags_ = u4Buf[0];
289     curIndex += sizeof(uint32_t);
290 
291     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
292     ehdrSize_ = u2Buf[0];
293     curIndex += sizeof(uint16_t);
294 
295     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
296     phdrEntSize_ = u2Buf[0];
297     curIndex += sizeof(uint16_t);
298 
299     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
300     phdrNumEnts_ = u2Buf[0];
301     curIndex += sizeof(uint16_t);
302 
303     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
304     shdrEntSize_ = u2Buf[0];
305     curIndex += sizeof(uint16_t);
306 
307     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
308     shdrNumEnts_ = u2Buf[0];
309     curIndex += sizeof(uint16_t);
310 
311     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
312     shdrStrTabIdx_ = u2Buf[0];
313 
314     return true;
315 }
316 
ParseElf64Header(unsigned char * const ehdrBuf,const std::size_t bufSize)317 bool ElfHeader::ParseElf64Header(unsigned char * const ehdrBuf, const std::size_t bufSize)
318 {
319     CHECK_TRUE(bufSize >= ehdr64Size, false, "bad elf64 header buffer");
320     size_t curIndex {EI_NIDENT};
321     uint16_t *u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
322     type_ = u2Buf[0];
323     curIndex += sizeof(uint16_t);
324 
325     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
326     machine_ = u2Buf[0];
327     curIndex += sizeof(uint16_t);
328 
329     uint32_t *u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
330     elfVersion_ = u4Buf[0];
331     curIndex += sizeof(uint32_t);
332 
333     uint64_t *u8Buf = reinterpret_cast<uint64_t *>(ehdrBuf + curIndex);
334     prgEntryVaddr_ = u8Buf[0];
335     curIndex += sizeof(uint64_t);
336 
337     u8Buf = reinterpret_cast<uint64_t *>(ehdrBuf + curIndex);
338     phdrOffset_ = u8Buf[0];
339     curIndex += sizeof(uint64_t);
340 
341     u8Buf = reinterpret_cast<uint64_t *>(ehdrBuf + curIndex);
342     shdrOffset_ = u8Buf[0];
343     curIndex += sizeof(uint64_t);
344 
345     u4Buf = reinterpret_cast<uint32_t *>(ehdrBuf + curIndex);
346     ehdrFlags_ = u4Buf[0];
347     curIndex += sizeof(uint32_t);
348 
349     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
350     ehdrSize_ = u2Buf[0];
351     curIndex += sizeof(uint16_t);
352 
353     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
354     phdrEntSize_ = u2Buf[0];
355     curIndex += sizeof(uint16_t);
356 
357     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
358     phdrNumEnts_ = u2Buf[0];
359     curIndex += sizeof(uint16_t);
360 
361     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
362     shdrEntSize_ = u2Buf[0];
363     curIndex += sizeof(uint16_t);
364 
365     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
366     shdrNumEnts_ = static_cast<long long>(*u2Buf);
367     curIndex += sizeof(uint16_t);
368 
369     u2Buf = reinterpret_cast<uint16_t *>(ehdrBuf + curIndex);
370     shdrStrTabIdx_ = u2Buf[0];
371 
372     return true;
373 }
374 
375 // SectionHeader
376 enum class NUMBER : int {
377     ZERO = 0,
378     ONE = 1,
379     TWO = 2,
380     THREE = 3,
381     FOUR = 4,
382     FIVE = 5,
383     SIX = 6,
384     SEVEN = 7,
385     EIGHT = 8,
386     NINE = 9,
387     TEN = 10,
388     ELEVEN = 11,
389     TWELVE = 12,
390 };
391 
MakeUnique(char * const shdrBuf,const size_t bufSize,const size_t index)392 std::unique_ptr<SectionHeader> SectionHeader::MakeUnique(char * const shdrBuf, const size_t bufSize,
393                                                          const size_t index)
394 {
395     std::unique_ptr<SectionHeader> shdr {new (std::nothrow) SectionHeader()};
396     if (shdr == nullptr) {
397         return nullptr;
398     }
399     CHECK_TRUE(shdr->Init(shdrBuf, bufSize, index), nullptr, "SectionHeader::Init(shdrBuf, bufSize, index) failed");
400     return shdr;
401 }
402 
ParseSecHeader32(char * const shdrBuf)403 bool SectionHeader::ParseSecHeader32(char * const shdrBuf)
404 {
405     uint32_t *u4Buf = reinterpret_cast<uint32_t *>(shdrBuf);
406     int index {0};
407     nameIndex_ = u4Buf[index];
408     index = static_cast<int>(NUMBER::ONE);
409     secType_ = u4Buf[index];
410     index = static_cast<int>(NUMBER::TWO);
411     secFlags_ = u4Buf[index];
412     index = static_cast<int>(NUMBER::SIX);
413     link_ = u4Buf[index];
414     index = static_cast<int>(NUMBER::SEVEN);
415     info_ = u4Buf[index];
416     index = static_cast<int>(NUMBER::THREE);
417     secVaddr_ = u4Buf[index];
418     index = static_cast<int>(NUMBER::FOUR);
419     fileOffset_ = u4Buf[index];
420     index = static_cast<int>(NUMBER::FIVE);
421     secSize_ = u4Buf[index];
422     index = static_cast<int>(NUMBER::EIGHT);
423     secAddrAlign_ = u4Buf[index];
424     index = static_cast<int>(NUMBER::NINE);
425     secEntrySize_ = u4Buf[index];
426     return true;
427 }
428 
ParseSecHeader64(char * const shdrBuf)429 bool SectionHeader::ParseSecHeader64(char * const shdrBuf)
430 {
431     uint64_t *u8Buf = reinterpret_cast<uint64_t *>(shdrBuf);
432     uint32_t *u4Buf = reinterpret_cast<uint32_t *>(shdrBuf);
433     size_t index {0};
434     nameIndex_ = u4Buf[index];
435     index = static_cast<size_t>(NUMBER::ONE);
436     secType_ = u4Buf[index];
437     secFlags_ = u8Buf[index];
438     index = static_cast<size_t>(NUMBER::TEN);
439     link_ = u4Buf[index];
440     index = static_cast<size_t>(NUMBER::ELEVEN);
441     info_ = u4Buf[index];
442     index = static_cast<size_t>(NUMBER::TWO);
443     secVaddr_ = u8Buf[index];
444     index = static_cast<size_t>(NUMBER::THREE);
445     fileOffset_ = u8Buf[index];
446     index = static_cast<size_t>(NUMBER::FOUR);
447     secSize_ = u8Buf[index];
448     index = static_cast<size_t>(NUMBER::SIX);
449     secAddrAlign_ = u8Buf[index];
450     index = static_cast<size_t>(NUMBER::SEVEN);
451     secEntrySize_ = u8Buf[index];
452     return true;
453 }
454 
455 // ProgramHeader
MakeUnique(char * const phdrBuf,const size_t bufSize)456 std::unique_ptr<ProgramHeader> ProgramHeader::MakeUnique(char * const phdrBuf, const size_t bufSize)
457 {
458     std::unique_ptr<ProgramHeader> phdr {new (std::nothrow) ProgramHeader()};
459     CHECK_NOTNULL(phdr, nullptr, "ProgramHeader() failed");
460     CHECK_TRUE(phdr->Init(phdrBuf, bufSize), nullptr, "ProgramHeader::Init(phdrBuf, bufSize) failed");
461     return phdr;
462 }
463 
ParsePrgHeader32(char * const phdrBuf)464 bool ProgramHeader::ParsePrgHeader32(char * const phdrBuf)
465 {
466     uint32_t *u4Buf = reinterpret_cast<uint32_t *>(phdrBuf);
467     size_t index {0};
468     type_ = u4Buf[index];
469     ++index;
470     offset_ = u4Buf[index];
471     ++index;
472     vaddr_ = u4Buf[index];
473     ++index;
474     paddr_ = u4Buf[index];
475     ++index;
476     fileSize_ = u4Buf[index];
477     ++index;
478     memSize_ = u4Buf[index];
479     ++index;
480     flags_ = u4Buf[index];
481     ++index;
482     secAlign_ = u4Buf[index];
483     return true;
484 }
485 
ParsePrgHeader64(char * const phdrBuf)486 bool ProgramHeader::ParsePrgHeader64(char * const phdrBuf)
487 {
488     uint32_t *u4Buf = reinterpret_cast<uint32_t *>(phdrBuf);
489     size_t index {0};
490     type_ = u4Buf[index];
491     ++index;
492     flags_ = u4Buf[index];
493 
494     uint64_t *u8Buf = reinterpret_cast<uint64_t *>(phdrBuf);
495     offset_ = u8Buf[index];
496     ++index;
497     vaddr_ = u8Buf[index];
498     ++index;
499     paddr_ = u8Buf[index];
500     ++index;
501     fileSize_ = u8Buf[index];
502     ++index;
503     memSize_ = u8Buf[index];
504     ++index;
505     secAlign_ = u8Buf[index];
506     return true;
507 }
508 } // namespace Hiebpf
509 } // namespace Developtools
510 } // namespace OHOS
511