1 /*
2 * Copyright (c) 2023-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 "unwinder.h"
17
18 #include <dlfcn.h>
19 #include <link.h>
20
21 #include "dfx_ark.h"
22 #include "dfx_define.h"
23 #include "dfx_errors.h"
24 #include "dfx_frame_formatter.h"
25 #include "dfx_instructions.h"
26 #include "dfx_log.h"
27 #include "dfx_regs_get.h"
28 #include "dfx_symbols.h"
29 #include "stack_util.h"
30 #include "string_printf.h"
31 #include "string_util.h"
32
33 namespace OHOS {
34 namespace HiviewDFX {
35 namespace {
36 #undef LOG_DOMAIN
37 #undef LOG_TAG
38 #define LOG_DOMAIN 0xD002D11
39 #define LOG_TAG "DfxUnwinder"
40 }
41
Init()42 void Unwinder::Init()
43 {
44 Destroy();
45 memory_ = std::make_shared<DfxMemory>(acc_);
46 #if defined(__arm__)
47 armExidx_ = std::make_shared<ArmExidx>(memory_);
48 #endif
49 dwarfSection_ = std::make_shared<DwarfSection>(memory_);
50
51 if (pid_ == UNWIND_TYPE_LOCAL) {
52 maps_ = DfxMaps::Create(getpid());
53 } else {
54 if (pid_ > 0) {
55 maps_ = DfxMaps::Create(pid_);
56 }
57 }
58 }
59
Clear()60 void Unwinder::Clear()
61 {
62 isFpStep_ = false;
63 pcs_.clear();
64 frames_.clear();
65 if (memset_s(&lastErrorData_, sizeof(UnwindErrorData), 0, sizeof(UnwindErrorData)) != 0) {
66 LOGE("Failed to memset lastErrorData");
67 }
68 }
69
Destroy()70 void Unwinder::Destroy()
71 {
72 Clear();
73 rsCache_.clear();
74 }
75
GetStackRange(uintptr_t & stackBottom,uintptr_t & stackTop)76 bool Unwinder::GetStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
77 {
78 if (getpid() == gettid()) {
79 if (maps_ == nullptr || !maps_->GetStackRange(stackBottom, stackTop)) {
80 return false;
81 }
82 } else {
83 if (GetSelfStackRange(stackBottom, stackTop) != 0) {
84 return false;
85 }
86 }
87 return true;
88 }
89
UnwindLocalWithContext(const ucontext_t & context,size_t maxFrameNum,size_t skipFrameNum)90 bool Unwinder::UnwindLocalWithContext(const ucontext_t& context, size_t maxFrameNum, size_t skipFrameNum)
91 {
92 regs_ = DfxRegs::CreateFromUcontext(context);
93 return UnwindLocal(true, maxFrameNum, skipFrameNum);
94 }
95
UnwindLocal(bool withRegs,size_t maxFrameNum,size_t skipFrameNum)96 bool Unwinder::UnwindLocal(bool withRegs, size_t maxFrameNum, size_t skipFrameNum)
97 {
98 uintptr_t stackBottom = 1, stackTop = static_cast<uintptr_t>(-1);
99 if (!GetStackRange(stackBottom, stackTop)) {
100 LOGE("Get stack range error");
101 return false;
102 }
103 LOGU("stackBottom: %" PRIx64 ", stackTop: %" PRIx64 "", (uint64_t)stackBottom, (uint64_t)stackTop);
104
105 if (!withRegs) {
106 regs_ = DfxRegs::Create();
107 auto regsData = regs_->RawData();
108 if (regsData == nullptr) {
109 LOGE("params is nullptr");
110 return false;
111 }
112 GetLocalRegs(regsData);
113 }
114
115 UnwindContext context;
116 context.pid = UNWIND_TYPE_LOCAL;
117 context.regs = regs_;
118 context.stackCheck = false;
119 context.stackBottom = stackBottom;
120 context.stackTop = stackTop;
121 bool ret = Unwind(&context, maxFrameNum, skipFrameNum);
122 return ret;
123 }
124
UnwindRemote(pid_t tid,bool withRegs,size_t maxFrameNum,size_t skipFrameNum)125 bool Unwinder::UnwindRemote(pid_t tid, bool withRegs, size_t maxFrameNum, size_t skipFrameNum)
126 {
127 if ((pid_ <= 0) || (tid < 0)) {
128 LOGE("params is nullptr, pid: %d", pid_);
129 return false;
130 }
131 if (tid == 0) {
132 tid = pid_;
133 }
134 LOGI("tid: %d", tid);
135 if (!withRegs) {
136 regs_ = DfxRegs::CreateRemoteRegs(tid);
137 }
138 if ((regs_ == nullptr)) {
139 LOGE("regs is nullptr");
140 return false;
141 }
142
143 UnwindContext context;
144 context.pid = tid;
145 context.regs = regs_;
146 bool ret = Unwind(&context, maxFrameNum, skipFrameNum);
147 return ret;
148 }
149
GetMapByPc(uintptr_t pc,void * ctx,std::shared_ptr<DfxMap> & map)150 bool Unwinder::GetMapByPc(uintptr_t pc, void *ctx, std::shared_ptr<DfxMap>& map)
151 {
152 if (ctx == nullptr) {
153 return false;
154 }
155 UnwindContext* uctx = reinterpret_cast<UnwindContext *>(ctx);
156 if (uctx->map != nullptr &&
157 (pc >= (uintptr_t)uctx->map->begin && pc < (uintptr_t)uctx->map->end)) {
158 LOGU("map had matched by ctx");
159 map = uctx->map;
160 return true;
161 }
162
163 for (size_t i = 0; i < frames_.size(); ++i) {
164 if (frames_[i].map != nullptr &&
165 (pc >= (uintptr_t)frames_[i].map->begin && pc < (uintptr_t)frames_[i].map->end)) {
166 LOGU("map had matched by frames");
167 map = frames_[i].map;
168 uctx->map = map;
169 return true;
170 }
171 }
172
173 if (!maps_->FindMapByAddr(pc, map) || (map == nullptr)) {
174 return false;
175 }
176 uctx->map = map;
177 return true;
178 }
179
180 #if defined(ENABLE_MIXSTACK)
StepArkJsFrame(size_t & curIdx)181 bool Unwinder::StepArkJsFrame(size_t& curIdx)
182 {
183 uintptr_t pc = regs_->GetPc();
184 uintptr_t sp = regs_->GetSp();
185 uintptr_t fp = regs_->GetFp();
186 const size_t JSFRAME_MAX = 64;
187 JsFrame jsFrames[JSFRAME_MAX];
188 size_t size = JSFRAME_MAX;
189 if (memset_s(jsFrames, sizeof(JsFrame) * JSFRAME_MAX, 0, sizeof(JsFrame) * JSFRAME_MAX) != 0) {
190 LOGE("Failed to memset_s jsFrames.");
191 return false;
192 }
193 uintptr_t prevPc = pc;
194 uintptr_t prevSp = sp;
195 uintptr_t prevFp = fp;
196 LOGI("Ark input pc: %" PRIx64 ", fp: %" PRIx64 ", sp: %" PRIx64 ".", (uint64_t)pc, (uint64_t)fp, (uint64_t)sp);
197 int ret = DfxArk::GetArkNativeFrameInfo(pid_, pc, fp, sp, jsFrames, size);
198 LOGI("Ark output pc: %" PRIx64 ", fp: %" PRIx64 ", sp: %" PRIx64 ", js frame size: %zu.",
199 (uint64_t)pc, (uint64_t)fp, (uint64_t)sp, size);
200
201 if (ret < 0 || (pc == prevPc && prevSp == sp && prevFp == fp)) {
202 return false;
203 }
204 for (size_t i = 0; i < size; ++i) {
205 DfxFrame frame;
206 frame.isJsFrame = true;
207 frame.index = (curIdx++);
208 frame.mapName = std::string(jsFrames[i].url);
209 frame.funcName = std::string(jsFrames[i].functionName);
210 frame.line = jsFrames[i].line;
211 frame.column = jsFrames[i].column;
212 frames_.emplace_back(frame);
213 }
214 regs_->SetPc(pc);
215 regs_->SetSp(sp);
216 regs_->SetFp(fp);
217 return true;
218 }
219 #endif
220
Unwind(void * ctx,size_t maxFrameNum,size_t skipFrameNum)221 bool Unwinder::Unwind(void *ctx, size_t maxFrameNum, size_t skipFrameNum)
222 {
223 if ((ctx == nullptr) || (regs_ == nullptr) || (maps_ == nullptr)) {
224 LOGE("params is nullptr?");
225 return false;
226 }
227 Clear();
228
229 bool needAdjustPc = false;
230 bool isFirstValidFrame = false;
231 size_t skipIndex = 0;
232 size_t curIndex = 0;
233 uintptr_t pc = 0, sp = 0, stepPc = 0;
234 std::shared_ptr<DfxMap> map = nullptr;
235 do {
236 if (skipIndex < skipFrameNum) {
237 skipIndex++;
238 continue;
239 }
240 if (curIndex >= maxFrameNum) {
241 lastErrorData_.SetCode(UNW_ERROR_MAX_FRAMES_EXCEEDED);
242 break;
243 }
244 SetLocalStackCheck(ctx, false);
245
246 pc = regs_->GetPc();
247 sp = regs_->GetSp();
248 if (!GetMapByPc(pc, ctx, map)) {
249 if (isFirstValidFrame) {
250 lastErrorData_.SetAddrAndCode(pc, UNW_ERROR_INVALID_MAP);
251 break;
252 }
253
254 if (enableLrFallback_ && regs_->SetPcFromReturnAddress(memory_)) {
255 LOGW("Failed to get map, lr fallback");
256 AddFrame(pc, sp, map, curIndex);
257 continue;
258 }
259
260 uintptr_t fp = regs_->GetFp();
261 if (!FpStep(fp, pc, ctx)) {
262 break;
263 }
264 LOGW("Failed to get map, fp fallback");
265 isFirstValidFrame = true;
266 continue;
267 }
268 isFirstValidFrame = true;
269
270 if (needAdjustPc) {
271 DoPcAdjust(pc);
272 }
273 needAdjustPc = true;
274
275 AddFrame(pc, sp, map, curIndex);
276 #if defined(ENABLE_MIXSTACK)
277 if (map->IsArkExecutable()) {
278 if (!StepArkJsFrame(curIndex)) {
279 LOGE("Failed to step ark Js frames, curIndex: %zu", curIndex);
280 break;
281 }
282 continue;
283 }
284 #endif
285
286 stepPc = pc;
287 if (!Step(stepPc, sp, ctx)) {
288 break;
289 }
290 } while (true);
291 LOGU("Last error code: %d, addr: %p", (int)GetLastErrorCode(), reinterpret_cast<void *>(GetLastErrorAddr()));
292 return (curIndex > 0);
293 }
294
UnwindByFp(void * ctx,size_t maxFrameNum,size_t skipFrameNum)295 bool Unwinder::UnwindByFp(void *ctx, size_t maxFrameNum, size_t skipFrameNum)
296 {
297 if (regs_ == nullptr) {
298 LOGE("params is nullptr?");
299 return false;
300 }
301 pcs_.clear();
302
303 size_t idx = 0;
304 size_t curIdx = 0;
305 uintptr_t pc = 0;
306 uintptr_t fp = 0;
307 do {
308 if (idx < skipFrameNum) {
309 idx++;
310 continue;
311 }
312
313 if (curIdx >= maxFrameNum) {
314 lastErrorData_.SetCode(UNW_ERROR_MAX_FRAMES_EXCEEDED);
315 break;
316 }
317
318 pc = regs_->GetPc();
319 fp = regs_->GetFp();
320 pcs_.emplace_back(pc);
321
322 if (!FpStep(fp, pc, ctx) || (pc == 0)) {
323 break;
324 }
325 curIdx++;
326 } while (true);
327 return (curIdx > 0);
328 }
329
Step(uintptr_t & pc,uintptr_t & sp,void * ctx)330 bool Unwinder::Step(uintptr_t& pc, uintptr_t& sp, void *ctx)
331 {
332 if (regs_ == nullptr || memory_ == nullptr) {
333 LOGE("params is nullptr");
334 return false;
335 }
336 LOGU("++++++pc: %" PRIx64 ", sp: %" PRIx64 "", (uint64_t)pc, (uint64_t)sp);
337 SetLocalStackCheck(ctx, false);
338 memory_->SetCtx(ctx);
339 bool isSignalFrame = false;
340 uintptr_t prevPc = pc;
341 uintptr_t prevSp = sp;
342
343 std::shared_ptr<RegLocState> rs = nullptr;
344 bool ret = false;
345 do {
346 if (isFpStep_) {
347 break;
348 }
349
350 if (enableCache_) {
351 // 1. find cache rs
352 auto iter = rsCache_.find(pc);
353 if (iter != rsCache_.end()) {
354 if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
355 LOGI("Find rs cache, pc: %p", reinterpret_cast<void *>(pc));
356 }
357 rs = iter->second;
358 ret = true;
359 break;
360 }
361 }
362
363 // Check if this is a signal frame.
364 if (regs_->StepIfSignalFrame(pc, memory_)) {
365 isSignalFrame = true;
366 break;
367 }
368
369 // 2. find unwind table and entry
370 UnwindTableInfo uti;
371 MAYBE_UNUSED int utiRet = acc_->FindUnwindTable(pc, uti, ctx);
372 if (utiRet != UNW_ERROR_NONE) {
373 lastErrorData_.SetAddrAndCode(pc, UNW_ERROR_NO_UNWIND_INFO);
374 LOGU("Failed to find unwind table ret: %d", utiRet);
375 break;
376 }
377
378 // 3. parse instructions and get cache rs
379 struct UnwindEntryInfo uei;
380 rs = std::make_shared<RegLocState>();
381 #if defined(__arm__)
382 if (!ret && uti.format == UNW_INFO_FORMAT_ARM_EXIDX) {
383 if (!armExidx_->SearchEntry(pc, uti, uei)) {
384 lastErrorData_.SetAddrAndCode(armExidx_->GetLastErrorAddr(), armExidx_->GetLastErrorCode());
385 LOGE("Failed to search unwind entry?");
386 break;
387 }
388 if (!armExidx_->Step((uintptr_t)uei.unwindInfo, rs)) {
389 lastErrorData_.SetAddrAndCode(armExidx_->GetLastErrorAddr(), armExidx_->GetLastErrorCode());
390 LOGU("Step exidx section error?");
391 } else {
392 ret = true;
393 }
394 }
395 #endif
396 if (!ret && uti.format == UNW_INFO_FORMAT_REMOTE_TABLE) {
397 if ((uti.isLinear == false && !dwarfSection_->SearchEntry(pc, uti, uei)) ||
398 (uti.isLinear == true && !dwarfSection_->LinearSearchEntry(pc, uti, uei))) {
399 lastErrorData_.SetAddrAndCode(dwarfSection_->GetLastErrorAddr(), dwarfSection_->GetLastErrorCode());
400 LOGU("Failed to search unwind entry?");
401 break;
402 }
403 memory_->SetDataOffset(uti.segbase);
404 if (!dwarfSection_->Step((uintptr_t)uei.unwindInfo, regs_, rs)) {
405 lastErrorData_.SetAddrAndCode(dwarfSection_->GetLastErrorAddr(), dwarfSection_->GetLastErrorCode());
406 LOGU("Step dwarf section error?");
407 } else {
408 ret = true;
409 }
410 }
411
412 if (ret && enableCache_) {
413 // 4. update rs cache
414 rsCache_.emplace(pc, rs);
415 break;
416 }
417 } while (false);
418
419 if (!isSignalFrame) {
420 // 5. update regs and regs state
421 if (ret) {
422 SetLocalStackCheck(ctx, true);
423 ret = Apply(regs_, rs);
424 }
425 } else {
426 LOGW("Step signal frame");
427 ret = true;
428 }
429
430 #if defined(__aarch64__)
431 if (!ret && enableFpFallback_) {
432 uintptr_t fp = regs_->GetFp();
433 ret = FpStep(fp, pc, ctx);
434 }
435 #endif
436
437 pc = regs_->GetPc();
438 sp = regs_->GetSp();
439 if (ret && (prevPc == pc) && (prevSp == sp)) {
440 if (pid_ >= 0) {
441 MAYBE_UNUSED UnwindContext* uctx = reinterpret_cast<UnwindContext *>(ctx);
442 LOGU("pc and sp is same, tid: %d", uctx->pid);
443 } else {
444 LOGU("pc and sp is same");
445 }
446 lastErrorData_.SetAddrAndCode(pc, UNW_ERROR_REPEATED_FRAME);
447 ret = false;
448 }
449
450 uintptr_t tmp = 0;
451 if (ret && ((pc == 0) || (!memory_->ReadUptr(sp, &tmp, false)))) {
452 LOGU("------pc: %" PRIx64 ", sp: %" PRIx64 " error?", (uint64_t)pc, (uint64_t)sp);
453 ret = false;
454 } else {
455 LOGU("------pc: %" PRIx64 ", sp: %" PRIx64 "", (uint64_t)pc, (uint64_t)sp);
456 }
457 return ret;
458 }
459
FpStep(uintptr_t & fp,uintptr_t & pc,void * ctx)460 bool Unwinder::FpStep(uintptr_t& fp, uintptr_t& pc, void *ctx)
461 {
462 #if defined(__aarch64__)
463 LOGU("++++++fp: %lx, pc: %lx", (uint64_t)fp, (uint64_t)pc);
464 if (!isFpStep_) {
465 LOGI("First enter fp step, pc: %p", reinterpret_cast<void *>(pc));
466 isFpStep_ = true;
467 }
468 SetLocalStackCheck(ctx, true);
469 memory_->SetCtx(ctx);
470
471 uintptr_t prevFp = fp;
472 uintptr_t ptr = fp;
473 if (memory_->ReadUptr(ptr, &fp, true) &&
474 memory_->ReadUptr(ptr, &pc, false)) {
475 if (enableFpCheckMapExec_) {
476 std::shared_ptr<DfxMap> map = nullptr;
477 if (!GetMapByPc(pc, ctx, map) || !map->IsMapExec()) {
478 return false;
479 }
480 }
481 regs_->SetReg(REG_FP, &fp);
482 regs_->SetReg(REG_PC, &pc);
483 regs_->SetReg(REG_SP, &prevFp);
484 if (pid_ == UNWIND_TYPE_CUSTOMIZE) {
485 regs_->SetPc(StripPac(pc, pacMask_));
486 }
487 LOGU("------fp: %lx, pc: %lx", (uint64_t)fp, (uint64_t)pc);
488 return true;
489 }
490 #endif
491 return false;
492 }
493
Apply(std::shared_ptr<DfxRegs> regs,std::shared_ptr<RegLocState> rs)494 bool Unwinder::Apply(std::shared_ptr<DfxRegs> regs, std::shared_ptr<RegLocState> rs)
495 {
496 bool ret = false;
497 if (rs == nullptr || regs == nullptr) {
498 return false;
499 }
500 ret = DfxInstructions::Apply(memory_, *(regs.get()), *(rs.get()));
501 if (!ret) {
502 LOGE("Failed to apply rs");
503 }
504 #if defined(__arm__) || defined(__aarch64__)
505 if (!rs->isPcSet) {
506 regs_->SetReg(REG_PC, regs->GetReg(REG_LR));
507 }
508 #endif
509
510 if (rs->pseudoReg != 0) {
511 regs->SetPc(StripPac(regs_->GetPc(), pacMask_));
512 }
513 return ret;
514 }
515
StripPac(uintptr_t inAddr,uintptr_t pacMask)516 uintptr_t Unwinder::StripPac(uintptr_t inAddr, uintptr_t pacMask)
517 {
518 uintptr_t outAddr = inAddr;
519 #if defined(__aarch64__)
520 if (outAddr != 0) {
521 if (pacMask != 0) {
522 outAddr &= ~pacMask;
523 } else {
524 register uint64_t x30 __asm("x30") = inAddr;
525 asm("hint 0x7" : "+r"(x30));
526 outAddr = x30;
527 }
528 if (outAddr != inAddr) {
529 LOGW("Strip pac in addr: %lx, out addr: %lx", (uint64_t)inAddr, (uint64_t)outAddr);
530 }
531 }
532 #endif
533 return outAddr;
534 }
535
DoPcAdjust(uintptr_t & pc)536 void Unwinder::DoPcAdjust(uintptr_t& pc)
537 {
538 if (pc <= 0x4) {
539 return;
540 }
541 uintptr_t sz = 0x4;
542 #if defined(__arm__)
543 if (pc & 0x1) {
544 uintptr_t val;
545 if (pc < 0x5 || !(memory_->ReadMem(pc - 0x5, &val)) ||
546 (val & 0xe000f000) != 0xe000f000) {
547 sz = 0x2;
548 }
549 }
550 #elif defined(__x86_64__)
551 sz = 0x1;
552 #endif
553 pc -= sz;
554 }
555
GetFrames()556 std::vector<DfxFrame>& Unwinder::GetFrames()
557 {
558 if (enableFillFrames_) {
559 FillFrames(frames_);
560 }
561 return frames_;
562 }
563
SetFrames(std::vector<DfxFrame> & frames)564 void Unwinder::SetFrames(std::vector<DfxFrame>& frames)
565 {
566 frames_ = frames;
567 }
568
AddFrame(uintptr_t pc,uintptr_t sp,std::shared_ptr<DfxMap> map,size_t & index)569 void Unwinder::AddFrame(uintptr_t pc, uintptr_t sp, std::shared_ptr<DfxMap> map, size_t& index)
570 {
571 pcs_.emplace_back(pc);
572 DfxFrame frame;
573 frame.index = (index++);
574 frame.sp = static_cast<uint64_t>(sp);
575 frame.pc = static_cast<uint64_t>(pc);
576 frame.map = map;
577 frames_.emplace_back(frame);
578 }
579
AddFrame(DfxFrame & frame)580 void Unwinder::AddFrame(DfxFrame& frame)
581 {
582 frames_.emplace_back(frame);
583 }
584
FillFrames(std::vector<DfxFrame> & frames)585 void Unwinder::FillFrames(std::vector<DfxFrame>& frames)
586 {
587 for (size_t i = 0; i < frames.size(); ++i) {
588 FillFrame(frames[i]);
589 }
590 }
591
FillFrame(DfxFrame & frame)592 void Unwinder::FillFrame(DfxFrame& frame)
593 {
594 if (frame.isJsFrame) {
595 return;
596 }
597 if (frame.map == nullptr) {
598 frame.relPc = frame.pc;
599 frame.mapName = "Not mapped";
600 LOGU("Current frame is not mapped.");
601 return;
602 }
603 frame.relPc = frame.map->GetRelPc(frame.pc);
604 frame.mapName = frame.map->GetElfName();
605 frame.mapOffset = frame.map->offset;
606 auto elf = frame.map->GetElf();
607 if (elf == nullptr) {
608 LOGU("elf is null, mapName: %s", frame.mapName.c_str());
609 return;
610 }
611 LOGU("mapName: %s, mapOffset: %" PRIx64 "", frame.mapName.c_str(), frame.mapOffset);
612 if (!DfxSymbols::GetFuncNameAndOffsetByPc(frame.relPc, elf, frame.funcName, frame.funcOffset)) {
613 LOGU("Failed to get symbol, mapName: %s, relPc: %" PRIx64 "", frame.mapName.c_str(), frame.relPc);
614 }
615 frame.buildId = elf->GetBuildId();
616 }
617
GetFramesByPcs(std::vector<DfxFrame> & frames,std::vector<uintptr_t> pcs,std::shared_ptr<DfxMaps> maps)618 void Unwinder::GetFramesByPcs(std::vector<DfxFrame>& frames, std::vector<uintptr_t> pcs,
619 std::shared_ptr<DfxMaps> maps)
620 {
621 frames.clear();
622 std::shared_ptr<DfxMap> map = nullptr;
623 for (size_t i = 0; i < pcs.size(); ++i) {
624 DfxFrame frame;
625 frame.index = i;
626 frame.pc = static_cast<uint64_t>(pcs[i]);
627 if ((map != nullptr) && map->Contain(frame.pc)) {
628 LOGU("map had matched");
629 } else {
630 if (!maps->FindMapByAddr(pcs[i], map) || (map == nullptr)) {
631 LOGE("map is null");
632 continue;
633 }
634 }
635 frame.map = map;
636 FillFrame(frame);
637 frames.emplace_back(frame);
638 }
639 }
640
GetSymbolByPc(uintptr_t pc,std::shared_ptr<DfxMaps> maps,std::string & funcName,uint64_t & funcOffset)641 bool Unwinder::GetSymbolByPc(uintptr_t pc, std::shared_ptr<DfxMaps> maps, std::string& funcName, uint64_t& funcOffset)
642 {
643 if (maps == nullptr) {
644 return false;
645 }
646 std::shared_ptr<DfxMap> map = nullptr;
647 if (!maps->FindMapByAddr(pc, map) || (map == nullptr)) {
648 LOGE("Find map is null");
649 return false;
650 }
651 uint64_t relPc = map->GetRelPc(static_cast<uint64_t>(pc));
652 auto elf = map->GetElf();
653 if (elf == nullptr) {
654 LOGE("Get elf is null");
655 return false;
656 }
657 return DfxSymbols::GetFuncNameAndOffsetByPc(relPc, elf, funcName, funcOffset);
658 }
659
GetFramesStr(const std::vector<DfxFrame> & frames)660 std::string Unwinder::GetFramesStr(const std::vector<DfxFrame>& frames)
661 {
662 return DfxFrameFormatter::GetFramesStr(frames);
663 }
664 } // namespace HiviewDFX
665 } // namespace OHOS
666