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