• 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 #define LOCAL_HANDLER_STACK_SIZE (128 * 1024) // 128K
47 
48 static CrashFdFunc g_crashFdFn = nullptr;
49 static void *g_reservedChildStack = nullptr;
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(nullptr, LOCAL_HANDLER_STACK_SIZE, \
61         PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 1, 0);
62     if (g_reservedChildStack == MAP_FAILED) {
63         DFXLOG_ERROR("Failed to alloc memory for child stack.");
64         return;
65     }
66     g_reservedChildStack = static_cast<void *>(static_cast<uint8_t *>(g_reservedChildStack) +
67         LOCAL_HANDLER_STACK_SIZE - 1);
68 }
69 
FutexWait(volatile void * ftx,int value)70 AT_UNUSED static void FutexWait(volatile void* ftx, int value)
71 {
72     syscall(__NR_futex, ftx, FUTEX_WAIT, value, NULL, NULL, 0);
73 }
74 
DoCrashHandler(void * arg)75 static int DoCrashHandler(void* arg)
76 {
77     (void)arg;
78     RegisterAllocator();
79     if (g_crashFdFn == nullptr) {
80         CrashLocalHandler(&g_request);
81     } else {
82         int fd = g_crashFdFn();
83         CrashLocalHandlerFd(fd, &g_request);
84         if (fd >= 0) {
85             close(fd);
86         }
87     }
88     UnregisterAllocator();
89     pthread_mutex_unlock(&g_signalHandlerMutex);
90     syscall(__NR_exit, 0);
91     return 0;
92 }
93 
DFX_SignalLocalHandler(int sig,siginfo_t * si,void * context)94 void DFX_SignalLocalHandler(int sig, siginfo_t *si, void *context)
95 {
96     pthread_mutex_lock(&g_signalHandlerMutex);
97     (void)memset_s(&g_request, sizeof(g_request), 0, sizeof(g_request));
98     g_request.type = static_cast<ProcessDumpType>(sig);
99     g_request.tid = gettid();
100     g_request.pid = getpid();
101     g_request.uid = getuid();
102     g_request.timeStamp = GetTimeMilliseconds();
103     DFXLOG_INFO("DFX_SignalLocalHandler :: sig(%d), pid(%d), tid(%d).", sig, g_request.pid, g_request.tid);
104 
105     GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
106     GetProcessName(g_request.processName, sizeof(g_request.processName));
107 
108     int ret = memcpy_s(&(g_request.siginfo), sizeof(siginfo_t), si, sizeof(siginfo_t));
109     if (ret < 0) {
110         DFXLOG_ERROR("memcpy_s siginfo fail, ret=%d", ret);
111     }
112     ret = memcpy_s(&(g_request.context), sizeof(ucontext_t), context, sizeof(ucontext_t));
113     if (ret < 0) {
114         DFXLOG_ERROR("memcpy_s context fail, ret=%d", ret);
115     }
116 #ifdef __aarch64__
117     DoCrashHandler(NULL);
118 #else
119     int pseudothreadTid = -1;
120     pid_t childTid = clone(DoCrashHandler, g_reservedChildStack, \
121         CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, \
122         &pseudothreadTid, NULL, NULL, &pseudothreadTid);
123     if (childTid == -1) {
124         DFXLOG_ERROR("Failed to create thread for crash local handler");
125         pthread_mutex_unlock(&g_signalHandlerMutex);
126         return;
127     }
128 
129     FutexWait(&pseudothreadTid, -1);
130     FutexWait(&pseudothreadTid, childTid);
131 
132     DFXLOG_INFO("child thread(%d) exit.", childTid);
133     syscall(__NR_exit, 0);
134 #endif
135 }
136 
DFX_GetCrashFdFunc(CrashFdFunc fn)137 void DFX_GetCrashFdFunc(CrashFdFunc fn)
138 {
139     g_crashFdFn = fn;
140 }
141 
DFX_InstallLocalSignalHandler(void)142 void DFX_InstallLocalSignalHandler(void)
143 {
144     ReserveChildThreadSignalStack();
145 
146     sigset_t set;
147     sigemptyset(&set);
148     struct sigaction action;
149     (void)memset_s(&action, sizeof(action), 0, sizeof(action));
150     sigfillset(&action.sa_mask);
151     action.sa_sigaction = DFX_SignalLocalHandler;
152     action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
153 
154     for (size_t i = 0; i < sizeof(g_platformSignals) / sizeof(g_platformSignals[0]); i++) {
155         int32_t sig = g_platformSignals[i];
156         remove_all_special_handler(sig);
157 
158         sigaddset(&set, sig);
159         if (sigaction(sig, &action, nullptr) != 0) {
160             DFXLOG_ERROR("Failed to register signal(%d)", sig);
161         }
162     }
163     sigprocmask(SIG_UNBLOCK, &set, nullptr);
164 }
165