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