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