• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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