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