1 /*
2 * Copyright (c) 2021-2023 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 "dfx_elf.h"
17
18 #include <algorithm>
19 #include <cstdlib>
20 #include <fcntl.h>
21 #include <securec.h>
22 #include <string>
23 #if is_mingw
24 #include "dfx_nonlinux_define.h"
25 #else
26 #include <elf.h>
27 #include <sys/mman.h>
28 #endif
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #include <utility>
33
34 #include "dfx_define.h"
35 #include "dfx_log.h"
36 #include "dfx_instr_statistic.h"
37 #include "dfx_util.h"
38 #include "dfx_maps.h"
39 #include "dwarf_define.h"
40 #if defined(ENABLE_MINIDEBUGINFO)
41 #include "dfx_xz_utils.h"
42 #endif
43 #include "string_util.h"
44 #include "unwinder_config.h"
45
46 namespace OHOS {
47 namespace HiviewDFX {
48 namespace {
49 #undef LOG_DOMAIN
50 #undef LOG_TAG
51 #define LOG_DOMAIN 0xD002D11
52 #define LOG_TAG "DfxElf"
53 }
54
Create(const std::string & path)55 std::shared_ptr<DfxElf> DfxElf::Create(const std::string& path)
56 {
57 auto elf = std::make_shared<DfxElf>(path);
58 if (elf->IsValid()) {
59 return elf;
60 }
61 return nullptr;
62 }
63
CreateFromHap(const std::string & file,std::shared_ptr<DfxMap> prevMap,uint64_t & offset)64 std::shared_ptr<DfxElf> DfxElf::CreateFromHap(const std::string& file, std::shared_ptr<DfxMap> prevMap,
65 uint64_t& offset)
66 {
67 #if is_ohos
68 // elf header is in the first mmap area
69 // c3840000-c38a6000 r--p 00174000 /data/storage/el1/bundle/entry.hap <- program header
70 // c38a6000-c3945000 r-xp 001d9000 /data/storage/el1/bundle/entry.hap <- pc is in this region
71 // c3945000-c394b000 r--p 00277000 /data/storage/el1/bundle/entry.hap
72 // c394b000-c394c000 rw-p 0027c000 /data/storage/el1/bundle/entry.hap
73 if (prevMap == nullptr) {
74 LOGE("current hap mapitem has no prev mapitem, maybe pc is wrong?");
75 return nullptr;
76 }
77 const std::vector<const std::string> validFilePath = { "/proc" };
78 if (!VerifyFilePath(file, validFilePath) || !EndsWith(file, ".hap")) {
79 LOGE("Illegal file path, please check file: %s", file.c_str());
80 return nullptr;
81 }
82 int fd = OHOS_TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY));
83 if (fd < 0) {
84 LOGE("Failed to open hap file, errno(%d)", errno);
85 return nullptr;
86 }
87 auto fileSize = GetFileSize(fd);
88 size_t elfSize = 0;
89 size_t size = prevMap->end - prevMap->begin;
90 do {
91 auto mmap = std::make_shared<DfxMmap>();
92 if (!mmap->Init(fd, size, (off_t)prevMap->offset)) {
93 LOGE("Failed to mmap program header in hap.");
94 break;
95 }
96
97 elfSize = GetElfSize(mmap->Get());
98 if (elfSize <= 0 || elfSize > static_cast<uint64_t>(fileSize) - prevMap->offset) {
99 LOGE("Invalid elf size? elf size: %d, hap size: %d", (int)elfSize, (int)fileSize);
100 elfSize = 0;
101 break;
102 }
103
104 offset -= prevMap->offset;
105 } while (false);
106
107 if (elfSize != 0) {
108 LOGU("elfSize: %zu", elfSize);
109 auto elf = std::make_shared<DfxElf>(fd, elfSize, prevMap->offset);
110 if (elf->IsValid()) {
111 close(fd);
112 elf->SetBaseOffset(prevMap->offset);
113 return elf;
114 }
115 }
116 close(fd);
117 #endif
118 return nullptr;
119 }
120
DfxElf(const std::string & file)121 DfxElf::DfxElf(const std::string& file)
122 {
123 #if is_ohos
124 if (mmap_ == nullptr && (!file.empty())) {
125 LOGU("file: %s", file.c_str());
126 if (!DfxMaps::IsLegalMapItem(file)) {
127 LOGE("Illegal map file, please check file: %s", file.c_str());
128 return;
129 }
130 std::string realPath = file;
131 if (!StartsWith(file, "/proc/")) { // sandbox file should not be check by realpath function
132 if (!RealPath(file, realPath)) {
133 DFXLOG_WARN("Failed to realpath %s", file.c_str());
134 return;
135 }
136 }
137 int fd = OHOS_TEMP_FAILURE_RETRY(open(realPath.c_str(), O_RDONLY));
138 if (fd > 0) {
139 auto size = static_cast<size_t>(GetFileSize(fd));
140 mmap_ = std::make_shared<DfxMmap>();
141 if (!mmap_->Init(fd, size, 0)) {
142 LOGE("Failed to mmap init.");
143 }
144 close(fd);
145 } else {
146 LOGE("Failed to open file: %s", file.c_str());
147 }
148 }
149 #endif
150 Init();
151 }
152
DfxElf(const int fd,const size_t elfSz,const off_t offset)153 DfxElf::DfxElf(const int fd, const size_t elfSz, const off_t offset)
154 {
155 if (mmap_ == nullptr) {
156 mmap_ = std::make_shared<DfxMmap>();
157 if (!mmap_->Init(fd, elfSz, offset)) {
158 LOGE("Failed to mmap init elf in hap.");
159 }
160 }
161 Init();
162 }
163
DfxElf(uint8_t * decompressedData,size_t size)164 DfxElf::DfxElf(uint8_t *decompressedData, size_t size)
165 {
166 if (mmap_ == nullptr) {
167 mmap_ = std::make_shared<DfxMmap>();
168 // this mean the embedded elf initialization.
169 mmap_->Init(decompressedData, size);
170 mmap_->SetNeedUnmap(false);
171 }
172 Init();
173 }
174
Init()175 void DfxElf::Init()
176 {
177 uti_.namePtr = 0;
178 uti_.format = -1;
179 hasTableInfo_ = false;
180 }
181
Clear()182 void DfxElf::Clear()
183 {
184 if (elfParse_ != nullptr) {
185 elfParse_.reset();
186 elfParse_ = nullptr;
187 }
188
189 if (mmap_ != nullptr) {
190 mmap_->Clear();
191 mmap_.reset();
192 mmap_ = nullptr;
193 }
194 }
195
IsEmbeddedElfValid()196 bool DfxElf::IsEmbeddedElfValid()
197 {
198 #if defined(ENABLE_MINIDEBUGINFO)
199 if (embeddedElf_ == nullptr) {
200 return InitEmbeddedElf();
201 }
202 return embeddedElf_ != nullptr && embeddedElf_->IsValid();
203 #endif
204 return false;
205 }
206
GetEmbeddedElf()207 std::shared_ptr<DfxElf> DfxElf::GetEmbeddedElf()
208 {
209 return embeddedElf_;
210 }
211
GetMiniDebugInfo()212 std::shared_ptr<MiniDebugInfo> DfxElf::GetMiniDebugInfo()
213 {
214 return miniDebugInfo_;
215 }
216
InitEmbeddedElf()217 bool DfxElf::InitEmbeddedElf()
218 {
219 #if defined(ENABLE_MINIDEBUGINFO)
220 if (!UnwinderConfig::GetEnableMiniDebugInfo() || miniDebugInfo_ == nullptr) {
221 return false;
222 }
223 uint8_t *addr = miniDebugInfo_->offset + const_cast<uint8_t*>(GetMmapPtr());
224 embeddedElfData_ = std::make_shared<std::vector<uint8_t>>();
225 if (embeddedElfData_ == nullptr) {
226 LOGE("Create embeddedElfData failed.");
227 return false;
228 }
229 if (XzDecompress(addr, miniDebugInfo_->size, embeddedElfData_)) {
230 // embeddedElfData_ store the decompressed bytes.
231 // use these bytes to construct an elf.
232 embeddedElf_ = std::make_shared<DfxElf>(embeddedElfData_->data(), embeddedElfData_->size());
233 if (embeddedElf_ != nullptr && embeddedElf_->IsValid()) {
234 return true;
235 } else {
236 LOGE("Failed to parse Embedded Elf.");
237 }
238 } else {
239 LOGE("Failed to decompressed .gnu_debugdata seciton.");
240 }
241 #endif
242 return false;
243 }
244
InitHeaders()245 bool DfxElf::InitHeaders()
246 {
247 if (mmap_ == nullptr) {
248 return false;
249 }
250
251 if (elfParse_ != nullptr) {
252 return true;
253 }
254
255 uint8_t ident[SELFMAG + 1];
256 if (!Read(0, ident, SELFMAG) || !IsValidElf(ident, SELFMAG)) {
257 return false;
258 }
259
260 if (!Read(EI_CLASS, &classType_, sizeof(uint8_t))) {
261 return false;
262 }
263
264 if (classType_ == ELFCLASS32) {
265 elfParse_ = std::unique_ptr<ElfParser>(new ElfParser32(mmap_));
266 } else if (classType_ == ELFCLASS64) {
267 elfParse_ = std::unique_ptr<ElfParser>(new ElfParser64(mmap_));
268 } else {
269 DFXLOG_WARN("InitHeaders failed, classType: %d", classType_);
270 return false;
271 }
272 if (elfParse_ != nullptr) {
273 valid_ = true;
274 elfParse_->InitHeaders();
275 #if defined(ENABLE_MINIDEBUGINFO)
276 miniDebugInfo_ = elfParse_->GetMiniDebugInfo();
277 #endif
278 }
279 return valid_;
280 }
281
IsValid()282 bool DfxElf::IsValid()
283 {
284 if (valid_ == false) {
285 InitHeaders();
286 }
287 return valid_;
288 }
289
GetClassType()290 uint8_t DfxElf::GetClassType()
291 {
292 if (IsValid()) {
293 return classType_;
294 }
295 return ELFCLASSNONE;
296 }
297
GetArchType()298 ArchType DfxElf::GetArchType()
299 {
300 if (IsValid()) {
301 elfParse_->GetArchType();
302 }
303 return ARCH_UNKNOWN;
304 }
305
GetLoadBias()306 int64_t DfxElf::GetLoadBias()
307 {
308 if (loadBias_ == 0) {
309 if (IsValid()) {
310 loadBias_ = elfParse_->GetLoadBias();
311 LOGU("Elf loadBias: %" PRIx64 "", (uint64_t)loadBias_);
312 }
313 }
314 return loadBias_;
315 }
316
GetLoadBase(uint64_t mapStart,uint64_t mapOffset)317 uint64_t DfxElf::GetLoadBase(uint64_t mapStart, uint64_t mapOffset)
318 {
319 if (loadBase_ == static_cast<uint64_t>(-1)) {
320 if (IsValid()) {
321 LOGU("mapStart: %" PRIx64 ", mapOffset: %" PRIx64 "", (uint64_t)mapStart, (uint64_t)mapOffset);
322 loadBase_ = mapStart - mapOffset - static_cast<uint64_t>(GetLoadBias());
323 LOGU("Elf loadBase: %" PRIx64 "", (uint64_t)loadBase_);
324 }
325 }
326 return loadBase_;
327 }
328
SetLoadBase(uint64_t base)329 void DfxElf::SetLoadBase(uint64_t base)
330 {
331 loadBase_ = base;
332 }
333
GetStartPc()334 uint64_t DfxElf::GetStartPc()
335 {
336 if (startPc_ == static_cast<uint64_t>(-1)) {
337 if (IsValid()) {
338 auto startVaddr = elfParse_->GetStartVaddr();
339 if (loadBase_ != static_cast<uint64_t>(-1) && startVaddr != static_cast<uint64_t>(-1)) {
340 startPc_ = startVaddr + loadBase_;
341 LOGU("Elf startPc: %" PRIx64 "", (uint64_t)startPc_);
342 }
343 }
344 }
345 return startPc_;
346 }
347
SetBaseOffset(uint64_t offset)348 void DfxElf::SetBaseOffset(uint64_t offset)
349 {
350 baseOffset_ = offset;
351 }
352
GetBaseOffset()353 uint64_t DfxElf::GetBaseOffset()
354 {
355 return baseOffset_;
356 }
357
GetStartVaddr()358 uint64_t DfxElf::GetStartVaddr()
359 {
360 if (IsValid()) {
361 return elfParse_->GetStartVaddr();
362 }
363 return 0;
364 }
365
GetEndPc()366 uint64_t DfxElf::GetEndPc()
367 {
368 if (endPc_ == 0) {
369 if (IsValid()) {
370 auto endVaddr = elfParse_->GetEndVaddr();
371 if (loadBase_ != static_cast<uint64_t>(-1) && endVaddr != 0) {
372 endPc_ = endVaddr + loadBase_;
373 LOGU("Elf endPc: %" PRIx64 "", (uint64_t)endPc_);
374 }
375 }
376 }
377 return endPc_;
378 }
379
GetEndVaddr()380 uint64_t DfxElf::GetEndVaddr()
381 {
382 if (IsValid()) {
383 return elfParse_->GetEndVaddr();
384 }
385 return 0;
386 }
387
GetStartOffset()388 uint64_t DfxElf::GetStartOffset()
389 {
390 if (IsValid()) {
391 return elfParse_->GetStartOffset();
392 }
393 return 0;
394 }
395
GetRelPc(uint64_t pc,uint64_t mapStart,uint64_t mapOffset)396 uint64_t DfxElf::GetRelPc(uint64_t pc, uint64_t mapStart, uint64_t mapOffset)
397 {
398 return (pc - GetLoadBase(mapStart, mapOffset));
399 }
400
GetElfSize()401 uint64_t DfxElf::GetElfSize()
402 {
403 if (!IsValid()) {
404 return 0;
405 }
406 return elfParse_->GetElfSize();
407 }
408
GetElfName()409 std::string DfxElf::GetElfName()
410 {
411 if (!IsValid()) {
412 return "";
413 }
414 return elfParse_->GetElfName();
415 }
416
SetBuildId(const std::string & buildId)417 void DfxElf::SetBuildId(const std::string& buildId)
418 {
419 buildId_ = buildId;
420 }
421
GetBuildId()422 std::string DfxElf::GetBuildId()
423 {
424 if (buildId_.empty()) {
425 if (!IsValid()) {
426 return "";
427 }
428 ShdrInfo shdr;
429 if (GetSectionInfo(shdr, NOTE_GNU_BUILD_ID) || GetSectionInfo(shdr, NOTES)) {
430 std::string buildIdHex = GetBuildId((uint64_t)((char*)GetMmapPtr() + shdr.offset), shdr.size);
431 if (!buildIdHex.empty()) {
432 buildId_ = ToReadableBuildId(buildIdHex);
433 LOGU("Elf buildId: %s", buildId_.c_str());
434 }
435 }
436 }
437 return buildId_;
438 }
439
GetBuildId(uint64_t noteAddr,uint64_t noteSize)440 std::string DfxElf::GetBuildId(uint64_t noteAddr, uint64_t noteSize)
441 {
442 uint64_t tmp;
443 if (__builtin_add_overflow(noteAddr, noteSize, &tmp)) {
444 LOGE("noteAddr overflow");
445 return "";
446 }
447 uint64_t offset = 0;
448 uint64_t ptr = noteAddr;
449 while (offset < noteSize) {
450 ElfW(Nhdr) nhdr;
451 if (noteSize - offset < sizeof(nhdr)) {
452 return "";
453 }
454 ptr = noteAddr + offset;
455 if (memcpy_s(&nhdr, sizeof(nhdr), reinterpret_cast<void*>(ptr), sizeof(nhdr)) != 0) {
456 LOGE("memcpy nhdr failed");
457 return "";
458 }
459 offset += sizeof(nhdr);
460 if (noteSize - offset < nhdr.n_namesz) {
461 return "";
462 }
463 if (nhdr.n_namesz > 0) {
464 std::string name(nhdr.n_namesz, '\0');
465 ptr = noteAddr + offset;
466 if (memcpy_s(&(name[0]), nhdr.n_namesz, reinterpret_cast<void*>(ptr), nhdr.n_namesz) != 0) {
467 LOGE("memcpy note name failed");
468 return "";
469 }
470 if (name.back() == '\0') { // Trim trailing \0 as GNU is stored as a C string in the ELF file.
471 name.resize(name.size() - 1);
472 }
473 // Align nhdr.n_namesz to next power multiple of 4. See man 5 elf.
474 offset += (nhdr.n_namesz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary
475 if (name != "GNU" || nhdr.n_type != NT_GNU_BUILD_ID) {
476 offset += (nhdr.n_descsz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary
477 continue;
478 }
479 if (noteSize - offset < nhdr.n_descsz || nhdr.n_descsz == 0) {
480 return "";
481 }
482 std::string buildIdRaw(nhdr.n_descsz, '\0');
483 ptr = noteAddr + offset;
484 if (memcpy_s(&buildIdRaw[0], nhdr.n_descsz, reinterpret_cast<void*>(ptr), nhdr.n_descsz) != 0) {
485 return "";
486 }
487 return buildIdRaw;
488 }
489 // Align hdr.n_descsz to next power multiple of 4. See man 5 elf.
490 offset += (nhdr.n_descsz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary
491 }
492 return "";
493 }
494
GetGlobalPointer()495 uintptr_t DfxElf::GetGlobalPointer()
496 {
497 if (!IsValid()) {
498 return 0;
499 }
500 return elfParse_->GetGlobalPointer();
501 }
502
ToReadableBuildId(const std::string & buildIdHex)503 std::string DfxElf::ToReadableBuildId(const std::string& buildIdHex)
504 {
505 if (buildIdHex.empty()) {
506 return "";
507 }
508 static const char HEXTABLE[] = "0123456789abcdef";
509 static const int HEXLENGTH = 16;
510 static const int HEX_EXPAND_PARAM = 2;
511 const size_t len = buildIdHex.length();
512 std::string buildId(len * HEX_EXPAND_PARAM, '\0');
513
514 for (size_t i = 0; i < len; i++) {
515 unsigned int n = buildIdHex[i];
516 buildId[i * HEX_EXPAND_PARAM] = HEXTABLE[(n >> 4) % HEXLENGTH]; // 4 : higher 4 bit of uint8
517 buildId[i * HEX_EXPAND_PARAM + 1] = HEXTABLE[n % HEXLENGTH];
518 }
519 return buildId;
520 }
521
GetSectionInfo(ShdrInfo & shdr,const std::string secName)522 bool DfxElf::GetSectionInfo(ShdrInfo& shdr, const std::string secName)
523 {
524 if (!IsValid()) {
525 return false;
526 }
527 return elfParse_->GetSectionInfo(shdr, secName);
528 }
529
GetSectionData(unsigned char * buf,uint64_t size,std::string secName)530 bool DfxElf::GetSectionData(unsigned char *buf, uint64_t size, std::string secName)
531 {
532 if (!IsValid()) {
533 return false;
534 }
535 return elfParse_->GetSectionData(buf, size, secName);
536 }
537
GetElfSymbols()538 const std::vector<ElfSymbol>& DfxElf::GetElfSymbols()
539 {
540 if (!elfSymbols_.empty()) {
541 return elfSymbols_;
542 }
543 elfSymbols_ = elfParse_->GetElfSymbols(false);
544 #if defined(ENABLE_MINIDEBUGINFO)
545 if (IsEmbeddedElfValid()) {
546 auto symbols = embeddedElf_->elfParse_->GetElfSymbols(false);
547 LOGU("Get EmbeddedElf ElfSymbols, size: %zu", symbols.size());
548 elfSymbols_.insert(elfSymbols_.end(), symbols.begin(), symbols.end());
549 }
550 #endif
551 std::sort(elfSymbols_.begin(), elfSymbols_.end(), [](const ElfSymbol& sym1, const ElfSymbol& sym2) {
552 return sym1.value < sym2.value;
553 });
554 auto pred = [](ElfSymbol a, ElfSymbol b) { return a.value == b.value; };
555 elfSymbols_.erase(std::unique(elfSymbols_.begin(), elfSymbols_.end(), pred), elfSymbols_.end());
556 elfSymbols_.shrink_to_fit();
557 LOGU("GetElfSymbols, size: %zu", elfSymbols_.size());
558 return elfSymbols_;
559 }
560
GetFuncSymbols()561 const std::vector<ElfSymbol>& DfxElf::GetFuncSymbols()
562 {
563 if (!funcSymbols_.empty()) {
564 return funcSymbols_;
565 }
566 funcSymbols_ = elfParse_->GetElfSymbols(true);
567 #if defined(ENABLE_MINIDEBUGINFO)
568 if (IsEmbeddedElfValid()) {
569 auto symbols = embeddedElf_->elfParse_->GetElfSymbols(true);
570 LOGU("Get EmbeddedElf FuncSymbols, size: %zu", symbols.size());
571 funcSymbols_.insert(funcSymbols_.end(), symbols.begin(), symbols.end());
572 }
573 #endif
574 std::sort(funcSymbols_.begin(), funcSymbols_.end(), [](const ElfSymbol& sym1, const ElfSymbol& sym2) {
575 return sym1.value < sym2.value;
576 });
577 auto pred = [](ElfSymbol a, ElfSymbol b) { return a.value == b.value; };
578 funcSymbols_.erase(std::unique(funcSymbols_.begin(), funcSymbols_.end(), pred), funcSymbols_.end());
579 funcSymbols_.shrink_to_fit();
580 LOGU("GetFuncSymbols, size: %zu", funcSymbols_.size());
581 return funcSymbols_;
582 }
583
GetFuncInfoLazily(uint64_t addr,ElfSymbol & elfSymbol)584 bool DfxElf::GetFuncInfoLazily(uint64_t addr, ElfSymbol& elfSymbol)
585 {
586 if (FindFuncSymbol(addr, funcSymbols_, elfSymbol)) {
587 return true;
588 }
589 bool findSymbol = false;
590 #if defined(ENABLE_MINIDEBUGINFO)
591 if (IsEmbeddedElfValid() &&
592 embeddedElf_->elfParse_->GetElfSymbolByAddr(addr, elfSymbol)) {
593 funcSymbols_.emplace_back(elfSymbol);
594 findSymbol = true;
595 }
596 #endif
597
598 if (!findSymbol && elfParse_->GetElfSymbolByAddr(addr, elfSymbol)) {
599 funcSymbols_.emplace_back(elfSymbol);
600 findSymbol = true;
601 }
602
603 if (findSymbol) {
604 std::sort(funcSymbols_.begin(), funcSymbols_.end(), [](const ElfSymbol& sym1, const ElfSymbol& sym2) {
605 return sym1.value < sym2.value;
606 });
607 auto pred = [](ElfSymbol a, ElfSymbol b) { return a.value == b.value; };
608 funcSymbols_.erase(std::unique(funcSymbols_.begin(), funcSymbols_.end(), pred), funcSymbols_.end());
609 funcSymbols_.shrink_to_fit();
610 LOGU("GetFuncInfoLazily, size: %zu", funcSymbols_.size());
611 return true;
612 }
613 return false;
614 }
615
GetFuncInfo(uint64_t addr,ElfSymbol & elfSymbol)616 bool DfxElf::GetFuncInfo(uint64_t addr, ElfSymbol& elfSymbol)
617 {
618 if (UnwinderConfig::GetEnableLoadSymbolLazily()) {
619 return GetFuncInfoLazily(addr, elfSymbol);
620 }
621
622 auto symbols = GetFuncSymbols();
623 return FindFuncSymbol(addr, symbols, elfSymbol);
624 }
625
FindFuncSymbol(uint64_t addr,const std::vector<ElfSymbol> & symbols,ElfSymbol & elfSymbol)626 bool DfxElf::FindFuncSymbol(uint64_t addr, const std::vector<ElfSymbol>& symbols, ElfSymbol& elfSymbol)
627 {
628 if (symbols.empty()) {
629 return false;
630 }
631 size_t begin = 0;
632 size_t end = symbols.size();
633 while (begin < end) {
634 size_t mid = begin + (end - begin) / 2;
635 const auto& symbol = symbols[mid];
636 if (addr < symbol.value) {
637 end = mid;
638 } else if (addr < (symbol.value + symbol.size)) {
639 elfSymbol = symbol;
640 return true;
641 } else {
642 begin = mid + 1;
643 }
644 }
645 return false;
646 }
647
GetPtLoads()648 const std::unordered_map<uint64_t, ElfLoadInfo>& DfxElf::GetPtLoads()
649 {
650 return elfParse_->GetPtLoads();
651 }
652
FillUnwindTableByExidx(ShdrInfo shdr,uintptr_t loadBase,struct UnwindTableInfo * uti)653 bool DfxElf::FillUnwindTableByExidx(ShdrInfo shdr, uintptr_t loadBase, struct UnwindTableInfo* uti)
654 {
655 uti->gp = 0;
656 uti->tableData = loadBase + shdr.addr;
657 uti->tableLen = shdr.size;
658 INSTR_STATISTIC(InstructionEntriesArmExidx, shdr.size, 0);
659 uti->format = UNW_INFO_FORMAT_ARM_EXIDX;
660 LOGU("tableData: %" PRIx64 ", tableLen: %d", (uint64_t)uti->tableData, (int)uti->tableLen);
661 return true;
662 }
663
664 #if is_ohos && !is_mingw
FillUnwindTableByEhhdrLocal(struct DwarfEhFrameHdr * hdr,struct UnwindTableInfo * uti)665 bool DfxElf::FillUnwindTableByEhhdrLocal(struct DwarfEhFrameHdr* hdr, struct UnwindTableInfo* uti)
666 {
667 if (hdr == nullptr) {
668 return false;
669 }
670 if (hdr->version != DW_EH_VERSION) {
671 LOGE("version(%d) error", hdr->version);
672 return false;
673 }
674
675 uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame));
676 LOGU("hdr: %" PRIx64 ", ehFrame: %" PRIx64 "", (uint64_t)hdr, (uint64_t)ptr);
677
678 auto acc = std::make_shared<DfxAccessorsLocal>();
679 auto memory = std::make_shared<DfxMemory>(acc);
680 LOGU("gp: %" PRIx64 ", ehFramePtrEnc: %x, fdeCountEnc: %x",
681 (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc);
682 memory->SetDataOffset(uti->gp);
683 MAYBE_UNUSED uintptr_t ehFrameStart = memory->ReadEncodedValue(ptr, hdr->ehFramePtrEnc);
684 uintptr_t fdeCount = memory->ReadEncodedValue(ptr, hdr->fdeCountEnc);
685 LOGU("ehFrameStart: %" PRIx64 ", fdeCount: %d", (uint64_t)ehFrameStart, (int)fdeCount);
686
687 if (hdr->tableEnc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) {
688 LOGU("tableEnc: %x", hdr->tableEnc);
689 if (hdr->fdeCountEnc == DW_EH_PE_omit) {
690 fdeCount = ~0UL;
691 }
692 if (hdr->ehFramePtrEnc == DW_EH_PE_omit) {
693 LOGE("ehFramePtrEnc(%x) error", hdr->ehFramePtrEnc);
694 return 0;
695 }
696 uti->isLinear = true;
697 uti->tableLen = fdeCount;
698 uti->tableData = ehFrameStart;
699 } else {
700 uti->isLinear = false;
701 uti->tableLen = (fdeCount * sizeof(DwarfTableEntry)) / sizeof(uintptr_t);
702 uti->tableData = ptr;
703 uti->segbase = (uintptr_t)hdr;
704 }
705 uti->format = UNW_INFO_FORMAT_REMOTE_TABLE;
706 LOGU("tableData: %" PRIx64 ", tableLen: %d", (uint64_t)uti->tableData, (int)uti->tableLen);
707 return true;
708 }
709 #endif
710
FillUnwindTableByEhhdr(struct DwarfEhFrameHdr * hdr,uintptr_t shdrBase,struct UnwindTableInfo * uti)711 bool DfxElf::FillUnwindTableByEhhdr(struct DwarfEhFrameHdr* hdr, uintptr_t shdrBase, struct UnwindTableInfo* uti)
712 {
713 if (hdr == nullptr) {
714 return false;
715 }
716 if (hdr->version != DW_EH_VERSION) {
717 LOGE("version(%d) error", hdr->version);
718 return false;
719 }
720 uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame));
721 LOGU("hdr: %" PRIx64 ", ehFrame: %" PRIx64 "", (uint64_t)hdr, (uint64_t)ptr);
722
723 uti->gp = GetGlobalPointer();
724 LOGU("gp: %" PRIx64 ", ehFramePtrEnc: %x, fdeCountEnc: %x",
725 (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc);
726 mmap_->SetDataOffset(uti->gp);
727 auto ptrOffset = ptr - reinterpret_cast<uintptr_t>(GetMmapPtr());
728 MAYBE_UNUSED uintptr_t ehFrameStart = mmap_->ReadEncodedValue(ptrOffset, hdr->ehFramePtrEnc);
729 uintptr_t fdeCount = mmap_->ReadEncodedValue(ptrOffset, hdr->fdeCountEnc);
730 LOGU("ehFrameStart: %" PRIx64 ", fdeCount: %d", (uint64_t)ehFrameStart, (int)fdeCount);
731 ptr = reinterpret_cast<uintptr_t>(GetMmapPtr()) + ptrOffset;
732
733 if (hdr->tableEnc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) {
734 LOGU("tableEnc: %x", hdr->tableEnc);
735 if (hdr->fdeCountEnc == DW_EH_PE_omit) {
736 fdeCount = ~0UL;
737 }
738 if (hdr->ehFramePtrEnc == DW_EH_PE_omit) {
739 LOGE("ehFramePtrEnc(%x) error", hdr->ehFramePtrEnc);
740 return 0;
741 }
742 uti->isLinear = true;
743 uti->tableLen = fdeCount;
744 uti->tableData = shdrBase + ehFrameStart;
745 uti->segbase = shdrBase;
746 } else {
747 uti->isLinear = false;
748 uti->tableLen = (fdeCount * sizeof(DwarfTableEntry)) / sizeof(uintptr_t);
749 uti->tableData = shdrBase + ptr - (uintptr_t)hdr;
750 uti->segbase = shdrBase;
751 }
752 uti->format = UNW_INFO_FORMAT_REMOTE_TABLE;
753 LOGU("tableData: %" PRIx64 ", tableLen: %d", (uint64_t)uti->tableData, (int)uti->tableLen);
754 return true;
755 }
756
FindUnwindTableInfo(uintptr_t pc,std::shared_ptr<DfxMap> map,struct UnwindTableInfo & uti)757 int DfxElf::FindUnwindTableInfo(uintptr_t pc, std::shared_ptr<DfxMap> map, struct UnwindTableInfo& uti)
758 {
759 if (hasTableInfo_) {
760 if (pc >= uti_.startPc && pc < uti_.endPc) {
761 uti = uti_;
762 LOGU("FindUnwindTableInfo had found");
763 return UNW_ERROR_NONE;
764 }
765 }
766 uintptr_t loadBase = GetLoadBase(map->begin, map->offset);
767 uti.startPc = GetStartPc();
768 uti.endPc = GetEndPc();
769 LOGU("Elf startPc: %" PRIx64 ", endPc: %" PRIx64 "", (uint64_t)uti.startPc, (uint64_t)uti.endPc);
770 if (pc < uti.startPc && pc >= uti.endPc) {
771 return UNW_ERROR_PC_NOT_IN_UNWIND_INFO;
772 }
773
774 ShdrInfo shdr;
775 #if defined(__arm__)
776 if (GetSectionInfo(shdr, ARM_EXIDX)) {
777 hasTableInfo_ = FillUnwindTableByExidx(shdr, loadBase, &uti);
778 }
779 #endif
780
781 if (!hasTableInfo_) {
782 struct DwarfEhFrameHdr* hdr = nullptr;
783 struct DwarfEhFrameHdr synthHdr;
784 if (GetSectionInfo(shdr, EH_FRAME_HDR)) {
785 INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0);
786 hdr = (struct DwarfEhFrameHdr *) (shdr.offset + (char *)GetMmapPtr());
787 } else if (GetSectionInfo(shdr, EH_FRAME)) {
788 LOGW("Elf(%s) no found .eh_frame_hdr section, using synthetic .eh_frame section", map->name.c_str());
789 INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0);
790 synthHdr.version = DW_EH_VERSION;
791 synthHdr.ehFramePtrEnc = DW_EH_PE_absptr |
792 ((sizeof(ElfW(Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); // 4 : four bytes
793 synthHdr.fdeCountEnc = DW_EH_PE_omit;
794 synthHdr.tableEnc = DW_EH_PE_omit;
795 synthHdr.ehFrame = (ElfW(Addr))(shdr.offset + (char*)GetMmapPtr());
796 hdr = &synthHdr;
797 }
798 uintptr_t shdrBase = static_cast<uintptr_t>(loadBase + shdr.addr);
799 hasTableInfo_ = FillUnwindTableByEhhdr(hdr, shdrBase, &uti);
800 }
801
802 if (hasTableInfo_) {
803 uti_ = uti;
804 return UNW_ERROR_NONE;
805 }
806 return UNW_ERROR_NO_UNWIND_INFO;
807 }
808
FindUnwindTableLocal(uintptr_t pc,struct UnwindTableInfo & uti)809 int DfxElf::FindUnwindTableLocal(uintptr_t pc, struct UnwindTableInfo& uti)
810 {
811 #if is_ohos && !is_mingw
812 DlCbData cbData;
813 (void)memset_s(&cbData, sizeof(cbData), 0, sizeof(cbData));
814 cbData.pc = pc;
815 cbData.uti.format = -1;
816 int ret = dl_iterate_phdr(DlPhdrCb, &cbData);
817 if (ret > 0) {
818 if (cbData.uti.format != -1) {
819 uti = cbData.uti;
820 return UNW_ERROR_NONE;
821 }
822 }
823 return UNW_ERROR_NO_UNWIND_INFO;
824 #else
825 return UNW_ERROR_UNSUPPORTED_VERSION;
826 #endif
827 }
828
829 #if is_ohos && !is_mingw
FindSection(struct dl_phdr_info * info,const std::string secName,ShdrInfo & shdr)830 bool DfxElf::FindSection(struct dl_phdr_info *info, const std::string secName, ShdrInfo& shdr)
831 {
832 const char *file = info->dlpi_name;
833 if (strlen(file) == 0) {
834 file = PROC_SELF_EXE_PATH;
835 }
836
837 auto elf = Create(file);
838 if (elf == nullptr) {
839 return false;
840 }
841
842 return elf->GetSectionInfo(shdr, secName);
843 }
844
DlPhdrCb(struct dl_phdr_info * info,size_t size,void * data)845 int DfxElf::DlPhdrCb(struct dl_phdr_info *info, size_t size, void *data)
846 {
847 struct DlCbData *cbData = (struct DlCbData *)data;
848 UnwindTableInfo* uti = &cbData->uti;
849 uintptr_t pc = cbData->pc;
850 const ElfW(Phdr) *pText = nullptr;
851 const ElfW(Phdr) *pDynamic = nullptr;
852 #if defined(__arm__)
853 const ElfW(Phdr) *pArmExidx = nullptr;
854 #endif
855 const ElfW(Phdr) *pEhHdr = nullptr;
856
857 const ElfW(Phdr) *phdr = info->dlpi_phdr;
858 ElfW(Addr) loadBase = info->dlpi_addr;
859 for (size_t i = 0; i < info->dlpi_phnum; i++, phdr++) {
860 switch (phdr->p_type) {
861 case PT_LOAD: {
862 ElfW(Addr) vaddr = phdr->p_vaddr + loadBase;
863 if (pc >= vaddr && pc < vaddr + phdr->p_memsz) {
864 pText = phdr;
865 }
866 break;
867 }
868 #if defined(__arm__)
869 case PT_ARM_EXIDX: {
870 pArmExidx = phdr;
871 break;
872 }
873 #endif
874 case PT_GNU_EH_FRAME: {
875 pEhHdr = phdr;
876 break;
877 }
878 case PT_DYNAMIC: {
879 pDynamic = phdr;
880 break;
881 }
882 default:
883 break;
884 }
885 }
886 if (pText == nullptr) {
887 return 0;
888 }
889 uti->startPc = pText->p_vaddr + loadBase;
890 uti->endPc = uti->startPc + pText->p_memsz;
891 LOGU("Elf name: %s", info->dlpi_name);
892 uti->namePtr = (uintptr_t) info->dlpi_name;
893
894 #if defined(__arm__)
895 if (pArmExidx) {
896 ShdrInfo shdr;
897 shdr.addr = pArmExidx->p_vaddr;
898 shdr.size = pArmExidx->p_memsz;
899 return FillUnwindTableByExidx(shdr, loadBase, uti);
900 }
901 #endif
902
903 if (pDynamic) {
904 ElfW(Dyn) *dyn = (ElfW(Dyn) *)(pDynamic->p_vaddr + loadBase);
905 for (; dyn->d_tag != DT_NULL; ++dyn) {
906 if (dyn->d_tag == DT_PLTGOT) {
907 uti->gp = dyn->d_un.d_ptr;
908 break;
909 }
910 }
911 } else {
912 uti->gp = 0;
913 }
914
915 struct DwarfEhFrameHdr *hdr = nullptr;
916 struct DwarfEhFrameHdr synthHdr;
917 if (pEhHdr) {
918 INSTR_STATISTIC(InstructionEntriesEhFrame, pEhHdr->p_memsz, 0);
919 hdr = (struct DwarfEhFrameHdr *) (pEhHdr->p_vaddr + loadBase);
920 } else {
921 ShdrInfo shdr;
922 if (FindSection(info, EH_FRAME, shdr)) {
923 LOGW("Elf(%s) no found .eh_frame_hdr section, using synthetic .eh_frame section", info->dlpi_name);
924 INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0);
925 synthHdr.version = DW_EH_VERSION;
926 synthHdr.ehFramePtrEnc = DW_EH_PE_absptr |
927 ((sizeof(ElfW(Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); // 4 : four bytes
928 synthHdr.fdeCountEnc = DW_EH_PE_omit;
929 synthHdr.tableEnc = DW_EH_PE_omit;
930 synthHdr.ehFrame = (ElfW(Addr))(shdr.addr + info->dlpi_addr);
931 hdr = &synthHdr;
932 }
933 }
934 return FillUnwindTableByEhhdrLocal(hdr, uti);
935 }
936 #endif
937
Read(uintptr_t pos,void * buf,size_t size)938 bool DfxElf::Read(uintptr_t pos, void *buf, size_t size)
939 {
940 if ((mmap_ != nullptr) && (mmap_->Read(pos, buf, size) == size)) {
941 return true;
942 }
943 return false;
944 }
945
GetMmapPtr()946 const uint8_t* DfxElf::GetMmapPtr()
947 {
948 if (mmap_ == nullptr) {
949 return nullptr;
950 }
951 return static_cast<uint8_t *>(mmap_->Get());
952 }
953
GetMmapSize()954 size_t DfxElf::GetMmapSize()
955 {
956 if (mmap_ == nullptr) {
957 return 0;
958 }
959 return mmap_->Size();
960 }
961
IsValidElf(const void * ptr,size_t size)962 bool DfxElf::IsValidElf(const void* ptr, size_t size)
963 {
964 if (ptr == nullptr) {
965 return false;
966 }
967
968 if (memcmp(ptr, ELFMAG, size) != 0) {
969 LOGW("Invalid elf hdr?");
970 return false;
971 }
972 return true;
973 }
974
975 #if is_ohos
GetElfSize(const void * ptr)976 size_t DfxElf::GetElfSize(const void* ptr)
977 {
978 if (!IsValidElf(ptr, SELFMAG)) {
979 return 0;
980 }
981
982 const uint8_t* data = static_cast<const uint8_t*>(ptr);
983 uint8_t classType = data[EI_CLASS];
984 if (classType == ELFCLASS32) {
985 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)data;
986 return static_cast<size_t>(ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum));
987 } else if (classType == ELFCLASS64) {
988 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)data;
989 return static_cast<size_t>(ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum));
990 }
991 DFXLOG_WARN("classType(%d) error", classType);
992 return 0;
993 }
994 #endif
995 } // namespace HiviewDFX
996 } // namespace OHOS
997