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 <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 #if defined (__LP64__)
68 #define RESERVED_CHILD_STACK_SIZE (32 * 1024) // 32K
69 #else
70 #define RESERVED_CHILD_STACK_SIZE (16 * 1024) // 16K
71 #endif
72
73 #define BOOL int
74 #define TRUE 1
75 #define FALSE 0
76
77 #ifndef NSIG
78 #define NSIG 64
79 #endif
80
81 #ifndef F_SETPIPE_SZ
82 #define F_SETPIPE_SZ 1031
83 #endif
84
85 #define NUMBER_SIXTYFOUR 64
86 #define INHERITABLE_OFFSET 32
87
88 #ifndef __MUSL__
InitHandler(void)89 void __attribute__((constructor)) InitHandler(void)
90 {
91 DFX_InstallSignalHandler();
92 }
93 #endif
94
95 static struct ProcessDumpRequest g_request;
96 static void *g_reservedChildStack = NULL;
97 static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
98
99 enum PIPE_FD_TYPE {
100 WRITE_TO_DUMP,
101 READ_FROM_DUMP_TO_MAIN,
102 READ_FORM_DUMP_TO_VIRTUAL,
103 PIPE_MAX,
104 };
105
106 static int g_pipeFds[PIPE_MAX][2] = {
107 {-1, -1},
108 {-1, -1},
109 {-1, -1}
110 };
111
112 static pthread_key_t g_crashObjKey;
113 static bool g_crashObjInit = false;
114 static BOOL g_hasInit = FALSE;
115 static const int SIGNALHANDLER_TIMEOUT = 10000; // 10000 us
116 static const int ALARM_TIME_S = 10;
117 static int g_prevHandledSignal = SIGDUMP;
118 static struct sigaction g_oldSigactionList[NSIG] = {};
119 static char g_appRunningId[MAX_APP_RUNNING_UNIQUE_ID_LEN];
120 enum DumpPreparationStage {
121 CREATE_PIPE_FAIL = 1,
122 SET_PIPE_LEN_FAIL,
123 WRITE_PIPE_FAIL,
124 INHERIT_CAP_FAIL,
125 EXEC_FAIL,
126 };
127
128 TraceInfo HiTraceGetId(void) __attribute__((weak));
FillTraceIdLocked(struct ProcessDumpRequest * request)129 static void FillTraceIdLocked(struct ProcessDumpRequest* request)
130 {
131 if (HiTraceGetId == NULL || request == NULL) {
132 return;
133 }
134
135 TraceInfo id = HiTraceGetId();
136 memcpy(&(request->traceInfo), &id, sizeof(TraceInfo));
137 }
138
139 const char* GetLastFatalMessage(void) __attribute__((weak));
140 fatal_msg_t *get_fatal_message(void) __attribute__((weak));
141 typedef struct ThreadCallbackItem {
142 int32_t tid;
143 ThreadInfoCallBack callback;
144 } ThreadCallbackItem;
145
146 #define CALLBACK_ITEM_COUNT 32
147 static ThreadCallbackItem g_callbackItems[CALLBACK_ITEM_COUNT];
InitCallbackItems(void)148 static void InitCallbackItems(void)
149 {
150 for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
151 g_callbackItems[i].tid = -1;
152 g_callbackItems[i].callback = NULL;
153 }
154 }
155
156 static GetStackIdFunc g_GetStackIdFunc = NULL;
SetAsyncStackCallbackFunc(void * func)157 void SetAsyncStackCallbackFunc(void* func)
158 {
159 g_GetStackIdFunc = (GetStackIdFunc)func;
160 }
161
162 // caller should set to NULL before exit thread
SetThreadInfoCallback(ThreadInfoCallBack func)163 void SetThreadInfoCallback(ThreadInfoCallBack func)
164 {
165 int32_t currentTid = syscall(SYS_gettid);
166 int32_t firstEmptySlot = -1;
167 int32_t currentThreadSlot = -1;
168 pthread_mutex_lock(&g_signalHandlerMutex);
169 for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
170 if (firstEmptySlot == -1 && g_callbackItems[i].tid == -1) {
171 firstEmptySlot = i;
172 }
173
174 if (g_callbackItems[i].tid == currentTid) {
175 currentThreadSlot = i;
176 break;
177 }
178 }
179
180 int32_t targetSlot = currentThreadSlot == -1 ? firstEmptySlot : currentThreadSlot;
181 if (targetSlot != -1) {
182 g_callbackItems[targetSlot].tid = func == NULL ? -1 : currentTid;
183 g_callbackItems[targetSlot].callback = func;
184 }
185 pthread_mutex_unlock(&g_signalHandlerMutex);
186 }
187
GetCallbackLocked()188 static ThreadInfoCallBack GetCallbackLocked()
189 {
190 int32_t currentTid = syscall(SYS_gettid);
191 for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
192 if (g_callbackItems[i].tid != currentTid) {
193 continue;
194 }
195
196 return g_callbackItems[i].callback;
197 }
198 return NULL;
199 }
200
FillLastFatalMessageLocked(int32_t sig,void * context)201 static void FillLastFatalMessageLocked(int32_t sig, void *context)
202 {
203 if (sig != SIGABRT) {
204 ThreadInfoCallBack callback = GetCallbackLocked();
205 if (callback != NULL) {
206 DFXLOG_INFO("Start collect crash thread info.");
207 callback(g_request.lastFatalMessage, sizeof(g_request.lastFatalMessage), context);
208 DFXLOG_INFO("Finish collect crash thread info.");
209 }
210 return;
211 }
212
213 const char* lastFatalMessage = NULL;
214 if (get_fatal_message != NULL) {
215 fatal_msg_t* fatalMsg = get_fatal_message();
216 lastFatalMessage = fatalMsg == NULL ? NULL : fatalMsg->msg;
217 }
218
219 if (lastFatalMessage == NULL && GetLastFatalMessage != NULL) {
220 lastFatalMessage = GetLastFatalMessage();
221 }
222
223 if (lastFatalMessage == NULL) {
224 return;
225 }
226
227 size_t len = strlen(lastFatalMessage);
228 if (len > MAX_FATAL_MSG_SIZE) {
229 DFXLOG_ERROR("Last message is longer than MAX_FATAL_MSG_SIZE");
230 return;
231 }
232
233 (void)strncpy(g_request.lastFatalMessage, lastFatalMessage, sizeof(g_request.lastFatalMessage) - 1);
234 }
235
GetCrashDescription(const int32_t errCode)236 static const char* GetCrashDescription(const int32_t errCode)
237 {
238 size_t i;
239
240 for (i = 0; i < sizeof(g_crashExceptionMap) / sizeof(g_crashExceptionMap[0]); i++) {
241 if (errCode == g_crashExceptionMap[i].errCode) {
242 return g_crashExceptionMap[i].str;
243 }
244 }
245 return g_crashExceptionMap[i - 1].str; /* the end of map is "unknown reason" */
246 }
247
FillCrashExceptionAndReport(const int err)248 static void FillCrashExceptionAndReport(const int err)
249 {
250 struct CrashDumpException exception;
251 memset(&exception, 0, sizeof(struct CrashDumpException));
252 exception.pid = g_request.pid;
253 exception.uid = (int32_t)(g_request.uid);
254 exception.error = err;
255 exception.time = (int64_t)(GetTimeMilliseconds());
256 (void)strncpy(exception.message, GetCrashDescription(err), sizeof(exception.message) - 1);
257 ReportException(exception);
258 }
259
IsDumpSignal(int sig)260 static bool IsDumpSignal(int sig)
261 {
262 return sig == SIGDUMP || sig == SIGLEAK_STACK;
263 }
264
FillDumpRequest(int sig,siginfo_t * si,void * context)265 static void FillDumpRequest(int sig, siginfo_t *si, void *context)
266 {
267 memset(&g_request, 0, sizeof(g_request));
268 g_request.type = sig;
269 g_request.pid = GetRealPid();
270 g_request.nsPid = syscall(SYS_getpid);
271 g_request.tid = syscall(SYS_gettid);
272 g_request.uid = getuid();
273 g_request.reserved = 0;
274 g_request.timeStamp = GetTimeMilliseconds();
275 g_request.fdTableAddr = (uint64_t)fdsan_get_fd_table();
276 memcpy(g_request.appRunningId, g_appRunningId, sizeof(g_request.appRunningId));
277 if (!IsDumpSignal(sig) && g_GetStackIdFunc!= NULL) {
278 g_request.stackId = g_GetStackIdFunc();
279 DFXLOG_INFO("g_GetStackIdFunc %p.", (void*)g_request.stackId);
280 }
281
282 GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
283 GetProcessName(g_request.processName, sizeof(g_request.processName));
284
285 memcpy(&(g_request.siginfo), si, sizeof(siginfo_t));
286 memcpy(&(g_request.context), context, sizeof(ucontext_t));
287
288 FillTraceIdLocked(&g_request);
289
290 FillLastFatalMessageLocked(sig, context);
291 g_request.crashObj = (uintptr_t)pthread_getspecific(g_crashObjKey);
292 }
293
InheritCapabilities(void)294 static int32_t InheritCapabilities(void)
295 {
296 struct __user_cap_header_struct capHeader;
297 memset(&capHeader, 0, sizeof(capHeader));
298
299 capHeader.version = _LINUX_CAPABILITY_VERSION_3;
300 capHeader.pid = 0;
301 struct __user_cap_data_struct capData[2];
302 if (capget(&capHeader, &capData[0]) == -1) {
303 DFXLOG_ERROR("Failed to get origin cap data");
304 return -1;
305 }
306
307 capData[0].inheritable = capData[0].permitted;
308 capData[1].inheritable = capData[1].permitted;
309 if (capset(&capHeader, &capData[0]) == -1) {
310 DFXLOG_ERROR("Failed to set cap data, errno(%d)", errno);
311 return -1;
312 }
313
314 uint64_t ambCap = capData[0].inheritable;
315 ambCap = ambCap | (((uint64_t)capData[1].inheritable) << INHERITABLE_OFFSET);
316 for (size_t i = 0; i < NUMBER_SIXTYFOUR; i++) {
317 if (ambCap & ((uint64_t)1)) {
318 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0) {
319 DFXLOG_ERROR("Failed to change the ambient capability set, errno(%d)", errno);
320 }
321 }
322 ambCap = ambCap >> 1;
323 }
324 return 0;
325 }
326
327 static const int SIGCHAIN_DUMP_SIGNAL_LIST[] = {
328 SIGDUMP, SIGLEAK_STACK
329 };
330
331 static const int SIGCHAIN_CRASH_SIGNAL_LIST[] = {
332 SIGILL, SIGABRT, SIGBUS, SIGFPE,
333 SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
334 };
335
SetInterestedSignalMasks(int how)336 static void SetInterestedSignalMasks(int how)
337 {
338 sigset_t set;
339 sigemptyset(&set);
340 for (size_t i = 0; i < sizeof(SIGCHAIN_DUMP_SIGNAL_LIST) / sizeof(SIGCHAIN_DUMP_SIGNAL_LIST[0]); i++) {
341 sigaddset(&set, SIGCHAIN_DUMP_SIGNAL_LIST[i]);
342 }
343 for (size_t i = 0; i < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); i++) {
344 sigaddset(&set, SIGCHAIN_CRASH_SIGNAL_LIST[i]);
345 }
346 sigprocmask(how, &set, NULL);
347 }
348
CloseFds(void)349 static void CloseFds(void)
350 {
351 const int closeFdCount = 1024;
352 for (int i = 0; i < closeFdCount; i++) {
353 syscall(SYS_close, i);
354 }
355 }
356
DFX_SetUpEnvironment(void)357 static void DFX_SetUpEnvironment(void)
358 {
359 // clear stdout and stderr
360 int devNull = OHOS_TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR));
361 if (devNull < 0) {
362 DFXLOG_ERROR("Failed to open dev/null.");
363 return;
364 }
365
366 OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDOUT_FILENO));
367 OHOS_TEMP_FAILURE_RETRY(dup2(devNull, STDERR_FILENO));
368 syscall(SYS_close, devNull);
369 SetInterestedSignalMasks(SIG_BLOCK);
370 }
371
DFX_SetUpSigAlarmAction(void)372 static void DFX_SetUpSigAlarmAction(void)
373 {
374 if (signal(SIGALRM, SIG_DFL) == SIG_ERR) {
375 DFXLOG_WARN("Default signal alarm error!");
376 }
377 sigset_t set;
378 sigemptyset(&set);
379 sigaddset(&set, SIGALRM);
380 sigprocmask(SIG_UNBLOCK, &set, NULL);
381 }
382
DFX_ExecDump(void)383 static int DFX_ExecDump(void)
384 {
385 DFX_SetUpEnvironment();
386 DFX_SetUpSigAlarmAction();
387 alarm(ALARM_TIME_S);
388 int pipefd[2] = {-1, -1};
389 // create pipe for passing request to processdump
390 if (g_request.dumpMode == SPLIT_MODE) {
391 if (pipe(pipefd) != 0) {
392 DFXLOG_ERROR("Failed to create pipe for transfering context, errno(%d)", errno);
393 return CREATE_PIPE_FAIL;
394 }
395 } else {
396 pipefd[0] = g_pipeFds[WRITE_TO_DUMP][0];
397 pipefd[1] = g_pipeFds[WRITE_TO_DUMP][1];
398 }
399
400 ssize_t writeLen = (long)(sizeof(struct ProcessDumpRequest));
401 if (fcntl(pipefd[1], F_SETPIPE_SZ, writeLen) < writeLen) {
402 DFXLOG_ERROR("Failed to set pipe buffer size, errno(%d).", errno);
403 return SET_PIPE_LEN_FAIL;
404 }
405
406 struct iovec iovs[1] = {
407 {
408 .iov_base = &g_request,
409 .iov_len = sizeof(struct ProcessDumpRequest)
410 },
411 };
412 if (OHOS_TEMP_FAILURE_RETRY(writev(pipefd[1], iovs, 1)) != writeLen) {
413 DFXLOG_ERROR("Failed to write pipe, errno(%d)", errno);
414 return WRITE_PIPE_FAIL;
415 }
416 OHOS_TEMP_FAILURE_RETRY(dup2(pipefd[0], STDIN_FILENO));
417 if (pipefd[0] != STDIN_FILENO) {
418 syscall(SYS_close, pipefd[0]);
419 }
420 syscall(SYS_close, pipefd[1]);
421
422 if (InheritCapabilities() != 0) {
423 DFXLOG_ERROR("Failed to inherit Capabilities from parent.");
424 FillCrashExceptionAndReport(CRASH_SIGNAL_EINHERITCAP);
425 return INHERIT_CAP_FAIL;
426 }
427 DFXLOG_INFO("execl processdump.");
428 #ifdef DFX_LOG_HILOG_BASE
429 execl("/system/bin/processdump", "processdump", "-signalhandler", NULL);
430 #else
431 execl("/bin/processdump", "processdump", "-signalhandler", NULL);
432 #endif
433 DFXLOG_ERROR("Failed to execl processdump, errno(%d)", errno);
434 FillCrashExceptionAndReport(CRASH_SIGNAL_EEXECL);
435 return errno;
436 }
437
IsMainThread(void)438 static bool IsMainThread(void)
439 {
440 if (syscall(SYS_getpid) == 1) {
441 if (syscall(SYS_gettid) == 1) {
442 return true;
443 }
444 } else {
445 if (syscall(SYS_getpid) == syscall(SYS_gettid)) {
446 return true;
447 }
448 }
449 return false;
450 }
451
ResetAndRethrowSignalIfNeed(int sig,siginfo_t * si)452 static void ResetAndRethrowSignalIfNeed(int sig, siginfo_t *si)
453 {
454 if (IsDumpSignal(sig)) {
455 return;
456 }
457
458 if (g_oldSigactionList[sig].sa_sigaction == NULL) {
459 signal(sig, SIG_DFL);
460 } else if (sigaction(sig, &(g_oldSigactionList[sig]), NULL) != 0) {
461 DFXLOG_ERROR("Failed to reset sig(%d).", sig);
462 signal(sig, SIG_DFL);
463 }
464
465 if (syscall(SYS_rt_tgsigqueueinfo, syscall(SYS_getpid), syscall(SYS_gettid), sig, si) != 0) {
466 DFXLOG_ERROR("Failed to rethrow sig(%d), errno(%d).", sig, errno);
467 } else {
468 DFXLOG_INFO("Current process(%ld) rethrow sig(%d).", syscall(SYS_getpid), sig);
469 }
470 }
471
PauseMainThreadHandler(int sig)472 static void PauseMainThreadHandler(int sig)
473 {
474 DFXLOG_INFO("Crash(%d) in child thread(%ld), lock main thread.", sig, syscall(SYS_gettid));
475 // only work when subthread crash and send SIGDUMP to mainthread.
476 pthread_mutex_lock(&g_signalHandlerMutex);
477 pthread_mutex_unlock(&g_signalHandlerMutex);
478 DFXLOG_INFO("Crash in child thread(%ld), exit main thread.", syscall(SYS_gettid));
479 }
480
BlockMainThreadIfNeed(int sig)481 static void BlockMainThreadIfNeed(int sig)
482 {
483 if (IsMainThread() || IsDumpSignal(sig)) {
484 return;
485 }
486
487 DFXLOG_INFO("Try block main thread.");
488 (void)signal(SIGQUIT, PauseMainThreadHandler);
489 if (syscall(SYS_tgkill, syscall(SYS_getpid), syscall(SYS_getpid), SIGQUIT) != 0) {
490 DFXLOG_ERROR("Failed to send SIGQUIT to main thread, errno(%d).", errno);
491 }
492 }
493
ForkBySyscall(void)494 static pid_t ForkBySyscall(void)
495 {
496 #ifdef SYS_fork
497 return syscall(SYS_fork);
498 #else
499 return syscall(SYS_clone, SIGCHLD, 0);
500 #endif
501 }
502
SetDumpState(void)503 static bool SetDumpState(void)
504 {
505 if (prctl(PR_SET_DUMPABLE, 1) != 0) {
506 DFXLOG_ERROR("Failed to set dumpable, errno(%d).", errno);
507 return false;
508 }
509
510 if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) != 0) {
511 if (errno != EINVAL) {
512 DFXLOG_ERROR("Failed to set ptracer, errno(%d).", errno);
513 return false;
514 }
515 }
516 return true;
517 }
518
RestoreDumpState(int prevState,bool isTracerStatusModified)519 static void RestoreDumpState(int prevState, bool isTracerStatusModified)
520 {
521 prctl(PR_SET_DUMPABLE, prevState);
522 if (isTracerStatusModified == true) {
523 prctl(PR_SET_PTRACER, 0);
524 }
525 }
526
SetSelfThreadParam(const char * name,int priority)527 static void SetSelfThreadParam(const char* name, int priority)
528 {
529 pthread_setname_np(pthread_self(), name);
530 struct sched_param schedParam;
531 schedParam.sched_priority = priority;
532 pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedParam);
533 }
534
WaitProcessExit(int childPid,const char * name)535 static bool WaitProcessExit(int childPid, const char* name)
536 {
537 int ret = -1;
538 int status = 0;
539 int startTime = (int)time(NULL);
540 bool isSuccess = false;
541 DFXLOG_INFO("(%ld) wait %s(%d) exit.", syscall(SYS_gettid), name, childPid);
542 do {
543 errno = 0;
544 ret = waitpid(childPid, &status, WNOHANG);
545 if (ret < 0) {
546 DFXLOG_ERROR("Failed to wait child process terminated, errno(%d)", errno);
547 return isSuccess;
548 }
549
550 if (ret == childPid) {
551 isSuccess = true;
552 break;
553 }
554
555 if ((int)time(NULL) - startTime > PROCESSDUMP_TIMEOUT) {
556 DFXLOG_INFO("(%ld) wait for (%d) timeout", syscall(SYS_gettid), childPid);
557 isSuccess = false;
558 break;
559 }
560 usleep(SIGNALHANDLER_TIMEOUT); // sleep 10ms
561 } while (1);
562
563 DFXLOG_INFO("(%ld) wait for %s(%d) return with ret(%d), status(%d)",
564 syscall(SYS_gettid), name, childPid, ret, status);
565 if (WIFEXITED(status)) {
566 int exitCode = WEXITSTATUS(status);
567 DFXLOG_INFO("wait %s(%d) exit code: %d", name, childPid, exitCode);
568 } else if (WIFSIGNALED(status)) {
569 int sigNum = WTERMSIG(status);
570 DFXLOG_INFO("wait %s(%d) exit with sig: %d", name, childPid, sigNum);
571 }
572 return isSuccess;
573 }
574
ForkAndExecProcessDump(void)575 static int ForkAndExecProcessDump(void)
576 {
577 int childPid = -1;
578 SetSelfThreadParam("dump_tmp_thread", 0);
579
580 // set privilege for dump ourself
581 int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
582 bool isTracerStatusModified = SetDumpState();
583 if (!isTracerStatusModified) {
584 FillCrashExceptionAndReport(CRASH_SIGNAL_ESETSTATE);
585 goto out;
586 }
587
588 // fork a child process that could ptrace us
589 childPid = ForkBySyscall();
590 if (childPid == 0) {
591 g_request.dumpMode = SPLIT_MODE;
592 DFXLOG_INFO("The exec processdump pid(%ld).", syscall(SYS_getpid));
593 _exit(DFX_ExecDump());
594 } else if (childPid < 0) {
595 DFXLOG_ERROR("Failed to fork child process, errno(%d).", errno);
596 FillCrashExceptionAndReport(CRASH_SIGNAL_EFORK);
597 goto out;
598 }
599 WaitProcessExit(childPid, "processdump");
600 out:
601 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
602 pthread_mutex_unlock(&g_signalHandlerMutex);
603 return 0;
604 }
605
CloneAndDoProcessDump(void * arg)606 static int CloneAndDoProcessDump(void* arg)
607 {
608 (void)arg;
609 DFXLOG_INFO("The clone thread(%ld).", syscall(SYS_gettid));
610 g_request.recycleTid = syscall(SYS_gettid);
611 return ForkAndExecProcessDump();
612 }
613
StartProcessdump(void)614 static bool StartProcessdump(void)
615 {
616 uint64_t startTime = GetAbsTimeMilliSeconds();
617 pid_t pid = ForkBySyscall();
618 if (pid < 0) {
619 DFXLOG_ERROR("Failed to fork dummy processdump(%d)", errno);
620 return false;
621 } else if (pid == 0) {
622 pid_t processDumpPid = ForkBySyscall();
623 if (processDumpPid < 0) {
624 DFXLOG_ERROR("Failed to fork processdump(%d)", errno);
625 _exit(0);
626 } else if (processDumpPid > 0) {
627 _exit(0);
628 } else {
629 uint64_t endTime;
630 int tid;
631 ParseSiValue(&g_request.siginfo, &endTime, &tid);
632 uint64_t curTime = GetAbsTimeMilliSeconds();
633 DFXLOG_INFO("start processdump, fork spend time %" PRIu64 "ms", curTime - startTime);
634 if (endTime != 0) {
635 DFXLOG_INFO("dump remain %" PRId64 "ms", endTime - curTime);
636 }
637 if (endTime == 0 || endTime > curTime) {
638 DFX_ExecDump();
639 } else {
640 DFXLOG_INFO("%s", "current has spend all time, not execl processdump");
641 }
642 _exit(0);
643 }
644 }
645
646 if (waitpid(pid, NULL, 0) <= 0) {
647 DFXLOG_ERROR("failed to wait dummy processdump(%d)", errno);
648 return false;
649 }
650 return true;
651 }
652
StartVMProcessUnwind(void)653 static bool StartVMProcessUnwind(void)
654 {
655 uint32_t startTime = GetAbsTimeMilliSeconds();
656 pid_t pid = ForkBySyscall();
657 if (pid < 0) {
658 DFXLOG_ERROR("Failed to fork vm process(%d)", errno);
659 return false;
660 } else if (pid == 0) {
661 pid_t vmPid = ForkBySyscall();
662 if (vmPid == 0) {
663 DFXLOG_INFO("start vm process, fork spend time %" PRIu64 "ms", GetAbsTimeMilliSeconds() - startTime);
664 close(g_pipeFds[WRITE_TO_DUMP][0]);
665 pid_t pids[PID_MAX] = {0};
666 pids[REAL_PROCESS_PID] = GetRealPid();
667 pids[VIRTUAL_PROCESS_PID] = syscall(SYS_getpid);
668
669 OHOS_TEMP_FAILURE_RETRY(write(g_pipeFds[WRITE_TO_DUMP][1], pids, sizeof(pids)));
670 close(g_pipeFds[WRITE_TO_DUMP][1]);
671
672 uint32_t finishUnwind = OPE_FAIL;
673 close(g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][1]);
674 OHOS_TEMP_FAILURE_RETRY(read(g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][0], &finishUnwind, sizeof(finishUnwind)));
675 close(g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][0]);
676 DFXLOG_INFO("processdump unwind finish, exit vm pid = %d", pids[VIRTUAL_PROCESS_PID]);
677 _exit(0);
678 } else {
679 DFXLOG_INFO("exit dummy vm process");
680 _exit(0);
681 }
682 }
683
684 if (waitpid(pid, NULL, 0) <= 0) {
685 DFXLOG_ERROR("failed to wait dummy vm process(%d)", errno);
686 return false;
687 }
688 return true;
689 }
690
CleanFd(int * pipeFd)691 static void CleanFd(int *pipeFd)
692 {
693 if (*pipeFd != -1) {
694 close(*pipeFd);
695 *pipeFd = -1;
696 }
697 }
698
CleanPipe(void)699 static void CleanPipe(void)
700 {
701 for (size_t i = 0; i < PIPE_MAX; i++) {
702 CleanFd(&g_pipeFds[i][0]);
703 CleanFd(&g_pipeFds[i][1]);
704 }
705 }
706
InitPipe(void)707 static bool InitPipe(void)
708 {
709 for (int i = 0; i < PIPE_MAX; i++) {
710 if (pipe(g_pipeFds[i]) == -1) {
711 DFXLOG_ERROR("create pipe fail, errno(%d)", errno);
712 FillCrashExceptionAndReport(CRASH_SIGNAL_ECREATEPIPE);
713 CleanPipe();
714 return false;
715 }
716 }
717
718 g_request.pmPipeFd[0] = g_pipeFds[READ_FROM_DUMP_TO_MAIN][0];
719 g_request.pmPipeFd[1] = g_pipeFds[READ_FROM_DUMP_TO_MAIN][1];
720 g_request.vmPipeFd[0] = g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][0];
721 g_request.vmPipeFd[1] = g_pipeFds[READ_FORM_DUMP_TO_VIRTUAL][1];
722 return true;
723 }
724
ReadPipeTimeout(int fd,uint64_t timeout,uint32_t * value)725 static bool ReadPipeTimeout(int fd, uint64_t timeout, uint32_t* value)
726 {
727 if (fd < 0 || value == NULL) {
728 return false;
729 }
730 struct pollfd pfds[1];
731 pfds[0].fd = fd;
732 pfds[0].events = POLLIN;
733
734 uint64_t startTime = GetTimeMilliseconds();
735 uint64_t endTime = startTime + timeout;
736 int pollRet = -1;
737 do {
738 pollRet = poll(pfds, 1, timeout);
739 if ((pollRet > 0) && (pfds[0].revents && POLLIN)) {
740 if (OHOS_TEMP_FAILURE_RETRY(read(fd, value, sizeof(uint32_t))) ==
741 (long int)(sizeof(uint32_t))) {
742 return true;
743 }
744 }
745
746 uint64_t now = GetTimeMilliseconds();
747 if (now >= endTime || now < startTime) {
748 break;
749 } else {
750 timeout = endTime - now;
751 }
752 } while (pollRet < 0 && errno == EINTR);
753 FillCrashExceptionAndReport(CRASH_SIGNAL_EREADPIPE);
754 DFXLOG_ERROR("read pipe failed , errno(%d)", errno);
755 return false;
756 }
757
ReadProcessDumpGetRegsMsg(void)758 static bool ReadProcessDumpGetRegsMsg(void)
759 {
760 CleanFd(&g_pipeFds[READ_FROM_DUMP_TO_MAIN][1]);
761
762 DFXLOG_INFO("start wait processdump read registers");
763 const uint64_t readRegsTimeout = 5000; // 5s
764 uint32_t isFinishGetRegs = OPE_FAIL;
765 if (ReadPipeTimeout(g_pipeFds[READ_FROM_DUMP_TO_MAIN][0], readRegsTimeout, &isFinishGetRegs)) {
766 if (isFinishGetRegs == OPE_SUCCESS) {
767 DFXLOG_INFO("processdump have get all registers .");
768 return true;
769 }
770 }
771
772 return false;
773 }
774
ReadUnwindFinishMsg(int sig)775 static void ReadUnwindFinishMsg(int sig)
776 {
777 if (sig == SIGDUMP) {
778 return;
779 }
780
781 DFXLOG_INFO("start wait processdump unwind");
782 const uint64_t unwindTimeout = 10000; // 10s
783 uint32_t isExitAfterUnwind = OPE_CONTINUE;
784 if (ReadPipeTimeout(g_pipeFds[READ_FROM_DUMP_TO_MAIN][0], unwindTimeout, &isExitAfterUnwind)) {
785 DFXLOG_INFO("processdump unwind finish");
786 } else {
787 DFXLOG_ERROR("wait processdump unwind finish timeout");
788 }
789 }
790
ProcessDump(int sig)791 static int ProcessDump(int sig)
792 {
793 int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
794 bool isTracerStatusModified = SetDumpState();
795
796 if (!InitPipe()) {
797 return -1;
798 }
799 g_request.dumpMode = FUSION_MODE;
800
801 do {
802 uint64_t endTime;
803 int tid;
804 ParseSiValue(&g_request.siginfo, &endTime, &tid);
805 if (endTime != 0 && endTime <= GetAbsTimeMilliSeconds()) {
806 DFXLOG_INFO("%s", "enter processdump has coat all time, just exit");
807 break;
808 }
809 if (!StartProcessdump()) {
810 DFXLOG_ERROR("start processdump fail");
811 break;
812 }
813
814 if (!ReadProcessDumpGetRegsMsg()) {
815 break;
816 }
817
818 if (!StartVMProcessUnwind()) {
819 DFXLOG_ERROR("start vm process unwind fail");
820 break;
821 }
822 ReadUnwindFinishMsg(sig);
823 } while (false);
824
825 CleanPipe();
826 DFXLOG_INFO("process dump end");
827 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
828 return 0;
829 }
830
ForkAndDoProcessDump(int sig)831 static void ForkAndDoProcessDump(int sig)
832 {
833 int prevDumpableStatus = prctl(PR_GET_DUMPABLE);
834 bool isTracerStatusModified = SetDumpState();
835 int childPid = ForkBySyscall();
836 if (childPid == 0) {
837 CloseFds();
838 g_request.vmNsPid = syscall(SYS_getpid);
839 g_request.vmPid = GetRealPid();
840 DFXLOG_INFO("The vm pid(%d:%d).", g_request.vmPid, g_request.vmNsPid);
841 DFX_SetUpSigAlarmAction();
842 alarm(ALARM_TIME_S);
843 _exit(ForkAndExecProcessDump());
844 } else if (childPid < 0) {
845 DFXLOG_ERROR("Failed to fork child process, errno(%d).", errno);
846 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
847 ForkAndExecProcessDump();
848 return;
849 }
850
851 DFXLOG_INFO("Start wait for VmProcess(%d) exit.", childPid);
852 errno = 0;
853 if (!WaitProcessExit(childPid, "VmProcess") &&
854 sig != SIGDUMP &&
855 sig != SIGLEAK_STACK) {
856 DFXLOG_INFO("Wait VmProcess(%d) exit timeout in handling critical signal.", childPid);
857 FillCrashExceptionAndReport(CRASH_SIGNAL_EWAITEXIT);
858 // do not left vm process
859 kill(childPid, SIGKILL);
860 }
861
862 RestoreDumpState(prevDumpableStatus, isTracerStatusModified);
863 pthread_mutex_unlock(&g_signalHandlerMutex);
864 }
865
DFX_SigchainHandler(int sig,siginfo_t * si,void * context)866 static bool DFX_SigchainHandler(int sig, siginfo_t *si, void *context)
867 {
868 int pid = syscall(SYS_getpid);
869 int tid = syscall(SYS_gettid);
870
871 DFXLOG_INFO("DFX_SigchainHandler :: sig(%d), pid(%d), tid(%d).", sig, pid, tid);
872 bool ret = false;
873 if (sig == SIGDUMP) {
874 if (si->si_code != DUMP_TYPE_REMOTE) {
875 DFXLOG_WARN("DFX_SigchainHandler :: sig(%d:%d) is not remote dump type, return directly",
876 sig, si->si_code);
877 return true;
878 }
879 }
880
881 // crash signal should never be skipped
882 pthread_mutex_lock(&g_signalHandlerMutex);
883 if (!IsDumpSignal(g_prevHandledSignal)) {
884 pthread_mutex_unlock(&g_signalHandlerMutex);
885 return ret;
886 }
887 BlockMainThreadIfNeed(sig);
888 g_prevHandledSignal = sig;
889
890 FillDumpRequest(sig, si, context);
891 DFXLOG_INFO("DFX_SigchainHandler :: sig(%d), pid(%d), processName(%s), threadName(%s).",
892 sig, g_request.pid, g_request.processName, g_request.threadName);
893 if (ProcessDump(sig) == 0) {
894 ret = sig == SIGDUMP || sig == SIGLEAK_STACK;
895 DFXLOG_INFO("Finish handle signal(%d) in %d:%d", sig, g_request.pid, g_request.tid);
896 pthread_mutex_unlock(&g_signalHandlerMutex);
897 return ret;
898 }
899 // for protecting g_reservedChildStack
900 // g_signalHandlerMutex will be unlocked in ForkAndExecProcessDump function
901 if (sig != SIGDUMP) {
902 ret = sig == SIGLEAK_STACK ? true : false;
903 ForkAndDoProcessDump(sig);
904 } else {
905 ret = true;
906 int recycleTid = clone(CloneAndDoProcessDump, g_reservedChildStack,\
907 CLONE_THREAD | CLONE_SIGHAND | CLONE_VM, NULL);
908 if (recycleTid == -1) {
909 DFXLOG_ERROR("Failed to clone thread for recycle dump process, errno(%d)", errno);
910 pthread_mutex_unlock(&g_signalHandlerMutex);
911 }
912 }
913
914 DFXLOG_INFO("Finish handle signal(%d) in %d:%d", sig, g_request.pid, g_request.tid);
915 return ret;
916 }
917
DFX_SignalHandler(int sig,siginfo_t * si,void * context)918 static void DFX_SignalHandler(int sig, siginfo_t *si, void *context)
919 {
920 DFX_SigchainHandler(sig, si, context);
921 ResetAndRethrowSignalIfNeed(sig, si);
922 }
923
InstallSigActionHandler(int sig)924 static void InstallSigActionHandler(int sig)
925 {
926 struct sigaction action;
927 memset(&action, 0, sizeof(action));
928 memset(&g_oldSigactionList, 0, sizeof(g_oldSigactionList));
929 sigfillset(&action.sa_mask);
930 action.sa_sigaction = DFX_SignalHandler;
931 action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
932 if (sigaction(sig, &action, &(g_oldSigactionList[sig])) != 0) {
933 DFXLOG_ERROR("Failed to register signal(%d)", sig);
934 }
935 }
936
DFX_InstallSignalHandler(void)937 void DFX_InstallSignalHandler(void)
938 {
939 if (g_hasInit) {
940 return;
941 }
942
943 InitCallbackItems();
944 // reserve stack for fork
945 g_reservedChildStack = mmap(NULL, RESERVED_CHILD_STACK_SIZE, \
946 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 1, 0);
947 if (g_reservedChildStack == NULL) {
948 DFXLOG_ERROR("Failed to alloc memory for child stack.");
949 return;
950 }
951 g_reservedChildStack = (void *)(((uint8_t *)g_reservedChildStack) + RESERVED_CHILD_STACK_SIZE - 1);
952
953 struct signal_chain_action sigchain = {
954 .sca_sigaction = DFX_SigchainHandler,
955 .sca_mask = {},
956 .sca_flags = 0,
957 };
958
959 for (size_t i = 0; i < sizeof(SIGCHAIN_DUMP_SIGNAL_LIST) / sizeof(SIGCHAIN_DUMP_SIGNAL_LIST[0]); i++) {
960 int32_t sig = SIGCHAIN_DUMP_SIGNAL_LIST[i];
961 sigfillset(&sigchain.sca_mask);
962 // dump signal not mask crash signal
963 for (size_t j = 0; j < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); j++) {
964 sigdelset(&sigchain.sca_mask, SIGCHAIN_CRASH_SIGNAL_LIST[j]);
965 }
966 add_special_handler_at_last(sig, &sigchain);
967 }
968 for (size_t i = 0; i < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); i++) {
969 int32_t sig = SIGCHAIN_CRASH_SIGNAL_LIST[i];
970 if (sig == SIGILL || sig == SIGSYS) {
971 InstallSigActionHandler(sig);
972 } else {
973 sigfillset(&sigchain.sca_mask);
974 add_special_handler_at_last(sig, &sigchain);
975 }
976 }
977
978 g_hasInit = TRUE;
979 if (pthread_key_create(&g_crashObjKey, NULL) == 0) {
980 g_crashObjInit = true;
981 }
982 }
983
DFX_SetAppRunningUniqueId(const char * appRunningId,size_t len)984 int DFX_SetAppRunningUniqueId(const char* appRunningId, size_t len)
985 {
986 size_t appRunningIdMaxLen = sizeof(g_appRunningId);
987 if (appRunningId == NULL || appRunningIdMaxLen <= len) {
988 DFXLOG_ERROR("param error. appRunningId is NULL or length overflow");
989 return -1;
990 }
991 memset(g_appRunningId, 0, appRunningIdMaxLen);
992 memcpy(g_appRunningId, appRunningId, len);
993 return 0;
994 }
995
DFX_SetCrashObj(uint8_t type,uintptr_t addr)996 uintptr_t DFX_SetCrashObj(uint8_t type, uintptr_t addr)
997 {
998 if (!g_crashObjInit) {
999 return 0;
1000 }
1001 #if defined __LP64__
1002 uintptr_t origin = (uintptr_t)pthread_getspecific(g_crashObjKey);
1003 uintptr_t crashObj = 0;
1004 const int moveBit = 56;
1005 crashObj = ((uintptr_t)type << moveBit) | (addr & 0x00ffffffffffffff);
1006 pthread_setspecific(g_crashObjKey, (void*)(crashObj));
1007 return origin;
1008 #endif
1009 return 0;
1010 }
1011
DFX_ResetCrashObj(uintptr_t crashObj)1012 void DFX_ResetCrashObj(uintptr_t crashObj)
1013 {
1014 if (!g_crashObjInit) {
1015 return;
1016 }
1017 #if defined __LP64__
1018 pthread_setspecific(g_crashObjKey, (void*)(crashObj));
1019 #endif
1020 }