• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 #include "elf_factory.h"
42 #include "string_util.h"
43 #include "unwinder_config.h"
44 
45 namespace OHOS {
46 namespace HiviewDFX {
47 namespace {
48 #undef LOG_DOMAIN
49 #undef LOG_TAG
50 #define LOG_DOMAIN 0xD002D11
51 #define LOG_TAG "DfxElf"
52 #if is_ohos && !is_mingw
53 enum HdrSection {
54     SECTION_TEXT = 0,
55     SECTION_ARMEXIDX = 1,
56     SECTION_DYNAMIC = 2,
57     SECTION_EHFRAMEHDR = 3
58 };
59 #endif
60 }
61 
Init()62 void DfxElf::Init()
63 {
64     uti_.namePtr = 0;
65     uti_.format = -1;
66     hasTableInfo_ = false;
67 }
68 
Clear()69 void DfxElf::Clear()
70 {
71     if (elfParse_ != nullptr) {
72         elfParse_.reset();
73         elfParse_ = nullptr;
74     }
75 
76     if (mmap_ != nullptr) {
77         mmap_->Clear();
78         mmap_.reset();
79         mmap_ = nullptr;
80     }
81 }
82 
InitHeaders()83 bool DfxElf::InitHeaders()
84 {
85     if (mmap_ == nullptr) {
86         return false;
87     }
88 
89     if (elfParse_ != nullptr) {
90         return true;
91     }
92 
93     uint8_t ident[SELFMAG + 1];
94     if (!Read(0, ident, SELFMAG) || !IsValidElf(ident, SELFMAG)) {
95         return false;
96     }
97 
98     if (!Read(EI_CLASS, &classType_, sizeof(uint8_t))) {
99         return false;
100     }
101 
102     if (classType_ == ELFCLASS32) {
103         elfParse_ = std::unique_ptr<ElfParser>(new ElfParser32(mmap_));
104     } else if (classType_ == ELFCLASS64) {
105         elfParse_ = std::unique_ptr<ElfParser>(new ElfParser64(mmap_));
106     } else {
107         DFXLOGW("InitHeaders failed, classType: %{public}d", classType_);
108         return false;
109     }
110     if (elfParse_ != nullptr) {
111         valid_ = true;
112         elfParse_->InitHeaders();
113     }
114     return valid_;
115 }
116 
IsValid()117 bool DfxElf::IsValid()
118 {
119     if (valid_ == false) {
120         InitHeaders();
121     }
122     return valid_;
123 }
124 
GetClassType()125 uint8_t DfxElf::GetClassType()
126 {
127     if (IsValid()) {
128         return classType_;
129     }
130     return ELFCLASSNONE;
131 }
132 
GetArchType()133 ArchType DfxElf::GetArchType()
134 {
135     if (IsValid()) {
136         elfParse_->GetArchType();
137     }
138     return ARCH_UNKNOWN;
139 }
140 
GetLoadBias()141 int64_t DfxElf::GetLoadBias()
142 {
143     if (loadBias_ == 0) {
144         if (IsValid()) {
145             loadBias_ = elfParse_->GetLoadBias();
146             DFXLOGU("Elf loadBias: %{public}" PRIx64 "", (uint64_t)loadBias_);
147         }
148     }
149     return loadBias_;
150 }
151 
GetLoadBase(uint64_t mapStart,uint64_t mapOffset)152 uint64_t DfxElf::GetLoadBase(uint64_t mapStart, uint64_t mapOffset)
153 {
154     if (loadBase_ == static_cast<uint64_t>(-1)) {
155         if (IsValid()) {
156             DFXLOGU("mapStart: %{public}" PRIx64 ", mapOffset: %{public}" PRIx64 "",
157                 (uint64_t)mapStart, (uint64_t)mapOffset);
158             loadBase_ = mapStart - mapOffset - static_cast<uint64_t>(GetLoadBias());
159             DFXLOGU("Elf loadBase: %{public}" PRIx64 "", (uint64_t)loadBase_);
160         }
161     }
162     return loadBase_;
163 }
164 
SetLoadBase(uint64_t base)165 void DfxElf::SetLoadBase(uint64_t base)
166 {
167     loadBase_ = base;
168 }
169 
SetBaseOffset(uint64_t offset)170 void DfxElf::SetBaseOffset(uint64_t offset)
171 {
172     baseOffset_ = offset;
173 }
174 
GetBaseOffset()175 uint64_t DfxElf::GetBaseOffset()
176 {
177     return baseOffset_;
178 }
179 
GetStartPc()180 uint64_t DfxElf::GetStartPc()
181 {
182     if (startPc_ == static_cast<uint64_t>(-1)) {
183         if (IsValid()) {
184             auto startVaddr = elfParse_->GetStartVaddr();
185             if (loadBase_ != static_cast<uint64_t>(-1) && startVaddr != static_cast<uint64_t>(-1)) {
186                 startPc_ = startVaddr + loadBase_;
187                 DFXLOGU("Elf startPc: %{public}" PRIx64 "", (uint64_t)startPc_);
188             }
189         }
190     }
191     return startPc_;
192 }
193 
GetStartVaddr()194 uint64_t DfxElf::GetStartVaddr()
195 {
196     if (IsValid()) {
197         return elfParse_->GetStartVaddr();
198     }
199     return 0;
200 }
201 
GetEndPc()202 uint64_t DfxElf::GetEndPc()
203 {
204     if (endPc_ == 0) {
205         if (IsValid()) {
206             auto endVaddr = elfParse_->GetEndVaddr();
207             if (loadBase_ != static_cast<uint64_t>(-1) && endVaddr != 0) {
208                 endPc_ = endVaddr + loadBase_;
209                 DFXLOGU("Elf endPc: %{public}" PRIx64 "", (uint64_t)endPc_);
210             }
211         }
212     }
213     return endPc_;
214 }
215 
GetEndVaddr()216 uint64_t DfxElf::GetEndVaddr()
217 {
218     if (IsValid()) {
219         return elfParse_->GetEndVaddr();
220     }
221     return 0;
222 }
223 
GetStartOffset()224 uint64_t DfxElf::GetStartOffset()
225 {
226     if (IsValid()) {
227         return elfParse_->GetStartOffset();
228     }
229     return 0;
230 }
231 
GetRelPc(uint64_t pc,uint64_t mapStart,uint64_t mapOffset)232 uint64_t DfxElf::GetRelPc(uint64_t pc, uint64_t mapStart, uint64_t mapOffset)
233 {
234     return (pc - GetLoadBase(mapStart, mapOffset));
235 }
236 
GetElfSize()237 uint64_t DfxElf::GetElfSize()
238 {
239     if (!IsValid()) {
240         return 0;
241     }
242     return elfParse_->GetElfSize();
243 }
244 
GetElfName()245 std::string DfxElf::GetElfName()
246 {
247     if (!IsValid()) {
248         return "";
249     }
250     return elfParse_->GetElfName();
251 }
252 
SetBuildId(const std::string & buildId)253 void DfxElf::SetBuildId(const std::string& buildId)
254 {
255     buildId_ = buildId;
256 }
257 
GetBuildId(uint64_t noteAddr,uint64_t noteSize)258 std::string DfxElf::GetBuildId(uint64_t noteAddr, uint64_t noteSize)
259 {
260     return ElfParser::ParseHexBuildId(noteAddr, noteSize);
261 }
262 
GetBuildId()263 std::string DfxElf::GetBuildId()
264 {
265     if (buildId_.empty()) {
266         if (!IsValid()) {
267             return "";
268         }
269         return elfParse_->GetBuildId();
270     }
271     return buildId_;
272 }
273 
274 
GetGlobalPointer()275 uintptr_t DfxElf::GetGlobalPointer()
276 {
277     if (!IsValid()) {
278         return 0;
279     }
280     return elfParse_->GetGlobalPointer();
281 }
282 
GetSectionInfo(ShdrInfo & shdr,const std::string secName)283 bool DfxElf::GetSectionInfo(ShdrInfo& shdr, const std::string secName)
284 {
285     if (!IsValid()) {
286         return false;
287     }
288     return elfParse_->GetSectionInfo(shdr, secName);
289 }
290 
GetSectionData(unsigned char * buf,uint64_t size,std::string secName)291 bool DfxElf::GetSectionData(unsigned char* buf, uint64_t size, std::string secName)
292 {
293     if (!IsValid()) {
294         return false;
295     }
296     return elfParse_->GetSectionData(buf, size, secName);
297 }
298 
GetGnuDebugDataHdr()299 GnuDebugDataHdr DfxElf::GetGnuDebugDataHdr()
300 {
301     if (!IsValid()) {
302         return {};
303     }
304     return elfParse_->GetGnuDebugDataHdr();
305 }
306 
IsMiniDebugInfoValid()307 bool DfxElf::IsMiniDebugInfoValid()
308 {
309     if (miniDebugInfo_ == nullptr) {
310 #if defined(ENABLE_MINIDEBUGINFO)
311         MiniDebugInfoFactory miniDebugInfoFactory(elfParse_->GetGnuDebugDataHdr());
312         miniDebugInfo_ = miniDebugInfoFactory.Create();
313 #endif
314     }
315     return miniDebugInfo_ != nullptr;
316 }
317 
GetFuncSymbols()318 const std::set<ElfSymbol>& DfxElf::GetFuncSymbols()
319 {
320     if (!IsValid() || !funcSymbols_.empty()) {
321         return funcSymbols_;
322     }
323     if (IsMiniDebugInfoValid()) {
324         funcSymbols_ = miniDebugInfo_->elfParse_->GetFuncSymbols();
325         DFXLOGU("Get MiniDebugInfo FuncSymbols, size: %{public}zu", funcSymbols_.size());
326     }
327     const auto &symbols = elfParse_->GetFuncSymbols();
328     funcSymbols_.insert(symbols.begin(), symbols.end());
329     DFXLOGU("GetFuncSymbols, size: %{public}zu", funcSymbols_.size());
330     return funcSymbols_;
331 }
332 
GetFuncInfoLazily(uint64_t addr,ElfSymbol & elfSymbol)333 bool DfxElf::GetFuncInfoLazily(uint64_t addr, ElfSymbol& elfSymbol)
334 {
335     DFX_TRACE_SCOPED_DLSYM("GetFuncInfoLazily");
336     if (FindFuncSymbol(addr, funcSymbols_, elfSymbol)) {
337         return true;
338     }
339     bool findSymbol = elfParse_->GetFuncSymbolByAddr(addr, elfSymbol);
340     if (!findSymbol && IsMiniDebugInfoValid()) {
341         findSymbol = miniDebugInfo_->elfParse_->GetFuncSymbolByAddr(addr, elfSymbol);
342     }
343 
344     if (findSymbol) {
345         funcSymbols_.emplace(elfSymbol);
346         DFXLOGU("GetFuncInfoLazily, size: %{public}zu", funcSymbols_.size());
347     }
348     return findSymbol;
349 }
350 
GetFuncInfo(uint64_t addr,ElfSymbol & elfSymbol)351 bool DfxElf::GetFuncInfo(uint64_t addr, ElfSymbol& elfSymbol)
352 {
353     if (!IsValid()) {
354         return false;
355     }
356     if (UnwinderConfig::GetEnableLoadSymbolLazily()) {
357         return GetFuncInfoLazily(addr, elfSymbol);
358     }
359 
360     const auto &symbols = GetFuncSymbols();
361     return FindFuncSymbol(addr, symbols, elfSymbol);
362 }
363 
FindFuncSymbol(uint64_t addr,const std::set<ElfSymbol> & symbols,ElfSymbol & elfSymbol)364 bool DfxElf::FindFuncSymbol(uint64_t addr, const std::set<ElfSymbol>& symbols, ElfSymbol& elfSymbol)
365 {
366     DFX_TRACE_SCOPED_DLSYM("FindFuncSymbol");
367     if (symbols.empty()) {
368         return false;
369     }
370     // Find the first position that is not less than value
371     ElfSymbol tmpSym;
372     tmpSym.value = addr;
373     auto next = symbols.upper_bound(tmpSym);
374     if (next != symbols.begin()) {
375         next--;
376     }
377     if (next->value <= addr && addr < (next->value + next->size)) {
378         elfSymbol = *next;
379         return true;
380     }
381     return false;
382 }
383 
GetPtLoads()384 const std::unordered_map<uint64_t, ElfLoadInfo>& DfxElf::GetPtLoads()
385 {
386     return elfParse_->GetPtLoads();
387 }
388 
FillUnwindTableByExidx(ShdrInfo shdr,uintptr_t loadBase,struct UnwindTableInfo * uti)389 bool DfxElf::FillUnwindTableByExidx(ShdrInfo shdr, uintptr_t loadBase, struct UnwindTableInfo* uti)
390 {
391     if (uti == nullptr) {
392         return false;
393     }
394     uti->gp = 0;
395     uti->tableData = loadBase + shdr.addr;
396     uti->tableLen = shdr.size;
397     INSTR_STATISTIC(InstructionEntriesArmExidx, shdr.size, 0);
398     uti->format = UNW_INFO_FORMAT_ARM_EXIDX;
399     DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__,
400         (uint64_t)uti->tableData, (int)uti->tableLen);
401     return true;
402 }
403 
404 #if is_ohos && !is_mingw
FillUnwindTableByEhhdrLocal(struct DwarfEhFrameHdr * hdr,struct UnwindTableInfo * uti)405 bool DfxElf::FillUnwindTableByEhhdrLocal(struct DwarfEhFrameHdr* hdr, struct UnwindTableInfo* uti)
406 {
407     if (hdr == nullptr) {
408         return false;
409     }
410     if (hdr->version != DW_EH_VERSION) {
411         DFXLOGE("[%{public}d]: version(%{public}d) error", __LINE__, hdr->version);
412         return false;
413     }
414 
415     uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame));
416     DFXLOGU("[%{public}d]: hdr: %{public}" PRIx64 ", ehFrame: %{public}" PRIx64 "", __LINE__,
417         (uint64_t)hdr, (uint64_t)ptr);
418     auto memory = std::make_shared<DfxMemory>(UNWIND_TYPE_LOCAL);
419     DFXLOGU("[%{public}d]: gp: %{public}" PRIx64 ", ehFramePtrEnc: %{public}x, fdeCountEnc: %{public}x", __LINE__,
420         (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc);
421     memory->SetDataOffset(uti->gp);
422     MAYBE_UNUSED uintptr_t ehFrameStart = memory->ReadEncodedValue(ptr, hdr->ehFramePtrEnc);
423     uintptr_t fdeCount = memory->ReadEncodedValue(ptr, hdr->fdeCountEnc);
424     DFXLOGU("[%{public}d]: ehFrameStart: %{public}" PRIx64 ", fdeCount: %{public}d", __LINE__,
425         (uint64_t)ehFrameStart, (int)fdeCount);
426 
427     if (hdr->tableEnc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) {
428         DFXLOGU("tableEnc: %{public}x", hdr->tableEnc);
429         if (hdr->fdeCountEnc == DW_EH_PE_omit) {
430             fdeCount = ~0UL;
431         }
432         if (hdr->ehFramePtrEnc == DW_EH_PE_omit) {
433             DFXLOGE("ehFramePtrEnc(%{public}x) error", hdr->ehFramePtrEnc);
434             return false;
435         }
436         uti->isLinear = true;
437         uti->tableLen = fdeCount;
438         uti->tableData = ehFrameStart;
439     } else {
440         uti->isLinear = false;
441         uti->tableLen = (fdeCount * sizeof(DwarfTableEntry)) / sizeof(uintptr_t);
442         uti->tableData = ptr;
443         uti->segbase = (uintptr_t)hdr;
444     }
445     uti->format = UNW_INFO_FORMAT_REMOTE_TABLE;
446     DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__,
447         (uint64_t)uti->tableData, (int)uti->tableLen);
448     return true;
449 }
450 #endif
451 
FillUnwindTableByEhhdr(struct DwarfEhFrameHdr * hdr,uintptr_t shdrBase,struct UnwindTableInfo * uti)452 bool DfxElf::FillUnwindTableByEhhdr(struct DwarfEhFrameHdr* hdr, uintptr_t shdrBase, struct UnwindTableInfo* uti)
453 {
454     if ((hdr == nullptr) || (uti == nullptr)) {
455         return false;
456     }
457     if (hdr->version != DW_EH_VERSION) {
458         DFXLOGE("[%{public}d]: version(%{public}d) error", __LINE__, hdr->version);
459         return false;
460     }
461     uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame));
462     DFXLOGU("[%{public}d]: hdr: %{public}" PRIx64 ", ehFrame: %{public}" PRIx64 "", __LINE__,
463         (uint64_t)hdr, (uint64_t)ptr);
464 
465     uti->gp = GetGlobalPointer();
466     DFXLOGU("[%{public}d]: gp: %{public}" PRIx64 ", ehFramePtrEnc: %{public}x, fdeCountEnc: %{public}x", __LINE__,
467         (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc);
468     mmap_->SetDataOffset(uti->gp);
469     auto ptrOffset = ptr - reinterpret_cast<uintptr_t>(GetMmapPtr());
470     MAYBE_UNUSED uintptr_t ehFrameStart = mmap_->ReadEncodedValue(ptrOffset, hdr->ehFramePtrEnc);
471     uintptr_t fdeCount = mmap_->ReadEncodedValue(ptrOffset, hdr->fdeCountEnc);
472     DFXLOGU("[%{public}d]: ehFrameStart: %{public}" PRIx64 ", fdeCount: %{public}d", __LINE__,
473         (uint64_t)ehFrameStart, (int)fdeCount);
474     ptr = reinterpret_cast<uintptr_t>(GetMmapPtr()) + ptrOffset;
475 
476     if (hdr->tableEnc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) {
477         DFXLOGU("[%{public}d]: tableEnc: %{public}x", __LINE__, hdr->tableEnc);
478         if (hdr->fdeCountEnc == DW_EH_PE_omit) {
479             fdeCount = ~0UL;
480         }
481         if (hdr->ehFramePtrEnc == DW_EH_PE_omit) {
482             DFXLOGE("[%{public}d]: ehFramePtrEnc(%{public}x) error", __LINE__, hdr->ehFramePtrEnc);
483             return false;
484         }
485         uti->isLinear = true;
486         uti->tableLen = fdeCount;
487         uti->tableData = shdrBase + ehFrameStart;
488         uti->segbase = shdrBase;
489     } else {
490         uti->isLinear = false;
491         uti->tableLen = (fdeCount * sizeof(DwarfTableEntry)) / sizeof(uintptr_t);
492         uti->tableData = shdrBase + ptr - (uintptr_t)hdr;
493         uti->segbase = shdrBase;
494     }
495     uti->format = UNW_INFO_FORMAT_REMOTE_TABLE;
496     DFXLOGU("[%{public}d]: tableData: %{public}" PRIx64 ", tableLen: %{public}d", __LINE__,
497         (uint64_t)uti->tableData, (int)uti->tableLen);
498     return true;
499 }
500 
FindUnwindTableInfo(uintptr_t pc,std::shared_ptr<DfxMap> map,struct UnwindTableInfo & uti)501 int DfxElf::FindUnwindTableInfo(uintptr_t pc, std::shared_ptr<DfxMap> map, struct UnwindTableInfo& uti)
502 {
503     if (hasTableInfo_ && pc >= uti_.startPc && pc < uti_.endPc) {
504         uti = uti_;
505         DFXLOGU("FindUnwindTableInfo had found");
506         return UNW_ERROR_NONE;
507     }
508     if (map == nullptr) {
509         return UNW_ERROR_INVALID_MAP;
510     }
511     uintptr_t loadBase = GetLoadBase(map->begin, map->offset);
512     uti.startPc = GetStartPc();
513     uti.endPc = GetEndPc();
514     if (pc < uti.startPc || pc >= uti.endPc) {
515         DFXLOGU("Elf startPc: %{public}" PRIx64 ", endPc: %{public}" PRIx64 "",
516             (uint64_t)uti.startPc, (uint64_t)uti.endPc);
517         return UNW_ERROR_PC_NOT_IN_UNWIND_INFO;
518     }
519 
520     ShdrInfo shdr;
521 #if defined(__arm__)
522     if (GetSectionInfo(shdr, ARM_EXIDX)) {
523         hasTableInfo_ = FillUnwindTableByExidx(shdr, loadBase, &uti);
524     }
525 #endif
526 
527     if (!hasTableInfo_) {
528         struct DwarfEhFrameHdr* hdr = nullptr;
529         struct DwarfEhFrameHdr synthHdr;
530         if (GetSectionInfo(shdr, EH_FRAME_HDR) && GetMmapPtr() != nullptr) {
531             INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0);
532             hdr = (struct DwarfEhFrameHdr *) (shdr.offset + (char *)GetMmapPtr());
533         } else if (GetSectionInfo(shdr, EH_FRAME) && GetMmapPtr() != nullptr) {
534             DFXLOGW("[%{public}d]: Elf(%{public}s) no found .eh_frame_hdr section, " \
535                 "using synthetic .eh_frame section", __LINE__, map->name.c_str());
536             INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0);
537             synthHdr.version = DW_EH_VERSION;
538             synthHdr.ehFramePtrEnc = DW_EH_PE_absptr |
539                 ((sizeof(ElfW(Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); // 4 : four bytes
540             synthHdr.fdeCountEnc = DW_EH_PE_omit;
541             synthHdr.tableEnc = DW_EH_PE_omit;
542             synthHdr.ehFrame = (ElfW(Addr))(shdr.offset + (char*)GetMmapPtr());
543             hdr = &synthHdr;
544         }
545         uintptr_t shdrBase = static_cast<uintptr_t>(loadBase + shdr.addr);
546         hasTableInfo_ = FillUnwindTableByEhhdr(hdr, shdrBase, &uti);
547     }
548 
549     if (hasTableInfo_) {
550         uti_ = uti;
551         return UNW_ERROR_NONE;
552     }
553     return UNW_ERROR_NO_UNWIND_INFO;
554 }
555 
FindUnwindTableLocal(uintptr_t pc,struct UnwindTableInfo & uti)556 int DfxElf::FindUnwindTableLocal(uintptr_t pc, struct UnwindTableInfo& uti)
557 {
558 #if is_ohos && !is_mingw
559     DlCbData cbData;
560     (void)memset_s(&cbData, sizeof(cbData), 0, sizeof(cbData));
561     cbData.pc = pc;
562     cbData.uti.format = -1;
563     int ret = dl_iterate_phdr(DlPhdrCb, &cbData);
564     if (ret > 0) {
565         if (cbData.uti.format != -1) {
566             uti = cbData.uti;
567             return UNW_ERROR_NONE;
568         }
569     }
570     return UNW_ERROR_NO_UNWIND_INFO;
571 #else
572     return UNW_ERROR_UNSUPPORTED_VERSION;
573 #endif
574 }
575 
576 #if is_ohos && !is_mingw
FindSection(struct dl_phdr_info * info,const std::string secName,ShdrInfo & shdr)577 bool DfxElf::FindSection(struct dl_phdr_info* info, const std::string secName, ShdrInfo& shdr)
578 {
579     if (info == nullptr) {
580         return false;
581     }
582     const char* file = info->dlpi_name;
583     if (strlen(file) == 0) {
584         file = PROC_SELF_EXE_PATH;
585     }
586     RegularElfFactory elfFactory(file);
587     auto elf = elfFactory.Create();
588     if (elf == nullptr) {
589         return false;
590     }
591 
592     return elf->GetSectionInfo(shdr, secName);
593 }
594 
ParsePhdr(struct dl_phdr_info * info,const ElfW (Phdr)* (& pHdrSections)[4],const uintptr_t pc)595 void DfxElf::ParsePhdr(struct dl_phdr_info* info, const ElfW(Phdr)* (&pHdrSections)[4], const uintptr_t pc)
596 {
597     const ElfW(Phdr)* phdr = info->dlpi_phdr;
598     for (size_t i = 0; i < info->dlpi_phnum && phdr != nullptr; i++, phdr++) {
599         switch (phdr->p_type) {
600             case PT_LOAD: {
601                 ElfW(Addr) vaddr = phdr->p_vaddr + info->dlpi_addr;
602                 if (pc >= vaddr && pc < vaddr + phdr->p_memsz) {
603                     pHdrSections[SECTION_TEXT] = phdr;
604                 }
605                 break;
606             }
607 #if defined(__arm__)
608             case PT_ARM_EXIDX: {
609                 pHdrSections[SECTION_ARMEXIDX] = phdr;
610                 break;
611             }
612 #endif
613             case PT_GNU_EH_FRAME: {
614                 pHdrSections[SECTION_EHFRAMEHDR] = phdr;
615                 break;
616             }
617             case PT_DYNAMIC: {
618                 pHdrSections[SECTION_DYNAMIC] = phdr;
619                 break;
620             }
621             default:
622                 break;
623         }
624     }
625 }
626 
ProccessDynamic(const ElfW (Phdr)* pDynamic,ElfW (Addr)loadBase,UnwindTableInfo * uti)627 bool DfxElf::ProccessDynamic(const ElfW(Phdr)* pDynamic, ElfW(Addr) loadBase, UnwindTableInfo* uti)
628 {
629     ElfW(Dyn)* dyn = reinterpret_cast<ElfW(Dyn) *>(pDynamic->p_vaddr + loadBase);
630     if (dyn == nullptr) {
631         return false;
632     }
633     for (; dyn->d_tag != DT_NULL; ++dyn) {
634         if (dyn->d_tag == DT_PLTGOT) {
635             uti->gp = dyn->d_un.d_ptr;
636             break;
637         }
638     }
639     return true;
640 }
641 
InitHdr(struct DwarfEhFrameHdr & synthHdr,struct dl_phdr_info * info,const ElfW (Phdr)* pEhHdr)642 struct DwarfEhFrameHdr* DfxElf::InitHdr(struct DwarfEhFrameHdr& synthHdr,
643     struct dl_phdr_info* info, const ElfW(Phdr)* pEhHdr)
644 {
645     struct DwarfEhFrameHdr* hdr = nullptr;
646     if (pEhHdr) {
647         INSTR_STATISTIC(InstructionEntriesEhFrame, pEhHdr->p_memsz, 0);
648         hdr = reinterpret_cast<struct DwarfEhFrameHdr *>(pEhHdr->p_vaddr + info->dlpi_addr);
649     } else {
650         ShdrInfo shdr;
651         if (FindSection(info, EH_FRAME, shdr)) {
652             DFXLOGW("[%{public}d]: Elf(%{public}s) no found .eh_frame_hdr section, " \
653                 "using synthetic .eh_frame section", __LINE__, info->dlpi_name);
654             INSTR_STATISTIC(InstructionEntriesEhFrame, shdr.size, 0);
655             synthHdr.version = DW_EH_VERSION;
656             synthHdr.ehFramePtrEnc = DW_EH_PE_absptr |
657                 ((sizeof(ElfW(Addr)) == 4) ? DW_EH_PE_udata4 : DW_EH_PE_udata8); // 4 : four bytes
658             synthHdr.fdeCountEnc = DW_EH_PE_omit;
659             synthHdr.tableEnc = DW_EH_PE_omit;
660             synthHdr.ehFrame = (ElfW(Addr))(shdr.addr + info->dlpi_addr);
661             hdr = &synthHdr;
662         }
663     }
664     return hdr;
665 }
666 
DlPhdrCb(struct dl_phdr_info * info,size_t size,void * data)667 int DfxElf::DlPhdrCb(struct dl_phdr_info* info, size_t size, void* data)
668 {
669     struct DlCbData* cbData = reinterpret_cast<struct DlCbData *>(data);
670     if ((info == nullptr) || (cbData == nullptr)) {
671         return -1;
672     }
673     UnwindTableInfo* uti = &cbData->uti;
674     uintptr_t pc = cbData->pc;
675     const int numOfPhdrSections = 4;
676     const ElfW(Phdr)* pHdrSections[numOfPhdrSections] = {nullptr};
677     ParsePhdr(info, pHdrSections, pc);
678 
679     if (pHdrSections[SECTION_TEXT] == nullptr) {
680         return 0;
681     }
682     ElfW(Addr) loadBase = info->dlpi_addr;
683     uti->startPc = pHdrSections[SECTION_TEXT]->p_vaddr + loadBase;
684     uti->endPc = uti->startPc + pHdrSections[SECTION_TEXT]->p_memsz;
685     DFXLOGU("Elf name: %{public}s", info->dlpi_name);
686     uti->namePtr = reinterpret_cast<uintptr_t>(info->dlpi_name);
687 
688 #if defined(__arm__)
689     if (pHdrSections[SECTION_ARMEXIDX]) {
690         ShdrInfo shdr;
691         shdr.addr = pHdrSections[SECTION_ARMEXIDX]->p_vaddr;
692         shdr.size = pHdrSections[SECTION_ARMEXIDX]->p_memsz;
693         return FillUnwindTableByExidx(shdr, loadBase, uti);
694     }
695 #endif
696 
697     if (pHdrSections[SECTION_DYNAMIC]) {
698         if (!ProccessDynamic(pHdrSections[SECTION_DYNAMIC], loadBase, uti)) {
699             return 0;
700         }
701     } else {
702         uti->gp = 0;
703     }
704 
705     struct DwarfEhFrameHdr synthHdr;
706     struct DwarfEhFrameHdr* hdr = InitHdr(synthHdr, info, pHdrSections[SECTION_EHFRAMEHDR]);
707 
708     return FillUnwindTableByEhhdrLocal(hdr, uti);
709 }
710 #endif
711 
Read(uintptr_t pos,void * buf,size_t size)712 bool DfxElf::Read(uintptr_t pos, void* buf, size_t size)
713 {
714     if ((mmap_ != nullptr) && (mmap_->Read(pos, buf, size) == size)) {
715         return true;
716     }
717     return false;
718 }
719 
GetMmapPtr()720 const uint8_t* DfxElf::GetMmapPtr()
721 {
722     if (mmap_ == nullptr) {
723         return nullptr;
724     }
725     return static_cast<uint8_t *>(mmap_->Get());
726 }
727 
GetMmapSize()728 size_t DfxElf::GetMmapSize()
729 {
730     if (mmap_ == nullptr) {
731         return 0;
732     }
733     return mmap_->Size();
734 }
735 
IsValidElf(const void * ptr,size_t size)736 bool DfxElf::IsValidElf(const void* ptr, size_t size)
737 {
738     if (ptr == nullptr) {
739         return false;
740     }
741 
742     if (memcmp(ptr, ELFMAG, size) != 0) {
743         DFXLOGD("Invalid elf hdr?");
744         return false;
745     }
746     return true;
747 }
748 } // namespace HiviewDFX
749 } // namespace OHOS
750