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