• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "dfx_signal_handler.h"
16 
17 #ifndef _GNU_SOURCE
18 #define _GNU_SOURCE 1
19 #endif
20 
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <poll.h>
24 #include <pthread.h>
25 #include <sched.h>
26 #include <signal.h>
27 #include <sigchain.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include <sys/capability.h>
35 #include <sys/mman.h>
36 #include <sys/prctl.h>
37 #include <sys/syscall.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/uio.h>
41 #include <sys/wait.h>
42 #include <info/fatal_message.h>
43 #include <linux/capability.h>
44 
45 #include "dfx_cutil.h"
46 #include "dfx_define.h"
47 #include "dfx_dump_request.h"
48 #include "dfx_signalhandler_exception.h"
49 #include <securec.h>
50 #include "dfx_log.h"
51 #include "dfx_dumprequest.h"
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 static void DFX_InstallSignalHandler(void);
78 // preload by libc
InitHandler(void)79 void __attribute__((constructor)) InitHandler(void)
80 {
81     DFX_InstallSignalHandler();
82 }
83 
84 static struct ProcessDumpRequest g_request;
85 static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
86 static pthread_key_t g_crashObjKey;
87 static uint64_t g_crashLogConfig = 0;
88 static bool g_crashObjInit = false;
89 static BOOL g_hasInit = FALSE;
90 static int g_prevHandledSignal = SIGDUMP;
91 static struct sigaction g_oldSigactionList[NSIG] = {};
92 static char g_appRunningId[MAX_APP_RUNNING_UNIQUE_ID_LEN];
93 
94 const char* GetLastFatalMessage(void) __attribute__((weak));
95 fatal_msg_t *get_fatal_message(void) __attribute__((weak));
96 
97 typedef struct ThreadCallbackItem {
98     int32_t tid;
99     ThreadInfoCallBack callback;
100 } ThreadCallbackItem;
101 
102 #define CALLBACK_ITEM_COUNT 32
103 static ThreadCallbackItem g_callbackItems[CALLBACK_ITEM_COUNT];
InitCallbackItems(void)104 static void InitCallbackItems(void)
105 {
106     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
107         g_callbackItems[i].tid = -1;
108         g_callbackItems[i].callback = NULL;
109     }
110 }
111 
112 static GetStackIdFunc g_getStackIdCallback = NULL;
DFX_SetAsyncStackCallback(GetStackIdFunc func)113 void DFX_SetAsyncStackCallback(GetStackIdFunc func)
114 {
115     g_getStackIdCallback = func;
116 }
117 
118 // caller should set to NULL before exit thread
SetThreadInfoCallback(ThreadInfoCallBack func)119 void SetThreadInfoCallback(ThreadInfoCallBack func)
120 {
121     int32_t currentTid = syscall(SYS_gettid);
122     int32_t firstEmptySlot = -1;
123     int32_t currentThreadSlot = -1;
124     pthread_mutex_lock(&g_signalHandlerMutex);
125     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
126         if (firstEmptySlot == -1 && g_callbackItems[i].tid == -1) {
127             firstEmptySlot = i;
128         }
129 
130         if (g_callbackItems[i].tid == currentTid) {
131             currentThreadSlot = i;
132             break;
133         }
134     }
135 
136     int32_t targetSlot = currentThreadSlot == -1 ? firstEmptySlot : currentThreadSlot;
137     if (targetSlot != -1) {
138         g_callbackItems[targetSlot].tid = func == NULL ? -1 : currentTid;
139         g_callbackItems[targetSlot].callback = func;
140     }
141     pthread_mutex_unlock(&g_signalHandlerMutex);
142 }
143 
GetCallbackLocked()144 static ThreadInfoCallBack GetCallbackLocked()
145 {
146     int32_t currentTid = syscall(SYS_gettid);
147     for (int i = 0; i < CALLBACK_ITEM_COUNT; i++) {
148         if (g_callbackItems[i].tid != currentTid) {
149             continue;
150         }
151 
152         return g_callbackItems[i].callback;
153     }
154     return NULL;
155 }
156 
FillLastFatalMessageLocked(int32_t signo)157 static void FillLastFatalMessageLocked(int32_t signo)
158 {
159     if (signo != SIGABRT) {
160         return;
161     }
162 
163     const char* lastFatalMessage = NULL;
164     if (get_fatal_message != NULL) {
165         fatal_msg_t* fatalMsg = get_fatal_message();
166         lastFatalMessage = fatalMsg == NULL ? NULL : fatalMsg->msg;
167     }
168 
169     if (lastFatalMessage == NULL && GetLastFatalMessage != NULL) {
170         lastFatalMessage = GetLastFatalMessage();
171     }
172 
173     g_request.msg.type = MESSAGE_FATAL;
174     if (strcpy_s(g_request.msg.body, sizeof(g_request.msg.body), lastFatalMessage) != EOK) {
175         DFXLOGE("Last message strcpy fail");
176     }
177 }
178 
FillDebugMessageLocked(int32_t signo,siginfo_t * si)179 static bool FillDebugMessageLocked(int32_t signo, siginfo_t *si)
180 {
181     if (signo != SIGLEAK_STACK || si == NULL ||
182         (si->si_code != SIGLEAK_STACK_FDSAN && si->si_code != SIGLEAK_STACK_JEMALLOC)) {
183         return true;
184     }
185 
186     // The pointer received by the Linux kernel must be NULL
187     debug_msg_t *dMsg = (debug_msg_t*)si->si_value.sival_ptr;
188     if (dMsg == NULL || g_request.timeStamp > dMsg->timestamp + PROCESSDUMP_TIMEOUT * NUMBER_ONE_THOUSAND) {
189         DFXLOGE("The event has timed out since it was triggered");
190         return false;
191     }
192     return true;
193 }
194 
IsDumpSignal(int signo)195 static bool IsDumpSignal(int signo)
196 {
197     return signo == SIGDUMP || signo == SIGLEAK_STACK;
198 }
GetDumpType(int signo,siginfo_t * si)199 static enum ProcessDumpType GetDumpType(int signo, siginfo_t *si)
200 {
201     if (signo == SIGDUMP) {
202         return DUMP_TYPE_DUMP_CATCH;
203     } else if (signo == SIGLEAK_STACK) {
204         switch (si->si_code) {
205             case SIGLEAK_STACK_FDSAN:
206                 return DUMP_TYPE_FDSAN;
207             case SIGLEAK_STACK_JEMALLOC:
208                 return DUMP_TYPE_JEMALLOC;
209             case SIGLEAK_STACK_COREDUMP:
210                 return DUMP_TYPE_COREDUMP;
211             case SIGLEAK_STACK_BADFD:
212                 return DUMP_TYPE_BADFD;
213             default:
214                 return DUMP_TYPE_MEM_LEAK;
215         }
216     } else {
217         return DUMP_TYPE_CPP_CRASH;
218     }
219 }
220 
FillDumpRequest(int signo,siginfo_t * si,void * context)221 static bool FillDumpRequest(int signo, siginfo_t *si, void *context)
222 {
223     (void)memset_s(&g_request, sizeof(g_request), 0, sizeof(g_request));
224     g_request.type = GetDumpType(signo, si);
225     g_request.pid = GetRealPid();
226     g_request.nsPid = syscall(SYS_getpid);
227     g_request.tid = syscall(SYS_gettid);
228     g_request.uid = getuid();
229     g_request.reserved = 0;
230     g_request.timeStamp = GetTimeMilliseconds();
231     g_request.fdTableAddr = (uint64_t)fdsan_get_fd_table();
232     if (memcpy_s(g_request.appRunningId, sizeof(g_request.appRunningId),
233                  g_appRunningId, sizeof(g_appRunningId)) != EOK) {
234         DFXLOGE("FillDumpRequest appRunningId memcpy fail!");
235     }
236     if (!IsDumpSignal(signo) && g_getStackIdCallback != NULL) {
237         g_request.stackId = g_getStackIdCallback();
238         DFXLOGI("g_GetStackIdFunc %{private}p.", (void*)g_request.stackId);
239     }
240     GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
241     GetProcessName(g_request.processName, sizeof(g_request.processName));
242     (void)memcpy_s(&(g_request.siginfo), sizeof(siginfo_t), si, sizeof(siginfo_t));
243     (void)memcpy_s(&(g_request.context), sizeof(ucontext_t), context, sizeof(ucontext_t));
244 
245     bool ret = true;
246     switch (signo) {
247         case SIGABRT:
248             FillLastFatalMessageLocked(signo);
249             break;
250         case SIGLEAK_STACK:
251             ret = FillDebugMessageLocked(signo, si);
252             AT_FALLTHROUGH;
253         default: {
254             ThreadInfoCallBack callback = GetCallbackLocked();
255             if (callback != NULL) {
256                 DFXLOGI("Start collect crash thread info.");
257                 g_request.msg.type = MESSAGE_CALLBACK;
258                 callback(g_request.msg.body, sizeof(g_request.msg.body), context);
259                 DFXLOGI("Finish collect crash thread info.");
260             }
261             break;
262         }
263     }
264     g_request.crashObj = (uintptr_t)pthread_getspecific(g_crashObjKey);
265     g_request.crashLogConfig = g_crashLogConfig;
266     return ret;
267 }
268 
269 static const int SIGCHAIN_DUMP_SIGNAL_LIST[] = {
270     SIGDUMP, SIGLEAK_STACK
271 };
272 
273 static const int SIGCHAIN_CRASH_SIGNAL_LIST[] = {
274     SIGILL, SIGABRT, SIGBUS, SIGFPE,
275     SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
276 };
277 
ResetAndRethrowSignalIfNeed(int signo,siginfo_t * si)278 static void ResetAndRethrowSignalIfNeed(int signo, siginfo_t *si)
279 {
280     if (IsDumpSignal(signo)) {
281         return;
282     }
283 
284     if (g_oldSigactionList[signo].sa_sigaction == NULL) {
285         signal(signo, SIG_DFL);
286     } else if (sigaction(signo, &(g_oldSigactionList[signo]), NULL) != 0) {
287         DFXLOGE("Failed to reset signo(%{public}d).", signo);
288         signal(signo, SIG_DFL);
289     }
290 
291     if (syscall(SYS_rt_tgsigqueueinfo, syscall(SYS_getpid), syscall(SYS_gettid), signo, si) != 0) {
292         DFXLOGE("Failed to rethrow signo(%{public}d), errno(%{public}d).", signo, errno);
293     } else {
294         DFXLOGI("Current process(%{public}ld) rethrow signo(%{public}d).", syscall(SYS_getpid), signo);
295     }
296 }
297 
DumpRequest(int signo)298 static void DumpRequest(int signo)
299 {
300     DfxDumpRequest(signo, &g_request);
301 }
302 
DFX_SigchainHandler(int signo,siginfo_t * si,void * context)303 static bool DFX_SigchainHandler(int signo, siginfo_t *si, void *context)
304 {
305     int pid = syscall(SYS_getpid);
306     int tid = syscall(SYS_gettid);
307     if (si == NULL) {
308         return IsDumpSignal(signo);
309     }
310 
311     DFXLOGI("DFX_SigchainHandler :: signo(%{public}d), si_code(%{public}d), pid(%{public}d), tid(%{public}d).",
312             signo, si->si_code, pid, tid);
313     if (signo == SIGDUMP) {
314         if (si->si_code != DUMP_TYPE_REMOTE && si->si_code != DUMP_TYPE_REMOTE_JSON) {
315             DFXLOGW("DFX_SigchainHandler :: signo(%{public}d:%{public}d) is not remote dump type, return directly",
316                 signo, si->si_code);
317             return IsDumpSignal(signo);
318         }
319     }
320 
321     // crash signal should never be skipped
322     pthread_mutex_lock(&g_signalHandlerMutex);
323     if (!IsDumpSignal(g_prevHandledSignal)) {
324         pthread_mutex_unlock(&g_signalHandlerMutex);
325         return IsDumpSignal(signo);
326     }
327     g_prevHandledSignal = signo;
328 
329     if (!FillDumpRequest(signo, si, context)) {
330         pthread_mutex_unlock(&g_signalHandlerMutex);
331         DFXLOGE("DFX_SigchainHandler :: signal(%{public}d) in %{public}d:%{public}d fill dump request faild.",
332             signo, g_request.pid, g_request.tid);
333         return IsDumpSignal(signo);
334     }
335     DFXLOGI("DFX_SigchainHandler :: signo(%{public}d), pid(%{public}d), processName(%{public}s), " \
336         "threadName(%{public}s).", signo, g_request.pid, g_request.processName, g_request.threadName);
337     DumpRequest(signo);
338     pthread_mutex_unlock(&g_signalHandlerMutex);
339     DFXLOGI("Finish handle signal(%{public}d) in %{public}d:%{public}d.", signo, g_request.pid, g_request.tid);
340     return IsDumpSignal(signo);
341 }
342 
DFX_SignalHandler(int signo,siginfo_t * si,void * context)343 static void DFX_SignalHandler(int signo, siginfo_t *si, void *context)
344 {
345     DFX_SigchainHandler(signo, si, context);
346     ResetAndRethrowSignalIfNeed(signo, si);
347 }
348 
InstallSigActionHandler(int signo)349 static void InstallSigActionHandler(int signo)
350 {
351     struct sigaction action;
352     (void)memset_s(&action, sizeof(action), 0, sizeof(action));
353     (void)memset_s(&g_oldSigactionList, sizeof(g_oldSigactionList), 0, sizeof(g_oldSigactionList));
354     sigfillset(&action.sa_mask);
355     action.sa_sigaction = DFX_SignalHandler;
356     action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
357     if (sigaction(signo, &action, &(g_oldSigactionList[signo])) != 0) {
358         DFXLOGE("Failed to register signal(%{public}d)", signo);
359     }
360 }
361 
DFX_InstallSignalHandler(void)362 static void DFX_InstallSignalHandler(void)
363 {
364     if (g_hasInit) {
365         return;
366     }
367 
368     InitCallbackItems();
369     struct signal_chain_action sigchain = {
370         .sca_sigaction = DFX_SigchainHandler,
371         .sca_mask = {},
372         .sca_flags = 0,
373     };
374 
375     for (size_t i = 0; i < sizeof(SIGCHAIN_DUMP_SIGNAL_LIST) / sizeof(SIGCHAIN_DUMP_SIGNAL_LIST[0]); i++) {
376         int32_t signo = SIGCHAIN_DUMP_SIGNAL_LIST[i];
377         if (signo == SIGLEAK_STACK) {
378             InstallSigActionHandler(signo);
379             continue;
380         }
381         sigfillset(&sigchain.sca_mask);
382         // dump signal not mask crash signal
383         for (size_t j = 0; j < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); j++) {
384             sigdelset(&sigchain.sca_mask, SIGCHAIN_CRASH_SIGNAL_LIST[j]);
385         }
386         add_special_signal_handler(signo, &sigchain);
387     }
388     for (size_t i = 0; i < sizeof(SIGCHAIN_CRASH_SIGNAL_LIST) / sizeof(SIGCHAIN_CRASH_SIGNAL_LIST[0]); i++) {
389         int32_t signo = SIGCHAIN_CRASH_SIGNAL_LIST[i];
390         if (signo == SIGILL || signo == SIGSYS) {
391             InstallSigActionHandler(signo);
392         } else {
393             sigfillset(&sigchain.sca_mask);
394             add_special_handler_at_last(signo, &sigchain);
395         }
396     }
397 
398     g_hasInit = TRUE;
399     if (pthread_key_create(&g_crashObjKey, NULL) == 0) {
400         g_crashObjInit = true;
401     }
402 }
403 
DFX_GetAppRunningUniqueId(void)404 const char* DFX_GetAppRunningUniqueId(void)
405 {
406     return g_appRunningId;
407 }
408 
DFX_SetAppRunningUniqueId(const char * appRunningId,size_t len)409 int DFX_SetAppRunningUniqueId(const char* appRunningId, size_t len)
410 {
411     (void)memset_s(g_appRunningId, sizeof(g_appRunningId), 0, sizeof(g_appRunningId));
412     if (memcpy_s(g_appRunningId, sizeof(g_appRunningId) - 1, appRunningId, len) != EOK) {
413         DFXLOGE("param error. appRunningId is NULL or length overflow");
414         return -1;
415     }
416     return 0;
417 }
418 
DFX_SetCrashObj(uint8_t type,uintptr_t addr)419 uintptr_t DFX_SetCrashObj(uint8_t type, uintptr_t addr)
420 {
421     if (!g_crashObjInit) {
422         return 0;
423     }
424 #if defined __LP64__
425     uintptr_t origin = (uintptr_t)pthread_getspecific(g_crashObjKey);
426     uintptr_t crashObj = 0;
427     const int moveBit = 56;
428     crashObj = ((uintptr_t)type << moveBit) | (addr & 0x00ffffffffffffff);
429     pthread_setspecific(g_crashObjKey, (void*)(crashObj));
430     return origin;
431 #else
432     return 0;
433 #endif
434 }
435 
DFX_ResetCrashObj(uintptr_t crashObj)436 void DFX_ResetCrashObj(uintptr_t crashObj)
437 {
438     if (!g_crashObjInit) {
439         return;
440     }
441 #if defined __LP64__
442     pthread_setspecific(g_crashObjKey, (void*)(crashObj));
443 #endif
444 }
445 
DFX_SetCrashLogConfig(uint8_t type,uint32_t value)446 int DFX_SetCrashLogConfig(uint8_t type, uint32_t value)
447 {
448     if (!g_hasInit) {
449         errno = EPERM;
450         return -1;
451     }
452     if ((type == EXTEND_PRINT_PC_LR || type == SIMPLIFY_PRINT_MAPS) && value > 1) {
453         DFXLOGE("invalid value %{public}u", value);
454         errno = EINVAL;
455         return -1;
456     }
457     const uint64_t extendPrintPcLrMask = 0xfffffffffffffffe;
458     const int moveBit = 32;
459     const uint64_t cutOffLogMask = 0xffffffff;
460     const uint64_t simplifyVmaMask = 0xfffffffffffffffd;
461     switch (type) {
462         case EXTEND_PRINT_PC_LR:
463             g_crashLogConfig = (g_crashLogConfig & extendPrintPcLrMask) + value;
464             break;
465         case CUT_OFF_LOG_FILE:
466             g_crashLogConfig = ((uint64_t)value << moveBit) + (g_crashLogConfig & cutOffLogMask);
467             break;
468         case SIMPLIFY_PRINT_MAPS:
469             g_crashLogConfig = (g_crashLogConfig & simplifyVmaMask) + (value << 1);
470             break;
471         default:
472             errno = EINVAL;
473             return -1;
474     }
475     return 0;
476 }
477