1 /*
2 * Copyright (c) 2021-2023 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
16 #include "dfx_signal_local_handler.h"
17
18 #include <securec.h>
19 #include <signal.h>
20 #include <sigchain.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <pthread.h>
25 #include <sched.h>
26 #include <sys/syscall.h>
27 #include <sys/mman.h>
28 #include <sys/prctl.h>
29 #include <sys/wait.h>
30 #include <linux/futex.h>
31 #include "dfx_crash_local_handler.h"
32 #include "dfx_cutil.h"
33 #include "dfx_log.h"
34 #include "dfx_signal_handler.h"
35
36 #ifdef LOG_DOMAIN
37 #undef LOG_DOMAIN
38 #define LOG_DOMAIN 0xD002D11
39 #endif
40
41 #ifdef LOG_TAG
42 #undef LOG_TAG
43 #define LOG_TAG "DfxSignalLocalHandler"
44 #endif
45
46 #define LOCAL_HANDLER_STACK_SIZE (64 * 1024) // 64K
47
48 static CrashFdFunc g_crashFdFn = NULL;
49 static void *g_reservedChildStack = NULL;
50 static struct ProcessDumpRequest g_request;
51 static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
52
53 static int g_platformSignals[] = {
54 SIGABRT, SIGBUS, SIGILL, SIGSEGV,
55 };
56
ReserveChildThreadSignalStack(void)57 static void ReserveChildThreadSignalStack(void)
58 {
59 // reserve stack for fork
60 g_reservedChildStack = mmap(NULL, LOCAL_HANDLER_STACK_SIZE, \
61 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 1, 0);
62 if (g_reservedChildStack == NULL) {
63 DFXLOG_ERROR("Failed to alloc memory for child stack.");
64 return;
65 }
66 g_reservedChildStack = (void *)(((uint8_t *)g_reservedChildStack) + LOCAL_HANDLER_STACK_SIZE - 1);
67 }
68
FutexWait(volatile void * ftx,int value)69 AT_UNUSED static void FutexWait(volatile void* ftx, int value)
70 {
71 syscall(__NR_futex, ftx, FUTEX_WAIT, value, NULL, NULL, 0);
72 }
73
DoCrashHandler(void * arg)74 static int DoCrashHandler(void* arg)
75 {
76 (void)arg;
77 if (g_crashFdFn == NULL) {
78 CrashLocalHandler(&g_request);
79 } else {
80 int fd = g_crashFdFn();
81 CrashLocalHandlerFd(fd, &g_request);
82 }
83 pthread_mutex_unlock(&g_signalHandlerMutex);
84 syscall(__NR_exit, 0);
85 return 0;
86 }
87
DFX_SignalLocalHandler(int sig,siginfo_t * si,void * context)88 static void DFX_SignalLocalHandler(int sig, siginfo_t * si, void * context)
89 {
90 pthread_mutex_lock(&g_signalHandlerMutex);
91 (void)memset_s(&g_request, sizeof(g_request), 0, sizeof(g_request));
92 g_request.type = sig;
93 g_request.tid = gettid();
94 g_request.pid = getpid();
95 g_request.timeStamp = GetTimeMilliseconds();
96 DFXLOG_INFO("DFX_SignalLocalHandler :: sig(%d), pid(%d), tid(%d).", sig, g_request.pid, g_request.tid);
97
98 GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
99 GetProcessName(g_request.processName, sizeof(g_request.processName));
100
101 int ret = memcpy_s(&(g_request.siginfo), sizeof(siginfo_t), si, sizeof(siginfo_t));
102 if (ret < 0) {
103 DFXLOG_ERROR("memcpy_s siginfo fail, ret=%d", ret);
104 }
105 ret = memcpy_s(&(g_request.context), sizeof(ucontext_t), context, sizeof(ucontext_t));
106 if (ret < 0) {
107 DFXLOG_ERROR("memcpy_s context fail, ret=%d", ret);
108 }
109 #ifdef __aarch64__
110 DoCrashHandler(NULL);
111 #else
112 int pseudothreadTid = -1;
113 pid_t childTid = clone(DoCrashHandler, g_reservedChildStack, \
114 CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, \
115 &pseudothreadTid, NULL, NULL, &pseudothreadTid);
116 if (childTid == -1) {
117 DFXLOG_ERROR("Failed to create thread for crash local handler");
118 pthread_mutex_unlock(&g_signalHandlerMutex);
119 return;
120 }
121
122 FutexWait(&pseudothreadTid, -1);
123 FutexWait(&pseudothreadTid, childTid);
124
125 DFXLOG_INFO("child thread(%d) exit.", childTid);
126 syscall(__NR_exit, 0);
127 #endif
128 }
129
DFX_GetCrashFdFunc(CrashFdFunc fn)130 void DFX_GetCrashFdFunc(CrashFdFunc fn)
131 {
132 g_crashFdFn = fn;
133 }
134
DFX_InstallLocalSignalHandler(void)135 void DFX_InstallLocalSignalHandler(void)
136 {
137 ReserveChildThreadSignalStack();
138
139 sigset_t set;
140 sigemptyset(&set);
141 struct sigaction action;
142 (void)memset_s(&action, sizeof(action), 0, sizeof(action));
143 sigfillset(&action.sa_mask);
144 action.sa_sigaction = DFX_SignalLocalHandler;
145 action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
146
147 for (size_t i = 0; i < sizeof(g_platformSignals) / sizeof(g_platformSignals[0]); i++) {
148 int32_t sig = g_platformSignals[i];
149 remove_all_special_handler(sig);
150
151 sigaddset(&set, sig);
152 if (sigaction(sig, &action, NULL) != 0) {
153 DFXLOG_ERROR("Failed to register signal(%d)", sig);
154 }
155 }
156 sigprocmask(SIG_UNBLOCK, &set, NULL);
157 }
158