1 /*
2  * Copyright (c) 2022-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 #include "dfx_crash_local_handler.h"
16 
17 #include <securec.h>
18 #include <csignal>
19 #include <sys/time.h>
20 #include <sys/ucontext.h>
21 #include <cinttypes>
22 #include <unistd.h>
23 #include <pthread.h>
24 #include <cerrno>
25 #include "dfx_log.h"
26 #include "dfx_cutil.h"
27 #include "dfx_signalhandler_exception.h"
28 #include "faultloggerd_client.h"
29 #include "unwinder.h"
30 
31 #ifdef LOG_DOMAIN
32 #undef LOG_DOMAIN
33 #define LOG_DOMAIN 0xD002D11
34 #endif
35 
36 #ifdef LOG_TAG
37 #undef LOG_TAG
38 #define LOG_TAG "DfxCrashLocalHandler"
39 #endif
40 
41 #define MAX_FRAME 64
42 #define BUF_SZ 512
43 #define MAPINFO_SIZE 256
44 #define TIME_DIV 1000
45 #define BUF_SZ_SMALL 256
46 
RequestOutputLogFile(const struct ProcessDumpRequest* request)47 static __attribute__((noinline)) int RequestOutputLogFile(const struct ProcessDumpRequest* request)
48 {
49     struct FaultLoggerdRequest faultloggerdRequest;
50     (void)memset_s(&faultloggerdRequest, sizeof(faultloggerdRequest), 0, sizeof(struct FaultLoggerdRequest));
51 
52     faultloggerdRequest.type = (int32_t)CPP_CRASH;
53     faultloggerdRequest.pid = request->pid;
54     faultloggerdRequest.tid = request->tid;
55     faultloggerdRequest.uid = request->uid;
56     faultloggerdRequest.time = request->timeStamp + 1;
57     return RequestFileDescriptorEx(&faultloggerdRequest);
58 }
59 
PrintLog(int fd, const char *format, ...)60 static __attribute__((noinline)) void PrintLog(int fd, const char *format, ...)
61 {
62     char buf[BUF_SZ] = {0};
63     va_list args;
64     va_start(args, format);
65     int size = vsnprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, args);
66     va_end(args);
67     if (size == -1) {
68         if (fd > 0) {
69             const char* error = "PrintLog vsnprintf_s fail\n";
70             (void)OHOS_TEMP_FAILURE_RETRY(write(fd, error, strlen(error)));
71         }
72         return;
73     }
74     DFXLOGE("%{public}s", buf);
75     if (fd > 0) {
76         (void)OHOS_TEMP_FAILURE_RETRY(write(fd, buf, strlen(buf)));
77     }
78 }
79 
CrashLocalUnwind(const int fd, const ucontext_t* uc)80 __attribute__((noinline)) void CrashLocalUnwind(const int fd, const ucontext_t* uc)
81 {
82     if (uc == nullptr) {
83         return;
84     }
85     OHOS::HiviewDFX::Unwinder unwind;
86     unwind.UnwindLocalWithContext(*uc);
87     auto regs = OHOS::HiviewDFX::DfxRegs::CreateFromUcontext(*uc);
88     std::string logContext = unwind.GetFramesStr(unwind.GetFrames()) + regs->PrintRegs();
89     logContext.append("\nMaps:\n");
90     for (const auto &map : unwind.GetMaps()->GetMaps()) {
91         logContext.append(map->ToString());
92     }
93 
94     for (unsigned int i = 0; i < logContext.length(); i += BUF_SZ_SMALL) {
95         PrintLog(fd, "%s", logContext.substr(i, BUF_SZ_SMALL).c_str());
96     }
97 }
98 
99 // currently, only stacktrace is logged to faultloggerd
CrashLocalHandler(const struct ProcessDumpRequest* request)100 void CrashLocalHandler(const struct ProcessDumpRequest* request)
101 {
102     int fd = RequestOutputLogFile(request);
103     CrashLocalHandlerFd(fd, request);
104     if (fd >= 0) {
105         close(fd);
106     }
107 }
108 
PrintTimeStamp(const int fd)109 static void PrintTimeStamp(const int fd)
110 {
111     uint64_t currentTime = GetTimeMilliseconds();
112     char secBuf[BUF_SZ] = {0};
113     char printBuf[BUF_SZ] = {0};
114     time_t sec = static_cast<time_t>(currentTime / TIME_DIV);
115     uint64_t millisec = currentTime % TIME_DIV;
116     struct tm* t = localtime(&sec);
117     if (!t) {
118         return;
119     }
120     (void)strftime(secBuf, sizeof(secBuf) - 1, "%Y-%m-%d %H:%M:%S", t);
121     if (snprintf_s(printBuf, sizeof(printBuf), sizeof(printBuf) - 1,
122             "%s.%03" PRIx64 "\n", secBuf, millisec) < 0) {
123         DFXLOGE("snprintf timestamp fail");
124         return;
125     }
126     PrintLog(fd, "Timestamp:%s", printBuf);
127 }
128 
ReportToHiview(const char* logPath, const struct ProcessDumpRequest* request)129 static void ReportToHiview(const char* logPath, const struct ProcessDumpRequest* request)
130 {
131     struct CrashDumpException exception;
132     (void)memset_s(&exception, sizeof(struct CrashDumpException), 0, sizeof(struct CrashDumpException));
133     exception.pid = request->pid;
134     exception.uid = request->uid;
135     exception.error = CRASH_DUMP_LOCAL_REPORT;
136     exception.time = static_cast<int64_t>(GetTimeMilliseconds());
137     if (strncpy_s(exception.message, sizeof(exception.message) - 1, logPath, strlen(logPath)) != 0) {
138         DFXLOGE("strcpy exception msg fail");
139         return;
140     }
141     ReportException(exception);
142 }
143 
CrashLocalHandlerFd(const int fd, const struct ProcessDumpRequest* request)144 void CrashLocalHandlerFd(const int fd, const struct ProcessDumpRequest* request)
145 {
146     if (request == nullptr) {
147         return;
148     }
149     PrintTimeStamp(fd);
150     PrintLog(fd, "Pid:%d\n", request->pid);
151     PrintLog(fd, "Uid:%d\n", request->uid);
152     PrintLog(fd, "Process name:%s\n", request->processName);
153 #if defined(__LP64__)
154     PrintLog(fd, "Reason:Signal(%d)@%018p\n", request->siginfo.si_signo, request->siginfo.si_addr);
155 #else
156     PrintLog(fd, "Reason:Signal(%d)@%010p\n", request->siginfo.si_signo, request->siginfo.si_addr);
157 #endif
158     PrintLog(fd, "Fault thread info:\n");
159     PrintLog(fd, "Tid:%d, Name:%s\n", request->tid, request->threadName);
160     CrashLocalUnwind(fd, &(request->context));
161     char logFileName[BUF_SZ] = {0};
162     if (snprintf_s(logFileName, sizeof(logFileName), sizeof(logFileName) - 1,
163         "/data/log/faultlog/temp/cppcrash-%d-%llu", request->pid, request->timeStamp + 1) < 0) {
164         DFXLOGE("snprintf logFileName fail");
165         return;
166     }
167     ReportToHiview(logFileName, request);
168 }
169