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