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