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