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