1/* 2 * Copyright (c) 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#include "fp_unwinder.h" 16 17#include <cinttypes> 18#include <csignal> 19#include <cstdio> 20#include <securec.h> 21#include <sys/stat.h> 22#include <sys/syscall.h> 23#include <unistd.h> 24#include <fcntl.h> 25#include <pthread.h> 26#include "dfx_log.h" 27#include "stack_util.h" 28 29namespace OHOS { 30namespace HiviewDFX { 31static int32_t g_validPipe[PIPE_NUM_SZ] = {-1, -1}; 32constexpr uintptr_t MAX_UNWIND_ADDR_RANGE = 16 * 1024; 33int32_t FpUnwinder::Unwind(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum) 34{ 35 GetFpPcRegs(pcs); 36 int32_t index = 0; 37 uintptr_t firstFp = pcs[1]; 38 uintptr_t fp = firstFp; 39 uintptr_t stackPtr = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); 40 uintptr_t stackBottom = 0; 41 uintptr_t stackTop = 0; 42 uint32_t realSz = 0; 43 if (getpid() == gettid()) { 44 GetMainStackRange(stackBottom, stackTop); 45 } else { 46 GetSelfStackRange(stackBottom, stackTop); 47 if (!(stackPtr >= stackBottom && stackPtr < stackTop)) { 48 GetSigAltStackRange(stackBottom, stackTop); 49 if (stackPtr < stackBottom || stackPtr >= stackTop) { 50 return realSz; 51 } 52 } 53 } 54 while ((index < sz - 1) && (fp - firstFp < MAX_UNWIND_ADDR_RANGE)) { 55 if (fp < stackBottom || fp >= stackTop - sizeof(uintptr_t)) { 56 break; 57 } 58 if ((++index) >= skipFrameNum) { 59 uintptr_t pc = *reinterpret_cast<uintptr_t*>(fp + sizeof(uintptr_t)); 60 pcs[index - skipFrameNum] = pc > 0x4 ? pc - 0x4 : pc; // adjust pc in Arm64 architecture 61 realSz = static_cast<uint32_t>(index - skipFrameNum + 1); 62 } 63 uintptr_t nextFp = *reinterpret_cast<uintptr_t*>(fp); 64 if (nextFp <= fp) { 65 break; 66 } 67 fp = nextFp; 68 } 69 return realSz; 70} 71 72int32_t FpUnwinder::UnwindFallback(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum) 73{ 74 if (pipe2(g_validPipe, O_CLOEXEC | O_NONBLOCK) != 0) { 75 DFXLOGE("Failed to init pipe, errno(%{public}d)", errno); 76 return 0; 77 } 78 uintptr_t firstFp = pcs[1]; 79 uintptr_t fp = firstFp; 80 int32_t index = 0; 81 int32_t realSz = 0; 82 while ((index < sz - 1) && (fp - firstFp < MAX_UNWIND_ADDR_RANGE)) { 83 uintptr_t addr = fp + sizeof(uintptr_t); 84 if (!ReadUintptrSafe(addr, pcs[++index])) { 85 break; 86 } 87 if ((++index) >= skipFrameNum) { 88 pcs[index - skipFrameNum] = 0; 89 realSz = index - skipFrameNum + 1; 90 } 91 uintptr_t prevFp = fp; 92 if (!ReadUintptrSafe(prevFp, fp)) { 93 break; 94 } 95 if (fp <= prevFp) { 96 break; 97 } 98 } 99 close(g_validPipe[PIPE_WRITE]); 100 close(g_validPipe[PIPE_READ]); 101 return realSz; 102} 103 104NO_SANITIZE bool FpUnwinder::ReadUintptrSafe(uintptr_t addr, uintptr_t& value) 105{ 106 if (OHOS_TEMP_FAILURE_RETRY(syscall(SYS_write, g_validPipe[PIPE_WRITE], addr, sizeof(uintptr_t))) == -1) { 107 DFXLOGE("Failed to write addr to pipe, it is a invalid addr"); 108 return false; 109 } 110 value = *reinterpret_cast<uintptr_t *>(addr); 111 return true; 112} 113} 114} 115