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> ®s)
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