1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#include "dfx_signal_local_handler.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <securec.h>
19800b99b8Sopenharmony_ci#include <csignal>
20800b99b8Sopenharmony_ci#include <sigchain.h>
21800b99b8Sopenharmony_ci#include <cstdint>
22800b99b8Sopenharmony_ci#include <cstdio>
23800b99b8Sopenharmony_ci#include <unistd.h>
24800b99b8Sopenharmony_ci#include <pthread.h>
25800b99b8Sopenharmony_ci#include <sched.h>
26800b99b8Sopenharmony_ci#include <sys/syscall.h>
27800b99b8Sopenharmony_ci#include <sys/mman.h>
28800b99b8Sopenharmony_ci#include <sys/prctl.h>
29800b99b8Sopenharmony_ci#include <sys/wait.h>
30800b99b8Sopenharmony_ci#include <linux/futex.h>
31800b99b8Sopenharmony_ci#include "dfx_allocator.h"
32800b99b8Sopenharmony_ci#include "dfx_crash_local_handler.h"
33800b99b8Sopenharmony_ci#include "dfx_cutil.h"
34800b99b8Sopenharmony_ci#include "dfx_log.h"
35800b99b8Sopenharmony_ci
36800b99b8Sopenharmony_ci#ifdef LOG_DOMAIN
37800b99b8Sopenharmony_ci#undef LOG_DOMAIN
38800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11
39800b99b8Sopenharmony_ci#endif
40800b99b8Sopenharmony_ci
41800b99b8Sopenharmony_ci#ifdef LOG_TAG
42800b99b8Sopenharmony_ci#undef LOG_TAG
43800b99b8Sopenharmony_ci#define LOG_TAG "DfxSignalLocalHandler"
44800b99b8Sopenharmony_ci#endif
45800b99b8Sopenharmony_ci
46800b99b8Sopenharmony_ci#define LOCAL_HANDLER_STACK_SIZE (128 * 1024) // 128K
47800b99b8Sopenharmony_ci
48800b99b8Sopenharmony_cistatic CrashFdFunc g_crashFdFn = nullptr;
49800b99b8Sopenharmony_cistatic void *g_reservedChildStack = nullptr;
50800b99b8Sopenharmony_cistatic struct ProcessDumpRequest g_request;
51800b99b8Sopenharmony_cistatic pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER;
52800b99b8Sopenharmony_ci
53800b99b8Sopenharmony_cistatic int g_platformSignals[] = {
54800b99b8Sopenharmony_ci    SIGABRT, SIGBUS, SIGILL, SIGSEGV,
55800b99b8Sopenharmony_ci};
56800b99b8Sopenharmony_ci
57800b99b8Sopenharmony_cistatic void ReserveChildThreadSignalStack(void)
58800b99b8Sopenharmony_ci{
59800b99b8Sopenharmony_ci    // reserve stack for fork
60800b99b8Sopenharmony_ci    g_reservedChildStack = mmap(nullptr, LOCAL_HANDLER_STACK_SIZE, \
61800b99b8Sopenharmony_ci        PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 1, 0);
62800b99b8Sopenharmony_ci    if (g_reservedChildStack == MAP_FAILED) {
63800b99b8Sopenharmony_ci        DFXLOGE("[%{public}d]: Failed to alloc memory for child stack.", __LINE__);
64800b99b8Sopenharmony_ci        return;
65800b99b8Sopenharmony_ci    }
66800b99b8Sopenharmony_ci    g_reservedChildStack = static_cast<void *>(static_cast<uint8_t *>(g_reservedChildStack) +
67800b99b8Sopenharmony_ci        LOCAL_HANDLER_STACK_SIZE - 1);
68800b99b8Sopenharmony_ci}
69800b99b8Sopenharmony_ci
70800b99b8Sopenharmony_ciAT_UNUSED static void FutexWait(volatile void* ftx, int value)
71800b99b8Sopenharmony_ci{
72800b99b8Sopenharmony_ci    syscall(__NR_futex, ftx, FUTEX_WAIT, value, NULL, NULL, 0);
73800b99b8Sopenharmony_ci}
74800b99b8Sopenharmony_ci
75800b99b8Sopenharmony_cistatic int DoCrashHandler(void* arg)
76800b99b8Sopenharmony_ci{
77800b99b8Sopenharmony_ci    (void)arg;
78800b99b8Sopenharmony_ci    RegisterAllocator();
79800b99b8Sopenharmony_ci    if (g_crashFdFn == nullptr) {
80800b99b8Sopenharmony_ci        CrashLocalHandler(&g_request);
81800b99b8Sopenharmony_ci    } else {
82800b99b8Sopenharmony_ci        int fd = g_crashFdFn();
83800b99b8Sopenharmony_ci        CrashLocalHandlerFd(fd, &g_request);
84800b99b8Sopenharmony_ci        if (fd >= 0) {
85800b99b8Sopenharmony_ci            close(fd);
86800b99b8Sopenharmony_ci        }
87800b99b8Sopenharmony_ci    }
88800b99b8Sopenharmony_ci    UnregisterAllocator();
89800b99b8Sopenharmony_ci    pthread_mutex_unlock(&g_signalHandlerMutex);
90800b99b8Sopenharmony_ci    syscall(__NR_exit, 0);
91800b99b8Sopenharmony_ci    return 0;
92800b99b8Sopenharmony_ci}
93800b99b8Sopenharmony_ci
94800b99b8Sopenharmony_civoid DFX_SignalLocalHandler(int sig, siginfo_t *si, void *context)
95800b99b8Sopenharmony_ci{
96800b99b8Sopenharmony_ci    pthread_mutex_lock(&g_signalHandlerMutex);
97800b99b8Sopenharmony_ci    (void)memset_s(&g_request, sizeof(g_request), 0, sizeof(g_request));
98800b99b8Sopenharmony_ci    g_request.type = static_cast<ProcessDumpType>(sig);
99800b99b8Sopenharmony_ci    g_request.tid = gettid();
100800b99b8Sopenharmony_ci    g_request.pid = getpid();
101800b99b8Sopenharmony_ci    g_request.uid = getuid();
102800b99b8Sopenharmony_ci    g_request.timeStamp = GetTimeMilliseconds();
103800b99b8Sopenharmony_ci    DFXLOGI("DFX_SignalLocalHandler :: sig(%{public}d), pid(%{public}d), tid(%{public}d).",
104800b99b8Sopenharmony_ci        sig, g_request.pid, g_request.tid);
105800b99b8Sopenharmony_ci
106800b99b8Sopenharmony_ci    GetThreadNameByTid(g_request.tid, g_request.threadName, sizeof(g_request.threadName));
107800b99b8Sopenharmony_ci    GetProcessName(g_request.processName, sizeof(g_request.processName));
108800b99b8Sopenharmony_ci
109800b99b8Sopenharmony_ci    int ret = memcpy_s(&(g_request.siginfo), sizeof(siginfo_t), si, sizeof(siginfo_t));
110800b99b8Sopenharmony_ci    if (ret < 0) {
111800b99b8Sopenharmony_ci        DFXLOGE("memcpy_s siginfo fail, ret=%{public}d", ret);
112800b99b8Sopenharmony_ci    }
113800b99b8Sopenharmony_ci    ret = memcpy_s(&(g_request.context), sizeof(ucontext_t), context, sizeof(ucontext_t));
114800b99b8Sopenharmony_ci    if (ret < 0) {
115800b99b8Sopenharmony_ci        DFXLOGE("memcpy_s context fail, ret=%{public}d", ret);
116800b99b8Sopenharmony_ci    }
117800b99b8Sopenharmony_ci#ifdef __aarch64__
118800b99b8Sopenharmony_ci    DoCrashHandler(NULL);
119800b99b8Sopenharmony_ci#else
120800b99b8Sopenharmony_ci    int pseudothreadTid = -1;
121800b99b8Sopenharmony_ci    pid_t childTid = clone(DoCrashHandler, g_reservedChildStack, \
122800b99b8Sopenharmony_ci        CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, \
123800b99b8Sopenharmony_ci        &pseudothreadTid, NULL, NULL, &pseudothreadTid);
124800b99b8Sopenharmony_ci    if (childTid == -1) {
125800b99b8Sopenharmony_ci        DFXLOGE("Failed to create thread for crash local handler");
126800b99b8Sopenharmony_ci        pthread_mutex_unlock(&g_signalHandlerMutex);
127800b99b8Sopenharmony_ci        return;
128800b99b8Sopenharmony_ci    }
129800b99b8Sopenharmony_ci
130800b99b8Sopenharmony_ci    FutexWait(&pseudothreadTid, -1);
131800b99b8Sopenharmony_ci    FutexWait(&pseudothreadTid, childTid);
132800b99b8Sopenharmony_ci
133800b99b8Sopenharmony_ci    DFXLOGI("child thread(%{public}d) exit.", childTid);
134800b99b8Sopenharmony_ci    syscall(__NR_exit, 0);
135800b99b8Sopenharmony_ci#endif
136800b99b8Sopenharmony_ci}
137800b99b8Sopenharmony_ci
138800b99b8Sopenharmony_civoid DFX_GetCrashFdFunc(CrashFdFunc fn)
139800b99b8Sopenharmony_ci{
140800b99b8Sopenharmony_ci    g_crashFdFn = fn;
141800b99b8Sopenharmony_ci}
142800b99b8Sopenharmony_ci
143800b99b8Sopenharmony_civoid DFX_InstallLocalSignalHandler(void)
144800b99b8Sopenharmony_ci{
145800b99b8Sopenharmony_ci    ReserveChildThreadSignalStack();
146800b99b8Sopenharmony_ci
147800b99b8Sopenharmony_ci    sigset_t set;
148800b99b8Sopenharmony_ci    sigemptyset(&set);
149800b99b8Sopenharmony_ci    struct sigaction action;
150800b99b8Sopenharmony_ci    (void)memset_s(&action, sizeof(action), 0, sizeof(action));
151800b99b8Sopenharmony_ci    sigfillset(&action.sa_mask);
152800b99b8Sopenharmony_ci    action.sa_sigaction = DFX_SignalLocalHandler;
153800b99b8Sopenharmony_ci    action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
154800b99b8Sopenharmony_ci
155800b99b8Sopenharmony_ci    for (size_t i = 0; i < sizeof(g_platformSignals) / sizeof(g_platformSignals[0]); i++) {
156800b99b8Sopenharmony_ci        int32_t sig = g_platformSignals[i];
157800b99b8Sopenharmony_ci        remove_all_special_handler(sig);
158800b99b8Sopenharmony_ci
159800b99b8Sopenharmony_ci        sigaddset(&set, sig);
160800b99b8Sopenharmony_ci        if (sigaction(sig, &action, nullptr) != 0) {
161800b99b8Sopenharmony_ci            DFXLOGE("Failed to register signal(%{public}d)", sig);
162800b99b8Sopenharmony_ci        }
163800b99b8Sopenharmony_ci    }
164800b99b8Sopenharmony_ci    sigprocmask(SIG_UNBLOCK, &set, nullptr);
165800b99b8Sopenharmony_ci}
166