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 static thread_local ThreadInfoCallBack threadInfoCallBack = NULL;
101 enum DumpPreparationStage {
102 CREATE_PIPE_FAIL = 1,
103 SET_PIPE_LEN_FAIL,
104 WRITE_PIPE_FAIL,
105 INHERIT_CAP_FAIL,
106 EXEC_FAIL,
107 };
108
109 TraceInfo HiTraceGetId(void) __attribute__((weak));
FillTraceIdLocked(struct ProcessDumpRequest * request)110 static void FillTraceIdLocked(struct ProcessDumpRequest* request)
111 {
112 if (HiTraceGetId == NULL || request == NULL) {
113 return;
114 }
115
116 TraceInfo id = HiTraceGetId();
117 memcpy(&(request->traceInfo), &id, sizeof(TraceInfo));
118 }
119
120 const char* GetLastFatalMessage(void) __attribute__((weak));
SetThreadInfoCallback(ThreadInfoCallBack func)121 void SetThreadInfoCallback(ThreadInfoCallBack func)
122 {
123 threadInfoCallBack = func;
124 }
FillLastFatalMessageLocked(int32_t sig,void * context)125 static void FillLastFatalMessageLocked(int32_t sig, void *context)
126 {
127 if (sig != SIGABRT && threadInfoCallBack != NULL) {
128 threadInfoCallBack(g_request.lastFatalMessage, sizeof(g_request.lastFatalMessage), context);
129 return;
130 }
131
132 if (GetLastFatalMessage == NULL) {
133 DFXLOG_ERROR("Could not find GetLastFatalMessage func");
134 return;
135 }
136
137 const char* lastFatalMessage = GetLastFatalMessage();
138 if (lastFatalMessage == NULL) {
139 DFXLOG_ERROR("Could not find last message");
140 return;
141 }
142
143 size_t len = strlen(lastFatalMessage);
144 if (len > MAX_FATAL_MSG_SIZE) {
145 DFXLOG_ERROR("Last message is longer than MAX_FATAL_MSG_SIZE");
146 return;
147 }
148
149 (void)strncpy(g_request.lastFatalMessage, lastFatalMessage, sizeof(g_request.lastFatalMessage) - 1);
150 }
151
FillDumpRequest(int sig,siginfo_t * si,void * context)152 static void FillDumpRequest(int sig, siginfo_t *si, void *context)
153 {
154 memset(&g_request, 0, sizeof(g_request));
155 g_request.type = sig;
156 g_request.pid = GetRealPid();
157 g_request.nsPid = syscall(SYS_getpid);
158 g_request.tid = syscall(SYS_gettid);
159 g_request.uid = getuid();
160 g_request.reserved = 0;
161 g_request.timeStamp = GetTimeMilliseconds();
162
163 GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
164 GetProcessName(g_request.processName, sizeof(g_request.processName));
165
166 memcpy(&(g_request.siginfo), si, sizeof(siginfo_t));
167 memcpy(&(g_request.context), context, sizeof(ucontext_t));
168
169 FillTraceIdLocked(&g_request);
170 FillLastFatalMessageLocked(sig, context);
171 }
172
InheritCapabilities(void)173 static int32_t InheritCapabilities(void)
174 {
175 struct __user_cap_header_struct capHeader;
176 memset(&capHeader, 0, sizeof(capHeader));
177
178 capHeader.version = _LINUX_CAPABILITY_VERSION_3;
179 capHeader.pid = 0;
180 struct __user_cap_data_struct capData[2];
181 if (capget(&capHeader, &capData[0]) == -1) {
182 DFXLOG_ERROR("Failed to get origin cap data");
183 return -1;
184 }
185
186 capData[0].inheritable = capData[0].permitted;
187 capData[1].inheritable = capData[1].permitted;
188 if (capset(&capHeader, &capData[0]) == -1) {
189 DFXLOG_ERROR("Failed to set cap data");
190 return -1;
191 }
192
193 uint64_t ambCap = capData[0].inheritable;
194 ambCap = ambCap | (((uint64_t)capData[1].inheritable) << INHERITABLE_OFFSET);
195 for (size_t i = 0; i < NUMBER_SIXTYFOUR; i++) {
196 if (ambCap & ((uint64_t)1)) {
197 (void)prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0);
198 }
199 ambCap = ambCap >> 1;
200 }
201 return 0;
202 }
203
204 static const int SIGCHAIN_SIGNAL_LIST[] = {
205 SIGABRT, SIGBUS, SIGDUMP, SIGFPE,
206 SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP,
207 };
208 static const int SIGACTION_SIGNAL_LIST[] = {
209 SIGILL,
210 };
211
SetInterestedSignalMasks(int how)212 static void SetInterestedSignalMasks(int how)
213 {
214 sigset_t set;
215 sigemptyset(&set);
216 for (size_t i = 0; i < sizeof(SIGCHAIN_SIGNAL_LIST) / sizeof(SIGCHAIN_SIGNAL_LIST[0]); i++) {
217 sigaddset(&set, SIGCHAIN_SIGNAL_LIST[i]);
218 }
219 sigprocmask(how, &set, NULL);
220 }
221
DFX_SetUpEnvironment()222 static void DFX_SetUpEnvironment()
223 {
224 // avoiding fd exhaust
225 const int closeFdCount = 1024;
226 for (int i = 0; i < closeFdCount; i++) {
227 syscall(SYS_close, i);
228 }
229 // clear stdout and stderr
230 int devNull = OHOS_TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
231 if (devNull < 0) {
232 DFXLOG_ERROR("Failed to open dev/null.");
233 return;
234 }
235
236 OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDOUT_FILENO));
237 OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDERR_FILENO));
238 syscall(SYS_close, devNull);
239 SetInterestedSignalMasks(SIG_BLOCK);
240 }
241
DFX_SetUpSigAlarmAction(void)242 static void DFX_SetUpSigAlarmAction(void)
243 {
244 if (signal(SIGALRM, SIG_DFL) == SIG_ERR) {
245 DFXLOG_WARN("Default signal alarm error!");
246 }
247 sigset_t set;
248 sigemptyset(&set);
249 sigaddset(&set, SIGALRM);
250 sigprocmask(SIG_UNBLOCK, &set, NULL);
251 }
252
DFX_ExecDump(void)253 static int DFX_ExecDump(void)
254 {
255 DFX_SetUpEnvironment();
256 DFX_SetUpSigAlarmAction();
257 alarm(ALARM_TIME_S);
258 // create pipe for passing request to processdump
259 if (pipe(g_pipefd) != 0) {
260 DFXLOG_ERROR("Failed to create pipe for transfering context.");
261 return CREATE_PIPE_FAIL;
262 }
263 ssize_t writeLen = (long)(sizeof(struct ProcessDumpRequest));
264 if (fcntl(g_pipefd[1], F_SETPIPE_SZ, writeLen) < writeLen) {
265 DFXLOG_ERROR("Failed to set pipe buffer size.");
266 return SET_PIPE_LEN_FAIL;
267 }
268
269 struct iovec iovs[1] = {
270 {
271 .iov_base = &g_request,
272 .iov_len = sizeof(struct ProcessDumpRequest)
273 },
274 };
275 ssize_t realWriteSize = OHOS_TEMP_FAILURE_RETRY(writev(g_pipefd[1], iovs, 1));
276 if ((ssize_t)writeLen != realWriteSize) {
277 DFXLOG_ERROR("Failed to write pipe.");
278 return WRITE_PIPE_FAIL;
279 }
280 OHOS_TEMP_FAILURE_RETRY(dup2(g_pipefd[0], STDIN_FILENO));
281 if (g_pipefd[0] != STDIN_FILENO) {
282 syscall(SYS_close, g_pipefd[0]);
283 }
284 syscall(SYS_close, g_pipefd[1]);
285
286 if (InheritCapabilities() != 0) {
287 DFXLOG_ERROR("Failed to inherit Capabilities from parent.");
288 return INHERIT_CAP_FAIL;
289 }
290 DFXLOG_INFO("execl processdump.");
291 #ifdef DFX_LOG_USE_HILOG_BASE
292 execl("/system/bin/processdump", "processdump", "-signalhandler", NULL);
293 #else
294 execl("/bin/processdump", "processdump", "-signalhandler", NULL);
295 #endif
296 DFXLOG_ERROR("Failed to execl processdump, errno: %d(%s)", errno, strerror(errno));
297 return errno;
298 }
299
IsMainThread(void)300 static bool IsMainThread(void)
301 {
302 if (syscall(SYS_getpid) == 1) {
303 if (syscall(SYS_gettid) == 1) {
304 return true;
305 }
306 } else {
307 if (syscall(SYS_getpid) == syscall(SYS_gettid)) {
308 return true;
309 }
310 }
311 return false;
312 }
313
ExitIfSandboxPid(int sig)314 static void ExitIfSandboxPid(int sig)
315 {
316 // real init will not handle crash signal,
317 // crash in pid namespace may not exit even if rethrow the signal, use exit instead
318 if (syscall(SYS_getpid) == 1) {
319 DFXLOG_ERROR("Sandbox process is about to exit with signal %d.", sig);
320 _exit(sig);
321 }
322 }
323
ResetAndRethrowSignalIfNeed(int sig,siginfo_t * si)324 static void ResetAndRethrowSignalIfNeed(int sig, siginfo_t *si)
325 {
326 if (sig == SIGDUMP) {
327 return;
328 }
329
330 if (g_oldSigactionList[sig].sa_sigaction == NULL) {
331 signal(sig, SIG_DFL);
332 } else if (sigaction(sig, &(g_oldSigactionList[sig]), NULL) != 0) {
333 DFXLOG_ERROR("Failed to reset sig(%d).", sig);
334 signal(sig, SIG_DFL);
335 }
336
337 if (syscall(SYS_rt_tgsigqueueinfo, syscall(SYS_getpid), syscall(SYS_gettid), sig, si) != 0) {
338 DFXLOG_ERROR("Failed to rethrow sig(%d), errno(%d).", sig, errno);
339 } else {
340 DFXLOG_INFO("Current process(%d) rethrow sig(%d).", syscall(SYS_getpid), sig);
341 }
342 }
343
PauseMainThreadHandler(int sig)344 static void PauseMainThreadHandler(int sig)
345 {
346 DFXLOG_INFO("Crash(%d) in child thread(%d), lock main thread.", sig, syscall(SYS_gettid));
347 // only work when subthread crash and send SIGDUMP to mainthread.
348 pthread_mutex_lock(&g_signalHandlerMutex);
349 pthread_mutex_unlock(&g_signalHandlerMutex);
350 DFXLOG_INFO("Crash in child thread(%d), exit main thread.", syscall(SYS_gettid));
351 }
352
BlockMainThreadIfNeed(int sig)353 static void BlockMainThreadIfNeed(int sig)
354 {
355 if (IsMainThread() || (sig == SIGDUMP)) {
356 return;
357 }
358
359 DFXLOG_INFO("Try block main thread.");
360 (void)signal(SIGQUIT, PauseMainThreadHandler);
361 if (syscall(SYS_tgkill, syscall(SYS_getpid), syscall(SYS_getpid), SIGQUIT) != 0) {
362 DFXLOG_ERROR("Failed to send SIGQUIT to main thread, errno(%d).", errno);
363 }
364 }
365
ForkBySyscall(void)366 static pid_t ForkBySyscall(void)
367 {
368 #ifdef SYS_fork
369 return syscall(SYS_fork);
370 #else
371 return syscall(SYS_clone, SIGCHLD, 0);
372 #endif
373 }
374
SetDumpState(void)375 static bool SetDumpState(void)
376 {
377 if (prctl(PR_SET_DUMPABLE, 1) != 0) {
378 DFXLOG_ERROR("Failed to set dumpable, errno(%d).", errno);
379 return false;
380 }
381
382 if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) != 0) {
383 if (errno != EINVAL) {
384 DFXLOG_ERROR("Failed to set ptracer, errno(%d).", errno);
385 return false;
386 }
387 }
388 return true;
389 }
390
RestoreDumpState(int prevState,bool isTracerStatusModified)391 static void RestoreDumpState(int prevState, bool isTracerStatusModified)
392 {
393 prctl(PR_SET_DUMPABLE, prevState);
394 if (isTracerStatusModified == true) {
395 prctl(PR_SET_PTRACER, 0);
396 }
397 }
398
SetSelfThreadParam(const char * name,int priority)399 static void SetSelfThreadParam(const char* name, int priority)
400 {
401 pthread_setname_np(pthread_self(), name);
402 struct sched_param schedParam;
403 schedParam.sched_priority = priority;
404 pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedParam);
405 }
406
WaitProcessExit(int childPid,const char * name)407 static bool WaitProcessExit(int childPid, const char* name)
408 {
409 int ret = -1;
410 int status = 0;
411 int startTime = (int)time(NULL);
412 bool isSuccess = false;
413 DFXLOG_INFO("(%d) wait %s(%d) exit.", syscall(SYS_gettid), name, childPid);
414 do {
415 errno = 0;
416 ret = waitpid(childPid, &status, WNOHANG);
417 if (ret < 0) {
418 DFXLOG_ERROR("Failed to wait child process terminated, errno(%d)", errno);
419 return isSuccess;
420 }
421
422 if (ret == childPid) {
423 isSuccess = true;
424 break;
425 }
426
427 if ((int)time(NULL) - startTime > PROCESSDUMP_TIMEOUT) {
428 DFXLOG_INFO("(%d) wait for (%d) timeout", syscall(SYS_gettid), childPid);
429 isSuccess = false;
430 break;
431 }
432 usleep(SIGNALHANDLER_TIMEOUT); // sleep 10ms
433 } while (1);
434 DFXLOG_INFO("(%d) wait for (%d) return with ret(%d) status(%d)",
435 syscall(SYS_gettid), childPid, ret, status);
436 return isSuccess;
437 }
438
ForkAndExecProcessDump(void)439 static int ForkAndExecProcessDump(void)
440 {
441 int childPid = -1;
442 SetSelfThreadParam("dump_tmp_thread", 0);
443
444 // set privilege for dump ourself
445 int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
446 bool isTracerStatusModified = SetDumpState();
447 if (!isTracerStatusModified) {
448 goto out;
449 }
450
451 // fork a child process that could ptrace us
452 childPid = ForkBySyscall();
453 if (childPid == 0) {
454 DFXLOG_INFO("The exec processdump pid(%d).", syscall(SYS_getpid));
455 _exit(DFX_ExecDump());
456 } else if (childPid < 0) {
457 DFXLOG_ERROR("Failed to fork child process, errno(%d).", errno);
458 goto out;
459 }
460 WaitProcessExit(childPid, "processdump");
461 out:
462 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
463 pthread_mutex_unlock(&g_signalHandlerMutex);
464 return 0;
465 }
466
CloneAndDoProcessDump(void * arg)467 static int CloneAndDoProcessDump(void* arg)
468 {
469 (void)arg;
470 DFXLOG_INFO("The clone thread(%d).", syscall(SYS_gettid));
471 g_request.recycleTid = syscall(SYS_gettid);
472 return ForkAndExecProcessDump();
473 }
474
ForkAndDoProcessDump(int sig)475 static void ForkAndDoProcessDump(int sig)
476 {
477 int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
478 bool isTracerStatusModified = SetDumpState();
479 int childPid = ForkBySyscall();
480 if (childPid == 0) {
481 g_request.vmNsPid = syscall(SYS_getpid);
482 g_request.vmPid = GetRealPid();
483 DFXLOG_INFO("The vm pid(%d:%d).", g_request.vmPid, g_request.vmNsPid);
484 DFX_SetUpSigAlarmAction();
485 alarm(ALARM_TIME_S);
486 _exit(ForkAndExecProcessDump());
487 } else if (childPid < 0) {
488 DFXLOG_ERROR("Failed to fork child process, errno(%d).", errno);
489 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
490 ForkAndExecProcessDump();
491 return;
492 }
493
494 DFXLOG_INFO("Start wait for VmProcess(%d) exit.", childPid);
495 errno = 0;
496 if (!WaitProcessExit(childPid, "VmProcess") && sig != SIGDUMP) {
497 DFXLOG_INFO("Wait VmProcess(%d) exit timeout in handling critical signal.", childPid);
498 _exit(0);
499 }
500 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
501 pthread_mutex_unlock(&g_signalHandlerMutex);
502 }
503
DFX_SigchainHandler(int sig,siginfo_t * si,void * context)504 static bool DFX_SigchainHandler(int sig, siginfo_t *si, void *context)
505 {
506 int pid = syscall(SYS_getpid);
507 int tid = syscall(SYS_gettid);
508 DFXLOG_INFO("DFX_SigchainHandler :: sig(%d), pid(%d), tid(%d).", sig, pid, tid);
509 bool ret = false;
510 if (sig == SIGDUMP) {
511 if (si->si_code != DUMP_TYPE_NATIVE) {
512 return true;
513 }
514
515 if ((si->si_value.sival_int == 0) && (pid != tid)) {
516 DFXLOG_INFO("DFX_SigchainHandler :: mismatch request(%d), pid(%d), tid(%d).",
517 si->si_value.sival_int, pid, tid);
518 return true;
519 }
520 }
521
522 // crash signal should never be skipped
523 pthread_mutex_lock(&g_signalHandlerMutex);
524 if (g_prevHandledSignal != SIGDUMP) {
525 pthread_mutex_unlock(&g_signalHandlerMutex);
526 ExitIfSandboxPid(sig);
527 return ret;
528 }
529 BlockMainThreadIfNeed(sig);
530 g_prevHandledSignal = sig;
531
532 FillDumpRequest(sig, si, context);
533 DFXLOG_INFO("DFX_SigchainHandler :: sig(%d), pid(%d), processName(%s), threadName(%s).",
534 sig, g_request.pid, g_request.processName, g_request.threadName);
535
536 // for protecting g_reservedChildStack
537 // g_signalHandlerMutex will be unlocked in ForkAndExecProcessDump function
538 if (sig != SIGDUMP) {
539 ForkAndDoProcessDump(sig);
540 ExitIfSandboxPid(sig);
541 } else {
542 ret = true;
543 int recycleTid = clone(CloneAndDoProcessDump, g_reservedChildStack,\
544 CLONE_THREAD | CLONE_SIGHAND | CLONE_VM, NULL);
545 if (recycleTid == -1) {
546 DFXLOG_ERROR("Failed to clone thread for recycle dump process, errno(%d)", errno);
547 pthread_mutex_unlock(&g_signalHandlerMutex);
548 }
549 }
550
551 DFXLOG_INFO("Finish handle signal(%d) in %d:%d", sig, g_request.pid, g_request.tid);
552 return ret;
553 }
554
DFX_SignalHandler(int sig,siginfo_t * si,void * context)555 static void DFX_SignalHandler(int sig, siginfo_t *si, void *context)
556 {
557 DFX_SigchainHandler(sig, si, context);
558 ResetAndRethrowSignalIfNeed(sig, si);
559 }
560
DFX_InstallSignalHandler(void)561 void DFX_InstallSignalHandler(void)
562 {
563 if (g_hasInit) {
564 return;
565 }
566
567 // reserve stack for fork
568 g_reservedChildStack = mmap(NULL, RESERVED_CHILD_STACK_SIZE, \
569 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 1, 0);
570 if (g_reservedChildStack == NULL) {
571 DFXLOG_ERROR("Failed to alloc memory for child stack.");
572 return;
573 }
574 g_reservedChildStack = (void *)(((uint8_t *)g_reservedChildStack) + RESERVED_CHILD_STACK_SIZE - 1);
575
576 struct signal_chain_action sigchain = {
577 .sca_sigaction = DFX_SigchainHandler,
578 .sca_mask = {},
579 .sca_flags = 0,
580 };
581 sigfillset(&sigchain.sca_mask);
582 for (size_t i = 0; i < sizeof(SIGCHAIN_SIGNAL_LIST) / sizeof(SIGCHAIN_SIGNAL_LIST[0]); i++) {
583 int32_t sig = SIGCHAIN_SIGNAL_LIST[i];
584 add_special_handler_at_last(sig, &sigchain);
585 }
586
587 struct sigaction action;
588 memset(&action, 0, sizeof(action));
589 memset(&g_oldSigactionList, 0, sizeof(g_oldSigactionList));
590 sigfillset(&action.sa_mask);
591 action.sa_sigaction = DFX_SignalHandler;
592 action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
593 for (size_t i = 0; i < sizeof(SIGACTION_SIGNAL_LIST) / sizeof(SIGACTION_SIGNAL_LIST[0]); i++) {
594 int32_t sig = SIGACTION_SIGNAL_LIST[i];
595 if (sigaction(sig, &action, &(g_oldSigactionList[sig])) != 0) {
596 DFXLOG_ERROR("Failed to register signal(%d)", sig);
597 }
598 }
599
600 g_hasInit = TRUE;
601 }
602