1 /*
2  * Copyright (c) 2023-2024 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_imitate.h"
17 
18 #include <cstdlib>
19 #include <securec.h>
20 #include <string>
21 #include <sys/mman.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <utility>
25 #include "dfx_define.h"
26 #include "dfx_log.h"
27 #include "dfx_util.h"
28 #include <iostream>
29 
30 #ifndef PAGE_SIZE
31 #define PAGE_SIZE 4096
32 #endif
33 
34 namespace {
35 const std::string EHDR_32 {"/data/test/resource/testdata/ehdr_from_readelf_32"};
36 const std::string EHDR_64 {"/data/test/resource/testdata/ehdr_from_readelf_64"};
37 const std::string SHDRS_32 {"/data/test/resource/testdata/shdrs_from_readelf_32"};
38 const std::string SHDRS_64 {"/data/test/resource/testdata/shdrs_from_readelf_64"};
39 const std::string PHDRS_32 {"/data/test/resource/testdata/phdrs_from_readelf_32"};
40 const std::string PHDRS_64 {"/data/test/resource/testdata/phdrs_from_readelf_64"};
41 const std::string SYMS_32 {"/data/test/resource/testdata/syms_from_readelf_32"};
42 const std::string SYMS_64 {"/data/test/resource/testdata/syms_from_readelf_64"};
43 } // namespace
44 namespace OHOS {
45 namespace HiviewDFX {
~ElfImitate()46 ElfImitate::~ElfImitate()
47 {
48     if (ehdrFP_ != nullptr) {
49         fclose(ehdrFP_);
50         ehdrFP_ = nullptr;
51     }
52     if (shdrFP_ != nullptr) {
53         fclose(shdrFP_);
54         shdrFP_ = nullptr;
55     }
56     if (phdrFP_ != nullptr) {
57         fclose(phdrFP_);
58         phdrFP_ = nullptr;
59     }
60     if (symTabFP_ != nullptr) {
61         fclose(symTabFP_);
62         symTabFP_ = nullptr;
63     }
64 }
65 
GetNextLine(FILE * fp,int * status)66 static const std::string GetNextLine(FILE *fp, int *status)
67 {
68     constexpr int bufSize {128};
69     char buf[bufSize] = {0};
70     if (fgets(buf, bufSize, fp) == nullptr) {
71         DFXLOG_ERROR("%s", "fgets() failed");
72         *status = -1;
73         return "";
74     }
75     *status = 0;
76     std::string res {buf};
77     if (res.back() == '\n') {
78         res.pop_back();
79     }
80     return res;
81 }
StringSplit(std::string src,const std::string split)82 std::vector<std::string> ElfImitate::StringSplit(std::string src, const std::string split)
83 {
84     std::vector<std::string> result;
85 
86     if (!split.empty()) {
87         size_t pos = 0;
88         while ((pos = src.find(split)) != std::string::npos) {
89             // split
90             std::string token = src.substr(0, pos);
91             if (!token.empty()) {
92                 result.push_back(token);
93             }
94             src.erase(0, pos + split.length());
95         }
96     }
97 
98     if (!src.empty()) {
99         result.push_back(src);
100     }
101     return result;
102 }
103 
ParseAllHeaders(ElfFileType fileType)104 bool ElfImitate::ParseAllHeaders(ElfFileType fileType)
105 {
106     if (fileType == ElfFileType::ELF32) {
107         ehdrFP_ = std::fopen(EHDR_32.c_str(), "rb");
108         if (ehdrFP_ == nullptr) {
109             DFXLOG_ERROR("%s", "fopen(EHDR_32, \"r\") failed");
110         }
111         shdrFP_ = fopen(SHDRS_32.c_str(), "rb");
112         if (shdrFP_ == nullptr) {
113             DFXLOG_ERROR("%s", "fopen(SHDRS_32, \"r\") failed");
114         }
115         phdrFP_ = fopen(PHDRS_32.c_str(), "rb");
116         if (phdrFP_ == nullptr) {
117             DFXLOG_ERROR("%s", "fopen(PHDRS_32, \"r\") failed");
118         }
119         symTabFP_ = fopen(SYMS_32.c_str(), "rb");
120         if (symTabFP_ == nullptr) {
121             DFXLOG_ERROR("%s", "fopen(SYMS_32, \"r\") failed");
122         }
123     } else if (fileType == ElfFileType::ELF64) {
124         ehdrFP_ = fopen(EHDR_64.c_str(), "rb");
125         if (ehdrFP_ == nullptr) {
126             DFXLOG_ERROR("%s", "fopen(EHDR_64, \"r\") failed");
127         }
128         shdrFP_ = fopen(SHDRS_64.c_str(), "rb");
129         if (shdrFP_ == nullptr) {
130             DFXLOG_ERROR("%s", "fopen(SHDRS_64, \"r\") failed");
131         }
132         phdrFP_ = fopen(PHDRS_64.c_str(), "rb");
133         if (phdrFP_ == nullptr) {
134             DFXLOG_ERROR("%s", "fopen(PHDRS_64, \"r\") failed");
135         }
136         symTabFP_ = fopen(SYMS_64.c_str(), "rb");
137         if (symTabFP_ == nullptr) {
138             DFXLOG_ERROR("%s", "fopen(SYMS_64, \"r\") failed");
139         }
140     }
141     if (!ParseElfHeaders()) {
142         DFXLOG_WARN("%s", "ParseElfHeaders failed");
143         return false;
144     }
145 
146     if (!ParseProgramHeaders(fileType)) {
147         DFXLOG_WARN("%s", "ParseProgramHeaders failed");
148         return false;
149     }
150 
151     if (!ParseSectionHeaders(fileType)) {
152         DFXLOG_WARN("%s", "ReadSectionHeaders failed");
153         return false;
154     }
155     if (!ParseElfSymbols()) {
156         DFXLOG_WARN("%s", "ParseElfSymbols failed");
157         return false;
158     }
159     return true;
160 }
161 
ParseElfHeaders()162 bool ElfImitate::ParseElfHeaders()
163 {
164     if (ehdrFP_ == nullptr) {
165         DFXLOG_ERROR("%s", "param is null");
166         return false;
167     }
168     int status {0};
169     // drop header line
170     GetNextLine(ehdrFP_, &status);
171     if (!GetMagic(ehdrFP_)) {
172         DFXLOG_ERROR("%s", "ElfImitate::InitMagic(ehdrFP_) failed:");
173         return false;
174     }
175     if (!GetClass(ehdrFP_)) {
176         DFXLOG_ERROR("%s", "ElfImitate::InitClass(ehdrFP_) failed:");
177         return false;
178     }
179     constexpr int numSkip {6};
180     // drop unused 6 lines
181     for (int count = 0; count < numSkip; ++count) {
182         GetNextLine(ehdrFP_, &status);
183     }
184     if (!GetMachine(ehdrFP_)) {
185         DFXLOG_ERROR("%s", "ElfImitate::InitMachine(ehdrFP_) failed:");
186     }
187 
188     if (machine_ == "ARM") {
189         archType_ = ARCH_ARM;
190     } else if (machine_ == "80386") {
191         archType_ = ARCH_X86;
192     } else if (machine_ == "AARCH64") {
193         archType_ = ARCH_ARM64;
194     } else if (machine_ == "X86-64") {
195         archType_ = ARCH_X86_64;
196     } else {
197         DFXLOG_WARN("Failed the machine = %s", machine_.c_str());
198     }
199 
200     if (!GetEntryAddr(ehdrFP_)) {
201         DFXLOG_ERROR("%s", "ElfImitate::InitEntryAddr(ehdrFP_) failed:");
202         return false;
203     }
204     if (!GetPrgOffset(ehdrFP_)) {
205         DFXLOG_ERROR("%s", "ElfImitate::InitPrgOffset(ehdrFP_) failed:");
206         return false;
207     }
208     if (!GetSecOffset(ehdrFP_)) {
209         DFXLOG_ERROR("%s", "ElfImitate::InitSecOffset(ehdrFP_) failed:");
210         return false;
211     }
212     if (!GetFlag(ehdrFP_)) {
213         DFXLOG_ERROR("%s", "ElfImitate::InitFlag(ehdrFP_) failed:");
214         return false;
215     }
216     if (!GetEhdrSize(ehdrFP_)) {
217         DFXLOG_ERROR("%s", "ElfImitate::InitEhdrSize(ehdrFP_) failed:");
218         return false;
219     }
220     if (!GetPhdrSize(ehdrFP_)) {
221         DFXLOG_ERROR("%s", "ElfImitate::InitPhdrSize(ehdrFP_) failed:");
222         return false;
223     }
224     if (!GetNumPhdrs(ehdrFP_)) {
225         DFXLOG_ERROR("%s", "ElfImitate::InitNumPhdrs(ehdrFP_) failed:");
226         return false;
227     }
228     if (!GetShdrSize(ehdrFP_)) {
229         DFXLOG_ERROR("%s", "ElfImitate::InitShdrSize(ehdrFP_) failed:");
230         return false;
231     }
232     if (!GetNumShdrs(ehdrFP_)) {
233         DFXLOG_ERROR("%s", "ElfImitate::InitNumShdrs(ehdrFP_) failed:");
234         return false;
235     }
236     if (!GetShdrStrTabIdx(ehdrFP_)) {
237         DFXLOG_ERROR("%s", "ElfImitate::InitShdrStrTabIdx(ehdrFP_) failed:");
238         return false;
239     }
240     elfSize_ = shdrOffset_ + shdrEntSize_ * shdrNumEnts_;
241     return true;
242 }
GetMagic(FILE * const fp)243 bool ElfImitate::GetMagic(FILE * const fp)
244 {
245     if (fp == nullptr) {
246         DFXLOG_ERROR("%s", "param is null");
247         return false;
248     }
249     int status {0};
250     std::string magicLine = GetNextLine(fp, &status);
251     if (status == -1) {
252         DFXLOG_ERROR("%s", "early end");
253         return false;
254     }
255     auto tmp = StringSplit(magicLine, " ");
256     std::vector<std::string> strVec {tmp.begin() + 1, tmp.end()};
257     if (strVec.size() != EI_NIDENT) {
258         DFXLOG_ERROR("%s", "line format incorrect:");
259         DFXLOG_ERROR("    line = %s", magicLine.c_str());
260         return false;
261     }
262     for (std::size_t count = 0; count < strVec.size(); ++count) {
263         std::string valStr = strVec[count];
264         constexpr int base {16};
265         ehdrIdent_[count] = static_cast<unsigned char>(std::stoul(valStr, nullptr, base));
266     }
267     return true;
268 }
269 
GetClass(FILE * const fp)270 bool ElfImitate::GetClass(FILE * const fp)
271 {
272     if (fp == nullptr) {
273         DFXLOG_ERROR("%s", "param is null");
274         return false;
275     }
276     int status {0};
277     std::string classLine = GetNextLine(fp, &status);
278     if (status == -1) {
279         DFXLOG_ERROR("%s", "early end");
280         return false;
281     }
282     auto strVec = StringSplit(classLine, " ");
283     constexpr int len {2};
284     if (strVec.size() != len) {
285         DFXLOG_ERROR("%s", "line format incorrect:");
286         DFXLOG_ERROR("    line = %s", classLine.c_str());
287         return false;
288     }
289     if (strVec.back() == "ELF32") {
290         classType_ = ELFCLASS32;
291     } else if (strVec.back() == "ELF64") {
292         classType_ = ELFCLASS64;
293     }
294     return true;
295 }
296 
GetMachine(FILE * const fp)297 bool ElfImitate::GetMachine(FILE * const fp)
298 {
299     int status {0};
300     std::string machineLine = GetNextLine(fp, &status);
301     if (status == -1) {
302         DFXLOG_ERROR("%s", "early end");
303         return false;
304     }
305     auto strVec = StringSplit(machineLine, " ");
306     constexpr int len {2};
307     if (strVec.size() != len) {
308         DFXLOG_ERROR("%s", "line format incorrect:");
309         DFXLOG_ERROR("    line = %s", machineLine.c_str());
310         return false;
311     }
312     machine_ = strVec.back();
313     return true;
314 }
GetEntryAddr(FILE * const fp)315 bool ElfImitate::GetEntryAddr(FILE * const fp)
316 {
317     int status {0};
318     std::string entryLine = GetNextLine(fp, &status);
319     if (status == -1) {
320         DFXLOG_ERROR("%s", "early end");
321         return false;
322     }
323     auto strVec = StringSplit(entryLine, " ");
324     constexpr int len {2};
325     if (strVec.size() != len) {
326         DFXLOG_ERROR("%s", "line format incorrect:");
327         DFXLOG_ERROR("    line = %s", entryLine.c_str());
328         return false;
329     }
330     std::string entryStr = strVec.back();
331     constexpr int base {16};
332     prgEntryVaddr_ = static_cast<uint64_t>(std::stoull(entryStr, nullptr, base));
333     return true;
334 }
335 
GetPrgOffset(FILE * const fp)336 bool ElfImitate::GetPrgOffset(FILE * const fp)
337 {
338     int status {0};
339     std::string line = GetNextLine(fp, &status);
340     if (status == -1) {
341         DFXLOG_ERROR("%s", "early end");
342         return false;
343     }
344     auto strVec = StringSplit(line, " ");
345     constexpr int len {5};
346     if (strVec.size() != len) {
347         DFXLOG_ERROR("%s", "line format incorrect:");
348         DFXLOG_ERROR("    line = %s", line.c_str());
349         return false;
350     }
351     constexpr int valIndex {1};
352     std::string valStr = strVec[valIndex];
353     phdrOffset_ = static_cast<uint64_t>(std::stoull(valStr));
354     return true;
355 }
356 
GetSecOffset(FILE * const fp)357 bool ElfImitate::GetSecOffset(FILE * const fp)
358 {
359     int status {0};
360     std::string line = GetNextLine(fp, &status);
361     if (status == -1) {
362         DFXLOG_ERROR("%s", "early end");
363         return false;
364     }
365     auto strVec = StringSplit(line, " ");
366     constexpr int len {8};
367     if (strVec.size() != len) {
368         DFXLOG_ERROR("%s", "line format incorrect:");
369         DFXLOG_ERROR("    line = %s", line.c_str());
370         return false;
371     }
372     constexpr int valIndex {4};
373     std::string valStr = strVec[valIndex];
374     shdrOffset_ = static_cast<uint64_t>(std::stoull(valStr));
375     return true;
376 }
377 
GetFlag(FILE * const fp)378 bool ElfImitate::GetFlag(FILE * const fp)
379 {
380     int status {0};
381     std::string line = GetNextLine(fp, &status);
382     if (status == -1) {
383         DFXLOG_ERROR("%s", "early end");
384         return false;
385     }
386     auto strVec = StringSplit(line, " ");
387     constexpr int len {2};
388     if (strVec.size() != len) {
389         DFXLOG_ERROR("%s", "line format incorrect:");
390         DFXLOG_ERROR("    line = %s", line.c_str());
391         return false;
392     }
393     constexpr int valIndex {1};
394     std::string valStr = strVec[valIndex];
395     ehdrFlags_ = static_cast<uint32_t>(std::stoul(valStr));
396     return true;
397 }
398 
GetEhdrSize(FILE * const fp)399 bool ElfImitate::GetEhdrSize(FILE * const fp)
400 {
401     int status {0};
402     std::string line = GetNextLine(fp, &status);
403     if (status == -1) {
404         DFXLOG_ERROR("%s", "early end");
405         return false;
406     }
407     auto strVec = StringSplit(line, " ");
408     constexpr int len {6};
409     if (strVec.size() != len) {
410         DFXLOG_ERROR("%s", "line format incorrect:");
411         DFXLOG_ERROR("    line = %s", line.c_str());
412         return false;
413     }
414     constexpr int valIndex {4};
415     std::string valStr = strVec[valIndex];
416     ehdrSize_ = static_cast<uint16_t>(std::stoull(valStr));
417     return true;
418 }
419 
GetPhdrSize(FILE * const fp)420 bool ElfImitate::GetPhdrSize(FILE * const fp)
421 {
422     int status {0};
423     std::string line = GetNextLine(fp, &status);
424     if (status == -1) {
425         DFXLOG_ERROR("%s", "early end");
426         return false;
427     }
428     auto strVec = StringSplit(line, " ");
429     constexpr int len {6};
430     if (strVec.size() != len) {
431         DFXLOG_ERROR("%s", "line format incorrect:");
432         DFXLOG_ERROR("    line = %s", line.c_str());
433         return false;
434     }
435     constexpr int valIndex {4};
436     std::string valStr = strVec[valIndex];
437     phdrEntSize_ = static_cast<uint16_t>(std::stoull(valStr));
438     return true;
439 }
440 
GetNumPhdrs(FILE * const fp)441 bool ElfImitate::GetNumPhdrs(FILE * const fp)
442 {
443     int status {0};
444     std::string line = GetNextLine(fp, &status);
445     if (status == -1) {
446         DFXLOG_ERROR("%s", "early end");
447         return false;
448     }
449     auto strVec = StringSplit(line, " ");
450     constexpr int len {5};
451     if (strVec.size() != len) {
452         DFXLOG_ERROR("%s", "line format incorrect:");
453         DFXLOG_ERROR("    line = %s", line.c_str());
454         return false;
455     }
456     constexpr int valIndex {4};
457     std::string valStr = strVec[valIndex];
458     phdrNumEnts_ = static_cast<uint16_t>(std::stoull(valStr));
459     return true;
460 }
461 
GetShdrSize(FILE * const fp)462 bool ElfImitate::GetShdrSize(FILE * const fp)
463 {
464     int status {0};
465     std::string line = GetNextLine(fp, &status);
466     if (status == -1) {
467         DFXLOG_ERROR("%s", "early end");
468         return false;
469     }
470     auto strVec = StringSplit(line, " ");
471     constexpr int len {6};
472     if (strVec.size() != len) {
473         DFXLOG_ERROR("%s", "line format incorrect:");
474         DFXLOG_ERROR("    line = %s", line.c_str());
475         return false;
476     }
477     constexpr int valIndex {4};
478     std::string valStr = strVec[valIndex];
479     shdrEntSize_ = static_cast<uint16_t>(std::stoull(valStr));
480     return true;
481 }
482 
GetNumShdrs(FILE * const fp)483 bool ElfImitate::GetNumShdrs(FILE * const fp)
484 {
485     int status {0};
486     std::string line = GetNextLine(fp, &status);
487     if (status == -1) {
488         DFXLOG_ERROR("%s", "early end");
489         return false;
490     }
491     auto strVec = StringSplit(line, " ");
492     constexpr int len {5};
493     if (strVec.size() != len) {
494         DFXLOG_ERROR("%s", "line format incorrect:");
495         DFXLOG_ERROR("    line = %s", line.c_str());
496         return false;
497     }
498     constexpr int valIndex {4};
499     std::string valStr = strVec[valIndex];
500     shdrNumEnts_ = static_cast<uint16_t>(std::stoull(valStr));
501     return true;
502 }
503 
GetShdrStrTabIdx(FILE * const fp)504 bool ElfImitate::GetShdrStrTabIdx(FILE * const fp)
505 {
506     int status {0};
507     std::string line = GetNextLine(fp, &status);
508     if (status == -1) {
509         DFXLOG_ERROR("%s", "early end");
510         return false;
511     }
512     auto strVec = StringSplit(line, " ");
513     constexpr int len {6};
514     if (strVec.size() != len) {
515         DFXLOG_ERROR("%s", "line format incorrect:");
516         DFXLOG_ERROR("    line = %s", line.c_str());
517         return false;
518     }
519     constexpr int valIndex {5};
520     std::string valStr = strVec[valIndex];
521     shdrStrTabIdx_ = static_cast<uint16_t>(std::stoull(valStr));
522     return true;
523 }
524 
ParseProgramHeaders(ElfFileType fileType)525 bool ElfImitate::ParseProgramHeaders(ElfFileType fileType)
526 {
527     bool firstLoadHeader = true;
528     while (true) {
529         std::string line {};
530         line = GetNextPhdrLine();
531         if (line.empty()) {
532             break;
533             DFXLOG_INFO("%s", "no more program lines");
534         }
535         if (fileType == ElfFileType::ELF64) {
536             int status = 0;
537             std::string lineAppend = GetNextLine(phdrFP_, &status);
538             if (status == -1) {
539                 DFXLOG_ERROR("%s", "GetNextLine(phdrFP_, &status) error:");
540                 break;
541             }
542             if (lineAppend.empty()) {
543                 break;
544                 DFXLOG_INFO("%s", "no more program lines");
545             }
546             line += lineAppend;
547         }
548 
549         auto strVec = StringSplit(line, " ");
550         std::string type = strVec[0];
551         int base = 16; // 16:HEX
552         uint64_t offset =  std::stoull(strVec[INDEX_I1], nullptr, base);
553         uint64_t vAddr = std::stoull(strVec[INDEX_I2], nullptr, base);
554         uint64_t memSize = std::stoull(strVec[INDEX_I5], nullptr, base);
555         std::string flg = strVec[INDEX_I6];
556         if (!std::all_of(strVec[INDEX_I7].begin(), strVec[INDEX_I7].end(), ::isdigit)) {
557             flg += strVec[INDEX_I7];
558         }
559         if (type == "LOAD") {
560             if (flg.find("E") == std::string::npos) {
561                 continue;
562             }
563             ptLoads_[offset] = ElfLoadInfo{offset, vAddr, static_cast<size_t>(memSize)};
564 
565             // Only set the load bias from the first executable load header.
566             if (firstLoadHeader) {
567                 loadBias_ = static_cast<int64_t>(static_cast<uint64_t>(vAddr) - offset);
568             }
569             firstLoadHeader = false;
570 
571             if (vAddr < startVaddr_) {
572                 startVaddr_ = vAddr;
573             }
574             if (vAddr + memSize > endVaddr_) {
575                 endVaddr_ = vAddr + memSize;
576             }
577         }
578     }
579     return true;
580 }
ParseSectionHeaders(ElfFileType fileType)581 bool ElfImitate::ParseSectionHeaders(ElfFileType fileType)
582 {
583     std::string line {};
584     int status = 0;
585     (void)GetNextShdrLine(); //skip index 0 section header
586     (void)GetNextLine(shdrFP_, &status);
587     while (true) {
588         status = 0;
589         line = GetNextShdrLine();
590         if (line.empty()) {
591             break;
592             DFXLOG_INFO("%s", "no more section lines");
593         }
594         if (fileType == ElfFileType::ELF64) {
595             std::string lineAppend = GetNextLine(shdrFP_, &status);
596             if (lineAppend.empty()) {
597                 break;
598                 DFXLOG_INFO("%s", "no more section lines");
599             }
600             line += lineAppend;
601         }
602 
603         auto secIndex = GetSecIndex(line);
604 
605         auto pos = line.find("]");
606         if (pos == std::string::npos) {
607             DFXLOG_INFO("incorrect section line: %s", line.c_str());
608             return false;
609         }
610         ++pos;
611         std::string tmpLine = line.substr(pos, line.length() - pos);
612         auto strVec = StringSplit(tmpLine, " ");
613         for (size_t i = 0; i < strVec.size(); ++i) {}
614 
615         constexpr int base {16};
616         std::string secName = strVec[0];
617         std::string secType = strVec[1];
618         uint64_t secAddr = std::stoull(strVec[2], nullptr, base);
619         uint64_t secOffset = std::stoull(strVec[3], nullptr, base);
620         uint64_t secSize = std::stoull(strVec[4], nullptr, base);
621         uint64_t secEntSize = std::stoull(strVec[5], nullptr, base);
622         uint64_t secLink = std::stoull(strVec[strVec.size() - 3], nullptr, base);
623         uint64_t secInfo = std::stoull(strVec[strVec.size() - 2], nullptr, base);
624         uint64_t secAddrAlign = std::stoull(strVec[strVec.size() - 1], nullptr, base);
625 
626         ShdrInfo shdrInfo;
627         shdrInfo.addr = secAddr;
628         shdrInfo.offset = secOffset;
629         shdrInfo.size = secSize;
630         shdrInfoPairs_.emplace(std::make_pair(secIndex, secName), shdrInfo);
631 
632         if (secType == "SYMTAB" || secType == "DYNSYM") {
633             ElfShdr elfShdr;
634             elfShdr.name = static_cast<uint32_t>(secIndex);
635             if (secType == "SYMTAB") {
636                 elfShdr.type = static_cast<uint32_t>(SHT_SYMTAB);
637             } else {
638                 elfShdr.type = static_cast<uint32_t>(SHT_DYNSYM);
639             }
640 
641             elfShdr.addr = secAddr;
642             elfShdr.offset = secOffset;
643             elfShdr.size = secSize;
644             elfShdr.link = static_cast<uint32_t>(secLink);
645             elfShdr.info = static_cast<uint32_t>(secInfo);
646             elfShdr.addrAlign = secAddrAlign;
647             elfShdr.entSize = secEntSize;
648             symShdrs_.emplace(secName, elfShdr);
649         }
650     }
651     return true;
652 }
GetNextPhdrLine()653 const std::string ElfImitate::GetNextPhdrLine()
654 {
655     const std::string effectFlag {"0x00"};
656     std::string line {};
657     int status {0};
658     while (true) {
659         line = GetNextLine(phdrFP_, &status);
660         if (status == -1) {
661             DFXLOG_ERROR("%s", "GetNextLine(phdrFP_, &status) error:");
662             line = "";
663             break;
664         }
665         if (line.find(effectFlag) != std::string::npos) {
666             DFXLOG_ERROR("effective program header line: %s", line.c_str());
667             break;
668         }
669     }
670     return line;
671 }
672 
GetNextShdrLine()673 const std::string ElfImitate::GetNextShdrLine()
674 {
675     const std::string effectFlag {"]"};
676     std::string line {};
677     int status {0};
678     while (true) {
679         line = GetNextLine(shdrFP_, &status);
680         if (status == -1) {
681             DFXLOG_ERROR("%s", "GetNextLine(phdrFP_, &status) error:");
682             line = "";
683             break;
684         }
685         auto pos = line.find(effectFlag);
686         if ((pos != std::string::npos) and isdigit(line.at(pos - 1))) {
687             DFXLOG_ERROR("effective section header line: %s", line.c_str());
688             break;
689         }
690     }
691     return line;
692 }
GetSecIndex(const std::string & line)693 int64_t ElfImitate::GetSecIndex(const std::string &line)
694 {
695     int64_t res {-1};
696     auto pos = line.find("[");
697     if (pos == std::string::npos) {
698         DFXLOG_INFO("no section index found: %s", line.c_str());
699         return res;
700     }
701     constexpr int len {4};
702     std::string str = line.substr(pos, len);
703     if (str.length() != len) {
704         DFXLOG_INFO("section index form incorrect: %s", str.c_str());
705         return res;
706     }
707     // section index is of the form "[xx]"
708     constexpr int firstDigit {1};
709     constexpr int numDigits {2};
710     str = str.substr(firstDigit, numDigits);
711     if (str[0] == ' ') {
712         // str = [ x], transform it to [xx]
713         str[0] = '0';
714     }
715     if (!str.empty() && std::all_of(str.begin(), str.end(), ::isdigit)) {
716         res = std::stoll(str);
717     } else {
718         DFXLOG_INFO("not digits: %s", str.c_str());
719     }
720     return res;
721 }
722 
ParseElfSymbols()723 bool ElfImitate::ParseElfSymbols()
724 {
725     std::unordered_map <std::string, uint8_t> typeMap = {
726         {"OBJECT", STT_OBJECT}, {"FUNC", STT_FUNC}, {"SECTION", STT_SECTION}, {"FILE", STT_FILE},
727         {"COMMON", STT_COMMON}, {"TLS", STT_TLS}, {"NUM", STT_NUM}, {"LOOS", STT_LOOS},
728         {"GNU_IFUNC", STT_GNU_IFUNC}, {"HIOS", STT_HIOS}, {"LOPROC", STT_LOPROC}, {"HIPROC", STT_HIPROC},
729     };
730     std::unordered_map <std::string, uint8_t> bindMap = {
731         {"LOCAL", STB_LOCAL}, {"GLOBAL", STB_GLOBAL}, {"WEAK", STB_WEAK}, {"NUM", STB_NUM}, {"LOOS", STB_LOOS},
732         {"GNU_UNIQUE", STB_GNU_UNIQUE}, {"HIOS", STB_HIOS}, {"LOPROC", STB_LOPROC}, {"HIPROC", STB_HIPROC}
733     };
734     std::unordered_map <std::string, uint8_t> vsMap = {
735         {"DEFAULT", STV_DEFAULT}, {"INTERNAL", STV_INTERNAL}, {"HIDDEN", STV_HIDDEN}, {"PROTECTED", STV_PROTECTED},
736     };
737     while (true) {
738         std::string line {};
739         line = GetNextSymLine();
740         if (line.empty()) {
741             DFXLOG_INFO("%s", "no more symbol lines");
742             break;
743         }
744         auto strVec = StringSplit(line, " ");
745         ElfSymbol elfSymbol;
746         constexpr int base {16}; // 16:HEX
747         elfSymbol.name = std::stoul(strVec[INDEX_I0].substr(0, strVec[INDEX_I0].size() -1));
748         elfSymbol.value = std::stoull(strVec[INDEX_I1], nullptr, base);
749         elfSymbol.size = std::stoull(strVec[INDEX_I2]);
750         elfSymbol.info = ELF32_ST_INFO(bindMap[strVec[INDEX_I4]], typeMap[strVec[INDEX_I3]]);
751         elfSymbol.other = vsMap["strVec[INDEX_I5]"];
752         if (strVec[INDEX_I6] == "UND") {
753             elfSymbol.shndx = SHN_UNDEF;
754         } else if (strVec[INDEX_I6] == "ABS") {
755             elfSymbol.shndx = SHN_ABS;
756         } else {
757             elfSymbol.shndx = static_cast<uint16_t>(std::stoul(strVec[INDEX_I6]));
758         }
759         elfSymbols_.push_back(elfSymbol);
760     }
761     return true;
762 }
GetNextSymLine()763 const std::string ElfImitate::GetNextSymLine()
764 {
765     const std::string effectFlag {":"};
766     std::string line {};
767     int status {0};
768     while (true) {
769         line = GetNextLine(symTabFP_, &status);
770         if (status == -1) {
771             DFXLOG_INFO("%s", "GetNextLine(phdrFP_, &status) error:");
772             line = "";
773             break;
774         }
775         auto pos = line.find(effectFlag);
776         if ((pos != std::string::npos) and isdigit(line.at(pos - 1))) {
777             DFXLOG_INFO("effective symbol line: %s", line.c_str());
778             break;
779         }
780     }
781     return line;
782 }
783 
GetSectionInfo(ShdrInfo & shdr,const std::string secName)784 bool ElfImitate::GetSectionInfo(ShdrInfo& shdr, const std::string secName)
785 {
786     for (const auto &iter: shdrInfoPairs_) {
787         auto tmpPair = iter.first;
788         if (tmpPair.second == secName) {
789             shdr = iter.second;
790             return true;
791         }
792     }
793     return false;
794 }
795 
GetElfSymbols()796 const std::vector<ElfSymbol>& ElfImitate::GetElfSymbols()
797 {
798     if (elfSymbols_.empty()) {
799         ParseElfSymbols();
800     }
801     return elfSymbols_;
802 }
GetLoadBase(uint64_t mapStart,uint64_t mapOffset)803 uint64_t ElfImitate::GetLoadBase(uint64_t mapStart, uint64_t mapOffset)
804 {
805     loadBase_ = mapStart - mapOffset - GetLoadBias();
806 
807     return loadBase_;
808 }
809 
GetStartPc()810 uint64_t ElfImitate::GetStartPc()
811 {
812     auto startVaddr = GetStartVaddr();
813     startPc_ = startVaddr + loadBase_;
814     return startPc_;
815 }
816 
GetEndPc()817 uint64_t ElfImitate::GetEndPc()
818 {
819     auto endVaddr = GetEndVaddr();
820     endPc_ = endVaddr + loadBase_;
821     return endPc_;
822 }
823 
GetRelPc(uint64_t pc,uint64_t mapStart,uint64_t mapOffset)824 uint64_t ElfImitate::GetRelPc(uint64_t pc, uint64_t mapStart, uint64_t mapOffset)
825 {
826     return (pc - GetLoadBase(mapStart, mapOffset));
827 }
828 
IsFunc(const ElfSymbol symbol)829 bool ElfImitate::IsFunc(const ElfSymbol symbol)
830 {
831     return ((symbol.shndx != SHN_UNDEF) &&
832         (ELF32_ST_TYPE(symbol.info) == STT_FUNC || ELF32_ST_TYPE(symbol.info) == STT_GNU_IFUNC));
833 }
834 
ParseSymbols(std::vector<DfxSymbol> & symbols,const std::string & filePath)835 bool ElfImitate::ParseSymbols(std::vector<DfxSymbol>& symbols, const std::string& filePath)
836 {
837     std::vector<ElfSymbol> elfSymbols = GetElfSymbols();
838     for (auto elfSymbol : elfSymbols) {
839         if (IsFunc(elfSymbol)) {
840             if (elfSymbol.value == 0 || elfSymbol.size == 0) {
841                 continue;
842             }
843             std::string nameStr = "";
844             symbols.emplace_back(elfSymbol.value, elfSymbol.size,
845                                  nameStr, DfxSymbols::Demangle(nameStr), filePath);
846         } else {
847             continue;
848         }
849     }
850     auto comp = [](DfxSymbol a, DfxSymbol b) { return a.funcVaddr_ < b.funcVaddr_; };
851     std::sort(symbols.begin(), symbols.end(), comp);
852     auto pred = [](DfxSymbol a, DfxSymbol b) { return a.funcVaddr_ == b.funcVaddr_; };
853     symbols.erase(std::unique(symbols.begin(), symbols.end(), pred), symbols.end());
854     symbols.shrink_to_fit();
855     return true;
856 }
857 
AddSymbolsByPlt(std::vector<DfxSymbol> & symbols,const std::string & filePath)858 bool ElfImitate::AddSymbolsByPlt(std::vector<DfxSymbol>& symbols, const std::string& filePath)
859 {
860     ShdrInfo shdr;
861     GetSectionInfo(shdr, PLT);
862     symbols.emplace_back(shdr.addr, shdr.size, PLT, filePath);
863     return true;
864 }
865 
GetFuncNameAndOffset(uint64_t pc,std::string & funcName,uint64_t & start,uint64_t & end)866 bool ElfImitate::GetFuncNameAndOffset(uint64_t pc, std::string& funcName, uint64_t& start, uint64_t& end)
867 {
868     std::vector<DfxSymbol> symbols;
869     if (!ParseSymbols(symbols, "")) {
870         return false;
871     }
872 
873     for (const auto& symbol : symbols) {
874         if (symbol.Contain(pc)) {
875             funcName = symbol.demangle_;
876             start = symbol.funcVaddr_;
877             end = symbol.funcVaddr_ + symbol.size_;
878             return true;
879         }
880     }
881     return false;
882 }
883 } // namespace HiviewDFX
884 } // namespace OHOS