1800b99b8Sopenharmony_ci/* 2800b99b8Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License. 5800b99b8Sopenharmony_ci * You may obtain a copy of the License at 6800b99b8Sopenharmony_ci * 7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8800b99b8Sopenharmony_ci * 9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and 13800b99b8Sopenharmony_ci * limitations under the License. 14800b99b8Sopenharmony_ci */ 15800b99b8Sopenharmony_ci#ifndef FP_UNWINDER_H 16800b99b8Sopenharmony_ci#define FP_UNWINDER_H 17800b99b8Sopenharmony_ci 18800b99b8Sopenharmony_ci#include <atomic> 19800b99b8Sopenharmony_ci#include <cinttypes> 20800b99b8Sopenharmony_ci#include <csignal> 21800b99b8Sopenharmony_ci#include <dlfcn.h> 22800b99b8Sopenharmony_ci#include <fcntl.h> 23800b99b8Sopenharmony_ci#include <memory> 24800b99b8Sopenharmony_ci#include <mutex> 25800b99b8Sopenharmony_ci#include <nocopyable.h> 26800b99b8Sopenharmony_ci#include <securec.h> 27800b99b8Sopenharmony_ci#include <sys/stat.h> 28800b99b8Sopenharmony_ci#include <sys/syscall.h> 29800b99b8Sopenharmony_ci#include <unistd.h> 30800b99b8Sopenharmony_ci#include "dfx_ark.h" 31800b99b8Sopenharmony_ci#include "dfx_define.h" 32800b99b8Sopenharmony_ci#include "stack_util.h" 33800b99b8Sopenharmony_ci 34800b99b8Sopenharmony_cinamespace OHOS { 35800b99b8Sopenharmony_cinamespace HiviewDFX { 36800b99b8Sopenharmony_ciclass FpUnwinder { 37800b99b8Sopenharmony_cipublic: 38800b99b8Sopenharmony_ci static FpUnwinder* GetPtr() 39800b99b8Sopenharmony_ci { 40800b99b8Sopenharmony_ci static std::unique_ptr<FpUnwinder> ptr = nullptr; 41800b99b8Sopenharmony_ci if (ptr == nullptr) { 42800b99b8Sopenharmony_ci static std::once_flag flag; 43800b99b8Sopenharmony_ci std::call_once(flag, [&] { 44800b99b8Sopenharmony_ci ptr.reset(new FpUnwinder()); 45800b99b8Sopenharmony_ci }); 46800b99b8Sopenharmony_ci } 47800b99b8Sopenharmony_ci return ptr.get(); 48800b99b8Sopenharmony_ci } 49800b99b8Sopenharmony_ci 50800b99b8Sopenharmony_ci size_t Unwind(uintptr_t pc, uintptr_t fp, uintptr_t* pcs, size_t maxSize, size_t skipFrameNum = 0) 51800b99b8Sopenharmony_ci { 52800b99b8Sopenharmony_ci if (pcs == nullptr) { 53800b99b8Sopenharmony_ci return 0; 54800b99b8Sopenharmony_ci } 55800b99b8Sopenharmony_ci if (gettid() == getpid()) { 56800b99b8Sopenharmony_ci if (!GetMainStackRange(stackBottom_, stackTop_)) { 57800b99b8Sopenharmony_ci return 0; 58800b99b8Sopenharmony_ci } 59800b99b8Sopenharmony_ci } else { 60800b99b8Sopenharmony_ci if (!GetSelfStackRange(stackBottom_, stackTop_)) { 61800b99b8Sopenharmony_ci return 0; 62800b99b8Sopenharmony_ci } 63800b99b8Sopenharmony_ci } 64800b99b8Sopenharmony_ci uintptr_t firstFp = fp; 65800b99b8Sopenharmony_ci size_t index = 0; 66800b99b8Sopenharmony_ci MAYBE_UNUSED uintptr_t sp = 0; 67800b99b8Sopenharmony_ci MAYBE_UNUSED bool isJsFrame = false; 68800b99b8Sopenharmony_ci while ((index < maxSize) && (fp - firstFp < maxUnwindAddrRange_)) { 69800b99b8Sopenharmony_ci if (index >= skipFrameNum) { 70800b99b8Sopenharmony_ci pcs[index - skipFrameNum] = pc; 71800b99b8Sopenharmony_ci } 72800b99b8Sopenharmony_ci index++; 73800b99b8Sopenharmony_ci uintptr_t prevFp = fp; 74800b99b8Sopenharmony_ci if ((!ReadUptr(prevFp, fp)) || 75800b99b8Sopenharmony_ci (!ReadUptr(prevFp + sizeof(uintptr_t), pc))) { 76800b99b8Sopenharmony_ci break; 77800b99b8Sopenharmony_ci } 78800b99b8Sopenharmony_ci if (fp <= prevFp || fp == 0) { 79800b99b8Sopenharmony_ci break; 80800b99b8Sopenharmony_ci } 81800b99b8Sopenharmony_ci } 82800b99b8Sopenharmony_ci return (index - skipFrameNum); 83800b99b8Sopenharmony_ci } 84800b99b8Sopenharmony_ci 85800b99b8Sopenharmony_ci NO_SANITIZE size_t UnwindSafe(uintptr_t pc, uintptr_t fp, uintptr_t* pcs, size_t maxSize, size_t skipFrameNum = 0) 86800b99b8Sopenharmony_ci { 87800b99b8Sopenharmony_ci if (pcs == nullptr) { 88800b99b8Sopenharmony_ci return 0; 89800b99b8Sopenharmony_ci } 90800b99b8Sopenharmony_ci int32_t pfd[PIPE_NUM_SZ] = {-1, -1}; 91800b99b8Sopenharmony_ci if (syscall(SYS_pipe2, pfd, O_CLOEXEC | O_NONBLOCK) != 0) { 92800b99b8Sopenharmony_ci return 0; 93800b99b8Sopenharmony_ci } 94800b99b8Sopenharmony_ci size_t index = 0; 95800b99b8Sopenharmony_ci MAYBE_UNUSED uintptr_t sp = 0; 96800b99b8Sopenharmony_ci MAYBE_UNUSED bool isJsFrame = false; 97800b99b8Sopenharmony_ci while (index < maxSize) { 98800b99b8Sopenharmony_ci if (index >= skipFrameNum) { 99800b99b8Sopenharmony_ci pcs[index - skipFrameNum] = pc; 100800b99b8Sopenharmony_ci } 101800b99b8Sopenharmony_ci index++; 102800b99b8Sopenharmony_ci uintptr_t prevFp = fp; 103800b99b8Sopenharmony_ci if ((!ReadUptrSafe(prevFp, pfd[PIPE_WRITE], fp)) || 104800b99b8Sopenharmony_ci (!ReadUptrSafe(prevFp + sizeof(uintptr_t), pfd[PIPE_WRITE], pc))) { 105800b99b8Sopenharmony_ci break; 106800b99b8Sopenharmony_ci } 107800b99b8Sopenharmony_ci pc = pc > 0x4 ? pc - 0x4 : pc; // adjust pc in Arm64 architecture 108800b99b8Sopenharmony_ci if (fp <= prevFp || fp == 0) { 109800b99b8Sopenharmony_ci break; 110800b99b8Sopenharmony_ci } 111800b99b8Sopenharmony_ci } 112800b99b8Sopenharmony_ci syscall(SYS_close, pfd[PIPE_WRITE]); 113800b99b8Sopenharmony_ci syscall(SYS_close, pfd[PIPE_READ]); 114800b99b8Sopenharmony_ci return (index - skipFrameNum); 115800b99b8Sopenharmony_ci } 116800b99b8Sopenharmony_ci 117800b99b8Sopenharmony_ci static inline AT_ALWAYS_INLINE void GetPcFpRegs(void *regs) 118800b99b8Sopenharmony_ci { 119800b99b8Sopenharmony_ci#if defined(__aarch64__) 120800b99b8Sopenharmony_ci asm volatile( 121800b99b8Sopenharmony_ci "1:\n" 122800b99b8Sopenharmony_ci "adr x12, 1b\n" 123800b99b8Sopenharmony_ci "stp x12, x29, [%[base], #0]\n" 124800b99b8Sopenharmony_ci : [base] "+r"(regs) 125800b99b8Sopenharmony_ci : 126800b99b8Sopenharmony_ci : "x12", "memory"); 127800b99b8Sopenharmony_ci#endif 128800b99b8Sopenharmony_ci } 129800b99b8Sopenharmony_ci 130800b99b8Sopenharmony_ciprivate: 131800b99b8Sopenharmony_ci FpUnwinder() = default; 132800b99b8Sopenharmony_ci DISALLOW_COPY_AND_MOVE(FpUnwinder); 133800b99b8Sopenharmony_ci 134800b99b8Sopenharmony_ci NO_SANITIZE bool ReadUptr(uintptr_t addr, uintptr_t& value) 135800b99b8Sopenharmony_ci { 136800b99b8Sopenharmony_ci if ((addr < stackBottom_) || (addr + sizeof(uintptr_t) >= stackTop_)) { 137800b99b8Sopenharmony_ci return false; 138800b99b8Sopenharmony_ci } 139800b99b8Sopenharmony_ci value = *reinterpret_cast<uintptr_t *>(addr); 140800b99b8Sopenharmony_ci return true; 141800b99b8Sopenharmony_ci } 142800b99b8Sopenharmony_ci 143800b99b8Sopenharmony_ci NO_SANITIZE bool ReadUptrSafe(uintptr_t addr, uint32_t fd, uintptr_t& value) 144800b99b8Sopenharmony_ci { 145800b99b8Sopenharmony_ci if (OHOS_TEMP_FAILURE_RETRY(syscall(SYS_write, fd, addr, sizeof(uintptr_t))) == -1) { 146800b99b8Sopenharmony_ci return false; 147800b99b8Sopenharmony_ci } 148800b99b8Sopenharmony_ci 149800b99b8Sopenharmony_ci value = *reinterpret_cast<uintptr_t *>(addr); 150800b99b8Sopenharmony_ci return true; 151800b99b8Sopenharmony_ci } 152800b99b8Sopenharmony_ci 153800b99b8Sopenharmony_ciprivate: 154800b99b8Sopenharmony_ci MAYBE_UNUSED const uintptr_t maxUnwindAddrRange_ = 16 * 1024; // 16: 16k 155800b99b8Sopenharmony_ci uintptr_t stackBottom_ = 0; 156800b99b8Sopenharmony_ci uintptr_t stackTop_ = 0; 157800b99b8Sopenharmony_ci MAYBE_UNUSED uintptr_t arkMapStart_ = 0; 158800b99b8Sopenharmony_ci MAYBE_UNUSED uintptr_t arkMapEnd_ = 0; 159800b99b8Sopenharmony_ci}; 160800b99b8Sopenharmony_ci} 161800b99b8Sopenharmony_ci} // namespace OHOS 162800b99b8Sopenharmony_ci#endif