1 /*
2  * Copyright (c) 2021 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 "faultlog_formatter.h"
16 
17 #include <cstdint>
18 #include <fstream>
19 #include <list>
20 #include "parameters.h"
21 #include <sstream>
22 #include <string>
23 #include <unistd.h>
24 
25 #include "faultlog_info.h"
26 #include "faultlog_util.h"
27 #include "file_util.h"
28 #include "string_util.h"
29 
30 namespace OHOS {
31 namespace HiviewDFX {
32 namespace FaultLogger {
33 constexpr int LOG_MAP_KEY = 0;
34 constexpr int LOG_MAP_VALUE = 1;
35 static const char *DEVICE_INFO[] = {"DEVICE_INFO", "Device info:"};
36 static const char *BUILD_INFO[] = {"BUILD_INFO", "Build info:"};
37 static const char *MODULE_NAME[] = {"MODULE", "Module name:"};
38 static const char *PROCESS_NAME[] = {"PNAME", "Process name:"};
39 static const char *MODULE_PID[] = {"PID", "Pid:"};
40 static const char *MODULE_UID[] = {"UID", "Uid:"};
41 static const char *MODULE_VERSION[] = {"VERSION", "Version:"};
42 static const char *FAULT_TYPE[] = {"FAULT_TYPE", "Fault type:"};
43 static const char *SYSVMTYPE[] = {"SYSVMTYPE", "SYSVMTYPE:"};
44 static const char *APPVMTYPE[] = {"APPVMTYPE", "APPVMTYPE:"};
45 static const char *FOREGROUND[] = {"FOREGROUND", "Foreground:"};
46 static const char *LIFETIME[] = {"LIFETIME", "Up time:"};
47 static const char *REASON[] = {"REASON", "Reason:"};
48 static const char *FAULT_MESSAGE[] = {"FAULT_MESSAGE", "Fault message:"};
49 static const char *STACKTRACE[] = {"TRUSTSTACK", "Selected stacktrace:\n"};
50 static const char *ROOT_CAUSE[] = {"BINDERMAX", "Blocked chain:\n"};
51 static const char *MSG_QUEUE_INFO[] = {"MSG_QUEUE_INFO", "Message queue info:\n"};
52 static const char *BINDER_TRANSACTION_INFO[] = {"BINDER_TRANSACTION_INFO", "Binder transaction info:\n"};
53 static const char *PROCESS_STACKTRACE[] = {"PROCESS_STACKTRACE", "Process stacktrace:\n"};
54 static const char *OTHER_THREAD_INFO[] = {"OTHER_THREAD_INFO", "Other thread info:\n"};
55 static const char *KEY_THREAD_INFO[] = {"KEY_THREAD_INFO", "Fault thread info:\n"};
56 static const char *KEY_THREAD_REGISTERS[] = {"KEY_THREAD_REGISTERS", "Registers:\n"};
57 static const char *MEMORY_USAGE[] = {"MEM_USAGE", "Memory Usage:\n"};
58 static const char *CPU_USAGE[] = {"FAULTCPU", "CPU Usage:"};
59 static const char *TRACE_ID[] = {"TRACEID", "Trace-Id:"};
60 static const char *SUMMARY[] = {"SUMMARY", "Summary:\n"};
61 static const char *TIMESTAMP[] = {"TIMESTAMP", "Timestamp:"};
62 static const char *MEMORY_NEAR_REGISTERS[] = {"MEMORY_NEAR_REGISTERS", "Memory near registers:\n"};
63 static const char *PRE_INSTALL[] = {"PRE_INSTALL", "PreInstalled:"};
64 static const char *VERSION_CODE[] = {"VERSION_CODE", "VersionCode:"};
65 static const char *FINGERPRINT[] = {"FINGERPRINT", "Fingerprint:"};
66 static const char *APPEND_ORIGIN_LOG[] = {"APPEND_ORIGIN_LOG", ""};
67 
68 auto CPP_CRASH_LOG_SEQUENCE = {
69     DEVICE_INFO, BUILD_INFO, FINGERPRINT, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
70     PRE_INSTALL, FOREGROUND, APPEND_ORIGIN_LOG, MODULE_PID, MODULE_UID, FAULT_TYPE,
71     SYSVMTYPE, APPVMTYPE, REASON, FAULT_MESSAGE, TRACE_ID, PROCESS_NAME, KEY_THREAD_INFO,
72     SUMMARY, KEY_THREAD_REGISTERS, OTHER_THREAD_INFO, MEMORY_NEAR_REGISTERS
73 };
74 
75 auto JAVASCRIPT_CRASH_LOG_SEQUENCE = {
76     DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
77     PRE_INSTALL, FOREGROUND, MODULE_PID, MODULE_UID, FAULT_TYPE, FAULT_MESSAGE, SYSVMTYPE, APPVMTYPE,
78     LIFETIME, REASON, TRACE_ID, SUMMARY
79 };
80 
81 auto APP_FREEZE_LOG_SEQUENCE = {
82     DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
83     PRE_INSTALL, FOREGROUND, MODULE_PID, MODULE_UID, FAULT_TYPE, SYSVMTYPE,
84     APPVMTYPE, REASON, TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
85     MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY
86 };
87 
88 auto SYS_FREEZE_LOG_SEQUENCE = {
89     DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, FOREGROUND,
90     MODULE_PID, MODULE_UID, FAULT_TYPE, SYSVMTYPE, APPVMTYPE, REASON,
91     TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
92     MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY
93 };
94 
95 auto SYS_WARNING_LOG_SEQUENCE = {
96     DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, FOREGROUND,
97     MODULE_PID, MODULE_UID, FAULT_TYPE, SYSVMTYPE, APPVMTYPE, REASON,
98     TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
99     MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY
100 };
101 
102 auto RUST_PANIC_LOG_SEQUENCE = {
103     DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, MODULE_PID,
104     MODULE_UID,  FAULT_TYPE, FAULT_MESSAGE, APPVMTYPE, REASON, SUMMARY
105 };
106 
107 auto ADDR_SANITIZER_LOG_SEQUENCE = {
108     DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, MODULE_PID,
109     MODULE_UID,  FAULT_TYPE, FAULT_MESSAGE, APPVMTYPE, REASON, SUMMARY
110 };
111 
GetLogParseList(int32_t logType)112 std::list<const char **> GetLogParseList(int32_t logType)
113 {
114     switch (logType) {
115         case FaultLogType::CPP_CRASH:
116             return CPP_CRASH_LOG_SEQUENCE;
117         case FaultLogType::JS_CRASH:
118             return JAVASCRIPT_CRASH_LOG_SEQUENCE;
119         case FaultLogType::APP_FREEZE:
120             return APP_FREEZE_LOG_SEQUENCE;
121         case FaultLogType::SYS_FREEZE:
122             return SYS_FREEZE_LOG_SEQUENCE;
123         case FaultLogType::SYS_WARNING:
124             return SYS_WARNING_LOG_SEQUENCE;
125         case FaultLogType::RUST_PANIC:
126             return RUST_PANIC_LOG_SEQUENCE;
127         case FaultLogType::ADDR_SANITIZER:
128             return ADDR_SANITIZER_LOG_SEQUENCE;
129         default:
130             return std::list<const char **>();
131     }
132 }
133 
GetSummaryByType(int32_t logType,std::map<std::string,std::string> sections)134 std::string GetSummaryByType(int32_t logType, std::map<std::string, std::string> sections)
135 {
136     std::string summary = "";
137     switch (logType) {
138         case FaultLogType::JS_CRASH:
139         case FaultLogType::APP_FREEZE:
140         case FaultLogType::SYS_FREEZE:
141         case FaultLogType::SYS_WARNING:
142             summary = sections[STACKTRACE[LOG_MAP_KEY]];
143             break;
144         case FaultLogType::CPP_CRASH:
145             summary = sections[KEY_THREAD_INFO[LOG_MAP_KEY]];
146             break;
147         case FaultLogType::ADDR_SANITIZER:
148         default:
149             summary = "Could not figure out summary for this fault.";
150             break;
151     }
152 
153     return summary;
154 }
155 
ParseFaultLogLine(const std::list<const char ** > & parseList,const std::string & line,const std::string & multline,std::string & multlineName,FaultLogInfo & info)156 bool ParseFaultLogLine(const std::list<const char **>& parseList, const std::string& line, const std::string& multline,
157     std::string& multlineName, FaultLogInfo& info)
158 {
159     for (auto &item : parseList) {
160         if (strlen(item[LOG_MAP_VALUE]) <= 1) {
161             continue;
162         }
163         std::string sectionHead = item[LOG_MAP_VALUE];
164         sectionHead = sectionHead.back() == '\n' ? sectionHead.substr(0, sectionHead.size() - 1) : sectionHead;
165         if (line.find(sectionHead) != std::string::npos) {
166             if (!line.empty() && line.at(line.size() - 1) == ':') {
167                 if ((item[LOG_MAP_KEY] != multlineName) && (!multline.empty())) {
168                     info.sectionMap[multlineName] = multline;
169                 }
170                 multlineName = item[LOG_MAP_KEY];
171             } else {
172                 info.sectionMap[item[LOG_MAP_KEY]] = line.substr(line.find_first_of(":") + 1);
173             }
174             return false;
175         }
176     }
177     return true;
178 }
179 
WriteStackTraceFromLog(int32_t fd,const std::string & pidStr,const std::string & path)180 void WriteStackTraceFromLog(int32_t fd, const std::string& pidStr, const std::string& path)
181 {
182     std::string realPath;
183     if (!FileUtil::PathToRealPath(path, realPath)) {
184         FileUtil::SaveStringToFd(fd, "Log file not exist.\n");
185         return;
186     }
187 
188     std::ifstream logFile(realPath);
189     std::string line;
190     bool startWrite = false;
191     while (std::getline(logFile, line)) {
192         if (!logFile.good()) {
193             break;
194         }
195 
196         if (line.empty()) {
197             continue;
198         }
199 
200         if ((line.find("----- pid") != std::string::npos) &&
201             (line.find(pidStr) != std::string::npos)) {
202             startWrite = true;
203         }
204 
205         if ((line.find("----- end") != std::string::npos) &&
206             (line.find(pidStr) != std::string::npos)) {
207             FileUtil::SaveStringToFd(fd, line + "\n");
208             break;
209         }
210 
211         if (startWrite) {
212             FileUtil::SaveStringToFd(fd, line + "\n");
213         }
214     }
215 }
216 
WriteDfxLogToFile(int32_t fd)217 void WriteDfxLogToFile(int32_t fd)
218 {
219     std::string dfxStr = std::string("Generated by HiviewDFX@OpenHarmony\n");
220     std::string sepStr = std::string("================================================================\n");
221     FileUtil::SaveStringToFd(fd, dfxStr);
222     FileUtil::SaveStringToFd(fd, sepStr);
223 }
224 
WriteFaultLogToFile(int32_t fd,int32_t logType,std::map<std::string,std::string> sections)225 void WriteFaultLogToFile(int32_t fd, int32_t logType, std::map<std::string, std::string> sections)
226 {
227     std::list<const char **> seq = GetLogParseList(logType);
228     for (auto &item : seq) {
229         auto value = sections[item[LOG_MAP_KEY]];
230         if (!value.empty()) {
231             std::string keyStr = item[LOG_MAP_KEY];
232             if (keyStr.find(APPEND_ORIGIN_LOG[LOG_MAP_KEY]) != std::string::npos) {
233                 if (WriteLogToFile(fd, value)) {
234                     break;
235                 }
236             }
237 
238             // Does not require adding an identifier header for Summary section
239             if (keyStr.find(SUMMARY[LOG_MAP_KEY]) == std::string::npos) {
240                 FileUtil::SaveStringToFd(fd, item[LOG_MAP_VALUE]);
241             }
242 
243             if (value.back() != '\n') {
244                 value.append("\n");
245             }
246             FileUtil::SaveStringToFd(fd, value);
247         }
248     }
249 
250     if (!sections["KEYLOGFILE"].empty()) {
251         FileUtil::SaveStringToFd(fd, "Additional Logs:\n");
252         WriteStackTraceFromLog(fd, sections["PID"], sections["KEYLOGFILE"]);
253     }
254 }
255 
UpdateFaultLogInfoFromTempFile(FaultLogInfo & info)256 static void UpdateFaultLogInfoFromTempFile(FaultLogInfo& info)
257 {
258     if (!info.module.empty()) {
259         return;
260     }
261 
262     StringUtil::ConvertStringTo<int32_t>(info.sectionMap[MODULE_UID[LOG_MAP_KEY]], info.id);
263     info.module = info.sectionMap[PROCESS_NAME[LOG_MAP_KEY]];
264     info.reason = info.sectionMap[REASON[LOG_MAP_KEY]];
265     info.summary = info.sectionMap[KEY_THREAD_INFO[LOG_MAP_KEY]];
266     info.registers = info.sectionMap[KEY_THREAD_REGISTERS[LOG_MAP_KEY]];
267     info.otherThreadInfo = info.sectionMap[OTHER_THREAD_INFO[LOG_MAP_KEY]];
268     size_t removeStartPos = info.summary.find("Tid:");
269     size_t removeEndPos = info.summary.find("Name:");
270     if (removeStartPos != std::string::npos && removeEndPos != std::string::npos) {
271         auto iterator = info.summary.begin() + removeEndPos;
272         while (iterator != info.summary.end() && *iterator != '\n') {
273             if (isdigit(*iterator)) {
274                 iterator = info.summary.erase(iterator);
275             } else {
276                 iterator++;
277             }
278         }
279         info.summary.replace(removeStartPos, removeEndPos - removeStartPos + 1, "Thread n");
280     }
281 }
282 
ParseFaultLogInfoFromFile(const std::string & path,bool isTempFile)283 FaultLogInfo ParseFaultLogInfoFromFile(const std::string &path, bool isTempFile)
284 {
285     auto fileName = FileUtil::ExtractFileName(path);
286     FaultLogInfo info;
287     if (!isTempFile) {
288         info = ExtractInfoFromFileName(fileName);
289     } else {
290         info = ExtractInfoFromTempFile(fileName);
291     }
292 
293     auto parseList = GetLogParseList(info.faultLogType);
294     std::ifstream logFile(path);
295     std::string line;
296     std::string multline;
297     std::string multlineName;
298     while (std::getline(logFile, line)) {
299         if (!logFile.good()) {
300             break;
301         }
302 
303         if (line.empty()) {
304             continue;
305         }
306 
307         if (ParseFaultLogLine(parseList, line, multline, multlineName, info)) {
308             multline.append(line).append("\n");
309         } else {
310             multline.clear();
311         }
312     }
313 
314     if (!multline.empty() && !multlineName.empty()) {
315         info.sectionMap[multlineName] = multline;
316     }
317     UpdateFaultLogInfoFromTempFile(info);
318     return info;
319 }
320 
WriteLogToFile(int32_t fd,const std::string & path)321 bool WriteLogToFile(int32_t fd, const std::string& path)
322 {
323     if ((fd < 0) || path.empty()) {
324         return false;
325     }
326 
327     std::string line;
328     std::ifstream logFile(path);
329     bool hasFindFirstLine = false;
330     while (std::getline(logFile, line)) {
331         if (!logFile.good()) {
332             return false;
333         }
334         if (!hasFindFirstLine && line.find("Build info:") != std::string::npos) {
335             continue;
336         }
337         hasFindFirstLine = true;
338         FileUtil::SaveStringToFd(fd, line);
339         FileUtil::SaveStringToFd(fd, "\n");
340     }
341     return true;
342 }
343 
IsFaultLogLimit()344 bool IsFaultLogLimit()
345 {
346     std::string isDev = OHOS::system::GetParameter("const.security.developermode.state", "");
347     std::string isBeta = OHOS::system::GetParameter("const.logsystem.versiontype", "");
348     if ((isDev == "true") || (isBeta == "beta")) {
349         return false;
350     }
351     return true;
352 }
353 
LimitCppCrashLog(int32_t fd,int32_t logType)354 void LimitCppCrashLog(int32_t fd, int32_t logType)
355 {
356     if ((fd < 0) || (logType != FaultLogType::CPP_CRASH) || !IsFaultLogLimit()) {
357         return;
358     }
359     // The CppCrash file size is limited to 1 MB before reporting CppCrash to AppEvent
360     constexpr int maxLogSize = 1 * 1024 * 1024;
361     off_t endPos = lseek(fd, 0, SEEK_END);
362     if ((endPos == -1) || (endPos <= maxLogSize)) {
363         return;
364     }
365 
366     if (ftruncate(fd, maxLogSize) < 0) {
367         return;
368     }
369     endPos = lseek(fd, maxLogSize, SEEK_SET);
370     if (endPos != -1) {
371         std::string limitOutStr = "\nThe cpp crash log length is " + std::to_string(endPos) +
372             ", which exceeesd the limit of " + std::to_string(maxLogSize) + " and is truncated.\n";
373         FileUtil::SaveStringToFd(fd, limitOutStr);
374     }
375 }
376 } // namespace FaultLogger
377 } // namespace HiviewDFX
378 } // namespace OHOS
379