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