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