• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 
16 #include "dfx_signal_local_handler.h"
17 
18 #include <securec.h>
19 #include <csignal>
20 #include <sigchain.h>
21 #include <cstdint>
22 #include <cstdio>
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_allocator.h"
32 #include "dfx_crash_local_handler.h"
33 #include "dfx_cutil.h"
34 #include "dfx_log.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 constexpr uint32_t FAULTLOGGERD_UID = 1202;
47 
48 static CrashFdFunc g_crashFdFn = nullptr;
49 static SigAlarmFunc g_sigAlarmCallbackFn = nullptr;
50 #if !defined(__aarch64__) && !defined(__loongarch_lp64)
51 constexpr uint32_t LOCAL_HANDLER_STACK_SIZE = 128 * 1024; // 128K
52 static void *g_reservedChildStack = nullptr;
53 #endif
54 static struct ProcessDumpRequest g_request;
55 static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
56 
57 static constexpr int CATCHER_STACK_SIGNALS[] = {
58     SIGABRT, SIGBUS, SIGILL, SIGSEGV, SIGALRM,
59 };
60 
61 #if !defined(__aarch64__) && !defined(__loongarch_lp64)
ReserveChildThreadSignalStack(void)62 static void ReserveChildThreadSignalStack(void)
63 {
64     // reserve stack for fork
65     g_reservedChildStack = mmap(nullptr, LOCAL_HANDLER_STACK_SIZE, \
66         PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 1, 0);
67     if (g_reservedChildStack == MAP_FAILED) {
68         DFXLOGE("[%{public}d]: Failed to alloc memory for child stack.", __LINE__);
69         return;
70     }
71     g_reservedChildStack = static_cast<void *>(static_cast<uint8_t *>(g_reservedChildStack) +
72         LOCAL_HANDLER_STACK_SIZE - 1);
73 }
74 #endif
75 
FutexWait(volatile void * ftx,int value)76 AT_UNUSED static void FutexWait(volatile void* ftx, int value)
77 {
78     syscall(__NR_futex, ftx, FUTEX_WAIT, value, NULL, NULL, 0);
79 }
80 
DoCrashHandler(void * arg)81 static int DoCrashHandler(void* arg)
82 {
83     int sig = *(static_cast<int *>(arg));
84     RegisterAllocator();
85     DFXLOGI("DoCrashHandler::start handle sig(%d)", sig);
86     if (sig == SIGALRM) {
87         if (g_sigAlarmCallbackFn != nullptr) {
88             g_sigAlarmCallbackFn();
89         }
90     } else {
91         if (g_crashFdFn == nullptr) {
92             CrashLocalHandler(&g_request);
93         } else {
94             int fd = g_crashFdFn(&g_request);
95             CrashLocalHandlerFd(fd, &g_request);
96             if (fd >= 0) {
97                 close(fd);
98             }
99         }
100     }
101     DFXLOGI("DoCrashHandler::finish handle sig(%d)", sig);
102     UnregisterAllocator();
103     pthread_mutex_unlock(&g_signalHandlerMutex);
104     _exit(0);
105     return 0;
106 }
107 
DFX_SignalLocalHandler(int sig,siginfo_t * si,void * context)108 void DFX_SignalLocalHandler(int sig, siginfo_t *si, void *context)
109 {
110     pthread_mutex_lock(&g_signalHandlerMutex);
111     if (sig != SIGALRM) {
112         (void)memset_s(&g_request, sizeof(g_request), 0, sizeof(g_request));
113         g_request.tid = gettid();
114         g_request.pid = getpid();
115         g_request.uid = FAULTLOGGERD_UID;
116         g_request.timeStamp = GetTimeMilliseconds();
117         DFXLOGI("DFX_SignalLocalHandler :: sig(%{public}d), pid(%{public}d), tid(%{public}d).",
118             sig, g_request.pid, g_request.tid);
119 
120         GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
121         GetProcessName(g_request.processName, sizeof(g_request.processName));
122         (void)memcpy_s(&(g_request.siginfo), sizeof(siginfo_t), si, sizeof(siginfo_t));
123         (void)memcpy_s(&(g_request.context), sizeof(ucontext_t), context, sizeof(ucontext_t));
124     }
125 #if defined(__aarch64__) || defined(__loongarch_lp64)
126     DoCrashHandler(&sig);
127 #else
128     int pseudothreadTid = -1;
129     pid_t childTid = clone(DoCrashHandler, g_reservedChildStack, \
130         CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, \
131         &sig, &pseudothreadTid, NULL, NULL, &pseudothreadTid);
132     if (childTid == -1) {
133         DFXLOGE("Failed to create thread for crash local handler");
134         pthread_mutex_unlock(&g_signalHandlerMutex);
135         return;
136     }
137 
138     FutexWait(&pseudothreadTid, -1);
139     FutexWait(&pseudothreadTid, childTid);
140 
141     DFXLOGI("child thread(%{public}d) exit.", childTid);
142     _exit(0);
143 #endif
144 }
145 
DFX_GetCrashFdFunc(CrashFdFunc fn)146 void DFX_GetCrashFdFunc(CrashFdFunc fn)
147 {
148     g_crashFdFn = fn;
149 }
150 
DFX_InstallLocalSignalHandler(void)151 void DFX_InstallLocalSignalHandler(void)
152 {
153 #if !defined(__aarch64__) && !defined(__loongarch_lp64)
154     ReserveChildThreadSignalStack();
155 #endif
156 
157     sigset_t set;
158     sigemptyset(&set);
159     struct sigaction action;
160     (void)memset_s(&action, sizeof(action), 0, sizeof(action));
161     sigfillset(&action.sa_mask);
162     action.sa_sigaction = DFX_SignalLocalHandler;
163     action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
164 
165     for (auto sig : CATCHER_STACK_SIGNALS) {
166         remove_all_special_handler(sig);
167         sigaddset(&set, sig);
168         if (sigaction(sig, &action, nullptr) != 0) {
169             DFXLOGE("Failed to register signal(%{public}d)", sig);
170         }
171     }
172     sigprocmask(SIG_UNBLOCK, &set, nullptr);
173 }
174 
DFX_SetSigAlarmCallBack(SigAlarmFunc func)175 void DFX_SetSigAlarmCallBack(SigAlarmFunc func)
176 {
177     g_sigAlarmCallbackFn = func;
178 }