• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 CANGJIE_ERROR_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, FAULT_MESSAGE, SYSVMTYPE, APPVMTYPE,
85     LIFETIME, REASON, TRACE_ID, SUMMARY
86 };
87 
88 auto APP_FREEZE_LOG_SEQUENCE = {
89     DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
90     PRE_INSTALL, FOREGROUND, MODULE_PID, MODULE_UID, FAULT_TYPE, SYSVMTYPE,
91     APPVMTYPE, REASON, TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
92     MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY
93 };
94 
95 auto SYS_FREEZE_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 SYS_WARNING_LOG_SEQUENCE = {
103     DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, FOREGROUND,
104     MODULE_PID, MODULE_UID, FAULT_TYPE, SYSVMTYPE, APPVMTYPE, REASON,
105     TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
106     MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY
107 };
108 
109 auto RUST_PANIC_LOG_SEQUENCE = {
110     DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, MODULE_PID,
111     MODULE_UID, FAULT_TYPE, FAULT_MESSAGE, APPVMTYPE, REASON, SUMMARY
112 };
113 
114 auto ADDR_SANITIZER_LOG_SEQUENCE = {
115     DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, MODULE_PID,
116     MODULE_UID, FAULT_TYPE, FAULT_MESSAGE, APPVMTYPE, REASON, SUMMARY
117 };
118 }
GetLogParseList(int32_t logType)119 std::list<const char* const*> GetLogParseList(int32_t logType)
120 {
121     switch (logType) {
122         case FaultLogType::CPP_CRASH:
123             return CPP_CRASH_LOG_SEQUENCE;
124         case FaultLogType::JS_CRASH:
125             return JAVASCRIPT_CRASH_LOG_SEQUENCE;
126         case FaultLogType::CJ_ERROR:
127             return CANGJIE_ERROR_LOG_SEQUENCE;
128         case FaultLogType::APP_FREEZE:
129             return APP_FREEZE_LOG_SEQUENCE;
130         case FaultLogType::SYS_FREEZE:
131             return SYS_FREEZE_LOG_SEQUENCE;
132         case FaultLogType::SYS_WARNING:
133             return SYS_WARNING_LOG_SEQUENCE;
134         case FaultLogType::RUST_PANIC:
135             return RUST_PANIC_LOG_SEQUENCE;
136         case FaultLogType::ADDR_SANITIZER:
137             return ADDR_SANITIZER_LOG_SEQUENCE;
138         default:
139             return {};
140     }
141 }
142 
GetSummaryByType(int32_t logType,std::map<std::string,std::string> sections)143 std::string GetSummaryByType(int32_t logType, std::map<std::string, std::string> sections)
144 {
145     std::string summary = "";
146     switch (logType) {
147         case FaultLogType::JS_CRASH:
148         case FaultLogType::APP_FREEZE:
149         case FaultLogType::SYS_FREEZE:
150         case FaultLogType::SYS_WARNING:
151             summary = sections[STACKTRACE[LOG_MAP_KEY]];
152             break;
153         case FaultLogType::CPP_CRASH:
154             summary = sections[KEY_THREAD_INFO[LOG_MAP_KEY]];
155             break;
156         case FaultLogType::ADDR_SANITIZER:
157         default:
158             summary = "Could not figure out summary for this fault.";
159             break;
160     }
161 
162     return summary;
163 }
164 
ParseFaultLogLine(const std::list<const char * const * > & parseList,const std::string & line,const std::string & multline,std::string & multlineName,FaultLogInfo & info)165 bool ParseFaultLogLine(const std::list<const char* const*>& parseList, const std::string& line,
166     const std::string& multline, std::string& multlineName, FaultLogInfo& info)
167 {
168     for (auto &item : parseList) {
169         if (strlen(item[LOG_MAP_VALUE]) <= 1) {
170             continue;
171         }
172         std::string sectionHead = item[LOG_MAP_VALUE];
173         sectionHead = sectionHead.back() == '\n' ? sectionHead.substr(0, sectionHead.size() - 1) : sectionHead;
174         if (line.find(sectionHead) == std::string::npos) {
175             continue;
176         }
177         if (!line.empty() && line.at(line.size() - 1) == ':') {
178             if ((item[LOG_MAP_KEY] != multlineName) && (!multline.empty())) {
179                 info.sectionMap[multlineName] = multline;
180             }
181             multlineName = item[LOG_MAP_KEY];
182         } else {
183             info.sectionMap[item[LOG_MAP_KEY]] = line.substr(line.find_first_of(":") + 1);
184         }
185         return false;
186     }
187     return true;
188 }
189 
WriteStackTraceFromLog(int32_t fd,const std::string & pidStr,const std::string & path)190 void WriteStackTraceFromLog(int32_t fd, const std::string& pidStr, const std::string& path)
191 {
192     std::string realPath;
193     if (!FileUtil::PathToRealPath(path, realPath)) {
194         FileUtil::SaveStringToFd(fd, "Log file not exist.\n");
195         return;
196     }
197 
198     std::ifstream logFile(realPath);
199     std::string line;
200     bool startWrite = false;
201     while (std::getline(logFile, line)) {
202         if (!logFile.good()) {
203             break;
204         }
205 
206         if (line.empty()) {
207             continue;
208         }
209 
210         if ((line.find("----- pid") != std::string::npos) &&
211             (line.find(pidStr) != std::string::npos)) {
212             startWrite = true;
213         }
214 
215         if ((line.find("----- end") != std::string::npos) &&
216             (line.find(pidStr) != std::string::npos)) {
217             FileUtil::SaveStringToFd(fd, line + "\n");
218             break;
219         }
220 
221         if (startWrite) {
222             FileUtil::SaveStringToFd(fd, line + "\n");
223         }
224     }
225 }
226 
WriteDfxLogToFile(int32_t fd)227 void WriteDfxLogToFile(int32_t fd)
228 {
229     std::string dfxStr = std::string("Generated by HiviewDFX@OpenHarmony\n");
230     std::string sepStr = std::string("================================================================\n");
231     FileUtil::SaveStringToFd(fd, dfxStr);
232     FileUtil::SaveStringToFd(fd, sepStr);
233 }
234 
WriteFaultLogToFile(int32_t fd,int32_t logType,std::map<std::string,std::string> sections)235 void WriteFaultLogToFile(int32_t fd, int32_t logType, std::map<std::string, std::string> sections)
236 {
237     auto seq = GetLogParseList(logType);
238     for (auto &item : seq) {
239         auto value = sections[item[LOG_MAP_KEY]];
240         if (!value.empty()) {
241             std::string keyStr = item[LOG_MAP_KEY];
242             if (keyStr.find(APPEND_ORIGIN_LOG[LOG_MAP_KEY]) != std::string::npos) {
243                 if (WriteLogToFile(fd, value)) {
244                     break;
245                 }
246             }
247 
248             // Does not require adding an identifier header for Summary section
249             if (keyStr.find(SUMMARY[LOG_MAP_KEY]) == std::string::npos) {
250                 FileUtil::SaveStringToFd(fd, item[LOG_MAP_VALUE]);
251             }
252 
253             if (value.back() != '\n') {
254                 value.append("\n");
255             }
256             FileUtil::SaveStringToFd(fd, value);
257         }
258     }
259 
260     if (!sections["KEYLOGFILE"].empty()) {
261         FileUtil::SaveStringToFd(fd, "Additional Logs:\n");
262         WriteStackTraceFromLog(fd, sections["PID"], sections["KEYLOGFILE"]);
263     }
264 }
265 
UpdateFaultLogInfoFromTempFile(FaultLogInfo & info)266 static void UpdateFaultLogInfoFromTempFile(FaultLogInfo& info)
267 {
268     if (!info.module.empty()) {
269         return;
270     }
271 
272     StringUtil::ConvertStringTo<int32_t>(info.sectionMap[MODULE_UID[LOG_MAP_KEY]], info.id);
273     info.module = info.sectionMap[PROCESS_NAME[LOG_MAP_KEY]];
274     info.reason = info.sectionMap[REASON[LOG_MAP_KEY]];
275     info.summary = info.sectionMap[KEY_THREAD_INFO[LOG_MAP_KEY]];
276     info.registers = info.sectionMap[KEY_THREAD_REGISTERS[LOG_MAP_KEY]];
277     info.otherThreadInfo = info.sectionMap[OTHER_THREAD_INFO[LOG_MAP_KEY]];
278     size_t removeStartPos = info.summary.find("Tid:");
279     size_t removeEndPos = info.summary.find("Name:");
280     if (removeStartPos != std::string::npos && removeEndPos != std::string::npos) {
281         auto iterator = info.summary.begin() + removeEndPos;
282         while (iterator != info.summary.end() && *iterator != '\n') {
283             if (isdigit(*iterator)) {
284                 iterator = info.summary.erase(iterator);
285             } else {
286                 iterator++;
287             }
288         }
289         info.summary.replace(removeStartPos, removeEndPos - removeStartPos + 1, "Thread n");
290     }
291 }
292 
ParseFaultLogInfoFromFile(const std::string & path,bool isTempFile)293 FaultLogInfo ParseFaultLogInfoFromFile(const std::string &path, bool isTempFile)
294 {
295     auto fileName = FileUtil::ExtractFileName(path);
296     FaultLogInfo info;
297     if (!isTempFile) {
298         info = ExtractInfoFromFileName(fileName);
299     } else {
300         info = ExtractInfoFromTempFile(fileName);
301     }
302 
303     auto parseList = GetLogParseList(info.faultLogType);
304     std::ifstream logFile(path);
305     std::string line;
306     std::string multline;
307     std::string multlineName;
308     while (std::getline(logFile, line)) {
309         if (!logFile.good()) {
310             break;
311         }
312 
313         if (line.empty()) {
314             continue;
315         }
316 
317         if (ParseFaultLogLine(parseList, line, multline, multlineName, info)) {
318             multline.append(line).append("\n");
319         } else {
320             multline.clear();
321         }
322     }
323 
324     if (!multline.empty() && !multlineName.empty()) {
325         info.sectionMap[multlineName] = multline;
326     }
327     UpdateFaultLogInfoFromTempFile(info);
328     return info;
329 }
330 
WriteLogToFile(int32_t fd,const std::string & path)331 bool WriteLogToFile(int32_t fd, const std::string& path)
332 {
333     if ((fd < 0) || path.empty()) {
334         return false;
335     }
336 
337     std::string line;
338     std::ifstream logFile(path);
339     bool hasFindFirstLine = false;
340     while (std::getline(logFile, line)) {
341         if (logFile.eof()) {
342             break;
343         }
344         if (!logFile.good()) {
345             return false;
346         }
347         if (!hasFindFirstLine && line.find("Build info:") != std::string::npos) {
348             continue;
349         }
350         hasFindFirstLine = true;
351         FileUtil::SaveStringToFd(fd, line);
352         FileUtil::SaveStringToFd(fd, "\n");
353     }
354     return true;
355 }
356 
IsFaultLogLimit()357 bool IsFaultLogLimit()
358 {
359     std::string isDev = OHOS::system::GetParameter("const.security.developermode.state", "");
360     std::string isBeta = OHOS::system::GetParameter("const.logsystem.versiontype", "");
361     if ((isDev == "true") || (isBeta == "beta")) {
362         return false;
363     }
364     return true;
365 }
366 
LimitCppCrashLog(int32_t fd,int32_t logType)367 void LimitCppCrashLog(int32_t fd, int32_t logType)
368 {
369     if ((fd < 0) || (logType != FaultLogType::CPP_CRASH) || !IsFaultLogLimit()) {
370         return;
371     }
372     // The CppCrash file size is limited to 4 MB before reporting CppCrash to AppEvent
373     constexpr int maxLogSize = 4 * 1024 * 1024;
374     off_t endPos = lseek(fd, 0, SEEK_END);
375     if ((endPos == -1) || (endPos <= maxLogSize)) {
376         return;
377     }
378 
379     if (ftruncate(fd, maxLogSize) < 0) {
380         return;
381     }
382     endPos = lseek(fd, maxLogSize, SEEK_SET);
383     if (endPos != -1) {
384         FileUtil::SaveStringToFd(fd, "\ncpp crash log is limit output.\n");
385     }
386 }
387 } // namespace FaultLogger
388 } // namespace HiviewDFX
389 } // namespace OHOS
390