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 
29 namespace OHOS {
30 namespace HiviewDFX {
31 static int32_t g_validPipe[PIPE_NUM_SZ] = {-1, -1};
32 constexpr uintptr_t MAX_UNWIND_ADDR_RANGE = 16 * 1024;
Unwind(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum)33 int32_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 
UnwindFallback(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum)72 int32_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 
ReadUintptrSafe(uintptr_t addr, uintptr_t& value)104 NO_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