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 #include "dfx_signal_handler.h"
16
17 #ifndef _GNU_SOURCE
18 #define _GNU_SOURCE 1
19 #endif
20
21 #include <fcntl.h>
22 #include <pthread.h>
23 #include <sched.h>
24 #include <signal.h>
25 #include <sigchain.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <sys/capability.h>
29 #include <sys/mman.h>
30 #include <sys/prctl.h>
31 #include <sys/syscall.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/uio.h>
35 #include <sys/wait.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include "dfx_define.h"
39 #include "dfx_dump_request.h"
40 #include "errno.h"
41 #include "linux/capability.h"
42 #include "stdbool.h"
43 #include "string.h"
44 #ifndef DFX_SIGNAL_LIBC
45 #include <securec.h>
46 #include "dfx_cutil.h"
47 #include "dfx_log.h"
48 #else
49 #include "musl_cutil.h"
50 #include "musl_log.h"
51 #endif
52
53 #ifdef LOG_DOMAIN
54 #undef LOG_DOMAIN
55 #define LOG_DOMAIN 0xD002D11
56 #endif
57
58 #ifdef LOG_TAG
59 #undef LOG_TAG
60 #define LOG_TAG "DfxSignalHandler"
61 #endif
62
63 #if defined (__LP64__)
64 #define RESERVED_CHILD_STACK_SIZE (32 * 1024) // 32K
65 #else
66 #define RESERVED_CHILD_STACK_SIZE (16 * 1024) // 16K
67 #endif
68
69 #define BOOL int
70 #define TRUE 1
71 #define FALSE 0
72
73 #ifndef NSIG
74 #define NSIG 64
75 #endif
76
77 #ifndef F_SETPIPE_SZ
78 #define F_SETPIPE_SZ 1031
79 #endif
80
81 #define NUMBER_SIXTYFOUR 64
82 #define INHERITABLE_OFFSET 32
83
84 #ifndef __MUSL__
InitHandler(void)85 void __attribute__((constructor)) InitHandler(void)
86 {
87 DFX_InstallSignalHandler();
88 }
89 #endif
90
91 static struct ProcessDumpRequest g_request;
92 static void *g_reservedChildStack = NULL;
93 static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
94 static int g_pipefd[2] = {-1, -1};
95 static BOOL g_hasInit = FALSE;
96 static const int SIGNALHANDLER_TIMEOUT = 10000; // 10000 us
97 static const int ALARM_TIME_S = 10;
98 static int g_prevHandledSignal = SIGDUMP;
99 static struct sigaction g_oldSigactionList[NSIG] = {};
100 enum DumpPreparationStage {
101 CREATE_PIPE_FAIL = 1,
102 SET_PIPE_LEN_FAIL,
103 WRITE_PIPE_FAIL,
104 INHERIT_CAP_FAIL,
105 EXEC_FAIL,
106 };
107
108 TraceInfo HiTraceGetId(void) __attribute__((weak));
FillTraceIdLocked(struct ProcessDumpRequest * request)109 static void FillTraceIdLocked(struct ProcessDumpRequest* request)
110 {
111 if (HiTraceGetId == NULL || request == NULL) {
112 return;
113 }
114
115 TraceInfo id = HiTraceGetId();
116 memcpy(&(request->traceInfo), &id, sizeof(TraceInfo));
117 }
118
119 const char* GetLastFatalMessage(void) __attribute__((weak));
120
121 typedef struct ThreadCallbackItem {
122 int32_t tid;
123 ThreadInfoCallBack callback;
124 } ThreadCallbackItem;
125
126 #define CALLBACK_ITEM_COUNT 32
127 static ThreadCallbackItem g_callbackItems[CALLBACK_ITEM_COUNT];
InitCallbackItems(void)128 static void InitCallbackItems(void)
129 {
130 for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
131 g_callbackItems[i].tid = -1;
132 g_callbackItems[i].callback = NULL;
133 }
134 }
135
136 // caller should set to NULL before exit thread
SetThreadInfoCallback(ThreadInfoCallBack func)137 void SetThreadInfoCallback(ThreadInfoCallBack func)
138 {
139 int32_t currentTid = syscall(SYS_gettid);
140 int32_t firstEmptySlot = -1;
141 int32_t currentThreadSlot = -1;
142 pthread_mutex_lock(&g_signalHandlerMutex);
143 for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
144 if (firstEmptySlot == -1 && g_callbackItems[i].tid == -1) {
145 firstEmptySlot = i;
146 }
147
148 if (g_callbackItems[i].tid == currentTid) {
149 currentThreadSlot = i;
150 break;
151 }
152 }
153
154 int32_t targetSlot = currentThreadSlot == -1 ? firstEmptySlot : currentThreadSlot;
155 if (targetSlot != -1) {
156 g_callbackItems[targetSlot].tid = func == NULL ? -1 : currentTid;
157 g_callbackItems[targetSlot].callback = func;
158 }
159 pthread_mutex_unlock(&g_signalHandlerMutex);
160 }
161
GetCallbackLocked()162 static ThreadInfoCallBack GetCallbackLocked()
163 {
164 int32_t currentTid = syscall(SYS_gettid);
165 for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
166 if (g_callbackItems[i].tid != currentTid) {
167 continue;
168 }
169
170 return g_callbackItems[i].callback;
171 }
172 return NULL;
173 }
174
FillLastFatalMessageLocked(int32_t sig,void * context)175 static void FillLastFatalMessageLocked(int32_t sig, void *context)
176 {
177 ThreadInfoCallBack callback = GetCallbackLocked();
178 if (sig != SIGABRT) {
179 if (callback != NULL) {
180 DFXLOG_INFO("Start collect crash thread info.");
181 callback(g_request.lastFatalMessage, sizeof(g_request.lastFatalMessage), context);
182 DFXLOG_INFO("Finish collect crash thread info.");
183 }
184 return;
185 }
186
187 if (GetLastFatalMessage == NULL) {
188 DFXLOG_INFO("Could not find GetLastFatalMessage func");
189 return;
190 }
191
192 const char* lastFatalMessage = GetLastFatalMessage();
193 if (lastFatalMessage == NULL) {
194 DFXLOG_ERROR("Could not find last message");
195 return;
196 }
197
198 size_t len = strlen(lastFatalMessage);
199 if (len > MAX_FATAL_MSG_SIZE) {
200 DFXLOG_ERROR("Last message is longer than MAX_FATAL_MSG_SIZE");
201 return;
202 }
203
204 (void)strncpy(g_request.lastFatalMessage, lastFatalMessage, sizeof(g_request.lastFatalMessage) - 1);
205 }
206
FillDumpRequest(int sig,siginfo_t * si,void * context)207 static void FillDumpRequest(int sig, siginfo_t *si, void *context)
208 {
209 memset(&g_request, 0, sizeof(g_request));
210 g_request.type = sig;
211 g_request.pid = GetRealPid();
212 g_request.nsPid = syscall(SYS_getpid);
213 g_request.tid = syscall(SYS_gettid);
214 g_request.uid = getuid();
215 g_request.reserved = 0;
216 g_request.timeStamp = GetTimeMilliseconds();
217
218 GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
219 GetProcessName(g_request.processName, sizeof(g_request.processName));
220
221 memcpy(&(g_request.siginfo), si, sizeof(siginfo_t));
222 memcpy(&(g_request.context), context, sizeof(ucontext_t));
223
224 FillTraceIdLocked(&g_request);
225 FillLastFatalMessageLocked(sig, context);
226 }
227
InheritCapabilities(void)228 static int32_t InheritCapabilities(void)
229 {
230 struct __user_cap_header_struct capHeader;
231 memset(&capHeader, 0, sizeof(capHeader));
232
233 capHeader.version = _LINUX_CAPABILITY_VERSION_3;
234 capHeader.pid = 0;
235 struct __user_cap_data_struct capData[2];
236 if (capget(&capHeader, &capData[0]) == -1) {
237 DFXLOG_ERROR("Failed to get origin cap data");
238 return -1;
239 }
240
241 capData[0].inheritable = capData[0].permitted;
242 capData[1].inheritable = capData[1].permitted;
243 if (capset(&capHeader, &capData[0]) == -1) {
244 DFXLOG_ERROR("Failed to set cap data");
245 return -1;
246 }
247
248 uint64_t ambCap = capData[0].inheritable;
249 ambCap = ambCap | (((uint64_t)capData[1].inheritable) << INHERITABLE_OFFSET);
250 for (size_t i = 0; i < NUMBER_SIXTYFOUR; i++) {
251 if (ambCap & ((uint64_t)1)) {
252 (void)prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0);
253 }
254 ambCap = ambCap >> 1;
255 }
256 return 0;
257 }
258
IsDumpSignal(int sig)259 static bool IsDumpSignal(int sig)
260 {
261 return sig == SIGDUMP || sig == SIGLEAK_STACK;
262 }
263
264 static const int SIGCHAIN_DUMP_SIGNAL_LIST[] = {
265 SIGDUMP, SIGLEAK_STACK
266 };
267
268 static const int SIGCHAIN_CRASH_SIGNAL_LIST[] = {
269 SIGILL, SIGABRT, SIGBUS, SIGFPE,
270 SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
271 };
272
SetInterestedSignalMasks(int how)273 static void SetInterestedSignalMasks(int how)
274 {
275 sigset_t set;
276 sigemptyset(&set);
277 for (size_t i = 0; i < sizeof(SIGCHAIN_DUMP_SIGNAL_LIST) / sizeof(SIGCHAIN_DUMP_SIGNAL_LIST[0]); i++) {
278 sigaddset(&set, SIGCHAIN_DUMP_SIGNAL_LIST[i]);
279 }
280 for (size_t i = 0; i < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); i++) {
281 sigaddset(&set, SIGCHAIN_CRASH_SIGNAL_LIST[i]);
282 }
283 sigprocmask(how, &set, NULL);
284 }
285
CloseFds()286 static void CloseFds()
287 {
288 const int closeFdCount = 1024;
289 for (int i = 0; i < closeFdCount; i++) {
290 syscall(SYS_close, i);
291 }
292 }
293
DFX_SetUpEnvironment()294 static void DFX_SetUpEnvironment()
295 {
296 // clear stdout and stderr
297 int devNull = OHOS_TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
298 if (devNull < 0) {
299 DFXLOG_ERROR("Failed to open dev/null.");
300 return;
301 }
302
303 OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDOUT_FILENO));
304 OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDERR_FILENO));
305 syscall(SYS_close, devNull);
306 SetInterestedSignalMasks(SIG_BLOCK);
307 }
308
DFX_SetUpSigAlarmAction(void)309 static void DFX_SetUpSigAlarmAction(void)
310 {
311 if (signal(SIGALRM, SIG_DFL) == SIG_ERR) {
312 DFXLOG_WARN("Default signal alarm error!");
313 }
314 sigset_t set;
315 sigemptyset(&set);
316 sigaddset(&set, SIGALRM);
317 sigprocmask(SIG_UNBLOCK, &set, NULL);
318 }
319
DFX_ExecDump(void)320 static int DFX_ExecDump(void)
321 {
322 DFX_SetUpEnvironment();
323 DFX_SetUpSigAlarmAction();
324 alarm(ALARM_TIME_S);
325 // create pipe for passing request to processdump
326 if (pipe(g_pipefd) != 0) {
327 DFXLOG_ERROR("Failed to create pipe for transfering context.");
328 return CREATE_PIPE_FAIL;
329 }
330 ssize_t writeLen = (long)(sizeof(struct ProcessDumpRequest));
331 if (fcntl(g_pipefd[1], F_SETPIPE_SZ, writeLen) < writeLen) {
332 DFXLOG_ERROR("Failed to set pipe buffer size.");
333 return SET_PIPE_LEN_FAIL;
334 }
335
336 struct iovec iovs[1] = {
337 {
338 .iov_base = &g_request,
339 .iov_len = sizeof(struct ProcessDumpRequest)
340 },
341 };
342 ssize_t realWriteSize = OHOS_TEMP_FAILURE_RETRY(writev(g_pipefd[1], iovs, 1));
343 if ((ssize_t)writeLen != realWriteSize) {
344 DFXLOG_ERROR("Failed to write pipe.");
345 return WRITE_PIPE_FAIL;
346 }
347 OHOS_TEMP_FAILURE_RETRY(dup2(g_pipefd[0], STDIN_FILENO));
348 if (g_pipefd[0] != STDIN_FILENO) {
349 syscall(SYS_close, g_pipefd[0]);
350 }
351 syscall(SYS_close, g_pipefd[1]);
352
353 if (InheritCapabilities() != 0) {
354 DFXLOG_ERROR("Failed to inherit Capabilities from parent.");
355 return INHERIT_CAP_FAIL;
356 }
357 DFXLOG_INFO("execl processdump.");
358 #ifdef DFX_LOG_HILOG_BASE
359 execl("/system/bin/processdump", "processdump", "-signalhandler", NULL);
360 #else
361 execl("/bin/processdump", "processdump", "-signalhandler", NULL);
362 #endif
363 DFXLOG_ERROR("Failed to execl processdump, errno: %d(%s)", errno, strerror(errno));
364 return errno;
365 }
366
IsMainThread(void)367 static bool IsMainThread(void)
368 {
369 if (syscall(SYS_getpid) == 1) {
370 if (syscall(SYS_gettid) == 1) {
371 return true;
372 }
373 } else {
374 if (syscall(SYS_getpid) == syscall(SYS_gettid)) {
375 return true;
376 }
377 }
378 return false;
379 }
380
ResetAndRethrowSignalIfNeed(int sig,siginfo_t * si)381 static void ResetAndRethrowSignalIfNeed(int sig, siginfo_t *si)
382 {
383 if (IsDumpSignal(sig)) {
384 return;
385 }
386
387 if (g_oldSigactionList[sig].sa_sigaction == NULL) {
388 signal(sig, SIG_DFL);
389 } else if (sigaction(sig, &(g_oldSigactionList[sig]), NULL) != 0) {
390 DFXLOG_ERROR("Failed to reset sig(%d).", sig);
391 signal(sig, SIG_DFL);
392 }
393
394 if (syscall(SYS_rt_tgsigqueueinfo, syscall(SYS_getpid), syscall(SYS_gettid), sig, si) != 0) {
395 DFXLOG_ERROR("Failed to rethrow sig(%d), errno(%d).", sig, errno);
396 } else {
397 DFXLOG_INFO("Current process(%ld) rethrow sig(%d).", syscall(SYS_getpid), sig);
398 }
399 }
400
PauseMainThreadHandler(int sig)401 static void PauseMainThreadHandler(int sig)
402 {
403 DFXLOG_INFO("Crash(%d) in child thread(%ld), lock main thread.", sig, syscall(SYS_gettid));
404 // only work when subthread crash and send SIGDUMP to mainthread.
405 pthread_mutex_lock(&g_signalHandlerMutex);
406 pthread_mutex_unlock(&g_signalHandlerMutex);
407 DFXLOG_INFO("Crash in child thread(%ld), exit main thread.", syscall(SYS_gettid));
408 }
409
BlockMainThreadIfNeed(int sig)410 static void BlockMainThreadIfNeed(int sig)
411 {
412 if (IsMainThread() || IsDumpSignal(sig)) {
413 return;
414 }
415
416 DFXLOG_INFO("Try block main thread.");
417 (void)signal(SIGQUIT, PauseMainThreadHandler);
418 if (syscall(SYS_tgkill, syscall(SYS_getpid), syscall(SYS_getpid), SIGQUIT) != 0) {
419 DFXLOG_ERROR("Failed to send SIGQUIT to main thread, errno(%d).", errno);
420 }
421 }
422
ForkBySyscall(void)423 static pid_t ForkBySyscall(void)
424 {
425 #ifdef SYS_fork
426 return syscall(SYS_fork);
427 #else
428 return syscall(SYS_clone, SIGCHLD, 0);
429 #endif
430 }
431
SetDumpState(void)432 static bool SetDumpState(void)
433 {
434 if (prctl(PR_SET_DUMPABLE, 1) != 0) {
435 DFXLOG_ERROR("Failed to set dumpable, errno(%d).", errno);
436 return false;
437 }
438
439 if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) != 0) {
440 if (errno != EINVAL) {
441 DFXLOG_ERROR("Failed to set ptracer, errno(%d).", errno);
442 return false;
443 }
444 }
445 return true;
446 }
447
RestoreDumpState(int prevState,bool isTracerStatusModified)448 static void RestoreDumpState(int prevState, bool isTracerStatusModified)
449 {
450 prctl(PR_SET_DUMPABLE, prevState);
451 if (isTracerStatusModified == true) {
452 prctl(PR_SET_PTRACER, 0);
453 }
454 }
455
SetSelfThreadParam(const char * name,int priority)456 static void SetSelfThreadParam(const char* name, int priority)
457 {
458 pthread_setname_np(pthread_self(), name);
459 struct sched_param schedParam;
460 schedParam.sched_priority = priority;
461 pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedParam);
462 }
463
WaitProcessExit(int childPid,const char * name)464 static bool WaitProcessExit(int childPid, const char* name)
465 {
466 int ret = -1;
467 int status = 0;
468 int startTime = (int)time(NULL);
469 bool isSuccess = false;
470 DFXLOG_INFO("(%ld) wait %s(%d) exit.", syscall(SYS_gettid), name, childPid);
471 do {
472 errno = 0;
473 ret = waitpid(childPid, &status, WNOHANG);
474 if (ret < 0) {
475 DFXLOG_ERROR("Failed to wait child process terminated, errno(%d)", errno);
476 return isSuccess;
477 }
478
479 if (ret == childPid) {
480 isSuccess = true;
481 break;
482 }
483
484 if ((int)time(NULL) - startTime > PROCESSDUMP_TIMEOUT) {
485 DFXLOG_INFO("(%ld) wait for (%d) timeout", syscall(SYS_gettid), childPid);
486 isSuccess = false;
487 break;
488 }
489 usleep(SIGNALHANDLER_TIMEOUT); // sleep 10ms
490 } while (1);
491 DFXLOG_INFO("(%ld) wait for (%d) return with ret(%d) status(%d)",
492 syscall(SYS_gettid), childPid, ret, status);
493 return isSuccess;
494 }
495
ForkAndExecProcessDump(void)496 static int ForkAndExecProcessDump(void)
497 {
498 int childPid = -1;
499 SetSelfThreadParam("dump_tmp_thread", 0);
500
501 // set privilege for dump ourself
502 int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
503 bool isTracerStatusModified = SetDumpState();
504 if (!isTracerStatusModified) {
505 goto out;
506 }
507
508 // fork a child process that could ptrace us
509 childPid = ForkBySyscall();
510 if (childPid == 0) {
511 DFXLOG_INFO("The exec processdump pid(%ld).", syscall(SYS_getpid));
512 _exit(DFX_ExecDump());
513 } else if (childPid < 0) {
514 DFXLOG_ERROR("Failed to fork child process, errno(%d).", errno);
515 goto out;
516 }
517 WaitProcessExit(childPid, "processdump");
518 out:
519 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
520 pthread_mutex_unlock(&g_signalHandlerMutex);
521 return 0;
522 }
523
CloneAndDoProcessDump(void * arg)524 static int CloneAndDoProcessDump(void* arg)
525 {
526 (void)arg;
527 DFXLOG_INFO("The clone thread(%ld).", syscall(SYS_gettid));
528 g_request.recycleTid = syscall(SYS_gettid);
529 return ForkAndExecProcessDump();
530 }
531
ForkAndDoProcessDump(int sig)532 static void ForkAndDoProcessDump(int sig)
533 {
534 int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
535 bool isTracerStatusModified = SetDumpState();
536 int childPid = ForkBySyscall();
537 if (childPid == 0) {
538 CloseFds();
539 g_request.vmNsPid = syscall(SYS_getpid);
540 g_request.vmPid = GetRealPid();
541 DFXLOG_INFO("The vm pid(%d:%d).", g_request.vmPid, g_request.vmNsPid);
542 DFX_SetUpSigAlarmAction();
543 alarm(ALARM_TIME_S);
544 _exit(ForkAndExecProcessDump());
545 } else if (childPid < 0) {
546 DFXLOG_ERROR("Failed to fork child process, errno(%d).", errno);
547 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
548 ForkAndExecProcessDump();
549 return;
550 }
551
552 DFXLOG_INFO("Start wait for VmProcess(%d) exit.", childPid);
553 errno = 0;
554 if (!WaitProcessExit(childPid, "VmProcess") &&
555 sig != SIGDUMP &&
556 sig != SIGLEAK_STACK) {
557 DFXLOG_INFO("Wait VmProcess(%d) exit timeout in handling critical signal.", childPid);
558 // do not left vm process
559 kill(childPid, SIGKILL);
560 }
561
562 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
563 pthread_mutex_unlock(&g_signalHandlerMutex);
564 }
565
DFX_SigchainHandler(int sig,siginfo_t * si,void * context)566 static bool DFX_SigchainHandler(int sig, siginfo_t *si, void *context)
567 {
568 int pid = syscall(SYS_getpid);
569 int tid = syscall(SYS_gettid);
570 DFXLOG_INFO("DFX_SigchainHandler :: sig(%d), pid(%d), tid(%d).", sig, pid, tid);
571 bool ret = false;
572 if (sig == SIGDUMP) {
573 if (si->si_code != DUMP_TYPE_NATIVE) {
574 return true;
575 }
576
577 if ((si->si_value.sival_int == 0) && (pid != tid)) {
578 DFXLOG_INFO("DFX_SigchainHandler :: mismatch request(%d), pid(%d), tid(%d).",
579 si->si_value.sival_int, pid, tid);
580 return true;
581 }
582 }
583
584 // crash signal should never be skipped
585 pthread_mutex_lock(&g_signalHandlerMutex);
586 if (!IsDumpSignal(g_prevHandledSignal)) {
587 pthread_mutex_unlock(&g_signalHandlerMutex);
588 return ret;
589 }
590 BlockMainThreadIfNeed(sig);
591 g_prevHandledSignal = sig;
592
593 FillDumpRequest(sig, si, context);
594 DFXLOG_INFO("DFX_SigchainHandler :: sig(%d), pid(%d), processName(%s), threadName(%s).",
595 sig, g_request.pid, g_request.processName, g_request.threadName);
596
597 // for protecting g_reservedChildStack
598 // g_signalHandlerMutex will be unlocked in ForkAndExecProcessDump function
599 if (sig != SIGDUMP) {
600 ret = sig == SIGLEAK_STACK ? true : false;
601 ForkAndDoProcessDump(sig);
602 } else {
603 ret = true;
604 int recycleTid = clone(CloneAndDoProcessDump, g_reservedChildStack,\
605 CLONE_THREAD | CLONE_SIGHAND | CLONE_VM, NULL);
606 if (recycleTid == -1) {
607 DFXLOG_ERROR("Failed to clone thread for recycle dump process, errno(%d)", errno);
608 pthread_mutex_unlock(&g_signalHandlerMutex);
609 }
610 }
611
612 DFXLOG_INFO("Finish handle signal(%d) in %d:%d", sig, g_request.pid, g_request.tid);
613 return ret;
614 }
615
DFX_SignalHandler(int sig,siginfo_t * si,void * context)616 static void DFX_SignalHandler(int sig, siginfo_t *si, void *context)
617 {
618 DFX_SigchainHandler(sig, si, context);
619 ResetAndRethrowSignalIfNeed(sig, si);
620 }
621
InstallSigActionHandler(int sig)622 static void InstallSigActionHandler(int sig)
623 {
624 struct sigaction action;
625 memset(&action, 0, sizeof(action));
626 memset(&g_oldSigactionList, 0, sizeof(g_oldSigactionList));
627 sigfillset(&action.sa_mask);
628 action.sa_sigaction = DFX_SignalHandler;
629 action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
630 if (sigaction(sig, &action, &(g_oldSigactionList[sig])) != 0) {
631 DFXLOG_ERROR("Failed to register signal(%d)", sig);
632 }
633 }
634
DFX_InstallSignalHandler(void)635 void DFX_InstallSignalHandler(void)
636 {
637 if (g_hasInit) {
638 return;
639 }
640
641 InitCallbackItems();
642 // reserve stack for fork
643 g_reservedChildStack = mmap(NULL, RESERVED_CHILD_STACK_SIZE, \
644 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 1, 0);
645 if (g_reservedChildStack == NULL) {
646 DFXLOG_ERROR("Failed to alloc memory for child stack.");
647 return;
648 }
649 g_reservedChildStack = (void *)(((uint8_t *)g_reservedChildStack) + RESERVED_CHILD_STACK_SIZE - 1);
650
651 struct signal_chain_action sigchain = {
652 .sca_sigaction = DFX_SigchainHandler,
653 .sca_mask = {},
654 .sca_flags = 0,
655 };
656
657 for (size_t i = 0; i < sizeof(SIGCHAIN_DUMP_SIGNAL_LIST) / sizeof(SIGCHAIN_DUMP_SIGNAL_LIST[0]); i++) {
658 int32_t sig = SIGCHAIN_DUMP_SIGNAL_LIST[i];
659 sigfillset(&sigchain.sca_mask);
660 // dump signal not mask crash signal
661 for (size_t j = 0; j < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); j++) {
662 sigdelset(&sigchain.sca_mask, SIGCHAIN_CRASH_SIGNAL_LIST[i]);
663 }
664 add_special_handler_at_last(sig, &sigchain);
665 }
666 for (size_t i = 0; i < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); i++) {
667 int32_t sig = SIGCHAIN_CRASH_SIGNAL_LIST[i];
668 if (sig == SIGILL) {
669 InstallSigActionHandler(sig);
670 } else {
671 sigfillset(&sigchain.sca_mask);
672 add_special_handler_at_last(sig, &sigchain);
673 }
674 }
675
676 g_hasInit = TRUE;
677 }
678