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