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