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 <unordered_map>
19 #include <dlfcn.h>
20 #include <link.h>
21 
22 #if defined(__arm__)
23 #include "arm_exidx.h"
24 #endif
25 #include "dfx_ark.h"
26 #include "dfx_define.h"
27 #include "dfx_errors.h"
28 #include "dfx_frame_formatter.h"
29 #include "dfx_hap.h"
30 #include "dfx_instructions.h"
31 #include "dfx_log.h"
32 #include "dfx_memory.h"
33 #include "dfx_param.h"
34 #include "dfx_regs_get.h"
35 #include "dfx_symbols.h"
36 #include "dfx_trace_dlsym.h"
37 #include "dwarf_section.h"
38 #include "fp_unwinder.h"
39 #include "stack_util.h"
40 #include "string_printf.h"
41 #include "string_util.h"
42 #include "thread_context.h"
43 #include "elapsed_time.h"
44 
45 namespace OHOS {
46 namespace HiviewDFX {
47 #undef LOG_DOMAIN
48 #undef LOG_TAG
49 #define LOG_DOMAIN 0xD002D11
50 #define LOG_TAG "DfxUnwinder"
51 
52 class Unwinder::Impl {
53 public:
54     // for local
Impl(bool needMaps)55     Impl(bool needMaps) : pid_(UNWIND_TYPE_LOCAL)
56     {
57         if (needMaps) {
58             maps_ = DfxMaps::Create();
59         }
60         acc_ = std::make_shared<DfxAccessorsLocal>();
61         enableFpCheckMapExec_ = true;
62         Init();
63     }
64 
65     // for remote
Impl(int pid, bool crash)66     Impl(int pid, bool crash) : pid_(pid)
67     {
68         if (pid <= 0) {
69             DFXLOGE("pid(%{public}d) error", pid);
70             return;
71         }
72         DfxEnableTraceDlsym(true);
73         maps_ = DfxMaps::Create(pid, crash);
74         acc_ = std::make_shared<DfxAccessorsRemote>();
75         enableFpCheckMapExec_ = true;
76         Init();
77     }
78 
Impl(int pid, int nspid, bool crash)79     Impl(int pid, int nspid, bool crash) : pid_(nspid)
80     {
81         if (pid <= 0 || nspid <= 0) {
82             DFXLOGE("pid(%{public}d) or nspid(%{public}d) error", pid, nspid);
83             return;
84         }
85         DfxEnableTraceDlsym(true);
86         maps_ = DfxMaps::Create(pid, crash);
87         acc_ = std::make_shared<DfxAccessorsRemote>();
88         enableFpCheckMapExec_ = true;
89         Init();
90     }
91 
92     // for customized
Impl(const std::shared_ptr<UnwindAccessors> &accessors, bool local)93     Impl(const std::shared_ptr<UnwindAccessors> &accessors, bool local)
94     {
95         if (local) {
96             pid_ = UNWIND_TYPE_CUSTOMIZE_LOCAL;
97         } else {
98             pid_ = UNWIND_TYPE_CUSTOMIZE;
99         }
100         acc_ = std::make_shared<DfxAccessorsCustomize>(accessors);
101         enableFpCheckMapExec_ = false;
102         enableFillFrames_ = false;
103     #if defined(__aarch64__)
104         pacMask_ = pacMaskDefault_;
105     #endif
106         Init();
107     }
108 
~Impl()109     ~Impl()
110     {
111         DfxEnableTraceDlsym(false);
112         Destroy();
113         if (pid_ == UNWIND_TYPE_LOCAL) {
114             LocalThreadContext::GetInstance().CleanUp();
115         }
116     }
117 
EnableUnwindCache(bool enableCache)118     inline void EnableUnwindCache(bool enableCache)
119     {
120         enableCache_ = enableCache;
121     }
EnableFpCheckMapExec(bool enableFpCheckMapExec)122     inline void EnableFpCheckMapExec(bool enableFpCheckMapExec)
123     {
124         enableFpCheckMapExec_ = enableFpCheckMapExec;
125     }
EnableFillFrames(bool enableFillFrames)126     inline void EnableFillFrames(bool enableFillFrames)
127     {
128         enableFillFrames_ = enableFillFrames;
129     }
EnableMethodIdLocal(bool enableMethodIdLocal)130     inline void EnableMethodIdLocal(bool enableMethodIdLocal)
131     {
132         enableMethodIdLocal_ = enableMethodIdLocal;
133     }
IgnoreMixstack(bool ignoreMixstack)134     inline void IgnoreMixstack(bool ignoreMixstack)
135     {
136         ignoreMixstack_ = ignoreMixstack;
137     }
138 
SetRegs(const std::shared_ptr<DfxRegs> &regs)139     inline void SetRegs(const std::shared_ptr<DfxRegs> &regs)
140     {
141         if (regs == nullptr) {
142             return;
143         }
144         regs_ = regs;
145         firstFrameSp_ = regs_->GetSp();
146     }
147 
GetRegs() const148     inline const std::shared_ptr<DfxRegs>& GetRegs() const
149     {
150         return regs_;
151     }
152 
GetMaps() const153     inline const std::shared_ptr<DfxMaps>& GetMaps() const
154     {
155         return maps_;
156     }
157 
GetLastErrorCode()158     inline uint16_t GetLastErrorCode()
159     {
160         return lastErrorData_.GetCode();
161     }
GetLastErrorAddr()162     inline uint64_t GetLastErrorAddr()
163     {
164         return lastErrorData_.GetAddr();
165     }
166 
167     bool GetStackRange(uintptr_t& stackBottom, uintptr_t& stackTop);
168 
169     bool UnwindLocalWithContext(const ucontext_t& context, size_t maxFrameNum, size_t skipFrameNum);
170     bool UnwindLocalWithTid(pid_t tid, size_t maxFrameNum, size_t skipFrameNum);
171     bool UnwindLocal(bool withRegs, bool fpUnwind, size_t maxFrameNum, size_t skipFrameNum);
172     bool UnwindRemote(pid_t tid, bool withRegs, size_t maxFrameNum, size_t skipFrameNum);
173     bool Unwind(void *ctx, size_t maxFrameNum, size_t skipFrameNum);
174     bool UnwindByFp(void *ctx, size_t maxFrameNum, size_t skipFrameNum);
175 
176     bool Step(uintptr_t& pc, uintptr_t& sp, void *ctx);
177     bool FpStep(uintptr_t& fp, uintptr_t& pc, void *ctx);
178 
179     void AddFrame(DfxFrame& frame);
180     const std::vector<DfxFrame>& GetFrames();
GetPcs() const181     inline const std::vector<uintptr_t>& GetPcs() const
182     {
183         return pcs_;
184     }
185     void FillFrames(std::vector<DfxFrame>& frames);
186     void FillFrame(DfxFrame& frame);
187     void FillJsFrame(DfxFrame& frame);
188     bool GetFrameByPc(uintptr_t pc, std::shared_ptr<DfxMaps> maps, DfxFrame& frame);
189     void GetFramesByPcs(std::vector<DfxFrame>& frames, std::vector<uintptr_t> pcs);
SetIsJitCrashFlag(bool isCrash)190     inline void SetIsJitCrashFlag(bool isCrash)
191     {
192         isJitCrash_ = isCrash;
193     }
194     int ArkWriteJitCodeToFile(int fd);
195     bool GetLockInfo(int32_t tid, char* buf, size_t sz);
SetFrames(const std::vector<DfxFrame>& frames)196     void SetFrames(const std::vector<DfxFrame>& frames)
197     {
198         frames_ = frames;
199     }
GetJitCache(void) const200     inline const std::vector<uintptr_t>& GetJitCache(void) const
201     {
202         return jitCache_;
203     }
204     static int DlPhdrCallback(struct dl_phdr_info *info, size_t size, void *data);
205 private:
206     struct StepFrame {
207         uintptr_t pc = 0;
208         uintptr_t methodid = 0;
209         uintptr_t sp = 0;
210         uintptr_t fp = 0;
211         bool isJsFrame {false};
212     };
213     struct StepCache {
214         std::shared_ptr<DfxMap> map = nullptr;
215         std::shared_ptr<RegLocState> rs = nullptr;
216     };
217     void Init();
218     void Clear();
219     void Destroy();
InitParam()220     void InitParam()
221     {
222 #if defined(ENABLE_MIXSTACK)
223         enableMixstack_ = DfxParam::EnableMixstack();
224 #endif
225     }
226     bool GetMainStackRangeInner(uintptr_t& stackBottom, uintptr_t& stackTop);
227     bool CheckAndReset(void* ctx);
228     void DoPcAdjust(uintptr_t& pc);
229     void AddFrame(const StepFrame& frame, std::shared_ptr<DfxMap> map);
230     bool StepInner(const bool isSigFrame, StepFrame& frame, void *ctx);
231     bool Apply(std::shared_ptr<DfxRegs> regs, std::shared_ptr<RegLocState> rs);
232 #if defined(ENABLE_MIXSTACK)
233     bool StepArkJsFrame(StepFrame& frame);
234 #endif
235     static uintptr_t StripPac(uintptr_t inAddr, uintptr_t pacMask);
SetLocalStackCheck(void* ctx, bool check) const236     inline void SetLocalStackCheck(void* ctx, bool check) const
237     {
238         if ((pid_ == UNWIND_TYPE_LOCAL) && (ctx != nullptr)) {
239             UnwindContext* uctx = reinterpret_cast<UnwindContext *>(ctx);
240             uctx->stackCheck = check;
241         }
242     }
243 
244 #if defined(__aarch64__)
245     MAYBE_UNUSED const uintptr_t pacMaskDefault_ = static_cast<uintptr_t>(0xFFFFFF8000000000);
246 #endif
247     bool enableCache_ = true;
248     bool enableFillFrames_ = true;
249     bool enableLrFallback_ = true;
250     bool enableFpCheckMapExec_ = false;
251     bool enableMethodIdLocal_ = false;
252     bool isFpStep_ = false;
253     MAYBE_UNUSED bool enableMixstack_ = true;
254     MAYBE_UNUSED bool ignoreMixstack_ = false;
255     MAYBE_UNUSED bool stopWhenArkFrame_ = false;
256     MAYBE_UNUSED bool isJitCrash_ = false;
257 
258     int32_t pid_ = 0;
259     uintptr_t pacMask_ = 0;
260     std::vector<uintptr_t> jitCache_ = {};
261     std::shared_ptr<DfxAccessors> acc_ = nullptr;
262     std::shared_ptr<DfxMemory> memory_ = nullptr;
263     std::unordered_map<uintptr_t, StepCache> stepCache_ {};
264     std::shared_ptr<DfxRegs> regs_ = nullptr;
265     std::shared_ptr<DfxMaps> maps_ = nullptr;
266     std::vector<uintptr_t> pcs_ {};
267     std::vector<DfxFrame> frames_ {};
268     UnwindErrorData lastErrorData_ {};
269 #if defined(__arm__)
270     std::shared_ptr<ArmExidx> armExidx_ = nullptr;
271 #endif
272     std::shared_ptr<DwarfSection> dwarfSection_ = nullptr;
273     uintptr_t firstFrameSp_ {0};
274 };
275 
276 // for local
Unwinder(bool needMaps)277 Unwinder::Unwinder(bool needMaps) : impl_(std::make_shared<Impl>(needMaps))
278 {
279 }
280 
281 // for remote
Unwinder(int pid, bool crash)282 Unwinder::Unwinder(int pid, bool crash) : impl_(std::make_shared<Impl>(pid, crash))
283 {
284 }
285 
Unwinder(int pid, int nspid, bool crash)286 Unwinder::Unwinder(int pid, int nspid, bool crash) : impl_(std::make_shared<Impl>(pid, nspid, crash))
287 {
288 }
289 
290 // for customized
Unwinder(std::shared_ptr<UnwindAccessors> accessors, bool local)291 Unwinder::Unwinder(std::shared_ptr<UnwindAccessors> accessors, bool local)
292     : impl_(std::make_shared<Impl>(accessors, local))
293 {
294 }
295 
EnableUnwindCache(bool enableCache)296 void Unwinder::EnableUnwindCache(bool enableCache)
297 {
298     impl_->EnableUnwindCache(enableCache);
299 }
300 
EnableFpCheckMapExec(bool enableFpCheckMapExec)301 void Unwinder::EnableFpCheckMapExec(bool enableFpCheckMapExec)
302 {
303     impl_->EnableFpCheckMapExec(enableFpCheckMapExec);
304 }
305 
EnableFillFrames(bool enableFillFrames)306 void Unwinder::EnableFillFrames(bool enableFillFrames)
307 {
308     impl_->EnableFillFrames(enableFillFrames);
309 }
EnableMethodIdLocal(bool enableMethodIdLocal)310 void Unwinder::EnableMethodIdLocal(bool enableMethodIdLocal)
311 {
312     impl_->EnableMethodIdLocal(enableMethodIdLocal);
313 }
IgnoreMixstack(bool ignoreMixstack)314 void Unwinder::IgnoreMixstack(bool ignoreMixstack)
315 {
316     impl_->IgnoreMixstack(ignoreMixstack);
317 }
318 
SetRegs(std::shared_ptr<DfxRegs> regs)319 void Unwinder::SetRegs(std::shared_ptr<DfxRegs> regs)
320 {
321     impl_->SetRegs(regs);
322 }
323 
GetRegs() const324 const std::shared_ptr<DfxRegs>& Unwinder::GetRegs() const
325 {
326     return impl_->GetRegs();
327 }
328 
GetMaps() const329 const std::shared_ptr<DfxMaps>& Unwinder::GetMaps() const
330 {
331     return impl_->GetMaps();
332 }
333 
GetLastErrorCode() const334 uint16_t Unwinder::GetLastErrorCode() const
335 {
336     return impl_->GetLastErrorCode();
337 }
338 
GetLastErrorAddr() const339 uint64_t Unwinder::GetLastErrorAddr() const
340 {
341     return impl_->GetLastErrorAddr();
342 }
343 
GetStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)344 bool Unwinder::GetStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
345 {
346     return impl_->GetStackRange(stackBottom, stackTop);
347 }
348 
UnwindLocalWithContext(const ucontext_t& context, size_t maxFrameNum, size_t skipFrameNum)349 bool Unwinder::UnwindLocalWithContext(const ucontext_t& context, size_t maxFrameNum, size_t skipFrameNum)
350 {
351     return impl_->UnwindLocalWithContext(context, maxFrameNum, skipFrameNum);
352 }
353 
UnwindLocalWithTid(pid_t tid, size_t maxFrameNum, size_t skipFrameNum)354 bool Unwinder::UnwindLocalWithTid(pid_t tid, size_t maxFrameNum, size_t skipFrameNum)
355 {
356     return impl_->UnwindLocalWithTid(tid, maxFrameNum, skipFrameNum);
357 }
358 
UnwindLocal(bool withRegs, bool fpUnwind, size_t maxFrameNum, size_t skipFrameNum)359 bool Unwinder::UnwindLocal(bool withRegs, bool fpUnwind, size_t maxFrameNum, size_t skipFrameNum)
360 {
361     return impl_->UnwindLocal(withRegs, fpUnwind, maxFrameNum, skipFrameNum);
362 }
363 
UnwindRemote(pid_t tid, bool withRegs, size_t maxFrameNum, size_t skipFrameNum)364 bool Unwinder::UnwindRemote(pid_t tid, bool withRegs, size_t maxFrameNum, size_t skipFrameNum)
365 {
366     return impl_->UnwindRemote(tid, withRegs, maxFrameNum, skipFrameNum);
367 }
368 
Unwind(void *ctx, size_t maxFrameNum, size_t skipFrameNum)369 bool Unwinder::Unwind(void *ctx, size_t maxFrameNum, size_t skipFrameNum)
370 {
371     return impl_->Unwind(ctx, maxFrameNum, skipFrameNum);
372 }
373 
UnwindByFp(void *ctx, size_t maxFrameNum, size_t skipFrameNum)374 bool Unwinder::UnwindByFp(void *ctx, size_t maxFrameNum, size_t skipFrameNum)
375 {
376     return impl_->UnwindByFp(ctx, maxFrameNum, skipFrameNum);
377 }
378 
Step(uintptr_t& pc, uintptr_t& sp, void *ctx)379 bool Unwinder::Step(uintptr_t& pc, uintptr_t& sp, void *ctx)
380 {
381     return impl_->Step(pc, sp, ctx);
382 }
383 
FpStep(uintptr_t& fp, uintptr_t& pc, void *ctx)384 bool Unwinder::FpStep(uintptr_t& fp, uintptr_t& pc, void *ctx)
385 {
386     return impl_->FpStep(fp, pc, ctx);
387 }
388 
AddFrame(DfxFrame& frame)389 void Unwinder::AddFrame(DfxFrame& frame)
390 {
391     impl_->AddFrame(frame);
392 }
393 
GetFrames() const394 const std::vector<DfxFrame>& Unwinder::GetFrames() const
395 {
396     return impl_->GetFrames();
397 }
398 
GetPcs() const399 const std::vector<uintptr_t>& Unwinder::GetPcs() const
400 {
401     return impl_->GetPcs();
402 }
403 
FillFrames(std::vector<DfxFrame>& frames)404 void Unwinder::FillFrames(std::vector<DfxFrame>& frames)
405 {
406     impl_->FillFrames(frames);
407 }
408 
FillFrame(DfxFrame& frame)409 void Unwinder::FillFrame(DfxFrame& frame)
410 {
411     impl_->FillFrame(frame);
412 }
413 
FillJsFrame(DfxFrame& frame)414 void Unwinder::FillJsFrame(DfxFrame& frame)
415 {
416     impl_->FillJsFrame(frame);
417 }
418 
GetFrameByPc(uintptr_t pc, std::shared_ptr<DfxMaps> maps, DfxFrame& frame)419 bool Unwinder::GetFrameByPc(uintptr_t pc, std::shared_ptr<DfxMaps> maps, DfxFrame& frame)
420 {
421     return impl_->GetFrameByPc(pc, maps, frame);
422 }
423 
GetFramesByPcs(std::vector<DfxFrame>& frames, std::vector<uintptr_t> pcs)424 void Unwinder::GetFramesByPcs(std::vector<DfxFrame>& frames, std::vector<uintptr_t> pcs)
425 {
426     impl_->GetFramesByPcs(frames, pcs);
427 }
428 
SetIsJitCrashFlag(bool isCrash)429 void Unwinder::SetIsJitCrashFlag(bool isCrash)
430 {
431     impl_->SetIsJitCrashFlag(isCrash);
432 }
433 
ArkWriteJitCodeToFile(int fd)434 int Unwinder::ArkWriteJitCodeToFile(int fd)
435 {
436     return impl_->ArkWriteJitCodeToFile(fd);
437 }
438 
GetJitCache()439 const std::vector<uintptr_t>& Unwinder::GetJitCache()
440 {
441     return impl_->GetJitCache();
442 }
443 
GetLockInfo(int32_t tid, char* buf, size_t sz)444 bool Unwinder::GetLockInfo(int32_t tid, char* buf, size_t sz)
445 {
446     return impl_->GetLockInfo(tid, buf, sz);
447 }
448 
SetFrames(std::vector<DfxFrame>& frames)449 void Unwinder::SetFrames(std::vector<DfxFrame>& frames)
450 {
451     impl_->SetFrames(frames);
452 }
453 
Init()454 void Unwinder::Impl::Init()
455 {
456     Destroy();
457     memory_ = std::make_shared<DfxMemory>(acc_);
458 #if defined(__arm__)
459     armExidx_ = std::make_shared<ArmExidx>(memory_);
460 #endif
461     dwarfSection_ = std::make_shared<DwarfSection>(memory_);
462 
463     InitParam();
464 #if defined(ENABLE_MIXSTACK)
465     DFXLOGD("Unwinder mixstack enable: %{public}d", enableMixstack_);
466 #else
467     DFXLOGD("Unwinder init");
468 #endif
469 }
470 
Clear()471 void Unwinder::Impl::Clear()
472 {
473     isFpStep_ = false;
474     enableMixstack_ = true;
475     pcs_.clear();
476     frames_.clear();
477     if (memset_s(&lastErrorData_, sizeof(UnwindErrorData), 0, sizeof(UnwindErrorData)) != 0) {
478         DFXLOGE("Failed to memset lastErrorData");
479     }
480 }
481 
Destroy()482 void Unwinder::Impl::Destroy()
483 {
484     Clear();
485     stepCache_.clear();
486 }
487 
CheckAndReset(void* ctx)488 bool Unwinder::Impl::CheckAndReset(void* ctx)
489 {
490     if ((ctx == nullptr) || (memory_ == nullptr)) {
491         return false;
492     }
493     memory_->SetCtx(ctx);
494     return true;
495 }
496 
GetMainStackRangeInner(uintptr_t& stackBottom, uintptr_t& stackTop)497 bool Unwinder::Impl::GetMainStackRangeInner(uintptr_t& stackBottom, uintptr_t& stackTop)
498 {
499     if (maps_ != nullptr && !maps_->GetStackRange(stackBottom, stackTop)) {
500         return false;
501     } else if (maps_ == nullptr && !GetMainStackRange(stackBottom, stackTop)) {
502         return false;
503     }
504     return true;
505 }
506 
GetStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)507 bool Unwinder::Impl::GetStackRange(uintptr_t& stackBottom, uintptr_t& stackTop)
508 {
509     if (gettid() == getpid()) {
510         return GetMainStackRangeInner(stackBottom, stackTop);
511     }
512     return GetSelfStackRange(stackBottom, stackTop);
513 }
514 
UnwindLocalWithTid(const pid_t tid, size_t maxFrameNum, size_t skipFrameNum)515 bool Unwinder::Impl::UnwindLocalWithTid(const pid_t tid, size_t maxFrameNum, size_t skipFrameNum)
516 {
517     if (tid < 0 || tid == gettid()) {
518         lastErrorData_.SetCode(UNW_ERROR_NOT_SUPPORT);
519         DFXLOGE("params is nullptr, tid: %{public}d", tid);
520         return false;
521     }
522     DFXLOGD("UnwindLocalWithTid:: tid: %{public}d", tid);
523     auto threadContext = LocalThreadContext::GetInstance().CollectThreadContext(tid);
524 #if defined(__aarch64__)
525     if (threadContext != nullptr && threadContext->frameSz > 0) {
526         pcs_.clear();
527         for (size_t i = 0; i < threadContext->frameSz; i++) {
528             pcs_.emplace_back(threadContext->pcs[i]);
529         }
530         firstFrameSp_ = threadContext->firstFrameSp;
531         return true;
532     }
533     return false;
534 #else
535     if (threadContext == nullptr || threadContext->ctx == nullptr) {
536         DFXLOGW("Failed to get thread context of tid(%{public}d)", tid);
537         LocalThreadContext::GetInstance().ReleaseThread(tid);
538         return false;
539     }
540     if (regs_ == nullptr) {
541         regs_ = DfxRegs::CreateFromUcontext(*(threadContext->ctx));
542     } else {
543         regs_->SetFromUcontext(*(threadContext->ctx));
544     }
545     uintptr_t stackBottom = 1;
546     uintptr_t stackTop = static_cast<uintptr_t>(-1);
547     if (tid == getpid()) {
548         if (!GetMainStackRangeInner(stackBottom, stackTop)) {
549             return false;
550         }
551     } else if (!LocalThreadContext::GetInstance().GetStackRange(tid, stackBottom, stackTop)) {
552         DFXLOGE("Failed to get stack range with tid(%{public}d), err(%{public}d)", tid, errno);
553         return false;
554     }
555     if (stackBottom == 0 || stackTop == 0) {
556         DFXLOGE("Invalid stack range, err(%{public}d)", errno);
557         return false;
558     }
559     DFXLOGU("[%{public}d]: stackBottom: %{public}" PRIx64 ", stackTop: %{public}" PRIx64 "", __LINE__,
560         (uint64_t)stackBottom, (uint64_t)stackTop);
561     UnwindContext context;
562     context.pid = UNWIND_TYPE_LOCAL;
563     context.regs = regs_;
564     context.maps = maps_;
565     context.stackCheck = false;
566     context.stackBottom = stackBottom;
567     context.stackTop = stackTop;
568     auto ret = Unwind(&context, maxFrameNum, skipFrameNum);
569     LocalThreadContext::GetInstance().ReleaseThread(tid);
570     return ret;
571 #endif
572 }
573 
UnwindLocalWithContext(const ucontext_t& context, size_t maxFrameNum, size_t skipFrameNum)574 bool Unwinder::Impl::UnwindLocalWithContext(const ucontext_t& context, size_t maxFrameNum, size_t skipFrameNum)
575 {
576     if (regs_ == nullptr) {
577         regs_ = DfxRegs::CreateFromUcontext(context);
578     } else {
579         regs_->SetFromUcontext(context);
580     }
581     return UnwindLocal(true, false, maxFrameNum, skipFrameNum);
582 }
583 
UnwindLocal(bool withRegs, bool fpUnwind, size_t maxFrameNum, size_t skipFrameNum)584 bool Unwinder::Impl::UnwindLocal(bool withRegs, bool fpUnwind, size_t maxFrameNum, size_t skipFrameNum)
585 {
586     DFXLOGI("UnwindLocal:: fpUnwind: %{public}d", fpUnwind);
587     uintptr_t stackBottom = 1;
588     uintptr_t stackTop = static_cast<uintptr_t>(-1);
589     if (!GetStackRange(stackBottom, stackTop)) {
590         DFXLOGE("Get stack range error");
591         return false;
592     }
593     DFXLOGU("[%{public}d]: stackBottom: %{public}" PRIx64 ", stackTop: %{public}" PRIx64 "", __LINE__,
594         (uint64_t)stackBottom, (uint64_t)stackTop);
595 
596     if (!withRegs) {
597 #if defined(__aarch64__)
598         if (fpUnwind) {
599             uintptr_t miniRegs[FP_MINI_REGS_SIZE] = {0};
600             GetFramePointerMiniRegs(miniRegs, sizeof(miniRegs) / sizeof(miniRegs[0]));
601             regs_ = DfxRegs::CreateFromRegs(UnwindMode::FRAMEPOINTER_UNWIND, miniRegs,
602                                             sizeof(miniRegs) / sizeof(miniRegs[0]));
603             withRegs = true;
604         }
605 #endif
606         if (!withRegs) {
607             regs_ = DfxRegs::Create();
608             auto regsData = regs_->RawData();
609             if (regsData == nullptr) {
610                 DFXLOGE("[%{public}d]: params is nullptr", __LINE__);
611                 return false;
612             }
613             GetLocalRegs(regsData);
614         }
615     }
616 
617     UnwindContext context;
618     context.pid = UNWIND_TYPE_LOCAL;
619     context.regs = regs_;
620     context.maps = maps_;
621     context.stackCheck = false;
622     context.stackBottom = stackBottom;
623     context.stackTop = stackTop;
624 #ifdef __aarch64__
625     if (fpUnwind) {
626         return UnwindByFp(&context, maxFrameNum, skipFrameNum);
627     }
628 #endif
629     return Unwind(&context, maxFrameNum, skipFrameNum);
630 }
631 
UnwindRemote(pid_t tid, bool withRegs, size_t maxFrameNum, size_t skipFrameNum)632 bool Unwinder::Impl::UnwindRemote(pid_t tid, bool withRegs, size_t maxFrameNum, size_t skipFrameNum)
633 {
634     std::string timeLimitCheck =
635         "Unwinder::Impl::UnwindRemote, tid: " + std::to_string(tid);
636     ElapsedTime counter(std::move(timeLimitCheck), 20); // 20 : limit cost time 20 ms
637     if ((maps_ == nullptr) || (pid_ <= 0) || (tid < 0)) {
638         DFXLOGE("params is nullptr, pid: %{public}d, tid: %{public}d", pid_, tid);
639         return false;
640     }
641     if (tid == 0) {
642         tid = pid_;
643     }
644     if (!withRegs) {
645         regs_ = DfxRegs::CreateRemoteRegs(tid);
646     }
647     if ((regs_ == nullptr)) {
648         DFXLOGE("regs is nullptr");
649         return false;
650     }
651 
652     firstFrameSp_ = regs_->GetSp();
653     UnwindContext context;
654     context.pid = tid;
655     context.regs = regs_;
656     context.maps = maps_;
657     return Unwind(&context, maxFrameNum, skipFrameNum);
658 }
659 
ArkWriteJitCodeToFile(int fd)660 int Unwinder::Impl::ArkWriteJitCodeToFile(int fd)
661 {
662 #if defined(ENABLE_MIXSTACK)
663     return DfxArk::JitCodeWriteFile(memory_.get(), &(Unwinder::AccessMem), fd, jitCache_.data(), jitCache_.size());
664 #else
665     return -1;
666 #endif
667 }
668 #if defined(ENABLE_MIXSTACK)
StepArkJsFrame(StepFrame& frame)669 bool Unwinder::Impl::StepArkJsFrame(StepFrame& frame)
670 {
671     DFX_TRACE_SCOPED_DLSYM("StepArkJsFrame pc: %p", reinterpret_cast<void *>(frame.pc));
672     std::string timeLimitCheck;
673     timeLimitCheck += "StepArkJsFrame, ark pc: " + std::to_string(frame.pc) +
674         ", fp:" + std::to_string(frame.fp) + ", sp:" + std::to_string(frame.sp) +
675         ", isJsFrame:" + std::to_string(frame.isJsFrame);
676     ElapsedTime counter(timeLimitCheck, 20); // 20 : limit cost time 20 ms
677     if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
678         DFXLOGD("+++ark pc: %{public}p, fp: %{public}p, sp: %{public}p, isJsFrame: %{public}d.",
679             reinterpret_cast<void *>(frame.pc),
680             reinterpret_cast<void *>(frame.fp), reinterpret_cast<void *>(frame.sp), frame.isJsFrame);
681     }
682 #if defined(ONLINE_MIXSTACK)
683     const size_t JSFRAME_MAX = 64;
684     JsFrame jsFrames[JSFRAME_MAX];
685     size_t size = JSFRAME_MAX;
686     if (memset_s(jsFrames, sizeof(JsFrame) * JSFRAME_MAX, 0, sizeof(JsFrame) * JSFRAME_MAX) != 0) {
687         DFXLOGE("Failed to memset_s jsFrames.");
688         return false;
689     }
690     int32_t pid = pid_;
691     if (pid_ == UNWIND_TYPE_LOCAL) {
692         pid = getpid();
693     }
694     if (DfxArk::GetArkNativeFrameInfo(pid, frame.pc, frame.fp, frame.sp, jsFrames, size) < 0) {
695         DFXLOGE("Failed to get ark frame info");
696         return false;
697     }
698 
699     if (!ignoreMixstack_) {
700         DFXLOGI("---ark js frame size: %{public}zu.", size);
701         for (size_t i = 0; i < size; ++i) {
702             DfxFrame dfxFrame;
703             dfxFrame.isJsFrame = true;
704             dfxFrame.index = frames_.size();
705             dfxFrame.mapName = std::string(jsFrames[i].url);
706             dfxFrame.funcName = std::string(jsFrames[i].functionName);
707             dfxFrame.line = jsFrames[i].line;
708             dfxFrame.column = jsFrames[i].column;
709             AddFrame(dfxFrame);
710         }
711     }
712 #else
713     int ret = -1;
714     uintptr_t *methodId = (pid_ > 0 || enableMethodIdLocal_) ? (&frame.methodid) : nullptr;
715     if (isJitCrash_) {
716         ArkUnwindParam arkParam(memory_.get(), &(Unwinder::AccessMem), &frame.fp, &frame.sp, &frame.pc,
717             methodId, &frame.isJsFrame, jitCache_);
718         ret = DfxArk::StepArkFrameWithJit(&arkParam);
719     } else {
720         ret = DfxArk::StepArkFrame(memory_.get(), &(Unwinder::AccessMem), &frame.fp, &frame.sp, &frame.pc,
721             methodId, &frame.isJsFrame);
722     }
723     if (ret < 0) {
724         DFXLOGE("Failed to step ark frame");
725         return false;
726     }
727     if (pid_ > 0) {
728         DFXLOGI("---ark js frame methodid: %{public}" PRIx64 "", (uint64_t)frame.methodid);
729     }
730 #endif
731     if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
732         DFXLOGD("---ark pc: %{public}p, fp: %{public}p, sp: %{public}p, isJsFrame: %{public}d.",
733             reinterpret_cast<void *>(frame.pc),
734             reinterpret_cast<void *>(frame.fp), reinterpret_cast<void *>(frame.sp), frame.isJsFrame);
735     }
736     return true;
737 }
738 #endif
739 
Unwind(void *ctx, size_t maxFrameNum, size_t skipFrameNum)740 bool Unwinder::Impl::Unwind(void *ctx, size_t maxFrameNum, size_t skipFrameNum)
741 {
742     if ((regs_ == nullptr) || (!CheckAndReset(ctx))) {
743         DFXLOGE("[%{public}d]: params is nullptr?", __LINE__);
744         lastErrorData_.SetCode(UNW_ERROR_INVALID_CONTEXT);
745         return false;
746     }
747     SetLocalStackCheck(ctx, false);
748     Clear();
749 
750     bool needAdjustPc = false;
751     bool resetFrames = false;
752     StepFrame frame;
753     do {
754         if (!resetFrames && (skipFrameNum != 0) && (frames_.size() >= skipFrameNum)) {
755             resetFrames = true;
756             DFXLOGU("frames size: %{public}zu, will be reset frames", frames_.size());
757             frames_.clear();
758         }
759         if (frames_.size() >= maxFrameNum) {
760             DFXLOGW("frames size: %{public}zu", frames_.size());
761             lastErrorData_.SetCode(UNW_ERROR_MAX_FRAMES_EXCEEDED);
762             break;
763         }
764 
765         frame.pc = regs_->GetPc();
766         frame.sp = regs_->GetSp();
767         frame.fp = regs_->GetFp();
768         // Check if this is a signal frame.
769         if (pid_ != UNWIND_TYPE_LOCAL && pid_ != UNWIND_TYPE_CUSTOMIZE_LOCAL &&
770             regs_->StepIfSignalFrame(static_cast<uintptr_t>(frame.pc), memory_)) {
771             DFXLOGW("Step signal frame, pc: %{public}p", reinterpret_cast<void *>(frame.pc));
772             StepInner(true, frame, ctx);
773             continue;
774         }
775 
776         if (!frame.isJsFrame && needAdjustPc) {
777             DoPcAdjust(frame.pc);
778         }
779         needAdjustPc = true;
780 
781         uintptr_t prevPc = frame.pc;
782         uintptr_t prevSp = frame.sp;
783         if (!StepInner(false, frame, ctx)) {
784             break;
785         }
786 
787         if (frame.pc == prevPc && frame.sp == prevSp) {
788             if (pid_ >= 0) {
789                 MAYBE_UNUSED UnwindContext* uctx = reinterpret_cast<UnwindContext *>(ctx);
790                 DFXLOGU("Failed to update pc and sp, tid: %{public}d", uctx->pid);
791             } else {
792                 DFXLOGU("Failed to update pc and sp");
793             }
794             lastErrorData_.SetAddrAndCode(frame.pc, UNW_ERROR_REPEATED_FRAME);
795             break;
796         }
797     } while (true);
798     DFXLOGU("Last error code: %{public}d, addr: %{public}p",
799         (int)GetLastErrorCode(), reinterpret_cast<void *>(GetLastErrorAddr()));
800     DFXLOGU("Last frame size: %{public}zu, last frame pc: %{public}p",
801         frames_.size(), reinterpret_cast<void *>(regs_->GetPc()));
802     return (frames_.size() > 0);
803 }
804 
UnwindByFp(void *ctx, size_t maxFrameNum, size_t skipFrameNum)805 bool Unwinder::Impl::UnwindByFp(void *ctx, size_t maxFrameNum, size_t skipFrameNum)
806 {
807     if (regs_ == nullptr) {
808         DFXLOGE("[%{public}d]: params is nullptr?", __LINE__);
809         return false;
810     }
811     pcs_.clear();
812     bool needAdjustPc = false;
813 
814     bool resetFrames = false;
815     do {
816         if (!resetFrames && skipFrameNum != 0 && (pcs_.size() == skipFrameNum)) {
817             DFXLOGU("pcs size: %{public}zu, will be reset pcs", pcs_.size());
818             resetFrames = true;
819             pcs_.clear();
820         }
821         if (pcs_.size() >= maxFrameNum) {
822             lastErrorData_.SetCode(UNW_ERROR_MAX_FRAMES_EXCEEDED);
823             break;
824         }
825 
826         uintptr_t pc = regs_->GetPc();
827         uintptr_t fp = regs_->GetFp();
828         if (needAdjustPc) {
829             DoPcAdjust(pc);
830         }
831         needAdjustPc = true;
832         pcs_.emplace_back(pc);
833 
834         if (!FpStep(fp, pc, ctx) || (pc == 0)) {
835             break;
836         }
837     } while (true);
838     return (pcs_.size() > 0);
839 }
840 
FpStep(uintptr_t& fp, uintptr_t& pc, void *ctx)841 bool Unwinder::Impl::FpStep(uintptr_t& fp, uintptr_t& pc, void *ctx)
842 {
843 #if defined(__aarch64__)
844     DFXLOGU("+fp: %{public}lx, pc: %{public}lx", (uint64_t)fp, (uint64_t)pc);
845     if ((regs_ == nullptr) || (memory_ == nullptr)) {
846         DFXLOGE("[%{public}d]: params is nullptr", __LINE__);
847         return false;
848     }
849     if (ctx != nullptr) {
850         memory_->SetCtx(ctx);
851     }
852 
853     uintptr_t prevFp = fp;
854     uintptr_t ptr = fp;
855     if (ptr != 0 && memory_->ReadUptr(ptr, &fp, true) &&
856         memory_->ReadUptr(ptr, &pc, false)) {
857         if (fp != 0 && fp <= prevFp) {
858             DFXLOGU("Illegal or same fp value");
859             lastErrorData_.SetAddrAndCode(pc, UNW_ERROR_ILLEGAL_VALUE);
860             return false;
861         }
862         regs_->SetReg(REG_FP, &fp);
863         regs_->SetReg(REG_SP, &prevFp);
864         regs_->SetPc(StripPac(pc, pacMask_));
865         DFXLOGU("-fp: %{public}lx, pc: %{public}lx", (uint64_t)fp, (uint64_t)pc);
866         return true;
867     }
868 #endif
869     return false;
870 }
871 
Step(uintptr_t& pc, uintptr_t& sp, void *ctx)872 bool Unwinder::Impl::Step(uintptr_t& pc, uintptr_t& sp, void *ctx)
873 {
874     DFX_TRACE_SCOPED_DLSYM("Step pc:%p", reinterpret_cast<void *>(pc));
875     if ((regs_ == nullptr) || (!CheckAndReset(ctx))) {
876         DFXLOGE("[%{public}d]: params is nullptr?", __LINE__);
877         return false;
878     }
879     bool ret = false;
880     StepFrame frame;
881     frame.pc = pc;
882     frame.sp = sp;
883     frame.fp = regs_->GetFp();
884     // Check if this is a signal frame.
885     if (regs_->StepIfSignalFrame(frame.pc, memory_)) {
886         DFXLOGW("Step signal frame, pc: %{public}p", reinterpret_cast<void *>(frame.pc));
887         ret = StepInner(true, frame, ctx);
888     } else {
889         ret = StepInner(false, frame, ctx);
890     }
891     pc = frame.pc;
892     sp = frame.sp;
893     return ret;
894 }
895 
StepInner(const bool isSigFrame, StepFrame& frame, void *ctx)896 bool Unwinder::Impl::StepInner(const bool isSigFrame, StepFrame& frame, void *ctx)
897 {
898     if ((regs_ == nullptr) || (!CheckAndReset(ctx))) {
899         DFXLOGE("[%{public}d]: params is nullptr", __LINE__);
900         return false;
901     }
902     SetLocalStackCheck(ctx, false);
903     DFXLOGU("+pc: %{public}p, sp: %{public}p, fp: %{public}p", reinterpret_cast<void *>(frame.pc),
904         reinterpret_cast<void *>(frame.sp), reinterpret_cast<void *>(frame.fp));
905     uintptr_t prevSp = frame.sp;
906 
907     bool ret = false;
908     std::shared_ptr<RegLocState> rs = nullptr;
909     std::shared_ptr<DfxMap> map = nullptr;
910     do {
911         if (enableCache_ && !isFpStep_) {
912             // 1. find cache rs
913             auto iter = stepCache_.find(frame.pc);
914             if (iter != stepCache_.end()) {
915                 if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
916                     DFXLOGU("Find rs cache, pc: %{public}p", reinterpret_cast<void *>(frame.pc));
917                 }
918                 rs = iter->second.rs;
919                 map = iter->second.map;
920                 AddFrame(frame, map);
921                 ret = true;
922                 break;
923             }
924         }
925 
926         // 2. find map
927         MAYBE_UNUSED int mapRet = acc_->GetMapByPc(frame.pc, map, ctx);
928         if (mapRet != UNW_ERROR_NONE) {
929             if (frame.isJsFrame) {
930                 DFXLOGW("Failed to get map with ark, frames size: %{public}zu", frames_.size());
931                 mapRet = UNW_ERROR_UNKNOWN_ARK_MAP;
932             }
933             if (frames_.size() > 2) { // 2, least 2 frame
934                 DFXLOGU("Failed to get map, frames size: %{public}zu", frames_.size());
935                 lastErrorData_.SetAddrAndCode(frame.pc, mapRet);
936                 return false;
937             }
938         }
939         AddFrame(frame, map);
940         if (isSigFrame) {
941             return true;
942         }
943 
944 #if defined(ENABLE_MIXSTACK)
945         if (stopWhenArkFrame_ && (map != nullptr && map->IsArkExecutable())) {
946             DFXLOGU("Stop by ark frame");
947             return false;
948         }
949         if ((enableMixstack_) && ((map != nullptr && map->IsArkExecutable()) || frame.isJsFrame)) {
950             if (!StepArkJsFrame(frame)) {
951                 DFXLOGE("Failed to step ark Js frame, pc: %{public}p", reinterpret_cast<void *>(frame.pc));
952                 lastErrorData_.SetAddrAndCode(frame.pc, UNW_ERROR_STEP_ARK_FRAME);
953                 ret = false;
954                 break;
955             }
956             regs_->SetPc(StripPac(frame.pc, pacMask_));
957             regs_->SetSp(frame.sp);
958             regs_->SetFp(frame.fp);
959 #if defined(OFFLINE_MIXSTACK)
960             return true;
961 #endif
962         }
963 #endif
964         if (isFpStep_) {
965             if (enableFpCheckMapExec_ && (map != nullptr && !map->IsMapExec())) {
966                 DFXLOGE("Fp step check map is not exec");
967                 return false;
968             }
969             break;
970         }
971 
972         // 3. find unwind table and entry
973         UnwindTableInfo uti;
974         MAYBE_UNUSED int utiRet = acc_->FindUnwindTable(frame.pc, uti, ctx);
975         if (utiRet != UNW_ERROR_NONE) {
976             lastErrorData_.SetAddrAndCode(frame.pc, utiRet);
977             DFXLOGU("Failed to find unwind table ret: %{public}d", utiRet);
978             break;
979         }
980 
981         // 4. parse instructions and get cache rs
982         struct UnwindEntryInfo uei;
983         rs = std::make_shared<RegLocState>();
984 #if defined(__arm__)
985         if (!ret && uti.format == UNW_INFO_FORMAT_ARM_EXIDX) {
986             if (!armExidx_->SearchEntry(frame.pc, uti, uei)) {
987                 lastErrorData_.SetAddrAndCode(armExidx_->GetLastErrorAddr(), armExidx_->GetLastErrorCode());
988                 DFXLOGE("Failed to search unwind entry?");
989                 break;
990             }
991             if (!armExidx_->Step((uintptr_t)uei.unwindInfo, rs)) {
992                 lastErrorData_.SetAddrAndCode(armExidx_->GetLastErrorAddr(), armExidx_->GetLastErrorCode());
993                 DFXLOGU("Step exidx section error?");
994             } else {
995                 ret = true;
996             }
997         }
998 #endif
999         if (!ret && uti.format == UNW_INFO_FORMAT_REMOTE_TABLE) {
1000             if ((uti.isLinear == false && !dwarfSection_->SearchEntry(frame.pc, uti, uei)) ||
1001                 (uti.isLinear == true && !dwarfSection_->LinearSearchEntry(frame.pc, uti, uei))) {
1002                 lastErrorData_.SetAddrAndCode(dwarfSection_->GetLastErrorAddr(), dwarfSection_->GetLastErrorCode());
1003                 DFXLOGU("Failed to search unwind entry?");
1004                 break;
1005             }
1006             memory_->SetDataOffset(uti.segbase);
1007             if (!dwarfSection_->Step(frame.pc, (uintptr_t)uei.unwindInfo, rs)) {
1008                 lastErrorData_.SetAddrAndCode(dwarfSection_->GetLastErrorAddr(), dwarfSection_->GetLastErrorCode());
1009                 DFXLOGU("Step dwarf section error?");
1010             } else {
1011                 ret = true;
1012             }
1013         }
1014 
1015         if (ret && enableCache_) {
1016             // 5. update rs cache
1017             StepCache cache;
1018             cache.map = map;
1019             cache.rs = rs;
1020             stepCache_.emplace(frame.pc, cache);
1021             break;
1022         }
1023     } while (false);
1024 
1025     // 5. update regs and regs state
1026     SetLocalStackCheck(ctx, true);
1027     if (ret) {
1028 #if defined(__arm__) || defined(__aarch64__)
1029         auto lr = *(regs_->GetReg(REG_LR));
1030 #endif
1031         ret = Apply(regs_, rs);
1032 #if defined(__arm__) || defined(__aarch64__)
1033         if (!ret && enableLrFallback_ && (frames_.size() == 1)) {
1034             regs_->SetPc(lr);
1035             ret = true;
1036             if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
1037                 DFXLOGW("Failed to apply first frame, lr fallback");
1038             }
1039         }
1040 #endif
1041     } else {
1042         if (enableLrFallback_ && (frames_.size() == 1) && regs_->SetPcFromReturnAddress(memory_)) {
1043             ret = true;
1044             if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
1045                 DFXLOGW("Failed to step first frame, lr fallback");
1046             }
1047         }
1048     }
1049     regs_->SetPc(StripPac(regs_->GetPc(), pacMask_));
1050 
1051 #if defined(__aarch64__)
1052     if (!ret) { // try fp
1053         ret = FpStep(frame.fp, frame.pc, ctx);
1054         if (ret && !isFpStep_) {
1055             if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
1056                 DFXLOGI("First enter fp step, pc: %{public}p", reinterpret_cast<void *>(frame.pc));
1057             }
1058             isFpStep_ = true;
1059         }
1060     }
1061 #endif
1062 
1063     frame.pc = regs_->GetPc();
1064     frame.sp = regs_->GetSp();
1065     frame.fp = regs_->GetFp();
1066     if (!isFpStep_ && (map != nullptr) && (!map->IsVdsoMap()) && (frame.sp < prevSp)) {
1067         DFXLOGU("Illegal sp value");
1068         lastErrorData_.SetAddrAndCode(frame.pc, UNW_ERROR_ILLEGAL_VALUE);
1069         ret = false;
1070     }
1071     if (ret && (frame.pc == 0)) {
1072         ret = false;
1073     }
1074     DFXLOGU("-pc: %{public}p, sp: %{public}p, fp: %{public}p, ret: %{public}d", reinterpret_cast<void *>(frame.pc),
1075         reinterpret_cast<void *>(frame.sp), reinterpret_cast<void *>(frame.fp), ret);
1076     return ret;
1077 }
1078 
Apply(std::shared_ptr<DfxRegs> regs, std::shared_ptr<RegLocState> rs)1079 bool Unwinder::Impl::Apply(std::shared_ptr<DfxRegs> regs, std::shared_ptr<RegLocState> rs)
1080 {
1081     if (rs == nullptr || regs == nullptr) {
1082         return false;
1083     }
1084 
1085     uintptr_t prevPc = regs->GetPc();
1086     uintptr_t prevSp = regs->GetSp();
1087     uint16_t errCode = 0;
1088     bool ret = DfxInstructions::Apply(memory_, *(regs.get()), *(rs.get()), errCode);
1089     uintptr_t tmp = 0;
1090     uintptr_t sp = regs->GetSp();
1091     if (ret && (!memory_->ReadUptr(sp, &tmp, false))) {
1092         errCode = UNW_ERROR_UNREADABLE_SP;
1093         ret = false;
1094     }
1095     if (regs->GetPc() == prevPc && regs->GetSp() == prevSp) {
1096         errCode = UNW_ERROR_REPEATED_FRAME;
1097         ret = false;
1098     }
1099     if (!ret) {
1100         lastErrorData_.SetCode(errCode);
1101         DFXLOGE("Failed to apply reg state, errCode: %{public}d", static_cast<int>(errCode));
1102     }
1103     return ret;
1104 }
1105 
DoPcAdjust(uintptr_t& pc)1106 void Unwinder::Impl::DoPcAdjust(uintptr_t& pc)
1107 {
1108     if (pc <= 0x4) {
1109         return;
1110     }
1111     uintptr_t sz = 0x4;
1112 #if defined(__arm__)
1113     if ((pc & 0x1) && (memory_ != nullptr)) {
1114         uintptr_t val;
1115         if (pc < 0x5 || !(memory_->ReadMem(pc - 0x5, &val)) ||
1116             (val & 0xe000f000) != 0xe000f000) {
1117             sz = 0x2;
1118         }
1119     }
1120 #elif defined(__x86_64__)
1121     sz = 0x1;
1122 #endif
1123     pc -= sz;
1124 }
1125 
StripPac(uintptr_t inAddr, uintptr_t pacMask)1126 uintptr_t Unwinder::Impl::StripPac(uintptr_t inAddr, uintptr_t pacMask)
1127 {
1128     uintptr_t outAddr = inAddr;
1129 #if defined(__aarch64__)
1130     if (outAddr != 0) {
1131         if (pacMask != 0) {
1132             outAddr &= ~pacMask;
1133         } else {
1134             register uint64_t x30 __asm("x30") = inAddr;
1135             asm("hint 0x7" : "+r"(x30));
1136             outAddr = x30;
1137         }
1138         if (outAddr != inAddr) {
1139             DFXLOGU("Strip pac in addr: %{public}lx, out addr: %{public}lx", (uint64_t)inAddr, (uint64_t)outAddr);
1140         }
1141     }
1142 #endif
1143     return outAddr;
1144 }
1145 
GetFrames()1146 const std::vector<DfxFrame>& Unwinder::Impl::GetFrames()
1147 {
1148     if (enableFillFrames_) {
1149         FillFrames(frames_);
1150     }
1151     return frames_;
1152 }
1153 
AddFrame(const StepFrame& frame, std::shared_ptr<DfxMap> map)1154 void Unwinder::Impl::AddFrame(const StepFrame& frame, std::shared_ptr<DfxMap> map)
1155 {
1156 #if defined(OFFLINE_MIXSTACK)
1157     if (ignoreMixstack_ && frame.isJsFrame) {
1158         return;
1159     }
1160 #endif
1161     pcs_.emplace_back(frame.pc);
1162     DfxFrame dfxFrame;
1163     dfxFrame.isJsFrame = frame.isJsFrame;
1164     dfxFrame.index = frames_.size();
1165     dfxFrame.pc = static_cast<uint64_t>(frame.pc);
1166     dfxFrame.sp = static_cast<uint64_t>(frame.sp);
1167 #if defined(OFFLINE_MIXSTACK)
1168     if (frame.isJsFrame) {
1169         dfxFrame.funcOffset = static_cast<uint64_t>(frame.methodid);
1170     }
1171 #endif
1172     dfxFrame.map = map;
1173     frames_.emplace_back(dfxFrame);
1174 }
1175 
AddFrame(DfxFrame& frame)1176 void Unwinder::Impl::AddFrame(DfxFrame& frame)
1177 {
1178     frames_.emplace_back(frame);
1179 }
1180 
AccessMem(void* memory, uintptr_t addr, uintptr_t *val)1181 bool Unwinder::AccessMem(void* memory, uintptr_t addr, uintptr_t *val)
1182 {
1183     return reinterpret_cast<DfxMemory*>(memory)->ReadMem(addr, val);
1184 }
1185 
FillLocalFrames(std::vector<DfxFrame>& frames)1186 void Unwinder::FillLocalFrames(std::vector<DfxFrame>& frames)
1187 {
1188     if (frames.empty()) {
1189         return;
1190     }
1191     auto it = frames.begin();
1192     while (it != frames.end()) {
1193         if (dl_iterate_phdr(Unwinder::Impl::DlPhdrCallback, &(*it)) != 1) {
1194             // clean up frames after first invalid frame
1195             frames.erase(it, frames.end());
1196             break;
1197         }
1198         it++;
1199     }
1200 }
1201 
FillFrames(std::vector<DfxFrame>& frames)1202 void Unwinder::Impl::FillFrames(std::vector<DfxFrame>& frames)
1203 {
1204     for (size_t i = 0; i < frames.size(); ++i) {
1205         auto& frame = frames[i];
1206         if (frame.isJsFrame) {
1207 #if defined(OFFLINE_MIXSTACK)
1208             FillJsFrame(frame);
1209 #endif
1210         } else {
1211             FillFrame(frame);
1212         }
1213     }
1214 }
1215 
FillFrame(DfxFrame& frame)1216 void Unwinder::Impl::FillFrame(DfxFrame& frame)
1217 {
1218     if (frame.map == nullptr) {
1219         frame.relPc = frame.pc;
1220         frame.mapName = "Not mapped";
1221         DFXLOGU("Current frame is not mapped.");
1222         return;
1223     }
1224     frame.mapName = frame.map->GetElfName();
1225     DFX_TRACE_SCOPED_DLSYM("FillFrame:%s", frame.mapName.c_str());
1226     frame.relPc = frame.map->GetRelPc(frame.pc);
1227     frame.mapOffset = frame.map->offset;
1228     DFXLOGU("mapName: %{public}s, mapOffset: %{public}" PRIx64 "", frame.mapName.c_str(), frame.mapOffset);
1229     auto elf = frame.map->GetElf();
1230     if (elf == nullptr) {
1231         if (pid_ == UNWIND_TYPE_LOCAL || pid_ == UNWIND_TYPE_CUSTOMIZE_LOCAL) {
1232             FillJsFrame(frame);
1233         }
1234         return;
1235     }
1236     if (!DfxSymbols::GetFuncNameAndOffsetByPc(frame.relPc, elf, frame.funcName, frame.funcOffset)) {
1237         DFXLOGU("Failed to get symbol, relPc: %{public}" PRIx64 ", mapName: %{public}s",
1238             frame.relPc, frame.mapName.c_str());
1239     }
1240     frame.buildId = elf->GetBuildId();
1241 }
1242 
FillJsFrame(DfxFrame& frame)1243 void Unwinder::Impl::FillJsFrame(DfxFrame& frame)
1244 {
1245     if (frame.map == nullptr) {
1246         DFXLOGU("Current js frame is not map.");
1247         return;
1248     }
1249     DFX_TRACE_SCOPED_DLSYM("FillJsFrame:%s", frame.map->name.c_str());
1250     DFXLOGU("Fill js frame, map name: %{public}s", frame.map->name.c_str());
1251     auto hap = frame.map->GetHap();
1252     if (hap == nullptr) {
1253         DFXLOGW("Get hap error, name: %{public}s", frame.map->name.c_str());
1254         return;
1255     }
1256     JsFunction jsFunction;
1257     if ((pid_ == UNWIND_TYPE_LOCAL) || (pid_ == UNWIND_TYPE_CUSTOMIZE_LOCAL) || enableMethodIdLocal_) {
1258         if (DfxArk::ParseArkFrameInfoLocal(static_cast<uintptr_t>(frame.pc), static_cast<uintptr_t>(frame.funcOffset),
1259             static_cast<uintptr_t>(frame.map->begin), static_cast<uintptr_t>(frame.map->offset), &jsFunction) < 0) {
1260             DFXLOGW("Failed to parse ark frame info local, pc: %{public}p, begin: %{public}p",
1261                 reinterpret_cast<void *>(frame.pc), reinterpret_cast<void *>(frame.map->begin));
1262             return;
1263         }
1264         frame.isJsFrame = true;
1265     } else {
1266         if (!hap->ParseHapInfo(pid_, frame.pc, static_cast<uintptr_t>(frame.funcOffset), frame.map, &jsFunction)) {
1267             DFXLOGW("Failed to parse hap info, pid: %{public}d", pid_);
1268             return;
1269         }
1270     }
1271     frame.mapName = std::string(jsFunction.url);
1272     frame.funcName = std::string(jsFunction.functionName);
1273     frame.line = static_cast<int32_t>(jsFunction.line);
1274     frame.column = jsFunction.column;
1275     DFXLOGU("Js frame mapName: %{public}s, funcName: %{public}s, line: %{public}d, column: %{public}d",
1276         frame.mapName.c_str(), frame.funcName.c_str(), frame.line, frame.column);
1277 }
1278 
GetFrameByPc(uintptr_t pc, std::shared_ptr<DfxMaps> maps, DfxFrame &frame)1279 bool Unwinder::Impl::GetFrameByPc(uintptr_t pc, std::shared_ptr<DfxMaps> maps, DfxFrame &frame)
1280 {
1281     frame.pc = static_cast<uint64_t>(StripPac(pc, 0));
1282     std::shared_ptr<DfxMap> map = nullptr;
1283     if ((maps == nullptr) || !maps->FindMapByAddr(pc, map) || map == nullptr) {
1284         DFXLOGE("Find map error");
1285         return false;
1286     }
1287 
1288     frame.map = map;
1289     FillFrame(frame);
1290     return true;
1291 }
1292 
GetLockInfo(int32_t tid, char* buf, size_t sz)1293 bool Unwinder::Impl::GetLockInfo(int32_t tid, char* buf, size_t sz)
1294 {
1295 #ifdef __aarch64__
1296     if (frames_.empty()) {
1297         return false;
1298     }
1299 
1300     if (frames_[0].funcName.find("__timedwait_cp") == std::string::npos) {
1301         return false;
1302     }
1303 
1304     uintptr_t lockPtrAddr = firstFrameSp_ + 56; // 56 : sp + 0x38
1305     uintptr_t lockAddr;
1306     UnwindContext context;
1307     context.pid = tid;
1308     if (acc_->AccessMem(lockPtrAddr, &lockAddr, &context) != UNW_ERROR_NONE) {
1309         DFXLOGW("Failed to find lock addr.");
1310         return false;
1311     }
1312 
1313     size_t rsize = DfxMemory::ReadProcMemByPid(tid, lockAddr, buf, sz);
1314     if (rsize != sz) {
1315         DFXLOGW("Failed to fetch lock content, read size:%{public}zu expected size:%{public}zu", rsize, sz);
1316         return false;
1317     }
1318     return true;
1319 #else
1320     return false;
1321 #endif
1322 }
1323 
GetFramesByPcs(std::vector<DfxFrame>& frames, std::vector<uintptr_t> pcs)1324 void Unwinder::Impl::GetFramesByPcs(std::vector<DfxFrame>& frames, std::vector<uintptr_t> pcs)
1325 {
1326     frames.clear();
1327     std::shared_ptr<DfxMap> map = nullptr;
1328     for (size_t i = 0; i < pcs.size(); ++i) {
1329         DfxFrame frame;
1330         frame.index = i;
1331         frame.pc = static_cast<uint64_t>(StripPac(pcs[i], 0));
1332         if ((map != nullptr) && map->Contain(frame.pc)) {
1333             DFXLOGU("map had matched");
1334         } else {
1335             if ((maps_ == nullptr) || !maps_->FindMapByAddr(pcs[i], map) || (map == nullptr)) {
1336                 DFXLOGE("Find map error");
1337             }
1338         }
1339         frame.map = map;
1340         FillFrame(frame);
1341         frames.emplace_back(frame);
1342     }
1343 }
1344 
GetLocalFramesByPcs(std::vector<DfxFrame>& frames, std::vector<uintptr_t> pcs)1345 void Unwinder::GetLocalFramesByPcs(std::vector<DfxFrame>& frames, std::vector<uintptr_t> pcs)
1346 {
1347     frames.clear();
1348     for (size_t i = 0; i < pcs.size(); ++i) {
1349         DfxFrame frame;
1350         frame.index = i;
1351         frame.pc = static_cast<uint64_t>(pcs[i]);
1352         frames.emplace_back(frame);
1353     }
1354     FillLocalFrames(frames);
1355 }
1356 
GetSymbolByPc(uintptr_t pc, std::shared_ptr<DfxMaps> maps, std::string& funcName, uint64_t& funcOffset)1357 bool Unwinder::GetSymbolByPc(uintptr_t pc, std::shared_ptr<DfxMaps> maps, std::string& funcName, uint64_t& funcOffset)
1358 {
1359     if (maps == nullptr) {
1360         return false;
1361     }
1362     std::shared_ptr<DfxMap> map = nullptr;
1363     if (!maps->FindMapByAddr(pc, map) || (map == nullptr)) {
1364         DFXLOGE("Find map is null");
1365         return false;
1366     }
1367     uint64_t relPc = map->GetRelPc(static_cast<uint64_t>(pc));
1368     auto elf = map->GetElf();
1369     if (elf == nullptr) {
1370         DFXLOGE("Get elf is null");
1371         return false;
1372     }
1373     return DfxSymbols::GetFuncNameAndOffsetByPc(relPc, elf, funcName, funcOffset);
1374 }
1375 
GetFramesStr(const std::vector<DfxFrame>& frames)1376 std::string Unwinder::GetFramesStr(const std::vector<DfxFrame>& frames)
1377 {
1378     return DfxFrameFormatter::GetFramesStr(frames);
1379 }
1380 
DlPhdrCallback(struct dl_phdr_info *info, size_t size, void *data)1381 int Unwinder::Impl::DlPhdrCallback(struct dl_phdr_info *info, size_t size, void *data)
1382 {
1383     auto frame = reinterpret_cast<DfxFrame *>(data);
1384     const ElfW(Phdr) *phdr = info->dlpi_phdr;
1385     frame->pc = StripPac(frame->pc, 0);
1386     for (int n = info->dlpi_phnum; --n >= 0; phdr++) {
1387         if (phdr->p_type == PT_LOAD) {
1388             ElfW(Addr) vaddr = phdr->p_vaddr + info->dlpi_addr;
1389             if (frame->pc >= vaddr && frame->pc < vaddr + phdr->p_memsz) {
1390                 frame->relPc = frame->pc - info->dlpi_addr;
1391                 frame->mapName = std::string(info->dlpi_name);
1392                 DFXLOGU("relPc: %{public}" PRIx64 ", mapName: %{public}s", frame->relPc, frame->mapName.c_str());
1393                 return 1;
1394             }
1395         }
1396     }
1397     return 0;
1398 }
1399 } // namespace HiviewDFX
1400 } // namespace OHOS
1401