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