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