1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2022-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#include "dfx_crash_local_handler.h"
16800b99b8Sopenharmony_ci
17800b99b8Sopenharmony_ci#include <securec.h>
18800b99b8Sopenharmony_ci#include <csignal>
19800b99b8Sopenharmony_ci#include <sys/time.h>
20800b99b8Sopenharmony_ci#include <sys/ucontext.h>
21800b99b8Sopenharmony_ci#include <cinttypes>
22800b99b8Sopenharmony_ci#include <unistd.h>
23800b99b8Sopenharmony_ci#include <pthread.h>
24800b99b8Sopenharmony_ci#include <cerrno>
25800b99b8Sopenharmony_ci#include "dfx_log.h"
26800b99b8Sopenharmony_ci#include "dfx_cutil.h"
27800b99b8Sopenharmony_ci#include "dfx_signalhandler_exception.h"
28800b99b8Sopenharmony_ci#include "faultloggerd_client.h"
29800b99b8Sopenharmony_ci#include "unwinder.h"
30800b99b8Sopenharmony_ci
31800b99b8Sopenharmony_ci#ifdef LOG_DOMAIN
32800b99b8Sopenharmony_ci#undef LOG_DOMAIN
33800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11
34800b99b8Sopenharmony_ci#endif
35800b99b8Sopenharmony_ci
36800b99b8Sopenharmony_ci#ifdef LOG_TAG
37800b99b8Sopenharmony_ci#undef LOG_TAG
38800b99b8Sopenharmony_ci#define LOG_TAG "DfxCrashLocalHandler"
39800b99b8Sopenharmony_ci#endif
40800b99b8Sopenharmony_ci
41800b99b8Sopenharmony_ci#define MAX_FRAME 64
42800b99b8Sopenharmony_ci#define BUF_SZ 512
43800b99b8Sopenharmony_ci#define MAPINFO_SIZE 256
44800b99b8Sopenharmony_ci#define TIME_DIV 1000
45800b99b8Sopenharmony_ci#define BUF_SZ_SMALL 256
46800b99b8Sopenharmony_ci
47800b99b8Sopenharmony_cistatic __attribute__((noinline)) int RequestOutputLogFile(const struct ProcessDumpRequest* request)
48800b99b8Sopenharmony_ci{
49800b99b8Sopenharmony_ci    struct FaultLoggerdRequest faultloggerdRequest;
50800b99b8Sopenharmony_ci    (void)memset_s(&faultloggerdRequest, sizeof(faultloggerdRequest), 0, sizeof(struct FaultLoggerdRequest));
51800b99b8Sopenharmony_ci
52800b99b8Sopenharmony_ci    faultloggerdRequest.type = (int32_t)CPP_CRASH;
53800b99b8Sopenharmony_ci    faultloggerdRequest.pid = request->pid;
54800b99b8Sopenharmony_ci    faultloggerdRequest.tid = request->tid;
55800b99b8Sopenharmony_ci    faultloggerdRequest.uid = request->uid;
56800b99b8Sopenharmony_ci    faultloggerdRequest.time = request->timeStamp + 1;
57800b99b8Sopenharmony_ci    return RequestFileDescriptorEx(&faultloggerdRequest);
58800b99b8Sopenharmony_ci}
59800b99b8Sopenharmony_ci
60800b99b8Sopenharmony_cistatic __attribute__((noinline)) void PrintLog(int fd, const char *format, ...)
61800b99b8Sopenharmony_ci{
62800b99b8Sopenharmony_ci    char buf[BUF_SZ] = {0};
63800b99b8Sopenharmony_ci    va_list args;
64800b99b8Sopenharmony_ci    va_start(args, format);
65800b99b8Sopenharmony_ci    int size = vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, args);
66800b99b8Sopenharmony_ci    va_end(args);
67800b99b8Sopenharmony_ci    if (size == -1) {
68800b99b8Sopenharmony_ci        if (fd > 0) {
69800b99b8Sopenharmony_ci            const char* error = "PrintLog vsnprintf_s fail\n";
70800b99b8Sopenharmony_ci            (void)OHOS_TEMP_FAILURE_RETRY(write(fd, error, strlen(error)));
71800b99b8Sopenharmony_ci        }
72800b99b8Sopenharmony_ci        return;
73800b99b8Sopenharmony_ci    }
74800b99b8Sopenharmony_ci    DFXLOGE("%{public}s", buf);
75800b99b8Sopenharmony_ci    if (fd > 0) {
76800b99b8Sopenharmony_ci        (void)OHOS_TEMP_FAILURE_RETRY(write(fd, buf, strlen(buf)));
77800b99b8Sopenharmony_ci    }
78800b99b8Sopenharmony_ci}
79800b99b8Sopenharmony_ci
80800b99b8Sopenharmony_ci__attribute__((noinline)) void CrashLocalUnwind(const int fd, const ucontext_t* uc)
81800b99b8Sopenharmony_ci{
82800b99b8Sopenharmony_ci    if (uc == nullptr) {
83800b99b8Sopenharmony_ci        return;
84800b99b8Sopenharmony_ci    }
85800b99b8Sopenharmony_ci    OHOS::HiviewDFX::Unwinder unwind;
86800b99b8Sopenharmony_ci    unwind.UnwindLocalWithContext(*uc);
87800b99b8Sopenharmony_ci    auto regs = OHOS::HiviewDFX::DfxRegs::CreateFromUcontext(*uc);
88800b99b8Sopenharmony_ci    std::string logContext = unwind.GetFramesStr(unwind.GetFrames()) + regs->PrintRegs();
89800b99b8Sopenharmony_ci    logContext.append("\nMaps:\n");
90800b99b8Sopenharmony_ci    for (const auto &map : unwind.GetMaps()->GetMaps()) {
91800b99b8Sopenharmony_ci        logContext.append(map->ToString());
92800b99b8Sopenharmony_ci    }
93800b99b8Sopenharmony_ci
94800b99b8Sopenharmony_ci    for (unsigned int i = 0; i < logContext.length(); i += BUF_SZ_SMALL) {
95800b99b8Sopenharmony_ci        PrintLog(fd, "%s", logContext.substr(i, BUF_SZ_SMALL).c_str());
96800b99b8Sopenharmony_ci    }
97800b99b8Sopenharmony_ci}
98800b99b8Sopenharmony_ci
99800b99b8Sopenharmony_ci// currently, only stacktrace is logged to faultloggerd
100800b99b8Sopenharmony_civoid CrashLocalHandler(const struct ProcessDumpRequest* request)
101800b99b8Sopenharmony_ci{
102800b99b8Sopenharmony_ci    int fd = RequestOutputLogFile(request);
103800b99b8Sopenharmony_ci    CrashLocalHandlerFd(fd, request);
104800b99b8Sopenharmony_ci    if (fd >= 0) {
105800b99b8Sopenharmony_ci        close(fd);
106800b99b8Sopenharmony_ci    }
107800b99b8Sopenharmony_ci}
108800b99b8Sopenharmony_ci
109800b99b8Sopenharmony_cistatic void PrintTimeStamp(const int fd)
110800b99b8Sopenharmony_ci{
111800b99b8Sopenharmony_ci    uint64_t currentTime = GetTimeMilliseconds();
112800b99b8Sopenharmony_ci    char secBuf[BUF_SZ] = {0};
113800b99b8Sopenharmony_ci    char printBuf[BUF_SZ] = {0};
114800b99b8Sopenharmony_ci    time_t sec = static_cast<time_t>(currentTime / TIME_DIV);
115800b99b8Sopenharmony_ci    uint64_t millisec = currentTime % TIME_DIV;
116800b99b8Sopenharmony_ci    struct tm* t = localtime(&sec);
117800b99b8Sopenharmony_ci    if (!t) {
118800b99b8Sopenharmony_ci        return;
119800b99b8Sopenharmony_ci    }
120800b99b8Sopenharmony_ci    (void)strftime(secBuf, sizeof(secBuf) - 1, "%Y-%m-%d %H:%M:%S", t);
121800b99b8Sopenharmony_ci    if (snprintf_s(printBuf, sizeof(printBuf), sizeof(printBuf) - 1,
122800b99b8Sopenharmony_ci            "%s.%03" PRIx64 "\n", secBuf, millisec) < 0) {
123800b99b8Sopenharmony_ci        DFXLOGE("snprintf timestamp fail");
124800b99b8Sopenharmony_ci        return;
125800b99b8Sopenharmony_ci    }
126800b99b8Sopenharmony_ci    PrintLog(fd, "Timestamp:%s", printBuf);
127800b99b8Sopenharmony_ci}
128800b99b8Sopenharmony_ci
129800b99b8Sopenharmony_cistatic void ReportToHiview(const char* logPath, const struct ProcessDumpRequest* request)
130800b99b8Sopenharmony_ci{
131800b99b8Sopenharmony_ci    struct CrashDumpException exception;
132800b99b8Sopenharmony_ci    (void)memset_s(&exception, sizeof(struct CrashDumpException), 0, sizeof(struct CrashDumpException));
133800b99b8Sopenharmony_ci    exception.pid = request->pid;
134800b99b8Sopenharmony_ci    exception.uid = request->uid;
135800b99b8Sopenharmony_ci    exception.error = CRASH_DUMP_LOCAL_REPORT;
136800b99b8Sopenharmony_ci    exception.time = static_cast<int64_t>(GetTimeMilliseconds());
137800b99b8Sopenharmony_ci    if (strncpy_s(exception.message, sizeof(exception.message) - 1, logPath, strlen(logPath)) != 0) {
138800b99b8Sopenharmony_ci        DFXLOGE("strcpy exception msg fail");
139800b99b8Sopenharmony_ci        return;
140800b99b8Sopenharmony_ci    }
141800b99b8Sopenharmony_ci    ReportException(exception);
142800b99b8Sopenharmony_ci}
143800b99b8Sopenharmony_ci
144800b99b8Sopenharmony_civoid CrashLocalHandlerFd(const int fd, const struct ProcessDumpRequest* request)
145800b99b8Sopenharmony_ci{
146800b99b8Sopenharmony_ci    if (request == nullptr) {
147800b99b8Sopenharmony_ci        return;
148800b99b8Sopenharmony_ci    }
149800b99b8Sopenharmony_ci    PrintTimeStamp(fd);
150800b99b8Sopenharmony_ci    PrintLog(fd, "Pid:%d\n", request->pid);
151800b99b8Sopenharmony_ci    PrintLog(fd, "Uid:%d\n", request->uid);
152800b99b8Sopenharmony_ci    PrintLog(fd, "Process name:%s\n", request->processName);
153800b99b8Sopenharmony_ci#if defined(__LP64__)
154800b99b8Sopenharmony_ci    PrintLog(fd, "Reason:Signal(%d)@%018p\n", request->siginfo.si_signo, request->siginfo.si_addr);
155800b99b8Sopenharmony_ci#else
156800b99b8Sopenharmony_ci    PrintLog(fd, "Reason:Signal(%d)@%010p\n", request->siginfo.si_signo, request->siginfo.si_addr);
157800b99b8Sopenharmony_ci#endif
158800b99b8Sopenharmony_ci    PrintLog(fd, "Fault thread info:\n");
159800b99b8Sopenharmony_ci    PrintLog(fd, "Tid:%d, Name:%s\n", request->tid, request->threadName);
160800b99b8Sopenharmony_ci    CrashLocalUnwind(fd, &(request->context));
161800b99b8Sopenharmony_ci    char logFileName[BUF_SZ] = {0};
162800b99b8Sopenharmony_ci    if (snprintf_s(logFileName, sizeof(logFileName), sizeof(logFileName) - 1,
163800b99b8Sopenharmony_ci        "/data/log/faultlog/temp/cppcrash-%d-%llu", request->pid, request->timeStamp + 1) < 0) {
164800b99b8Sopenharmony_ci        DFXLOGE("snprintf logFileName fail");
165800b99b8Sopenharmony_ci        return;
166800b99b8Sopenharmony_ci    }
167800b99b8Sopenharmony_ci    ReportToHiview(logFileName, request);
168800b99b8Sopenharmony_ci}
169