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