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 <fstream>
26 #include <pthread.h>
27 #include "dfx_log.h"
28 #include "stack_util.h"
29 
30 namespace OHOS {
31 namespace HiviewDFX {
32 static int32_t g_validPipe[PIPE_NUM_SZ] = {-1, -1};
33 constexpr uintptr_t MAX_UNWIND_ADDR_RANGE = 16 * 1024;
Unwind(uintptr_t * pcs,int32_t sz,int32_t skipFrameNum)34 int32_t FpUnwinder::Unwind(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum)
35 {
36     GetFpPcRegs(pcs);
37     int32_t index = 0;
38     uintptr_t firstFp = pcs[1];
39     uintptr_t fp = firstFp;
40     uintptr_t stackPtr = reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
41     uintptr_t stackBottom = 0;
42     uintptr_t stackTop = 0;
43     uint32_t realSz = 0;
44     if (getpid() == gettid()) {
45         GetMainStackRange(stackBottom, stackTop);
46     } else {
47         GetSelfStackRange(stackBottom, stackTop);
48         if (!(stackPtr >= stackBottom && stackPtr < stackTop)) {
49             GetSigAltStackRange(stackBottom, stackTop);
50             if (stackPtr < stackBottom || stackPtr >= stackTop) {
51                 return realSz;
52             }
53         }
54     }
55     while ((index < sz - 1) && (fp - firstFp < MAX_UNWIND_ADDR_RANGE)) {
56         if (fp < stackBottom || fp >= stackTop - sizeof(uintptr_t)) {
57             break;
58         }
59         if ((++index) >= skipFrameNum) {
60             pcs[index - skipFrameNum] = *reinterpret_cast<uintptr_t*>(fp + sizeof(uintptr_t));
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         LOGE("Failed to init pipe, errno(%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         LOGE("%s", "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