1 /*
2  * Copyright (c) 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 #ifndef _GNU_SOURCE
16 #define _GNU_SOURCE 1
17 #endif
18 
19 #include "dfx_dumprequest.h"
20 
21 #include <fcntl.h>
22 #include <poll.h>
23 #include <pthread.h>
24 #include <sched.h>
25 #include <signal.h>
26 #include <sigchain.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <sys/capability.h>
30 #include <sys/mman.h>
31 #include <sys/prctl.h>
32 #include <sys/syscall.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <sys/uio.h>
36 #include <sys/wait.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include "dfx_define.h"
40 #include "dfx_dump_request.h"
41 #include "dfx_signalhandler_exception.h"
42 #include "errno.h"
43 #include "linux/capability.h"
44 #include "stdbool.h"
45 #include "string.h"
46 #ifndef DFX_SIGNAL_LIBC
47 #include <securec.h>
48 #include "dfx_cutil.h"
49 #include "dfx_log.h"
50 #else
51 #include "musl_cutil.h"
52 #include "musl_log.h"
53 #endif
54 
55 #include "info/fatal_message.h"
56 
57 #ifdef LOG_DOMAIN
58 #undef LOG_DOMAIN
59 #define LOG_DOMAIN 0xD002D11
60 #endif
61 
62 #ifdef LOG_TAG
63 #undef LOG_TAG
64 #define LOG_TAG "DfxSignalHandler"
65 #endif
66 
67 #ifndef F_SETPIPE_SZ
68 #define F_SETPIPE_SZ 1031
69 #endif
70 
71 #define NUMBER_SIXTYFOUR 64
72 #define INHERITABLE_OFFSET 32
73 
74 static struct ProcessDumpRequest *g_request = NULL;
75 static void *g_reservedChildStack = NULL;
76 
77 enum PIPE_FD_TYPE {
78     WRITE_TO_DUMP,
79     READ_FROM_DUMP_TO_MAIN,
80     READ_FORM_DUMP_TO_VIRTUAL,
81     PIPE_MAX,
82 };
83 
84 static int g_pipeFds[PIPE_MAX][2] = {
85     {-1, -1},
86     {-1, -1},
87     {-1, -1}
88 };
89 
90 static const int SIGNALHANDLER_TIMEOUT = 10000; // 10000 us
91 static const int ALARM_TIME_S = 10;
92 enum DumpPreparationStage {
93     CREATE_PIPE_FAIL = 1,
94     SET_PIPE_LEN_FAIL,
95     WRITE_PIPE_FAIL,
96     INHERIT_CAP_FAIL,
97     EXEC_FAIL,
98 };
99 
GetCrashDescription(const int32_t errCode)100 static const char* GetCrashDescription(const int32_t errCode)
101 {
102     size_t i;
103 
104     for (i = 0; i < sizeof(g_crashExceptionMap) / sizeof(g_crashExceptionMap[0]); i++) {
105         if (errCode == g_crashExceptionMap[i].errCode) {
106             return g_crashExceptionMap[i].str;
107         }
108     }
109     return g_crashExceptionMap[i - 1].str;    /* the end of map is "unknown reason" */
110 }
111 
FillCrashExceptionAndReport(const int err)112 static void FillCrashExceptionAndReport(const int err)
113 {
114     struct CrashDumpException exception;
115     (void)memset_s(&exception, sizeof(struct CrashDumpException), 0, sizeof(struct CrashDumpException));
116     exception.pid = g_request->pid;
117     exception.uid = (int32_t)(g_request->uid);
118     exception.error = err;
119     exception.time = (int64_t)(GetTimeMilliseconds());
120     if (strncpy_s(exception.message, sizeof(exception.message), GetCrashDescription(err),
121         sizeof(exception.message) - 1) != 0) {
122         DFXLOGE("strcpy exception message fail");
123         return;
124     }
125     ReportException(exception);
126 }
127 
InheritCapabilities(void)128 static int32_t InheritCapabilities(void)
129 {
130     struct __user_cap_header_struct capHeader;
131     (void)memset_s(&capHeader, sizeof(capHeader), 0, sizeof(capHeader));
132 
133     capHeader.version = _LINUX_CAPABILITY_VERSION_3;
134     capHeader.pid = 0;
135     struct __user_cap_data_struct capData[2];
136     if (capget(&capHeader, &capData[0]) == -1) {
137         DFXLOGE("Failed to get origin cap data");
138         return -1;
139     }
140 
141     capData[0].inheritable = capData[0].permitted;
142     capData[1].inheritable = capData[1].permitted;
143     if (capset(&capHeader, &capData[0]) == -1) {
144         DFXLOGE("Failed to set cap data, errno(%{public}d)", errno);
145         return -1;
146     }
147 
148     uint64_t ambCap = capData[0].inheritable;
149     ambCap = ambCap | (((uint64_t)capData[1].inheritable) << INHERITABLE_OFFSET);
150     for (size_t i = 0; i < NUMBER_SIXTYFOUR; i++) {
151         if (ambCap & ((uint64_t)1)) {
152             if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0) {
153                 DFXLOGE("Failed to change the ambient capability set, errno(%{public}d)", errno);
154             }
155         }
156         ambCap = ambCap >> 1;
157     }
158     return 0;
159 }
160 
161 static const int SIGCHAIN_DUMP_SIGNAL_LIST[] = {
162     SIGDUMP, SIGLEAK_STACK
163 };
164 
165 static const int SIGCHAIN_CRASH_SIGNAL_LIST[] = {
166     SIGILL, SIGABRT, SIGBUS, SIGFPE,
167     SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
168 };
169 
SetInterestedSignalMasks(int how)170 static void SetInterestedSignalMasks(int how)
171 {
172     sigset_t set;
173     sigemptyset(&set);
174     for (size_t i = 0; i < sizeof(SIGCHAIN_DUMP_SIGNAL_LIST) / sizeof(SIGCHAIN_DUMP_SIGNAL_LIST[0]); i++) {
175         sigaddset(&set, SIGCHAIN_DUMP_SIGNAL_LIST[i]);
176     }
177     for (size_t i = 0; i < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); i++) {
178         sigaddset(&set, SIGCHAIN_CRASH_SIGNAL_LIST[i]);
179     }
180     sigprocmask(how, &set, NULL);
181 }
182 
CloseFds(void)183 static void CloseFds(void)
184 {
185     const int closeFdCount = 1024;
186     for (int i = 0; i < closeFdCount; i++) {
187         syscall(SYS_close, i);
188     }
189 }
190 
DFX_SetUpEnvironment(void)191 static void DFX_SetUpEnvironment(void)
192 {
193     // clear stdout and stderr
194     int devNull = OHOS_TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
195     if (devNull < 0) {
196         DFXLOGE("Failed to open dev/null.");
197         return;
198     }
199 
200     OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDOUT_FILENO));
201     OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDERR_FILENO));
202     syscall(SYS_close, devNull);
203     SetInterestedSignalMasks(SIG_BLOCK);
204 }
205 
DFX_SetUpSigAlarmAction(void)206 static void DFX_SetUpSigAlarmAction(void)
207 {
208     if (signal(SIGALRM, SIG_DFL) == SIG_ERR) {
209         DFXLOGW("Default signal alarm error!");
210     }
211     sigset_t set;
212     sigemptyset(&set);
213     sigaddset(&set, SIGALRM);
214     sigprocmask(SIG_UNBLOCK, &set, NULL);
215 }
216 
DFX_ExecDump(void)217 static int DFX_ExecDump(void)
218 {
219     DFX_SetUpEnvironment();
220     DFX_SetUpSigAlarmAction();
221     alarm(ALARM_TIME_S);
222     int pipefd[2] = {-1, -1};
223     // create pipe for passing request to processdump
224     if (g_request->dumpMode == SPLIT_MODE) {
225         if (syscall(SYS_pipe2, pipefd, 0) != 0) {
226             DFXLOGE("Failed to create pipe for transfering context, errno(%{public}d)", errno);
227             return CREATE_PIPE_FAIL;
228         }
229     } else {
230         pipefd[0] = g_pipeFds[WRITE_TO_DUMP][0];
231         pipefd[1] = g_pipeFds[WRITE_TO_DUMP][1];
232     }
233 
234     ssize_t writeLen = (long)(sizeof(struct ProcessDumpRequest));
235     if (fcntl(pipefd[1], F_SETPIPE_SZ, writeLen) < writeLen) {
236         DFXLOGE("Failed to set pipe buffer size, errno(%{public}d).", errno);
237         return SET_PIPE_LEN_FAIL;
238     }
239 
240     struct iovec iovs[1] = {
241         {
242             .iov_base = g_request,
243             .iov_len = sizeof(struct ProcessDumpRequest)
244         },
245     };
246     if (OHOS_TEMP_FAILURE_RETRY(writev(pipefd[1], iovs, 1)) != writeLen) {
247         DFXLOGE("Failed to write pipe, errno(%{public}d)", errno);
248         return WRITE_PIPE_FAIL;
249     }
250     OHOS_TEMP_FAILURE_RETRY(dup2(pipefd[0], STDIN_FILENO));
251     if (pipefd[0] != STDIN_FILENO) {
252         syscall(SYS_close, pipefd[0]);
253     }
254     syscall(SYS_close, pipefd[1]);
255 
256     if (InheritCapabilities() != 0) {
257         DFXLOGE("Failed to inherit Capabilities from parent.");
258         FillCrashExceptionAndReport(CRASH_SIGNAL_EINHERITCAP);
259         return INHERIT_CAP_FAIL;
260     }
261     DFXLOGW("execl processdump.");
262 #ifdef DFX_LOG_HILOG_BASE
263     execl("/system/bin/processdump", "processdump", "-signalhandler", NULL);
264 #else
265     execl("/bin/processdump", "processdump", "-signalhandler", NULL);
266 #endif
267     DFXLOGE("Failed to execl processdump, errno(%{public}d)", errno);
268     FillCrashExceptionAndReport(CRASH_SIGNAL_EEXECL);
269     return errno;
270 }
271 
ForkBySyscall(void)272 static pid_t ForkBySyscall(void)
273 {
274 #ifdef SYS_fork
275     return syscall(SYS_fork);
276 #else
277     return syscall(SYS_clone, SIGCHLD, 0);
278 #endif
279 }
280 
SetDumpState(void)281 static bool SetDumpState(void)
282 {
283     if (prctl(PR_SET_DUMPABLE, 1) != 0) {
284         DFXLOGE("Failed to set dumpable, errno(%{public}d).", errno);
285         return false;
286     }
287 
288     if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) != 0) {
289         if (errno != EINVAL) {
290             DFXLOGE("Failed to set ptracer, errno(%{public}d).", errno);
291             return false;
292         }
293     }
294     return true;
295 }
296 
RestoreDumpState(int prevState, bool isTracerStatusModified)297 static void RestoreDumpState(int prevState, bool isTracerStatusModified)
298 {
299     prctl(PR_SET_DUMPABLE, prevState);
300     if (isTracerStatusModified == true) {
301         prctl(PR_SET_PTRACER, 0);
302     }
303 }
304 
SetSelfThreadParam(const char* name, int priority)305 static void SetSelfThreadParam(const char* name, int priority)
306 {
307     pthread_setname_np(pthread_self(), name);
308     struct sched_param schedParam;
309     schedParam.sched_priority = priority;
310     pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedParam);
311 }
312 
WaitProcessExit(int childPid, const char* name)313 static bool WaitProcessExit(int childPid, const char* name)
314 {
315     int ret = -1;
316     int status = 0;
317     int startTime = (int)time(NULL);
318     bool isSuccess = false;
319     DFXLOGI("(%{public}ld) wait %{public}s(%{public}d) exit.", syscall(SYS_gettid), name, childPid);
320     do {
321         errno = 0;
322         ret = waitpid(childPid, &status, WNOHANG);
323         if (ret < 0) {
324             DFXLOGE("Failed to wait child process terminated, errno(%{public}d)", errno);
325             return isSuccess;
326         }
327 
328         if (ret == childPid) {
329             isSuccess = true;
330             break;
331         }
332 
333         if ((int)time(NULL) - startTime > PROCESSDUMP_TIMEOUT) {
334             DFXLOGI("(%{public}ld) wait for (%{public}d) timeout", syscall(SYS_gettid), childPid);
335             isSuccess = false;
336             break;
337         }
338         usleep(SIGNALHANDLER_TIMEOUT); // sleep 10ms
339     } while (1);
340 
341     DFXLOGI("(%{public}ld) wait for %{public}s(%{public}d) return with ret(%{public}d), status(%{public}d)",
342         syscall(SYS_gettid), name, childPid, ret, status);
343     if (WIFEXITED(status)) {
344         int exitCode = WEXITSTATUS(status);
345         DFXLOGI("wait %{public}s(%{public}d) exit code: %{public}d", name, childPid, exitCode);
346     } else if (WIFSIGNALED(status)) {
347         int sigNum = WTERMSIG(status);
348         DFXLOGI("wait %{public}s(%{public}d) exit with sig: %{public}d", name, childPid, sigNum);
349     }
350     return isSuccess;
351 }
352 
Exit(int flag)353 static void Exit(int flag)
354 {
355     _exit(flag); // Avoid crashes that occur when directly using the _exit()
356 }
357 
ForkAndExecProcessDump(void)358 static int ForkAndExecProcessDump(void)
359 {
360     int childPid = -1;
361     SetSelfThreadParam("dump_tmp_thread", 0);
362 
363     // set privilege for dump ourself
364     int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
365     bool isTracerStatusModified = SetDumpState();
366     if (!isTracerStatusModified) {
367         FillCrashExceptionAndReport(CRASH_SIGNAL_ESETSTATE);
368         goto out;
369     }
370 
371     // fork a child process that could ptrace us
372     childPid = ForkBySyscall();
373     if (childPid == 0) {
374         g_request->dumpMode = SPLIT_MODE;
375         DFXLOGI("The exec processdump pid(%{public}ld).", syscall(SYS_getpid));
376         Exit(DFX_ExecDump());
377     } else if (childPid < 0) {
378         DFXLOGE("[%{public}d]: Failed to fork child process, errno(%{public}d).", __LINE__, errno);
379         FillCrashExceptionAndReport(CRASH_SIGNAL_EFORK);
380         goto out;
381     }
382     WaitProcessExit(childPid, "processdump");
383 out:
384     RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
385     return 0;
386 }
387 
CloneAndDoProcessDump(void* arg)388 static int CloneAndDoProcessDump(void* arg)
389 {
390     (void)arg;
391     DFXLOGI("The clone thread(%{public}ld).", syscall(SYS_gettid));
392     g_request->recycleTid = syscall(SYS_gettid);
393     return ForkAndExecProcessDump();
394 }
395 
StartProcessdump(void)396 static bool StartProcessdump(void)
397 {
398     uint64_t startTime = GetAbsTimeMilliSeconds();
399     pid_t pid = ForkBySyscall();
400     if (pid < 0) {
401         DFXLOGE("Failed to fork dummy processdump(%{public}d)", errno);
402         return false;
403     } else if (pid == 0) {
404         pid_t processDumpPid = ForkBySyscall();
405         if (processDumpPid < 0) {
406             DFXLOGE("Failed to fork processdump(%{public}d)", errno);
407             _exit(0);
408         } else if (processDumpPid > 0) {
409             _exit(0);
410         } else {
411             uint64_t endTime;
412             int tid;
413             ParseSiValue(&g_request->siginfo, &endTime, &tid);
414             uint64_t curTime = GetAbsTimeMilliSeconds();
415             DFXLOGW("start processdump, fork spend time %{public}" PRIu64 "ms", curTime - startTime);
416             if (endTime != 0) {
417                 DFXLOGW("dump remain %{public}" PRId64 "ms", endTime - curTime);
418             }
419             if (endTime == 0 || endTime > curTime) {
420                 DFX_ExecDump();
421             } else {
422                 DFXLOGW("current has spend all time, not execl processdump");
423             }
424             _exit(0);
425         }
426     }
427 
428     if (waitpid(pid, NULL, 0) <= 0) {
429         DFXLOGE("failed to wait dummy processdump(%{public}d)", errno);
430     }
431     return true;
432 }
433 
StartVMProcessUnwind(void)434 static bool StartVMProcessUnwind(void)
435 {
436     uint32_t startTime = GetAbsTimeMilliSeconds();
437     pid_t pid = ForkBySyscall();
438     if (pid < 0) {
439         DFXLOGE("Failed to fork vm process(%{public}d)", errno);
440         return false;
441     } else if (pid == 0) {
442         pid_t vmPid = ForkBySyscall();
443         if (vmPid == 0) {
444             DFXLOGW("start vm process, fork spend time %{public}" PRIu64 "ms", GetAbsTimeMilliSeconds() - startTime);
445             syscall(SYS_close, g_pipeFds[WRITE_TO_DUMP][0]);
446             pid_t pids[PID_MAX] = {0};
447             pids[REAL_PROCESS_PID] = GetRealPid();
448             pids[VIRTUAL_PROCESS_PID] = syscall(SYS_getpid);
449             OHOS_TEMP_FAILURE_RETRY(write(g_pipeFds[WRITE_TO_DUMP][1], pids, sizeof(pids)));
450             syscall(SYS_close, g_pipeFds[WRITE_TO_DUMP][1]);
451 
452             uint32_t finishUnwind = OPE_FAIL;
453             syscall(SYS_close, g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][1]);
454             OHOS_TEMP_FAILURE_RETRY(read(g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][0], &finishUnwind, sizeof(finishUnwind)));
455             syscall(SYS_close, g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][0]);
456             DFXLOGI("processdump unwind finish, exit vm pid = %{public}d", pids[VIRTUAL_PROCESS_PID]);
457             _exit(0);
458         } else {
459             DFXLOGI("exit dummy vm process");
460             _exit(0);
461         }
462     }
463 
464     if (waitpid(pid, NULL, 0) <= 0) {
465         DFXLOGE("failed to wait dummy vm process(%{public}d)", errno);
466     }
467     return true;
468 }
469 
CleanFd(int *pipeFd)470 static void CleanFd(int *pipeFd)
471 {
472     if (*pipeFd != -1) {
473         syscall(SYS_close, *pipeFd);
474         *pipeFd = -1;
475     }
476 }
477 
CleanPipe(void)478 static void CleanPipe(void)
479 {
480     for (size_t i = 0; i < PIPE_MAX; i++) {
481         CleanFd(&g_pipeFds[i][0]);
482         CleanFd(&g_pipeFds[i][1]);
483     }
484 }
485 
InitPipe(void)486 static bool InitPipe(void)
487 {
488     for (int i = 0; i < PIPE_MAX; i++) {
489         if (syscall(SYS_pipe2, g_pipeFds[i], 0) == -1) {
490             DFXLOGE("create pipe fail, errno(%{public}d)", errno);
491             FillCrashExceptionAndReport(CRASH_SIGNAL_ECREATEPIPE);
492             CleanPipe();
493             return false;
494         }
495     }
496 
497     g_request->pmPipeFd[0] = g_pipeFds[READ_FROM_DUMP_TO_MAIN][0];
498     g_request->pmPipeFd[1] = g_pipeFds[READ_FROM_DUMP_TO_MAIN][1];
499     g_request->vmPipeFd[0] = g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][0];
500     g_request->vmPipeFd[1] = g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][1];
501     return true;
502 }
503 
ReadPipeTimeout(int fd, uint64_t timeout, uint32_t* value)504 static bool ReadPipeTimeout(int fd, uint64_t timeout, uint32_t* value)
505 {
506     if (fd < 0 || value == NULL) {
507         return false;
508     }
509     struct pollfd pfds[1];
510     pfds[0].fd = fd;
511     pfds[0].events = POLLIN;
512 
513     uint64_t startTime = GetTimeMilliseconds();
514     uint64_t endTime = startTime + timeout;
515     int pollRet = -1;
516     do {
517         pollRet = poll(pfds, 1, timeout);
518         if ((pollRet > 0) && (pfds[0].revents && POLLIN)) {
519             if (OHOS_TEMP_FAILURE_RETRY(read(fd, value, sizeof(uint32_t))) ==
520                 (long int)(sizeof(uint32_t))) {
521                 return true;
522             }
523         }
524 
525         uint64_t now = GetTimeMilliseconds();
526         if (now >= endTime || now < startTime) {
527             break;
528         } else {
529             timeout = endTime - now;
530         }
531     } while (pollRet < 0 && errno == EINTR);
532     FillCrashExceptionAndReport(CRASH_SIGNAL_EREADPIPE);
533     DFXLOGE("read pipe failed , errno(%{public}d)", errno);
534     return false;
535 }
536 
ReadProcessDumpGetRegsMsg(void)537 static bool ReadProcessDumpGetRegsMsg(void)
538 {
539     CleanFd(&g_pipeFds[READ_FROM_DUMP_TO_MAIN][1]);
540 
541     DFXLOGI("start wait processdump read registers");
542     const uint64_t readRegsTimeout = 5000; // 5s
543     uint32_t isFinishGetRegs = OPE_FAIL;
544     if (ReadPipeTimeout(g_pipeFds[READ_FROM_DUMP_TO_MAIN][0], readRegsTimeout, &isFinishGetRegs)) {
545         if (isFinishGetRegs == OPE_SUCCESS) {
546             DFXLOGI("processdump have get all registers .");
547             return true;
548         }
549     }
550 
551     return false;
552 }
553 
ReadUnwindFinishMsg(int sig)554 static void ReadUnwindFinishMsg(int sig)
555 {
556     if (sig == SIGDUMP) {
557         return;
558     }
559 
560     DFXLOGI("start wait processdump unwind");
561     const uint64_t unwindTimeout = 10000; // 10s
562     uint32_t isExitAfterUnwind = OPE_CONTINUE;
563     if (ReadPipeTimeout(g_pipeFds[READ_FROM_DUMP_TO_MAIN][0], unwindTimeout, &isExitAfterUnwind)) {
564         DFXLOGI("processdump unwind finish");
565     } else {
566         DFXLOGE("wait processdump unwind finish timeout");
567     }
568 }
569 
ProcessDump(int sig)570 static int ProcessDump(int sig)
571 {
572     int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
573     bool isTracerStatusModified = SetDumpState();
574 
575     if (!InitPipe()) {
576         return -1;
577     }
578     g_request->dumpMode = FUSION_MODE;
579 
580     do {
581         uint64_t endTime;
582         int tid;
583         ParseSiValue(&g_request->siginfo, &endTime, &tid);
584         if (endTime != 0 && endTime <= GetAbsTimeMilliSeconds()) {
585             DFXLOGW("enter processdump has coat all time, just exit");
586             break;
587         }
588         if (!StartProcessdump()) {
589             DFXLOGE("start processdump fail");
590             break;
591         }
592 
593         if (!ReadProcessDumpGetRegsMsg()) {
594             break;
595         }
596 
597         if (!StartVMProcessUnwind()) {
598             DFXLOGE("start vm process unwind fail");
599             break;
600         }
601         ReadUnwindFinishMsg(sig);
602     } while (false);
603 
604     CleanPipe();
605     RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
606     return 0;
607 }
608 
ForkAndDoProcessDump(int sig)609 static void ForkAndDoProcessDump(int sig)
610 {
611     int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
612     bool isTracerStatusModified = SetDumpState();
613     int childPid = ForkBySyscall();
614     if (childPid == 0) {
615         CloseFds();
616         g_request->vmNsPid = syscall(SYS_getpid);
617         g_request->vmPid = GetRealPid();
618         DFXLOGI("The vm pid(%{public}d:%{public}d).", g_request->vmPid, g_request->vmNsPid);
619         DFX_SetUpSigAlarmAction();
620         alarm(ALARM_TIME_S);
621         _exit(ForkAndExecProcessDump());
622     } else if (childPid < 0) {
623         DFXLOGE("[%{public}d]: Failed to fork child process, errno(%{public}d).", __LINE__, errno);
624         RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
625         ForkAndExecProcessDump();
626         return;
627     }
628 
629     DFXLOGI("Start wait for VmProcess(%{public}d) exit.", childPid);
630     errno = 0;
631     if (!WaitProcessExit(childPid, "VmProcess") &&
632         sig != SIGDUMP &&
633         sig != SIGLEAK_STACK) {
634         DFXLOGI("Wait VmProcess(%{public}d) exit timeout in handling critical signal.", childPid);
635         FillCrashExceptionAndReport(CRASH_SIGNAL_EWAITEXIT);
636         // do not left vm process
637         kill(childPid, SIGKILL);
638     }
639 
640     RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
641 }
642 
DfxDumpRequest(int sig, struct ProcessDumpRequest *request, void *reservedChildStack)643 int DfxDumpRequest(int sig, struct ProcessDumpRequest *request, void *reservedChildStack)
644 {
645     int ret = 0;
646     if (request == NULL || reservedChildStack == NULL) {
647         DFXLOGE("Failed to DumpRequest because of error parameters!");
648         return ret;
649     }
650     g_request = request;
651     g_reservedChildStack = reservedChildStack;
652     if (ProcessDump(sig) == 0) {
653         ret = sig == SIGDUMP || sig == SIGLEAK_STACK;
654         return ret;
655     }
656 
657     if (sig != SIGDUMP) {
658         ret = sig == SIGLEAK_STACK ? true : false;
659         ForkAndDoProcessDump(sig);
660     } else {
661         ret = true;
662         int recycleTid = clone(CloneAndDoProcessDump, reservedChildStack,\
663             CLONE_THREAD | CLONE_SIGHAND | CLONE_VM, NULL);
664         if (recycleTid == -1) {
665             DFXLOGE("Failed to clone thread for recycle dump process, errno(%{public}d)", errno);
666         }
667     }
668     return ret;
669 }
670