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