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