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