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