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 (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> & regs)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 LOGD("Unwinder mixstack enable: %d", enableMixstack_);
466 #else
467 LOGD("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 LOGE("%s", "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 LOGE("params is nullptr, tid: %d", tid);
520 return false;
521 }
522 LOGD("UnwindLocalWithTid:: tid: %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 LOGW("Failed to get thread context of tid(%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 LOGE("Failed to get stack range with tid(%d), err(%d)", tid, errno);
553 return false;
554 }
555 if (stackBottom == 0 || stackTop == 0) {
556 LOGE("Invalid stack range, err(%d)", errno);
557 return false;
558 }
559 LOGU("stackBottom: %" PRIx64 ", stackTop: %" PRIx64 "", (uint64_t)stackBottom, (uint64_t)stackTop);
560 UnwindContext context;
561 context.pid = UNWIND_TYPE_LOCAL;
562 context.regs = regs_;
563 context.maps = maps_;
564 context.stackCheck = false;
565 context.stackBottom = stackBottom;
566 context.stackTop = stackTop;
567 auto ret = Unwind(&context, maxFrameNum, skipFrameNum);
568 LocalThreadContext::GetInstance().ReleaseThread(tid);
569 return ret;
570 #endif
571 }
572
UnwindLocalWithContext(const ucontext_t & context,size_t maxFrameNum,size_t skipFrameNum)573 bool Unwinder::Impl::UnwindLocalWithContext(const ucontext_t& context, size_t maxFrameNum, size_t skipFrameNum)
574 {
575 if (regs_ == nullptr) {
576 regs_ = DfxRegs::CreateFromUcontext(context);
577 } else {
578 regs_->SetFromUcontext(context);
579 }
580 return UnwindLocal(true, false, maxFrameNum, skipFrameNum);
581 }
582
UnwindLocal(bool withRegs,bool fpUnwind,size_t maxFrameNum,size_t skipFrameNum)583 bool Unwinder::Impl::UnwindLocal(bool withRegs, bool fpUnwind, size_t maxFrameNum, size_t skipFrameNum)
584 {
585 LOGI("UnwindLocal:: fpUnwind: %d", fpUnwind);
586 uintptr_t stackBottom = 1;
587 uintptr_t stackTop = static_cast<uintptr_t>(-1);
588 if (!GetStackRange(stackBottom, stackTop)) {
589 LOGE("%s", "Get stack range error");
590 return false;
591 }
592 LOGU("stackBottom: %" PRIx64 ", stackTop: %" PRIx64 "", (uint64_t)stackBottom, (uint64_t)stackTop);
593
594 if (!withRegs) {
595 #if defined(__aarch64__)
596 if (fpUnwind) {
597 uintptr_t miniRegs[FP_MINI_REGS_SIZE] = {0};
598 GetFramePointerMiniRegs(miniRegs, sizeof(miniRegs) / sizeof(miniRegs[0]));
599 regs_ = DfxRegs::CreateFromRegs(UnwindMode::FRAMEPOINTER_UNWIND, miniRegs,
600 sizeof(miniRegs) / sizeof(miniRegs[0]));
601 withRegs = true;
602 }
603 #endif
604 if (!withRegs) {
605 regs_ = DfxRegs::Create();
606 auto regsData = regs_->RawData();
607 if (regsData == nullptr) {
608 LOGE("%s", "params is nullptr");
609 return false;
610 }
611 GetLocalRegs(regsData);
612 }
613 }
614
615 UnwindContext context;
616 context.pid = UNWIND_TYPE_LOCAL;
617 context.regs = regs_;
618 context.maps = maps_;
619 context.stackCheck = false;
620 context.stackBottom = stackBottom;
621 context.stackTop = stackTop;
622 #ifdef __aarch64__
623 if (fpUnwind) {
624 return UnwindByFp(&context, maxFrameNum, skipFrameNum);
625 }
626 #endif
627 return Unwind(&context, maxFrameNum, skipFrameNum);
628 }
629
UnwindRemote(pid_t tid,bool withRegs,size_t maxFrameNum,size_t skipFrameNum)630 bool Unwinder::Impl::UnwindRemote(pid_t tid, bool withRegs, size_t maxFrameNum, size_t skipFrameNum)
631 {
632 std::string timeLimitCheck =
633 "Unwinder::Impl::UnwindRemote, tid: " + std::to_string(tid);
634 ElapsedTime counter(std::move(timeLimitCheck), 20); // 20 : limit cost time 20 ms
635 if ((maps_ == nullptr) || (pid_ <= 0) || (tid < 0)) {
636 LOGE("params is nullptr, pid: %d, tid: %d", pid_, tid);
637 return false;
638 }
639 if (tid == 0) {
640 tid = pid_;
641 }
642 if (!withRegs) {
643 regs_ = DfxRegs::CreateRemoteRegs(tid);
644 }
645 if ((regs_ == nullptr)) {
646 LOGE("%s", "regs is nullptr");
647 return false;
648 }
649
650 firstFrameSp_ = regs_->GetSp();
651 UnwindContext context;
652 context.pid = tid;
653 context.regs = regs_;
654 context.maps = maps_;
655 return Unwind(&context, maxFrameNum, skipFrameNum);
656 }
657
ArkWriteJitCodeToFile(int fd)658 int Unwinder::Impl::ArkWriteJitCodeToFile(int fd)
659 {
660 #if defined(ENABLE_MIXSTACK)
661 return DfxArk::JitCodeWriteFile(memory_.get(), &(Unwinder::AccessMem), fd, jitCache_.data(), jitCache_.size());
662 #else
663 return -1;
664 #endif
665 }
666 #if defined(ENABLE_MIXSTACK)
StepArkJsFrame(StepFrame & frame)667 bool Unwinder::Impl::StepArkJsFrame(StepFrame& frame)
668 {
669 DFX_TRACE_SCOPED_DLSYM("StepArkJsFrame pc: %p", reinterpret_cast<void *>(frame.pc));
670 std::stringstream timeLimitCheck;
671 timeLimitCheck << "StepArkJsFrame, ark pc: " << reinterpret_cast<void *>(frame.pc) <<
672 ", fp:" << reinterpret_cast<void *>(frame.fp) << ", sp:" << reinterpret_cast<void *>(frame.sp) <<
673 ", isJsFrame:" << frame.isJsFrame;
674 ElapsedTime counter(timeLimitCheck.str(), 20); // 20 : limit cost time 20 ms
675 if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
676 LOGD("+++ark pc: %p, fp: %p, sp: %p, isJsFrame: %d.", reinterpret_cast<void *>(frame.pc),
677 reinterpret_cast<void *>(frame.fp), reinterpret_cast<void *>(frame.sp), frame.isJsFrame);
678 }
679 #if defined(ONLINE_MIXSTACK)
680 const size_t JSFRAME_MAX = 64;
681 JsFrame jsFrames[JSFRAME_MAX];
682 size_t size = JSFRAME_MAX;
683 if (memset_s(jsFrames, sizeof(JsFrame) * JSFRAME_MAX, 0, sizeof(JsFrame) * JSFRAME_MAX) != 0) {
684 LOGE("%s", "Failed to memset_s jsFrames.");
685 return false;
686 }
687 int32_t pid = pid_;
688 if (pid_ == UNWIND_TYPE_LOCAL) {
689 pid = getpid();
690 }
691 if (DfxArk::GetArkNativeFrameInfo(pid, frame.pc, frame.fp, frame.sp, jsFrames, size) < 0) {
692 LOGE("%s", "Failed to get ark frame info");
693 return false;
694 }
695
696 if (!ignoreMixstack_) {
697 LOGI("---ark js frame size: %zu.", size);
698 for (size_t i = 0; i < size; ++i) {
699 DfxFrame dfxFrame;
700 dfxFrame.isJsFrame = true;
701 dfxFrame.index = frames_.size();
702 dfxFrame.mapName = std::string(jsFrames[i].url);
703 dfxFrame.funcName = std::string(jsFrames[i].functionName);
704 dfxFrame.line = jsFrames[i].line;
705 dfxFrame.column = jsFrames[i].column;
706 AddFrame(dfxFrame);
707 }
708 }
709 #else
710 int ret = -1;
711 uintptr_t *methodId = (pid_ > 0 || enableMethodIdLocal_) ? (&frame.methodid) : nullptr;
712 if (isJitCrash_) {
713 ArkUnwindParam arkParam(memory_.get(), &(Unwinder::AccessMem), &frame.fp, &frame.sp, &frame.pc,
714 methodId, &frame.isJsFrame, jitCache_);
715 ret = DfxArk::StepArkFrameWithJit(&arkParam);
716 } else {
717 ret = DfxArk::StepArkFrame(memory_.get(), &(Unwinder::AccessMem), &frame.fp, &frame.sp, &frame.pc,
718 methodId, &frame.isJsFrame);
719 }
720 if (ret < 0) {
721 LOGE("%s", "Failed to step ark frame");
722 return false;
723 }
724 if (pid_ > 0) {
725 LOGI("---ark js frame methodid: %" PRIx64 "", (uint64_t)frame.methodid);
726 }
727 #endif
728 if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
729 LOGD("---ark pc: %p, fp: %p, sp: %p, isJsFrame: %d.", reinterpret_cast<void *>(frame.pc),
730 reinterpret_cast<void *>(frame.fp), reinterpret_cast<void *>(frame.sp), frame.isJsFrame);
731 }
732 return true;
733 }
734 #endif
735
Unwind(void * ctx,size_t maxFrameNum,size_t skipFrameNum)736 bool Unwinder::Impl::Unwind(void *ctx, size_t maxFrameNum, size_t skipFrameNum)
737 {
738 if ((regs_ == nullptr) || (!CheckAndReset(ctx))) {
739 LOGE("%s", "params is nullptr?");
740 lastErrorData_.SetCode(UNW_ERROR_INVALID_CONTEXT);
741 return false;
742 }
743 SetLocalStackCheck(ctx, false);
744 Clear();
745
746 bool needAdjustPc = false;
747 bool resetFrames = false;
748 StepFrame frame;
749 do {
750 if (!resetFrames && (skipFrameNum != 0) && (frames_.size() >= skipFrameNum)) {
751 resetFrames = true;
752 LOGU("frames size: %zu, will be reset frames", frames_.size());
753 frames_.clear();
754 }
755 if (frames_.size() >= maxFrameNum) {
756 LOGW("frames size: %zu", frames_.size());
757 lastErrorData_.SetCode(UNW_ERROR_MAX_FRAMES_EXCEEDED);
758 break;
759 }
760
761 frame.pc = regs_->GetPc();
762 frame.sp = regs_->GetSp();
763 frame.fp = regs_->GetFp();
764 // Check if this is a signal frame.
765 if (pid_ != UNWIND_TYPE_LOCAL && pid_ != UNWIND_TYPE_CUSTOMIZE_LOCAL &&
766 regs_->StepIfSignalFrame(static_cast<uintptr_t>(frame.pc), memory_)) {
767 LOGW("Step signal frame, pc: %p", reinterpret_cast<void *>(frame.pc));
768 StepInner(true, frame, ctx);
769 continue;
770 }
771
772 if (!frame.isJsFrame && needAdjustPc) {
773 DoPcAdjust(frame.pc);
774 }
775 needAdjustPc = true;
776
777 uintptr_t prevPc = frame.pc;
778 uintptr_t prevSp = frame.sp;
779 if (!StepInner(false, frame, ctx)) {
780 break;
781 }
782
783 if (frame.pc == prevPc && frame.sp == prevSp) {
784 if (pid_ >= 0) {
785 MAYBE_UNUSED UnwindContext* uctx = reinterpret_cast<UnwindContext *>(ctx);
786 LOGU("Failed to update pc and sp, tid: %d", uctx->pid);
787 } else {
788 LOGU("%s", "Failed to update pc and sp");
789 }
790 lastErrorData_.SetAddrAndCode(frame.pc, UNW_ERROR_REPEATED_FRAME);
791 break;
792 }
793 } while (true);
794 LOGU("Last error code: %d, addr: %p", (int)GetLastErrorCode(), reinterpret_cast<void *>(GetLastErrorAddr()));
795 LOGU("Last frame size: %zu, last frame pc: %p", frames_.size(), reinterpret_cast<void *>(regs_->GetPc()));
796 return (frames_.size() > 0);
797 }
798
UnwindByFp(void * ctx,size_t maxFrameNum,size_t skipFrameNum)799 bool Unwinder::Impl::UnwindByFp(void *ctx, size_t maxFrameNum, size_t skipFrameNum)
800 {
801 if (regs_ == nullptr) {
802 LOGE("%s", "params is nullptr?");
803 return false;
804 }
805 pcs_.clear();
806 bool needAdjustPc = false;
807
808 bool resetFrames = false;
809 do {
810 if (!resetFrames && skipFrameNum != 0 && (pcs_.size() == skipFrameNum)) {
811 LOGU("pcs size: %zu, will be reset pcs", pcs_.size());
812 resetFrames = true;
813 pcs_.clear();
814 }
815 if (pcs_.size() >= maxFrameNum) {
816 lastErrorData_.SetCode(UNW_ERROR_MAX_FRAMES_EXCEEDED);
817 break;
818 }
819
820 uintptr_t pc = regs_->GetPc();
821 uintptr_t fp = regs_->GetFp();
822 if (needAdjustPc) {
823 DoPcAdjust(pc);
824 }
825 needAdjustPc = true;
826 pcs_.emplace_back(pc);
827
828 if (!FpStep(fp, pc, ctx) || (pc == 0)) {
829 break;
830 }
831 } while (true);
832 return (pcs_.size() > 0);
833 }
834
FpStep(uintptr_t & fp,uintptr_t & pc,void * ctx)835 bool Unwinder::Impl::FpStep(uintptr_t& fp, uintptr_t& pc, void *ctx)
836 {
837 #if defined(__aarch64__)
838 LOGU("+fp: %lx, pc: %lx", (uint64_t)fp, (uint64_t)pc);
839 if ((regs_ == nullptr) || (memory_ == nullptr)) {
840 LOGE("%s", "params is nullptr");
841 return false;
842 }
843 if (ctx != nullptr) {
844 memory_->SetCtx(ctx);
845 }
846
847 uintptr_t prevFp = fp;
848 uintptr_t ptr = fp;
849 if (ptr != 0 && memory_->ReadUptr(ptr, &fp, true) &&
850 memory_->ReadUptr(ptr, &pc, false)) {
851 if (fp != 0 && fp <= prevFp) {
852 LOGU("Illegal or same fp value");
853 lastErrorData_.SetAddrAndCode(pc, UNW_ERROR_ILLEGAL_VALUE);
854 return false;
855 }
856 regs_->SetReg(REG_FP, &fp);
857 regs_->SetReg(REG_SP, &prevFp);
858 regs_->SetPc(StripPac(pc, pacMask_));
859 LOGU("-fp: %lx, pc: %lx", (uint64_t)fp, (uint64_t)pc);
860 return true;
861 }
862 #endif
863 return false;
864 }
865
Step(uintptr_t & pc,uintptr_t & sp,void * ctx)866 bool Unwinder::Impl::Step(uintptr_t& pc, uintptr_t& sp, void *ctx)
867 {
868 DFX_TRACE_SCOPED_DLSYM("Step pc:%p", reinterpret_cast<void *>(pc));
869 if ((regs_ == nullptr) || (!CheckAndReset(ctx))) {
870 LOGE("%s", "params is nullptr?");
871 return false;
872 }
873 bool ret = false;
874 StepFrame frame;
875 frame.pc = pc;
876 frame.sp = sp;
877 frame.fp = regs_->GetFp();
878 // Check if this is a signal frame.
879 if (regs_->StepIfSignalFrame(frame.pc, memory_)) {
880 LOGW("Step signal frame, pc: %p", reinterpret_cast<void *>(frame.pc));
881 ret = StepInner(true, frame, ctx);
882 } else {
883 ret = StepInner(false, frame, ctx);
884 }
885 pc = frame.pc;
886 sp = frame.sp;
887 return ret;
888 }
889
StepInner(const bool isSigFrame,StepFrame & frame,void * ctx)890 bool Unwinder::Impl::StepInner(const bool isSigFrame, StepFrame& frame, void *ctx)
891 {
892 if ((regs_ == nullptr) || (!CheckAndReset(ctx))) {
893 LOGE("%s", "params is nullptr");
894 return false;
895 }
896 SetLocalStackCheck(ctx, false);
897 LOGU("+pc: %p, sp: %p, fp: %p", reinterpret_cast<void *>(frame.pc),
898 reinterpret_cast<void *>(frame.sp), reinterpret_cast<void *>(frame.fp));
899 uintptr_t prevSp = frame.sp;
900
901 bool ret = false;
902 std::shared_ptr<RegLocState> rs = nullptr;
903 std::shared_ptr<DfxMap> map = nullptr;
904 do {
905 if (enableCache_ && !isFpStep_) {
906 // 1. find cache rs
907 auto iter = stepCache_.find(frame.pc);
908 if (iter != stepCache_.end()) {
909 if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
910 LOGU("Find rs cache, pc: %p", reinterpret_cast<void *>(frame.pc));
911 }
912 rs = iter->second.rs;
913 map = iter->second.map;
914 AddFrame(frame, map);
915 ret = true;
916 break;
917 }
918 }
919
920 // 2. find map
921 MAYBE_UNUSED int mapRet = acc_->GetMapByPc(frame.pc, map, ctx);
922 if (mapRet != UNW_ERROR_NONE) {
923 if (frame.isJsFrame) {
924 LOGW("Failed to get map with ark, frames size: %zu", frames_.size());
925 mapRet = UNW_ERROR_UNKNOWN_ARK_MAP;
926 }
927 if (frames_.size() > 2) { // 2, least 2 frame
928 LOGU("Failed to get map, frames size: %zu", frames_.size());
929 lastErrorData_.SetAddrAndCode(frame.pc, mapRet);
930 return false;
931 }
932 }
933 AddFrame(frame, map);
934 if (isSigFrame) {
935 return true;
936 }
937
938 #if defined(ENABLE_MIXSTACK)
939 if (stopWhenArkFrame_ && (map != nullptr && map->IsArkExecutable())) {
940 LOGU("Stop by ark frame");
941 return false;
942 }
943 if ((enableMixstack_) && ((map != nullptr && map->IsArkExecutable()) || frame.isJsFrame)) {
944 if (!StepArkJsFrame(frame)) {
945 LOGE("Failed to step ark Js frame, pc: %p", reinterpret_cast<void *>(frame.pc));
946 lastErrorData_.SetAddrAndCode(frame.pc, UNW_ERROR_STEP_ARK_FRAME);
947 ret = false;
948 break;
949 }
950 regs_->SetPc(StripPac(frame.pc, pacMask_));
951 regs_->SetSp(frame.sp);
952 regs_->SetFp(frame.fp);
953 #if defined(OFFLINE_MIXSTACK)
954 return true;
955 #endif
956 }
957 #endif
958 if (isFpStep_) {
959 if (enableFpCheckMapExec_ && (map != nullptr && !map->IsMapExec())) {
960 LOGE("%s", "Fp step check map is not exec");
961 return false;
962 }
963 break;
964 }
965
966 // 3. find unwind table and entry
967 UnwindTableInfo uti;
968 MAYBE_UNUSED int utiRet = acc_->FindUnwindTable(frame.pc, uti, ctx);
969 if (utiRet != UNW_ERROR_NONE) {
970 lastErrorData_.SetAddrAndCode(frame.pc, utiRet);
971 LOGU("Failed to find unwind table ret: %d", utiRet);
972 break;
973 }
974
975 // 4. parse instructions and get cache rs
976 struct UnwindEntryInfo uei;
977 rs = std::make_shared<RegLocState>();
978 #if defined(__arm__)
979 if (!ret && uti.format == UNW_INFO_FORMAT_ARM_EXIDX) {
980 if (!armExidx_->SearchEntry(frame.pc, uti, uei)) {
981 lastErrorData_.SetAddrAndCode(armExidx_->GetLastErrorAddr(), armExidx_->GetLastErrorCode());
982 LOGE("%s", "Failed to search unwind entry?");
983 break;
984 }
985 if (!armExidx_->Step((uintptr_t)uei.unwindInfo, rs)) {
986 lastErrorData_.SetAddrAndCode(armExidx_->GetLastErrorAddr(), armExidx_->GetLastErrorCode());
987 LOGU("%s", "Step exidx section error?");
988 } else {
989 ret = true;
990 }
991 }
992 #endif
993 if (!ret && uti.format == UNW_INFO_FORMAT_REMOTE_TABLE) {
994 if ((uti.isLinear == false && !dwarfSection_->SearchEntry(frame.pc, uti, uei)) ||
995 (uti.isLinear == true && !dwarfSection_->LinearSearchEntry(frame.pc, uti, uei))) {
996 lastErrorData_.SetAddrAndCode(dwarfSection_->GetLastErrorAddr(), dwarfSection_->GetLastErrorCode());
997 LOGU("%s", "Failed to search unwind entry?");
998 break;
999 }
1000 memory_->SetDataOffset(uti.segbase);
1001 if (!dwarfSection_->Step(frame.pc, (uintptr_t)uei.unwindInfo, rs)) {
1002 lastErrorData_.SetAddrAndCode(dwarfSection_->GetLastErrorAddr(), dwarfSection_->GetLastErrorCode());
1003 LOGU("%s", "Step dwarf section error?");
1004 } else {
1005 ret = true;
1006 }
1007 }
1008
1009 if (ret && enableCache_) {
1010 // 5. update rs cache
1011 StepCache cache;
1012 cache.map = map;
1013 cache.rs = rs;
1014 stepCache_.emplace(frame.pc, cache);
1015 break;
1016 }
1017 } while (false);
1018
1019 // 5. update regs and regs state
1020 SetLocalStackCheck(ctx, true);
1021 if (ret) {
1022 #if defined(__arm__) || defined(__aarch64__)
1023 auto lr = *(regs_->GetReg(REG_LR));
1024 #endif
1025 ret = Apply(regs_, rs);
1026 #if defined(__arm__) || defined(__aarch64__)
1027 if (!ret && enableLrFallback_ && (frames_.size() == 1)) {
1028 regs_->SetPc(lr);
1029 ret = true;
1030 if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
1031 LOGW("%s", "Failed to apply first frame, lr fallback");
1032 }
1033 }
1034 #endif
1035 } else {
1036 if (enableLrFallback_ && (frames_.size() == 1) && regs_->SetPcFromReturnAddress(memory_)) {
1037 ret = true;
1038 if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
1039 LOGW("%s", "Failed to step first frame, lr fallback");
1040 }
1041 }
1042 }
1043 regs_->SetPc(StripPac(regs_->GetPc(), pacMask_));
1044
1045 #if defined(__aarch64__)
1046 if (!ret) { // try fp
1047 ret = FpStep(frame.fp, frame.pc, ctx);
1048 if (ret && !isFpStep_) {
1049 if (pid_ != UNWIND_TYPE_CUSTOMIZE) {
1050 LOGI("First enter fp step, pc: %p", reinterpret_cast<void *>(frame.pc));
1051 }
1052 isFpStep_ = true;
1053 }
1054 }
1055 #endif
1056
1057 frame.pc = regs_->GetPc();
1058 frame.sp = regs_->GetSp();
1059 frame.fp = regs_->GetFp();
1060 if (!isFpStep_ && (map != nullptr) && (!map->IsVdsoMap()) && (frame.sp < prevSp)) {
1061 LOGU("Illegal sp value");
1062 lastErrorData_.SetAddrAndCode(frame.pc, UNW_ERROR_ILLEGAL_VALUE);
1063 ret = false;
1064 }
1065 if (ret && (frame.pc == 0)) {
1066 ret = false;
1067 }
1068 LOGU("-pc: %p, sp: %p, fp: %p, ret: %d", reinterpret_cast<void *>(frame.pc),
1069 reinterpret_cast<void *>(frame.sp), reinterpret_cast<void *>(frame.fp), ret);
1070 return ret;
1071 }
1072
Apply(std::shared_ptr<DfxRegs> regs,std::shared_ptr<RegLocState> rs)1073 bool Unwinder::Impl::Apply(std::shared_ptr<DfxRegs> regs, std::shared_ptr<RegLocState> rs)
1074 {
1075 if (rs == nullptr || regs == nullptr) {
1076 return false;
1077 }
1078
1079 uintptr_t prevPc = regs->GetPc();
1080 uintptr_t prevSp = regs->GetSp();
1081 uint16_t errCode = 0;
1082 bool ret = DfxInstructions::Apply(memory_, *(regs.get()), *(rs.get()), errCode);
1083 uintptr_t tmp = 0;
1084 uintptr_t sp = regs->GetSp();
1085 if (ret && (!memory_->ReadUptr(sp, &tmp, false))) {
1086 errCode = UNW_ERROR_UNREADABLE_SP;
1087 ret = false;
1088 }
1089 if (regs->GetPc() == prevPc && regs->GetSp() == prevSp) {
1090 errCode = UNW_ERROR_REPEATED_FRAME;
1091 ret = false;
1092 }
1093 if (!ret) {
1094 lastErrorData_.SetCode(errCode);
1095 LOGE("Failed to apply reg state, errCode: %d", static_cast<int>(errCode));
1096 }
1097 return ret;
1098 }
1099
DoPcAdjust(uintptr_t & pc)1100 void Unwinder::Impl::DoPcAdjust(uintptr_t& pc)
1101 {
1102 if (pc <= 0x4) {
1103 return;
1104 }
1105 uintptr_t sz = 0x4;
1106 #if defined(__arm__)
1107 if ((pc & 0x1) && (memory_ != nullptr)) {
1108 uintptr_t val;
1109 if (pc < 0x5 || !(memory_->ReadMem(pc - 0x5, &val)) ||
1110 (val & 0xe000f000) != 0xe000f000) {
1111 sz = 0x2;
1112 }
1113 }
1114 #elif defined(__x86_64__)
1115 sz = 0x1;
1116 #endif
1117 pc -= sz;
1118 }
1119
StripPac(uintptr_t inAddr,uintptr_t pacMask)1120 uintptr_t Unwinder::Impl::StripPac(uintptr_t inAddr, uintptr_t pacMask)
1121 {
1122 uintptr_t outAddr = inAddr;
1123 #if defined(__aarch64__)
1124 if (outAddr != 0) {
1125 if (pacMask != 0) {
1126 outAddr &= ~pacMask;
1127 } else {
1128 register uint64_t x30 __asm("x30") = inAddr;
1129 asm("hint 0x7" : "+r"(x30));
1130 outAddr = x30;
1131 }
1132 if (outAddr != inAddr) {
1133 LOGU("Strip pac in addr: %lx, out addr: %lx", (uint64_t)inAddr, (uint64_t)outAddr);
1134 }
1135 }
1136 #endif
1137 return outAddr;
1138 }
1139
GetFrames()1140 const std::vector<DfxFrame>& Unwinder::Impl::GetFrames()
1141 {
1142 if (enableFillFrames_) {
1143 FillFrames(frames_);
1144 }
1145 return frames_;
1146 }
1147
AddFrame(const StepFrame & frame,std::shared_ptr<DfxMap> map)1148 void Unwinder::Impl::AddFrame(const StepFrame& frame, std::shared_ptr<DfxMap> map)
1149 {
1150 #if defined(OFFLINE_MIXSTACK)
1151 if (ignoreMixstack_ && frame.isJsFrame) {
1152 return;
1153 }
1154 #endif
1155 pcs_.emplace_back(frame.pc);
1156 DfxFrame dfxFrame;
1157 dfxFrame.isJsFrame = frame.isJsFrame;
1158 dfxFrame.index = frames_.size();
1159 dfxFrame.pc = static_cast<uint64_t>(frame.pc);
1160 dfxFrame.sp = static_cast<uint64_t>(frame.sp);
1161 #if defined(OFFLINE_MIXSTACK)
1162 if (frame.isJsFrame) {
1163 dfxFrame.funcOffset = static_cast<uint64_t>(frame.methodid);
1164 }
1165 #endif
1166 dfxFrame.map = map;
1167 frames_.emplace_back(dfxFrame);
1168 }
1169
AddFrame(DfxFrame & frame)1170 void Unwinder::Impl::AddFrame(DfxFrame& frame)
1171 {
1172 frames_.emplace_back(frame);
1173 }
1174
AccessMem(void * memory,uintptr_t addr,uintptr_t * val)1175 bool Unwinder::AccessMem(void* memory, uintptr_t addr, uintptr_t *val)
1176 {
1177 return reinterpret_cast<DfxMemory*>(memory)->ReadMem(addr, val);
1178 }
1179
FillLocalFrames(std::vector<DfxFrame> & frames)1180 void Unwinder::FillLocalFrames(std::vector<DfxFrame>& frames)
1181 {
1182 if (frames.empty()) {
1183 return;
1184 }
1185 auto it = frames.begin();
1186 while (it != frames.end()) {
1187 if (dl_iterate_phdr(Unwinder::Impl::DlPhdrCallback, &(*it)) != 1) {
1188 // clean up frames after first invalid frame
1189 frames.erase(it, frames.end());
1190 break;
1191 }
1192 it++;
1193 }
1194 }
1195
FillFrames(std::vector<DfxFrame> & frames)1196 void Unwinder::Impl::FillFrames(std::vector<DfxFrame>& frames)
1197 {
1198 for (size_t i = 0; i < frames.size(); ++i) {
1199 auto& frame = frames[i];
1200 if (frame.isJsFrame) {
1201 #if defined(OFFLINE_MIXSTACK)
1202 FillJsFrame(frame);
1203 #endif
1204 } else {
1205 FillFrame(frame);
1206 }
1207 }
1208 }
1209
FillFrame(DfxFrame & frame)1210 void Unwinder::Impl::FillFrame(DfxFrame& frame)
1211 {
1212 if (frame.map == nullptr) {
1213 frame.relPc = frame.pc;
1214 frame.mapName = "Not mapped";
1215 LOGU("%s", "Current frame is not mapped.");
1216 return;
1217 }
1218 frame.mapName = frame.map->GetElfName();
1219 DFX_TRACE_SCOPED_DLSYM("FillFrame:%s", frame.mapName.c_str());
1220 frame.relPc = frame.map->GetRelPc(frame.pc);
1221 frame.mapOffset = frame.map->offset;
1222 LOGU("mapName: %s, mapOffset: %" PRIx64 "", frame.mapName.c_str(), frame.mapOffset);
1223 auto elf = frame.map->GetElf();
1224 if (elf == nullptr) {
1225 if (pid_ == UNWIND_TYPE_LOCAL || pid_ == UNWIND_TYPE_CUSTOMIZE_LOCAL) {
1226 FillJsFrame(frame);
1227 }
1228 return;
1229 }
1230 if (!DfxSymbols::GetFuncNameAndOffsetByPc(frame.relPc, elf, frame.funcName, frame.funcOffset)) {
1231 LOGU("Failed to get symbol, relPc: %" PRIx64 ", mapName: %s", frame.relPc, frame.mapName.c_str());
1232 }
1233 frame.buildId = elf->GetBuildId();
1234 }
1235
FillJsFrame(DfxFrame & frame)1236 void Unwinder::Impl::FillJsFrame(DfxFrame& frame)
1237 {
1238 if (frame.map == nullptr) {
1239 LOGU("%s", "Current js frame is not map.");
1240 return;
1241 }
1242 DFX_TRACE_SCOPED_DLSYM("FillJsFrame:%s", frame.map->name.c_str());
1243 LOGU("Fill js frame, map name: %s", frame.map->name.c_str());
1244 auto hap = frame.map->GetHap();
1245 if (hap == nullptr) {
1246 LOGW("Get hap error, name: %s", frame.map->name.c_str());
1247 return;
1248 }
1249 JsFunction jsFunction;
1250 if ((pid_ == UNWIND_TYPE_LOCAL) || (pid_ == UNWIND_TYPE_CUSTOMIZE_LOCAL) || enableMethodIdLocal_) {
1251 if (DfxArk::ParseArkFrameInfoLocal(static_cast<uintptr_t>(frame.pc), static_cast<uintptr_t>(frame.funcOffset),
1252 static_cast<uintptr_t>(frame.map->begin), static_cast<uintptr_t>(frame.map->offset), &jsFunction) < 0) {
1253 LOGW("Failed to parse ark frame info local, pc: %p, begin: %p",
1254 reinterpret_cast<void *>(frame.pc), reinterpret_cast<void *>(frame.map->begin));
1255 return;
1256 }
1257 frame.isJsFrame = true;
1258 } else {
1259 if (!hap->ParseHapInfo(pid_, frame.pc, static_cast<uintptr_t>(frame.funcOffset), frame.map, &jsFunction)) {
1260 LOGW("Failed to parse hap info, pid: %d", pid_);
1261 return;
1262 }
1263 }
1264 frame.mapName = std::string(jsFunction.url);
1265 frame.funcName = std::string(jsFunction.functionName);
1266 frame.line = static_cast<int32_t>(jsFunction.line);
1267 frame.column = jsFunction.column;
1268 LOGU("Js frame mapName: %s, funcName: %s, line: %d, column: %d",
1269 frame.mapName.c_str(), frame.funcName.c_str(), frame.line, frame.column);
1270 }
1271
GetFrameByPc(uintptr_t pc,std::shared_ptr<DfxMaps> maps,DfxFrame & frame)1272 bool Unwinder::Impl::GetFrameByPc(uintptr_t pc, std::shared_ptr<DfxMaps> maps, DfxFrame &frame)
1273 {
1274 frame.pc = static_cast<uint64_t>(StripPac(pc, 0));
1275 std::shared_ptr<DfxMap> map = nullptr;
1276 if ((maps == nullptr) || !maps->FindMapByAddr(pc, map) || map == nullptr) {
1277 LOGE("%s", "Find map error");
1278 return false;
1279 }
1280
1281 frame.map = map;
1282 FillFrame(frame);
1283 return true;
1284 }
1285
GetLockInfo(int32_t tid,char * buf,size_t sz)1286 bool Unwinder::Impl::GetLockInfo(int32_t tid, char* buf, size_t sz)
1287 {
1288 #ifdef __aarch64__
1289 if (frames_.empty()) {
1290 return false;
1291 }
1292
1293 if (frames_[0].funcName.find("__timedwait_cp") == std::string::npos) {
1294 return false;
1295 }
1296
1297 uintptr_t lockPtrAddr = firstFrameSp_ + 56; // 56 : sp + 0x38
1298 uintptr_t lockAddr;
1299 UnwindContext context;
1300 context.pid = tid;
1301 if (acc_->AccessMem(lockPtrAddr, &lockAddr, &context) != UNW_ERROR_NONE) {
1302 LOGW("%s", "Failed to find lock addr.");
1303 return false;
1304 }
1305
1306 size_t rsize = DfxMemory::ReadProcMemByPid(tid, lockAddr, buf, sz);
1307 if (rsize != sz) {
1308 LOGW("Failed to fetch lock content, read size:%zu expected size:%zu", rsize, sz);
1309 return false;
1310 }
1311 return true;
1312 #else
1313 return false;
1314 #endif
1315 }
1316
GetFramesByPcs(std::vector<DfxFrame> & frames,std::vector<uintptr_t> pcs)1317 void Unwinder::Impl::GetFramesByPcs(std::vector<DfxFrame>& frames, std::vector<uintptr_t> pcs)
1318 {
1319 frames.clear();
1320 std::shared_ptr<DfxMap> map = nullptr;
1321 for (size_t i = 0; i < pcs.size(); ++i) {
1322 DfxFrame frame;
1323 frame.index = i;
1324 frame.pc = static_cast<uint64_t>(StripPac(pcs[i], 0));
1325 if ((map != nullptr) && map->Contain(frame.pc)) {
1326 LOGU("%s", "map had matched");
1327 } else {
1328 if ((maps_ == nullptr) || !maps_->FindMapByAddr(pcs[i], map) || (map == nullptr)) {
1329 LOGE("%s", "Find map error");
1330 }
1331 }
1332 frame.map = map;
1333 FillFrame(frame);
1334 frames.emplace_back(frame);
1335 }
1336 }
1337
GetLocalFramesByPcs(std::vector<DfxFrame> & frames,std::vector<uintptr_t> pcs)1338 void Unwinder::GetLocalFramesByPcs(std::vector<DfxFrame>& frames, std::vector<uintptr_t> pcs)
1339 {
1340 frames.clear();
1341 for (size_t i = 0; i < pcs.size(); ++i) {
1342 DfxFrame frame;
1343 frame.index = i;
1344 frame.pc = static_cast<uint64_t>(pcs[i]);
1345 frames.emplace_back(frame);
1346 }
1347 FillLocalFrames(frames);
1348 }
1349
GetSymbolByPc(uintptr_t pc,std::shared_ptr<DfxMaps> maps,std::string & funcName,uint64_t & funcOffset)1350 bool Unwinder::GetSymbolByPc(uintptr_t pc, std::shared_ptr<DfxMaps> maps, std::string& funcName, uint64_t& funcOffset)
1351 {
1352 if (maps == nullptr) {
1353 return false;
1354 }
1355 std::shared_ptr<DfxMap> map = nullptr;
1356 if (!maps->FindMapByAddr(pc, map) || (map == nullptr)) {
1357 LOGE("%s", "Find map is null");
1358 return false;
1359 }
1360 uint64_t relPc = map->GetRelPc(static_cast<uint64_t>(pc));
1361 auto elf = map->GetElf();
1362 if (elf == nullptr) {
1363 LOGE("%s", "Get elf is null");
1364 return false;
1365 }
1366 return DfxSymbols::GetFuncNameAndOffsetByPc(relPc, elf, funcName, funcOffset);
1367 }
1368
GetFramesStr(const std::vector<DfxFrame> & frames)1369 std::string Unwinder::GetFramesStr(const std::vector<DfxFrame>& frames)
1370 {
1371 return DfxFrameFormatter::GetFramesStr(frames);
1372 }
1373
DlPhdrCallback(struct dl_phdr_info * info,size_t size,void * data)1374 int Unwinder::Impl::DlPhdrCallback(struct dl_phdr_info *info, size_t size, void *data)
1375 {
1376 auto frame = reinterpret_cast<DfxFrame *>(data);
1377 const ElfW(Phdr) *phdr = info->dlpi_phdr;
1378 frame->pc = StripPac(frame->pc, 0);
1379 for (int n = info->dlpi_phnum; --n >= 0; phdr++) {
1380 if (phdr->p_type == PT_LOAD) {
1381 ElfW(Addr) vaddr = phdr->p_vaddr + info->dlpi_addr;
1382 if (frame->pc >= vaddr && frame->pc < vaddr + phdr->p_memsz) {
1383 frame->relPc = frame->pc - info->dlpi_addr;
1384 frame->mapName = std::string(info->dlpi_name);
1385 LOGU("relPc: %" PRIx64 ", mapName: %s", frame->relPc, frame->mapName.c_str());
1386 return 1;
1387 }
1388 }
1389 }
1390 return 0;
1391 }
1392 } // namespace HiviewDFX
1393 } // namespace OHOS
1394