• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "dfx_util.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             uintptr_t pc = StripPac(*reinterpret_cast<uintptr_t*>(fp + sizeof(uintptr_t)), 0);
61             pcs[index - skipFrameNum] = pc > 0x4 ? pc - 0x4 : pc; // adjust pc in Arm64 architecture
62             realSz = static_cast<uint32_t>(index - skipFrameNum + 1);
63         }
64         uintptr_t nextFp = *reinterpret_cast<uintptr_t*>(fp);
65         if (nextFp <= fp) {
66             break;
67         }
68         fp = nextFp;
69     }
70     return realSz;
71 }
72 
UnwindFallback(uintptr_t * pcs,int32_t sz,int32_t skipFrameNum)73 int32_t FpUnwinder::UnwindFallback(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum)
74 {
75     if (pipe2(g_validPipe, O_CLOEXEC | O_NONBLOCK) != 0) {
76         DFXLOGE("Failed to init pipe, errno(%{public}d)", errno);
77         return 0;
78     }
79     uintptr_t firstFp = pcs[1];
80     uintptr_t fp = firstFp;
81     int32_t index = 0;
82     int32_t realSz = 0;
83     while ((index < sz - 1) && (fp - firstFp < MAX_UNWIND_ADDR_RANGE)) {
84         uintptr_t addr = fp + sizeof(uintptr_t);
85         if (!ReadUintptrSafe(addr, pcs[++index])) {
86             break;
87         }
88         if ((++index) >= skipFrameNum) {
89             pcs[index - skipFrameNum] = 0;
90             realSz = index - skipFrameNum + 1;
91         }
92         uintptr_t prevFp = fp;
93         if (!ReadUintptrSafe(prevFp, fp)) {
94             break;
95         }
96         if (fp <= prevFp) {
97             break;
98         }
99     }
100     close(g_validPipe[PIPE_WRITE]);
101     close(g_validPipe[PIPE_READ]);
102     return realSz;
103 }
104 
ReadUintptrSafe(uintptr_t addr,uintptr_t & value)105 NO_SANITIZE bool FpUnwinder::ReadUintptrSafe(uintptr_t addr, uintptr_t& value)
106 {
107     if (OHOS_TEMP_FAILURE_RETRY(syscall(SYS_write, g_validPipe[PIPE_WRITE], addr, sizeof(uintptr_t))) == -1) {
108         DFXLOGE("Failed to write addr to pipe, it is a invalid addr");
109         return false;
110     }
111     value = *reinterpret_cast<uintptr_t *>(addr);
112     return true;
113 }
114 }
115 }
116