• 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 #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