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