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#include "fp_unwinder.h" 16800b99b8Sopenharmony_ci 17800b99b8Sopenharmony_ci#include <cinttypes> 18800b99b8Sopenharmony_ci#include <csignal> 19800b99b8Sopenharmony_ci#include <cstdio> 20800b99b8Sopenharmony_ci#include <securec.h> 21800b99b8Sopenharmony_ci#include <sys/stat.h> 22800b99b8Sopenharmony_ci#include <sys/syscall.h> 23800b99b8Sopenharmony_ci#include <unistd.h> 24800b99b8Sopenharmony_ci#include <fcntl.h> 25800b99b8Sopenharmony_ci#include <pthread.h> 26800b99b8Sopenharmony_ci#include "dfx_log.h" 27800b99b8Sopenharmony_ci#include "stack_util.h" 28800b99b8Sopenharmony_ci 29800b99b8Sopenharmony_cinamespace OHOS { 30800b99b8Sopenharmony_cinamespace HiviewDFX { 31800b99b8Sopenharmony_cistatic int32_t g_validPipe[PIPE_NUM_SZ] = {-1, -1}; 32800b99b8Sopenharmony_ciconstexpr uintptr_t MAX_UNWIND_ADDR_RANGE = 16 * 1024; 33800b99b8Sopenharmony_ciint32_t FpUnwinder::Unwind(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum) 34800b99b8Sopenharmony_ci{ 35800b99b8Sopenharmony_ci GetFpPcRegs(pcs); 36800b99b8Sopenharmony_ci int32_t index = 0; 37800b99b8Sopenharmony_ci uintptr_t firstFp = pcs[1]; 38800b99b8Sopenharmony_ci uintptr_t fp = firstFp; 39800b99b8Sopenharmony_ci uintptr_t stackPtr = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); 40800b99b8Sopenharmony_ci uintptr_t stackBottom = 0; 41800b99b8Sopenharmony_ci uintptr_t stackTop = 0; 42800b99b8Sopenharmony_ci uint32_t realSz = 0; 43800b99b8Sopenharmony_ci if (getpid() == gettid()) { 44800b99b8Sopenharmony_ci GetMainStackRange(stackBottom, stackTop); 45800b99b8Sopenharmony_ci } else { 46800b99b8Sopenharmony_ci GetSelfStackRange(stackBottom, stackTop); 47800b99b8Sopenharmony_ci if (!(stackPtr >= stackBottom && stackPtr < stackTop)) { 48800b99b8Sopenharmony_ci GetSigAltStackRange(stackBottom, stackTop); 49800b99b8Sopenharmony_ci if (stackPtr < stackBottom || stackPtr >= stackTop) { 50800b99b8Sopenharmony_ci return realSz; 51800b99b8Sopenharmony_ci } 52800b99b8Sopenharmony_ci } 53800b99b8Sopenharmony_ci } 54800b99b8Sopenharmony_ci while ((index < sz - 1) && (fp - firstFp < MAX_UNWIND_ADDR_RANGE)) { 55800b99b8Sopenharmony_ci if (fp < stackBottom || fp >= stackTop - sizeof(uintptr_t)) { 56800b99b8Sopenharmony_ci break; 57800b99b8Sopenharmony_ci } 58800b99b8Sopenharmony_ci if ((++index) >= skipFrameNum) { 59800b99b8Sopenharmony_ci uintptr_t pc = *reinterpret_cast<uintptr_t*>(fp + sizeof(uintptr_t)); 60800b99b8Sopenharmony_ci pcs[index - skipFrameNum] = pc > 0x4 ? pc - 0x4 : pc; // adjust pc in Arm64 architecture 61800b99b8Sopenharmony_ci realSz = static_cast<uint32_t>(index - skipFrameNum + 1); 62800b99b8Sopenharmony_ci } 63800b99b8Sopenharmony_ci uintptr_t nextFp = *reinterpret_cast<uintptr_t*>(fp); 64800b99b8Sopenharmony_ci if (nextFp <= fp) { 65800b99b8Sopenharmony_ci break; 66800b99b8Sopenharmony_ci } 67800b99b8Sopenharmony_ci fp = nextFp; 68800b99b8Sopenharmony_ci } 69800b99b8Sopenharmony_ci return realSz; 70800b99b8Sopenharmony_ci} 71800b99b8Sopenharmony_ci 72800b99b8Sopenharmony_ciint32_t FpUnwinder::UnwindFallback(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum) 73800b99b8Sopenharmony_ci{ 74800b99b8Sopenharmony_ci if (pipe2(g_validPipe, O_CLOEXEC | O_NONBLOCK) != 0) { 75800b99b8Sopenharmony_ci DFXLOGE("Failed to init pipe, errno(%{public}d)", errno); 76800b99b8Sopenharmony_ci return 0; 77800b99b8Sopenharmony_ci } 78800b99b8Sopenharmony_ci uintptr_t firstFp = pcs[1]; 79800b99b8Sopenharmony_ci uintptr_t fp = firstFp; 80800b99b8Sopenharmony_ci int32_t index = 0; 81800b99b8Sopenharmony_ci int32_t realSz = 0; 82800b99b8Sopenharmony_ci while ((index < sz - 1) && (fp - firstFp < MAX_UNWIND_ADDR_RANGE)) { 83800b99b8Sopenharmony_ci uintptr_t addr = fp + sizeof(uintptr_t); 84800b99b8Sopenharmony_ci if (!ReadUintptrSafe(addr, pcs[++index])) { 85800b99b8Sopenharmony_ci break; 86800b99b8Sopenharmony_ci } 87800b99b8Sopenharmony_ci if ((++index) >= skipFrameNum) { 88800b99b8Sopenharmony_ci pcs[index - skipFrameNum] = 0; 89800b99b8Sopenharmony_ci realSz = index - skipFrameNum + 1; 90800b99b8Sopenharmony_ci } 91800b99b8Sopenharmony_ci uintptr_t prevFp = fp; 92800b99b8Sopenharmony_ci if (!ReadUintptrSafe(prevFp, fp)) { 93800b99b8Sopenharmony_ci break; 94800b99b8Sopenharmony_ci } 95800b99b8Sopenharmony_ci if (fp <= prevFp) { 96800b99b8Sopenharmony_ci break; 97800b99b8Sopenharmony_ci } 98800b99b8Sopenharmony_ci } 99800b99b8Sopenharmony_ci close(g_validPipe[PIPE_WRITE]); 100800b99b8Sopenharmony_ci close(g_validPipe[PIPE_READ]); 101800b99b8Sopenharmony_ci return realSz; 102800b99b8Sopenharmony_ci} 103800b99b8Sopenharmony_ci 104800b99b8Sopenharmony_ciNO_SANITIZE bool FpUnwinder::ReadUintptrSafe(uintptr_t addr, uintptr_t& value) 105800b99b8Sopenharmony_ci{ 106800b99b8Sopenharmony_ci if (OHOS_TEMP_FAILURE_RETRY(syscall(SYS_write, g_validPipe[PIPE_WRITE], addr, sizeof(uintptr_t))) == -1) { 107800b99b8Sopenharmony_ci DFXLOGE("Failed to write addr to pipe, it is a invalid addr"); 108800b99b8Sopenharmony_ci return false; 109800b99b8Sopenharmony_ci } 110800b99b8Sopenharmony_ci value = *reinterpret_cast<uintptr_t *>(addr); 111800b99b8Sopenharmony_ci return true; 112800b99b8Sopenharmony_ci} 113800b99b8Sopenharmony_ci} 114800b99b8Sopenharmony_ci} 115